WFD: Add Wi-Fi Display support
This commit adds control interface commands and internal storage of Wi-Fi Display related configuration. In addition, WFD IE is now added to various P2P frames, Probe Request/Response, and (Re)Association Request/Response frames. WFD subelements from peers are stored in the P2P peer table. Following control interface commands are now available: SET wifi_display <0/1> GET wifi_display WFD_SUBELEM_SET <subelem> [hexdump of length+body] WFD_SUBELEM_GET <subelem> Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
eb7719ff22
commit
9675ce354a
19 changed files with 1020 additions and 23 deletions
|
@ -12,6 +12,7 @@
|
||||||
#include "drivers/driver.h"
|
#include "drivers/driver.h"
|
||||||
#include "common/ieee802_11_defs.h"
|
#include "common/ieee802_11_defs.h"
|
||||||
#include "wps/wps.h"
|
#include "wps/wps.h"
|
||||||
|
#include "p2p/p2p.h"
|
||||||
#include "hostapd.h"
|
#include "hostapd.h"
|
||||||
#include "ieee802_11.h"
|
#include "ieee802_11.h"
|
||||||
#include "sta_info.h"
|
#include "sta_info.h"
|
||||||
|
@ -148,6 +149,16 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_P2P_MANAGER */
|
#endif /* CONFIG_P2P_MANAGER */
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (hapd->p2p_group) {
|
||||||
|
struct wpabuf *a;
|
||||||
|
a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
|
||||||
|
if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
|
||||||
|
wpabuf_put_buf(assocresp, a);
|
||||||
|
wpabuf_free(a);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
#ifdef CONFIG_HS20
|
#ifdef CONFIG_HS20
|
||||||
pos = buf;
|
pos = buf;
|
||||||
pos = hostapd_eid_hs20_indication(hapd, pos);
|
pos = hostapd_eid_hs20_indication(hapd, pos);
|
||||||
|
|
|
@ -97,6 +97,11 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
|
||||||
elems->p2p = pos;
|
elems->p2p = pos;
|
||||||
elems->p2p_len = elen;
|
elems->p2p_len = elen;
|
||||||
break;
|
break;
|
||||||
|
case WFD_OUI_TYPE:
|
||||||
|
/* Wi-Fi Alliance - WFD IE */
|
||||||
|
elems->wfd = pos;
|
||||||
|
elems->wfd_len = elen;
|
||||||
|
break;
|
||||||
case HS20_INDICATION_OUI_TYPE:
|
case HS20_INDICATION_OUI_TYPE:
|
||||||
/* Hotspot 2.0 */
|
/* Hotspot 2.0 */
|
||||||
elems->hs20 = pos;
|
elems->hs20 = pos;
|
||||||
|
|
|
@ -37,6 +37,7 @@ struct ieee802_11_elems {
|
||||||
const u8 *vht_operation;
|
const u8 *vht_operation;
|
||||||
const u8 *vendor_ht_cap;
|
const u8 *vendor_ht_cap;
|
||||||
const u8 *p2p;
|
const u8 *p2p;
|
||||||
|
const u8 *wfd;
|
||||||
const u8 *link_id;
|
const u8 *link_id;
|
||||||
const u8 *interworking;
|
const u8 *interworking;
|
||||||
const u8 *hs20;
|
const u8 *hs20;
|
||||||
|
@ -69,6 +70,7 @@ struct ieee802_11_elems {
|
||||||
u8 vht_operation_len;
|
u8 vht_operation_len;
|
||||||
u8 vendor_ht_cap_len;
|
u8 vendor_ht_cap_len;
|
||||||
u8 p2p_len;
|
u8 p2p_len;
|
||||||
|
u8 wfd_len;
|
||||||
u8 interworking_len;
|
u8 interworking_len;
|
||||||
u8 hs20_len;
|
u8 hs20_len;
|
||||||
u8 ext_capab_len;
|
u8 ext_capab_len;
|
||||||
|
|
|
@ -701,6 +701,8 @@ struct ieee80211_vht_operation {
|
||||||
#define WPS_IE_VENDOR_TYPE 0x0050f204
|
#define WPS_IE_VENDOR_TYPE 0x0050f204
|
||||||
#define OUI_WFA 0x506f9a
|
#define OUI_WFA 0x506f9a
|
||||||
#define P2P_IE_VENDOR_TYPE 0x506f9a09
|
#define P2P_IE_VENDOR_TYPE 0x506f9a09
|
||||||
|
#define WFD_IE_VENDOR_TYPE 0x506f9a0a
|
||||||
|
#define WFD_OUI_TYPE 10
|
||||||
#define HS20_IE_VENDOR_TYPE 0x506f9a10
|
#define HS20_IE_VENDOR_TYPE 0x506f9a10
|
||||||
|
|
||||||
#define WMM_OUI_TYPE 2
|
#define WMM_OUI_TYPE 2
|
||||||
|
@ -934,6 +936,20 @@ enum p2p_sd_status {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum wifi_display_subelem {
|
||||||
|
WFD_SUBELEM_DEVICE_INFO = 0,
|
||||||
|
WFD_SUBELEM_ASSOCIATED_BSSID = 1,
|
||||||
|
WFD_SUBELEM_AUDIO_FORMATS = 2,
|
||||||
|
WFD_SUBELEM_VIDEO_FORMATS = 3,
|
||||||
|
WFD_SUBELEM_3D_VIDEO_FORMATS = 4,
|
||||||
|
WFD_SUBELEM_CONTENT_PROTECTION = 5,
|
||||||
|
WFD_SUBELEM_COUPLED_SINK = 6,
|
||||||
|
WFD_SUBELEM_EXT_CAPAB = 7,
|
||||||
|
WFD_SUBELEM_LOCAL_IP_ADDRESS = 8,
|
||||||
|
WFD_SUBELEM_SESSION_INFO = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
|
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
|
||||||
|
|
||||||
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
|
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
|
||||||
|
|
218
src/p2p/p2p.c
218
src/p2p/p2p.c
|
@ -680,6 +680,11 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, int level,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msg.wfd_subelems) {
|
||||||
|
wpabuf_free(dev->info.wfd_subelems);
|
||||||
|
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
|
||||||
|
}
|
||||||
|
|
||||||
if (scan_res) {
|
if (scan_res) {
|
||||||
p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
|
p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
|
||||||
msg.group_info, msg.group_info_len);
|
msg.group_info, msg.group_info_len);
|
||||||
|
@ -737,6 +742,8 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev)
|
||||||
dev->info.wps_vendor_ext[i] = NULL;
|
dev->info.wps_vendor_ext[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wpabuf_free(dev->info.wfd_subelems);
|
||||||
|
|
||||||
os_free(dev);
|
os_free(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1375,6 +1382,11 @@ void p2p_add_dev_info(struct p2p_data *p2p, const u8 *addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (msg->wfd_subelems) {
|
||||||
|
wpabuf_free(dev->info.wfd_subelems);
|
||||||
|
dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
|
||||||
|
}
|
||||||
|
|
||||||
if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
|
if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
|
||||||
dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
|
dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
|
||||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
|
@ -1712,6 +1724,11 @@ static void p2p_add_dev_from_probe_req(struct p2p_data *p2p, const u8 *addr,
|
||||||
|
|
||||||
p2p_copy_wps_info(dev, 1, &msg);
|
p2p_copy_wps_info(dev, 1, &msg);
|
||||||
|
|
||||||
|
if (msg.wfd_subelems) {
|
||||||
|
wpabuf_free(dev->info.wfd_subelems);
|
||||||
|
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
|
||||||
|
}
|
||||||
|
|
||||||
p2p_parse_free(&msg);
|
p2p_parse_free(&msg);
|
||||||
|
|
||||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
|
@ -1810,8 +1827,14 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
u8 *len;
|
u8 *len;
|
||||||
int pw_id = -1;
|
int pw_id = -1;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
buf = wpabuf_alloc(1000);
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_probe_resp)
|
||||||
|
extra = wpabuf_len(p2p->wfd_ie_probe_resp);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(1000 + extra);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1822,6 +1845,11 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
|
||||||
|
|
||||||
p2p_build_wps_ie(p2p, buf, pw_id, 1);
|
p2p_build_wps_ie(p2p, buf, pw_id, 1);
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_probe_resp)
|
||||||
|
wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
/* P2P IE */
|
/* P2P IE */
|
||||||
len = p2p_buf_add_ie_hdr(buf);
|
len = p2p_buf_add_ie_hdr(buf);
|
||||||
p2p_buf_add_capability(buf, p2p->dev_capab &
|
p2p_buf_add_capability(buf, p2p->dev_capab &
|
||||||
|
@ -2106,20 +2134,31 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf,
|
||||||
struct p2p_device *peer;
|
struct p2p_device *peer;
|
||||||
size_t tmplen;
|
size_t tmplen;
|
||||||
int res;
|
int res;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
if (!p2p_group)
|
if (!p2p_group)
|
||||||
return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie);
|
return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie);
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_assoc_req)
|
||||||
|
extra = wpabuf_len(p2p->wfd_ie_assoc_req);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (Re)Association Request - P2P IE
|
* (Re)Association Request - P2P IE
|
||||||
* P2P Capability attribute (shall be present)
|
* P2P Capability attribute (shall be present)
|
||||||
* Extended Listen Timing (may be present)
|
* Extended Listen Timing (may be present)
|
||||||
* P2P Device Info attribute (shall be present)
|
* P2P Device Info attribute (shall be present)
|
||||||
*/
|
*/
|
||||||
tmp = wpabuf_alloc(200);
|
tmp = wpabuf_alloc(200 + extra);
|
||||||
if (tmp == NULL)
|
if (tmp == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_assoc_req)
|
||||||
|
wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
|
peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
|
||||||
|
|
||||||
lpos = p2p_buf_add_ie_hdr(tmp);
|
lpos = p2p_buf_add_ie_hdr(tmp);
|
||||||
|
@ -2303,6 +2342,20 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
|
||||||
|
|
||||||
void p2p_deinit(struct p2p_data *p2p)
|
void p2p_deinit(struct p2p_data *p2p)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
wpabuf_free(p2p->wfd_ie_beacon);
|
||||||
|
wpabuf_free(p2p->wfd_ie_probe_req);
|
||||||
|
wpabuf_free(p2p->wfd_ie_probe_resp);
|
||||||
|
wpabuf_free(p2p->wfd_ie_assoc_req);
|
||||||
|
wpabuf_free(p2p->wfd_ie_invitation);
|
||||||
|
wpabuf_free(p2p->wfd_ie_prov_disc_req);
|
||||||
|
wpabuf_free(p2p->wfd_ie_prov_disc_resp);
|
||||||
|
wpabuf_free(p2p->wfd_ie_go_neg);
|
||||||
|
wpabuf_free(p2p->wfd_dev_info);
|
||||||
|
wpabuf_free(p2p->wfd_assoc_bssid);
|
||||||
|
wpabuf_free(p2p->wfd_coupled_sink_info);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL);
|
eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL);
|
||||||
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
|
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
|
||||||
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
|
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
|
||||||
|
@ -2675,7 +2728,14 @@ void p2p_scan_res_handled(struct p2p_data *p2p)
|
||||||
|
|
||||||
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
|
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
|
||||||
{
|
{
|
||||||
u8 *len = p2p_buf_add_ie_hdr(ies);
|
u8 *len;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_probe_req)
|
||||||
|
wpabuf_put_buf(ies, p2p->wfd_ie_probe_req);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
len = p2p_buf_add_ie_hdr(ies);
|
||||||
p2p_buf_add_capability(ies, p2p->dev_capab &
|
p2p_buf_add_capability(ies, p2p->dev_capab &
|
||||||
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
|
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
|
||||||
if (dev_id)
|
if (dev_id)
|
||||||
|
@ -2694,7 +2754,14 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
|
||||||
|
|
||||||
size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
|
size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
|
||||||
{
|
{
|
||||||
return 100;
|
size_t len = 100;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p && p2p->wfd_ie_probe_req)
|
||||||
|
len += wpabuf_len(p2p->wfd_ie_probe_req);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3398,6 +3465,24 @@ int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
|
||||||
pos += res;
|
pos += res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (dev->info.wfd_subelems) {
|
||||||
|
res = os_snprintf(pos, end - pos, "wfd_subelems=");
|
||||||
|
if (res < 0 || res >= end - pos)
|
||||||
|
return pos - buf;
|
||||||
|
pos += res;
|
||||||
|
|
||||||
|
pos += wpa_snprintf_hex(pos, end - pos,
|
||||||
|
wpabuf_head(dev->info.wfd_subelems),
|
||||||
|
wpabuf_len(dev->info.wfd_subelems));
|
||||||
|
|
||||||
|
res = os_snprintf(pos, end - pos, "\n");
|
||||||
|
if (res < 0 || res >= end - pos)
|
||||||
|
return pos - buf;
|
||||||
|
pos += res;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
return pos - buf;
|
return pos - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4018,3 +4103,128 @@ void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay)
|
||||||
if (p2p && p2p->search_delay < delay)
|
if (p2p && p2p->search_delay < delay)
|
||||||
p2p->search_delay = delay;
|
p2p->search_delay = delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
|
||||||
|
static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
|
||||||
|
{
|
||||||
|
size_t g;
|
||||||
|
struct p2p_group *group;
|
||||||
|
|
||||||
|
for (g = 0; g < p2p->num_groups; g++) {
|
||||||
|
group = p2p->groups[g];
|
||||||
|
p2p_group_update_ies(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_ie_beacon);
|
||||||
|
p2p->wfd_ie_beacon = ie;
|
||||||
|
p2p_update_wfd_ie_groups(p2p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_ie_probe_req);
|
||||||
|
p2p->wfd_ie_probe_req = ie;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_ie_probe_resp);
|
||||||
|
p2p->wfd_ie_probe_resp = ie;
|
||||||
|
p2p_update_wfd_ie_groups(p2p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_ie_assoc_req);
|
||||||
|
p2p->wfd_ie_assoc_req = ie;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_ie_invitation);
|
||||||
|
p2p->wfd_ie_invitation = ie;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_ie_prov_disc_req);
|
||||||
|
p2p->wfd_ie_prov_disc_req = ie;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_ie_prov_disc_resp);
|
||||||
|
p2p->wfd_ie_prov_disc_resp = ie;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_ie_go_neg);
|
||||||
|
p2p->wfd_ie_go_neg = ie;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_dev_info);
|
||||||
|
if (elem) {
|
||||||
|
p2p->wfd_dev_info = wpabuf_dup(elem);
|
||||||
|
if (p2p->wfd_dev_info == NULL)
|
||||||
|
return -1;
|
||||||
|
} else
|
||||||
|
p2p->wfd_dev_info = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_assoc_bssid);
|
||||||
|
if (elem) {
|
||||||
|
p2p->wfd_assoc_bssid = wpabuf_dup(elem);
|
||||||
|
if (p2p->wfd_assoc_bssid == NULL)
|
||||||
|
return -1;
|
||||||
|
} else
|
||||||
|
p2p->wfd_assoc_bssid = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
|
||||||
|
const struct wpabuf *elem)
|
||||||
|
{
|
||||||
|
wpabuf_free(p2p->wfd_coupled_sink_info);
|
||||||
|
if (elem) {
|
||||||
|
p2p->wfd_coupled_sink_info = wpabuf_dup(elem);
|
||||||
|
if (p2p->wfd_coupled_sink_info == NULL)
|
||||||
|
return -1;
|
||||||
|
} else
|
||||||
|
p2p->wfd_coupled_sink_info = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
|
@ -211,6 +211,11 @@ struct p2p_peer_info {
|
||||||
size_t wps_sec_dev_type_list_len;
|
size_t wps_sec_dev_type_list_len;
|
||||||
|
|
||||||
struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
|
struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wfd_subelems - Wi-Fi Display subelements from WFD IE(s)
|
||||||
|
*/
|
||||||
|
struct wpabuf *wfd_subelems;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum p2p_prov_disc_status {
|
enum p2p_prov_disc_status {
|
||||||
|
@ -1710,4 +1715,18 @@ void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
|
||||||
|
|
||||||
void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay);
|
void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay);
|
||||||
|
|
||||||
|
int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie);
|
||||||
|
int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie);
|
||||||
|
int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie);
|
||||||
|
int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie);
|
||||||
|
int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie);
|
||||||
|
int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie);
|
||||||
|
int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie);
|
||||||
|
int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie);
|
||||||
|
int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem);
|
||||||
|
int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem);
|
||||||
|
int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
|
||||||
|
const struct wpabuf *elem);
|
||||||
|
struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
|
||||||
|
|
||||||
#endif /* P2P_H */
|
#endif /* P2P_H */
|
||||||
|
|
|
@ -134,8 +134,14 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
u8 *len;
|
u8 *len;
|
||||||
u8 group_capab;
|
u8 group_capab;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
buf = wpabuf_alloc(1000);
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_go_neg)
|
||||||
|
extra = wpabuf_len(p2p->wfd_ie_go_neg);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(1000 + extra);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -177,6 +183,11 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
|
||||||
/* WPS IE with Device Password ID attribute */
|
/* WPS IE with Device Password ID attribute */
|
||||||
p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
|
p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_go_neg)
|
||||||
|
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,10 +257,17 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
u8 *len;
|
u8 *len;
|
||||||
u8 group_capab;
|
u8 group_capab;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
"P2P: Building GO Negotiation Response");
|
"P2P: Building GO Negotiation Response");
|
||||||
buf = wpabuf_alloc(1000);
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_go_neg)
|
||||||
|
extra = wpabuf_len(p2p->wfd_ie_go_neg);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(1000 + extra);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -308,6 +326,12 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
|
||||||
p2p_wps_method_pw_id(peer ? peer->wps_method :
|
p2p_wps_method_pw_id(peer ? peer->wps_method :
|
||||||
WPS_NOT_READY), 0);
|
WPS_NOT_READY), 0);
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_go_neg)
|
||||||
|
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,10 +734,17 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
|
||||||
u8 *len;
|
u8 *len;
|
||||||
struct p2p_channels res;
|
struct p2p_channels res;
|
||||||
u8 group_capab;
|
u8 group_capab;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
|
||||||
"P2P: Building GO Negotiation Confirm");
|
"P2P: Building GO Negotiation Confirm");
|
||||||
buf = wpabuf_alloc(1000);
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_go_neg)
|
||||||
|
extra = wpabuf_len(p2p->wfd_ie_go_neg);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(1000 + extra);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -752,6 +783,11 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p,
|
||||||
}
|
}
|
||||||
p2p_buf_update_ie_hdr(buf, len);
|
p2p_buf_update_ie_hdr(buf, len);
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_go_neg)
|
||||||
|
wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ struct p2p_group_member {
|
||||||
u8 addr[ETH_ALEN]; /* P2P Interface Address */
|
u8 addr[ETH_ALEN]; /* P2P Interface Address */
|
||||||
u8 dev_addr[ETH_ALEN]; /* P2P Device Address */
|
u8 dev_addr[ETH_ALEN]; /* P2P Device Address */
|
||||||
struct wpabuf *p2p_ie;
|
struct wpabuf *p2p_ie;
|
||||||
|
struct wpabuf *wfd_ie;
|
||||||
struct wpabuf *client_info;
|
struct wpabuf *client_info;
|
||||||
u8 dev_capab;
|
u8 dev_capab;
|
||||||
};
|
};
|
||||||
|
@ -37,12 +38,10 @@ struct p2p_group {
|
||||||
int group_formation;
|
int group_formation;
|
||||||
int beacon_update;
|
int beacon_update;
|
||||||
struct wpabuf *noa;
|
struct wpabuf *noa;
|
||||||
|
struct wpabuf *wfd_ie;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void p2p_group_update_ies(struct p2p_group *group);
|
|
||||||
|
|
||||||
|
|
||||||
struct p2p_group * p2p_group_init(struct p2p_data *p2p,
|
struct p2p_group * p2p_group_init(struct p2p_data *p2p,
|
||||||
struct p2p_group_config *config)
|
struct p2p_group_config *config)
|
||||||
{
|
{
|
||||||
|
@ -74,6 +73,7 @@ struct p2p_group * p2p_group_init(struct p2p_data *p2p,
|
||||||
|
|
||||||
static void p2p_group_free_member(struct p2p_group_member *m)
|
static void p2p_group_free_member(struct p2p_group_member *m)
|
||||||
{
|
{
|
||||||
|
wpabuf_free(m->wfd_ie);
|
||||||
wpabuf_free(m->p2p_ie);
|
wpabuf_free(m->p2p_ie);
|
||||||
wpabuf_free(m->client_info);
|
wpabuf_free(m->client_info);
|
||||||
os_free(m);
|
os_free(m);
|
||||||
|
@ -118,6 +118,7 @@ void p2p_group_deinit(struct p2p_group *group)
|
||||||
p2p_group_free_members(group);
|
p2p_group_free_members(group);
|
||||||
os_free(group->cfg);
|
os_free(group->cfg);
|
||||||
wpabuf_free(group->noa);
|
wpabuf_free(group->noa);
|
||||||
|
wpabuf_free(group->wfd_ie);
|
||||||
os_free(group);
|
os_free(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,11 +173,22 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
|
||||||
{
|
{
|
||||||
struct wpabuf *ie;
|
struct wpabuf *ie;
|
||||||
u8 *len;
|
u8 *len;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
ie = wpabuf_alloc(257);
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (group->p2p->wfd_ie_beacon)
|
||||||
|
extra = wpabuf_len(group->p2p->wfd_ie_beacon);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
ie = wpabuf_alloc(257 + extra);
|
||||||
if (ie == NULL)
|
if (ie == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (group->p2p->wfd_ie_beacon)
|
||||||
|
wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
len = p2p_buf_add_ie_hdr(ie);
|
len = p2p_buf_add_ie_hdr(ie);
|
||||||
p2p_group_add_common_ies(group, ie);
|
p2p_group_add_common_ies(group, ie);
|
||||||
p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
|
p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
|
||||||
|
@ -187,17 +199,193 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
|
||||||
|
struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g)
|
||||||
|
{
|
||||||
|
return g->wfd_ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct wpabuf * wifi_display_encaps(struct wpabuf *subelems)
|
||||||
|
{
|
||||||
|
struct wpabuf *ie;
|
||||||
|
const u8 *pos, *end;
|
||||||
|
|
||||||
|
if (subelems == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ie = wpabuf_alloc(wpabuf_len(subelems) + 100);
|
||||||
|
if (ie == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pos = wpabuf_head(subelems);
|
||||||
|
end = pos + wpabuf_len(subelems);
|
||||||
|
|
||||||
|
while (end > pos) {
|
||||||
|
size_t frag_len = end - pos;
|
||||||
|
if (frag_len > 251)
|
||||||
|
frag_len = 251;
|
||||||
|
wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
|
||||||
|
wpabuf_put_u8(ie, 4 + frag_len);
|
||||||
|
wpabuf_put_be32(ie, WFD_IE_VENDOR_TYPE);
|
||||||
|
wpabuf_put_data(ie, pos, frag_len);
|
||||||
|
pos += frag_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
|
||||||
|
struct p2p_group_member *m)
|
||||||
|
{
|
||||||
|
const u8 *pos, *end;
|
||||||
|
const u8 *dev_info = NULL;
|
||||||
|
const u8 *assoc_bssid = NULL;
|
||||||
|
const u8 *coupled_sink = NULL;
|
||||||
|
u8 zero_addr[ETH_ALEN];
|
||||||
|
|
||||||
|
if (m->wfd_ie == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
os_memset(zero_addr, 0, ETH_ALEN);
|
||||||
|
pos = wpabuf_head_u8(m->wfd_ie);
|
||||||
|
end = pos + wpabuf_len(m->wfd_ie);
|
||||||
|
while (pos + 1 < end) {
|
||||||
|
u8 id;
|
||||||
|
u16 len;
|
||||||
|
|
||||||
|
id = *pos++;
|
||||||
|
len = WPA_GET_BE16(pos);
|
||||||
|
pos += 2;
|
||||||
|
if (pos + len > end)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case WFD_SUBELEM_DEVICE_INFO:
|
||||||
|
if (len < 6)
|
||||||
|
break;
|
||||||
|
dev_info = pos;
|
||||||
|
break;
|
||||||
|
case WFD_SUBELEM_ASSOCIATED_BSSID:
|
||||||
|
if (len < ETH_ALEN)
|
||||||
|
break;
|
||||||
|
assoc_bssid = pos;
|
||||||
|
break;
|
||||||
|
case WFD_SUBELEM_COUPLED_SINK:
|
||||||
|
if (len < 1 + ETH_ALEN)
|
||||||
|
break;
|
||||||
|
coupled_sink = pos;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_info == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
wpabuf_put_u8(buf, 23);
|
||||||
|
wpabuf_put_data(buf, m->dev_addr, ETH_ALEN);
|
||||||
|
if (assoc_bssid)
|
||||||
|
wpabuf_put_data(buf, assoc_bssid, ETH_ALEN);
|
||||||
|
else
|
||||||
|
wpabuf_put_data(buf, zero_addr, ETH_ALEN);
|
||||||
|
wpabuf_put_data(buf, dev_info, 2); /* WFD Device Info */
|
||||||
|
wpabuf_put_data(buf, dev_info + 4, 2); /* WFD Device Max Throughput */
|
||||||
|
if (coupled_sink) {
|
||||||
|
wpabuf_put_data(buf, coupled_sink, 1 + ETH_ALEN);
|
||||||
|
} else {
|
||||||
|
wpabuf_put_u8(buf, 0);
|
||||||
|
wpabuf_put_data(buf, zero_addr, ETH_ALEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct wpabuf *
|
||||||
|
wifi_display_build_go_ie(struct p2p_group *group)
|
||||||
|
{
|
||||||
|
struct wpabuf *wfd_subelems, *wfd_ie;
|
||||||
|
struct p2p_group_member *m;
|
||||||
|
u8 *len;
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
if (!group->p2p->wfd_ie_probe_resp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
wfd_subelems = wpabuf_alloc(wpabuf_len(group->p2p->wfd_ie_probe_resp) +
|
||||||
|
group->num_members * 24 + 100);
|
||||||
|
if (wfd_subelems == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (group->p2p->wfd_dev_info)
|
||||||
|
wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info);
|
||||||
|
if (group->p2p->wfd_assoc_bssid)
|
||||||
|
wpabuf_put_buf(wfd_subelems,
|
||||||
|
group->p2p->wfd_assoc_bssid);
|
||||||
|
if (group->p2p->wfd_coupled_sink_info)
|
||||||
|
wpabuf_put_buf(wfd_subelems,
|
||||||
|
group->p2p->wfd_coupled_sink_info);
|
||||||
|
|
||||||
|
/* Build WFD Session Info */
|
||||||
|
wpabuf_put_u8(wfd_subelems, WFD_SUBELEM_SESSION_INFO);
|
||||||
|
len = wpabuf_put(wfd_subelems, 2);
|
||||||
|
m = group->members;
|
||||||
|
while (m) {
|
||||||
|
if (wifi_display_add_dev_info_descr(wfd_subelems, m))
|
||||||
|
count++;
|
||||||
|
m = m->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0) {
|
||||||
|
/* No Wi-Fi Display clients - do not include subelement */
|
||||||
|
wfd_subelems->used -= 3;
|
||||||
|
} else {
|
||||||
|
WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len -
|
||||||
|
2);
|
||||||
|
wpa_printf(MSG_DEBUG, "WFD: WFD Session Info: %u descriptors",
|
||||||
|
count);
|
||||||
|
}
|
||||||
|
|
||||||
|
wfd_ie = wifi_display_encaps(wfd_subelems);
|
||||||
|
wpabuf_free(wfd_subelems);
|
||||||
|
|
||||||
|
return wfd_ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wifi_display_group_update(struct p2p_group *group)
|
||||||
|
{
|
||||||
|
wpabuf_free(group->wfd_ie);
|
||||||
|
group->wfd_ie = wifi_display_build_go_ie(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
|
||||||
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
|
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
|
||||||
{
|
{
|
||||||
u8 *group_info;
|
u8 *group_info;
|
||||||
struct wpabuf *ie;
|
struct wpabuf *ie;
|
||||||
struct p2p_group_member *m;
|
struct p2p_group_member *m;
|
||||||
u8 *len;
|
u8 *len;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
ie = wpabuf_alloc(257);
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (group->wfd_ie)
|
||||||
|
extra += wpabuf_len(group->wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
ie = wpabuf_alloc(257 + extra);
|
||||||
if (ie == NULL)
|
if (ie == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (group->wfd_ie)
|
||||||
|
wpabuf_put_buf(ie, group->wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
len = p2p_buf_add_ie_hdr(ie);
|
len = p2p_buf_add_ie_hdr(ie);
|
||||||
|
|
||||||
p2p_group_add_common_ies(group, ie);
|
p2p_group_add_common_ies(group, ie);
|
||||||
|
@ -216,15 +404,20 @@ static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
|
||||||
(u8 *) wpabuf_put(ie, 0) - group_info - 3);
|
(u8 *) wpabuf_put(ie, 0) - group_info - 3);
|
||||||
|
|
||||||
p2p_buf_update_ie_hdr(ie, len);
|
p2p_buf_update_ie_hdr(ie, len);
|
||||||
|
|
||||||
return ie;
|
return ie;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void p2p_group_update_ies(struct p2p_group *group)
|
void p2p_group_update_ies(struct p2p_group *group)
|
||||||
{
|
{
|
||||||
struct wpabuf *beacon_ie;
|
struct wpabuf *beacon_ie;
|
||||||
struct wpabuf *probe_resp_ie;
|
struct wpabuf *probe_resp_ie;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
wifi_display_group_update(group);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
probe_resp_ie = p2p_group_build_probe_resp_ie(group);
|
probe_resp_ie = p2p_group_build_probe_resp_ie(group);
|
||||||
if (probe_resp_ie == NULL)
|
if (probe_resp_ie == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -354,6 +547,9 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
|
||||||
&m->dev_capab,
|
&m->dev_capab,
|
||||||
m->dev_addr);
|
m->dev_addr);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
m->wfd_ie = ieee802_11_vendor_ie_concat(ie, len, WFD_IE_VENDOR_TYPE);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
p2p_group_remove_member(group, addr);
|
p2p_group_remove_member(group, addr);
|
||||||
|
|
||||||
|
@ -361,8 +557,9 @@ int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
|
||||||
group->members = m;
|
group->members = m;
|
||||||
group->num_members++;
|
group->num_members++;
|
||||||
wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
|
wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
|
||||||
" to group (p2p=%d client_info=%d); num_members=%u/%u",
|
" to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u",
|
||||||
MAC2STR(addr), m->p2p_ie ? 1 : 0, m->client_info ? 1 : 0,
|
MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0,
|
||||||
|
m->client_info ? 1 : 0,
|
||||||
group->num_members, group->cfg->max_clients);
|
group->num_members, group->cfg->max_clients);
|
||||||
if (group->num_members == group->cfg->max_clients)
|
if (group->num_members == group->cfg->max_clients)
|
||||||
group->beacon_update = 1;
|
group->beacon_update = 1;
|
||||||
|
@ -378,6 +575,12 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
|
||||||
{
|
{
|
||||||
struct wpabuf *resp;
|
struct wpabuf *resp;
|
||||||
u8 *rlen;
|
u8 *rlen;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (group->wfd_ie)
|
||||||
|
extra = wpabuf_len(group->wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (Re)Association Response - P2P IE
|
* (Re)Association Response - P2P IE
|
||||||
|
@ -385,9 +588,15 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status)
|
||||||
* denied)
|
* denied)
|
||||||
* Extended Listen Timing (may be present)
|
* Extended Listen Timing (may be present)
|
||||||
*/
|
*/
|
||||||
resp = wpabuf_alloc(20);
|
resp = wpabuf_alloc(20 + extra);
|
||||||
if (resp == NULL)
|
if (resp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (group->wfd_ie)
|
||||||
|
wpabuf_put_buf(resp, group->wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
rlen = p2p_buf_add_ie_hdr(resp);
|
rlen = p2p_buf_add_ie_hdr(resp);
|
||||||
if (status != P2P_SC_SUCCESS)
|
if (status != P2P_SC_SUCCESS)
|
||||||
p2p_buf_add_status(resp, status);
|
p2p_buf_add_status(resp, status);
|
||||||
|
|
|
@ -436,6 +436,20 @@ struct p2p_data {
|
||||||
/* Extra delay in milliseconds between search iterations */
|
/* Extra delay in milliseconds between search iterations */
|
||||||
unsigned int search_delay;
|
unsigned int search_delay;
|
||||||
int in_search_delay;
|
int in_search_delay;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
struct wpabuf *wfd_ie_beacon;
|
||||||
|
struct wpabuf *wfd_ie_probe_req;
|
||||||
|
struct wpabuf *wfd_ie_probe_resp;
|
||||||
|
struct wpabuf *wfd_ie_assoc_req;
|
||||||
|
struct wpabuf *wfd_ie_invitation;
|
||||||
|
struct wpabuf *wfd_ie_prov_disc_req;
|
||||||
|
struct wpabuf *wfd_ie_prov_disc_resp;
|
||||||
|
struct wpabuf *wfd_ie_go_neg;
|
||||||
|
struct wpabuf *wfd_dev_info;
|
||||||
|
struct wpabuf *wfd_assoc_bssid;
|
||||||
|
struct wpabuf *wfd_coupled_sink_info;
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -444,6 +458,7 @@ struct p2p_data {
|
||||||
struct p2p_message {
|
struct p2p_message {
|
||||||
struct wpabuf *p2p_attributes;
|
struct wpabuf *p2p_attributes;
|
||||||
struct wpabuf *wps_attributes;
|
struct wpabuf *wps_attributes;
|
||||||
|
struct wpabuf *wfd_subelems;
|
||||||
|
|
||||||
u8 dialog_token;
|
u8 dialog_token;
|
||||||
|
|
||||||
|
@ -564,6 +579,8 @@ u8 p2p_group_presence_req(struct p2p_group *group,
|
||||||
const u8 *noa, size_t noa_len);
|
const u8 *noa, size_t noa_len);
|
||||||
int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
|
int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
|
||||||
size_t group_id_len);
|
size_t group_id_len);
|
||||||
|
void p2p_group_update_ies(struct p2p_group *group);
|
||||||
|
struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g);
|
||||||
|
|
||||||
|
|
||||||
void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
|
void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
|
||||||
|
|
|
@ -21,8 +21,27 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
u8 *len;
|
u8 *len;
|
||||||
const u8 *dev_addr;
|
const u8 *dev_addr;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
buf = wpabuf_alloc(1000);
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
|
||||||
|
if (wfd_ie && p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < p2p->num_groups; i++) {
|
||||||
|
struct p2p_group *g = p2p->groups[i];
|
||||||
|
struct wpabuf *ie;
|
||||||
|
ie = p2p_group_get_wfd_ie(g);
|
||||||
|
if (ie) {
|
||||||
|
wfd_ie = ie;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wfd_ie)
|
||||||
|
extra = wpabuf_len(wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(1000 + extra);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -55,6 +74,11 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p,
|
||||||
p2p_buf_add_device_info(buf, p2p, peer);
|
p2p_buf_add_device_info(buf, p2p, peer);
|
||||||
p2p_buf_update_ie_hdr(buf, len);
|
p2p_buf_update_ie_hdr(buf, len);
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (wfd_ie)
|
||||||
|
wpabuf_put_buf(buf, wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,8 +92,30 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
|
||||||
{
|
{
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
u8 *len;
|
u8 *len;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
buf = wpabuf_alloc(1000);
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
|
||||||
|
if (wfd_ie && group_bssid) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < p2p->num_groups; i++) {
|
||||||
|
struct p2p_group *g = p2p->groups[i];
|
||||||
|
struct wpabuf *ie;
|
||||||
|
if (!p2p_group_is_group_id_match(g, group_bssid,
|
||||||
|
ETH_ALEN))
|
||||||
|
continue;
|
||||||
|
ie = p2p_group_get_wfd_ie(g);
|
||||||
|
if (ie) {
|
||||||
|
wfd_ie = ie;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wfd_ie)
|
||||||
|
extra = wpabuf_len(wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(1000 + extra);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -88,6 +134,11 @@ static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p,
|
||||||
p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
|
p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
|
||||||
p2p_buf_update_ie_hdr(buf, len);
|
p2p_buf_update_ie_hdr(buf, len);
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (wfd_ie)
|
||||||
|
wpabuf_put_buf(buf, wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -414,6 +414,13 @@ int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (elems.wfd) {
|
||||||
|
msg->wfd_subelems = ieee802_11_vendor_ie_concat(
|
||||||
|
data, len, WFD_IE_VENDOR_TYPE);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,6 +460,10 @@ void p2p_parse_free(struct p2p_message *msg)
|
||||||
msg->p2p_attributes = NULL;
|
msg->p2p_attributes = NULL;
|
||||||
wpabuf_free(msg->wps_attributes);
|
wpabuf_free(msg->wps_attributes);
|
||||||
msg->wps_attributes = NULL;
|
msg->wps_attributes = NULL;
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
wpabuf_free(msg->wfd_subelems);
|
||||||
|
msg->wfd_subelems = NULL;
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,8 +46,14 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
|
||||||
{
|
{
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
u8 *len;
|
u8 *len;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
buf = wpabuf_alloc(1000);
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_prov_disc_req)
|
||||||
|
extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(1000 + extra);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -66,17 +72,46 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
|
||||||
/* WPS IE with Config Methods attribute */
|
/* WPS IE with Config Methods attribute */
|
||||||
p2p_build_wps_ie_config_methods(buf, config_methods);
|
p2p_build_wps_ie_config_methods(buf, config_methods);
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (p2p->wfd_ie_prov_disc_req)
|
||||||
|
wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
|
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
|
||||||
u8 dialog_token,
|
u8 dialog_token,
|
||||||
u16 config_methods)
|
u16 config_methods,
|
||||||
|
const u8 *group_id,
|
||||||
|
size_t group_id_len)
|
||||||
{
|
{
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
|
size_t extra = 0;
|
||||||
|
|
||||||
buf = wpabuf_alloc(100);
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
|
||||||
|
if (wfd_ie && group_id) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < p2p->num_groups; i++) {
|
||||||
|
struct p2p_group *g = p2p->groups[i];
|
||||||
|
struct wpabuf *ie;
|
||||||
|
if (!p2p_group_is_group_id_match(g, group_id,
|
||||||
|
group_id_len))
|
||||||
|
continue;
|
||||||
|
ie = p2p_group_get_wfd_ie(g);
|
||||||
|
if (ie) {
|
||||||
|
wfd_ie = ie;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wfd_ie)
|
||||||
|
extra = wpabuf_len(wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
buf = wpabuf_alloc(100 + extra);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -85,6 +120,11 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
|
||||||
/* WPS IE with Config Methods attribute */
|
/* WPS IE with Config Methods attribute */
|
||||||
p2p_build_wps_ie_config_methods(buf, config_methods);
|
p2p_build_wps_ie_config_methods(buf, config_methods);
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (wfd_ie)
|
||||||
|
wpabuf_put_buf(buf, wfd_ie);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +157,9 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||||
"P2P: Provision Discovery Request add device "
|
"P2P: Provision Discovery Request add device "
|
||||||
"failed " MACSTR, MAC2STR(sa));
|
"failed " MACSTR, MAC2STR(sa));
|
||||||
}
|
}
|
||||||
|
} else if (msg.wfd_subelems) {
|
||||||
|
wpabuf_free(dev->info.wfd_subelems);
|
||||||
|
dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(msg.wps_config_methods &
|
if (!(msg.wps_config_methods &
|
||||||
|
@ -162,7 +205,8 @@ void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
|
||||||
|
|
||||||
out:
|
out:
|
||||||
resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
|
resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
|
||||||
reject ? 0 : msg.wps_config_methods);
|
reject ? 0 : msg.wps_config_methods,
|
||||||
|
msg.group_id, msg.group_id_len);
|
||||||
if (resp == NULL) {
|
if (resp == NULL) {
|
||||||
p2p_parse_free(&msg);
|
p2p_parse_free(&msg);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -237,6 +237,11 @@ CFLAGS += -DCONFIG_P2P_STRICT
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
CFLAGS += -DCONFIG_WIFI_DISPLAY
|
||||||
|
OBJS += wifi_display.o
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef CONFIG_HS20
|
ifdef CONFIG_HS20
|
||||||
OBJS += hs20_supplicant.o
|
OBJS += hs20_supplicant.o
|
||||||
CFLAGS += -DCONFIG_HS20
|
CFLAGS += -DCONFIG_HS20
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "p2p_supplicant.h"
|
#include "p2p_supplicant.h"
|
||||||
#include "p2p/p2p.h"
|
#include "p2p/p2p.h"
|
||||||
#include "hs20_supplicant.h"
|
#include "hs20_supplicant.h"
|
||||||
|
#include "wifi_display.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "bss.h"
|
#include "bss.h"
|
||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
|
@ -283,6 +284,10 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
} else if (os_strcasecmp(cmd, "ps") == 0) {
|
} else if (os_strcasecmp(cmd, "ps") == 0) {
|
||||||
ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
|
ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
|
||||||
|
wifi_display_enable(wpa_s->global, !!atoi(value));
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
|
} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
|
||||||
ret = set_bssid_filter(wpa_s, value);
|
ret = set_bssid_filter(wpa_s, value);
|
||||||
} else {
|
} else {
|
||||||
|
@ -310,6 +315,14 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
|
||||||
res = os_snprintf(buf, buflen, "%c%c",
|
res = os_snprintf(buf, buflen, "%c%c",
|
||||||
wpa_s->conf->country[0],
|
wpa_s->conf->country[0],
|
||||||
wpa_s->conf->country[1]);
|
wpa_s->conf->country[1]);
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
|
||||||
|
res = os_snprintf(buf, buflen, "%d",
|
||||||
|
wpa_s->global->wifi_display);
|
||||||
|
if (res < 0 || (unsigned int) res >= buflen)
|
||||||
|
return -1;
|
||||||
|
return res;
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res < 0 || (unsigned int) res >= buflen)
|
if (res < 0 || (unsigned int) res >= buflen)
|
||||||
|
@ -4555,6 +4568,14 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
|
||||||
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
|
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
|
||||||
|
if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
|
||||||
|
reply_len = -1;
|
||||||
|
} else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
|
||||||
|
reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
|
||||||
|
reply, reply_size);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
#ifdef CONFIG_INTERWORKING
|
#ifdef CONFIG_INTERWORKING
|
||||||
} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
|
} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
|
||||||
if (interworking_fetch_anqp(wpa_s) < 0)
|
if (interworking_fetch_anqp(wpa_s) < 0)
|
||||||
|
|
251
wpa_supplicant/wifi_display.c
Normal file
251
wpa_supplicant/wifi_display.c
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
/*
|
||||||
|
* wpa_supplicant - Wi-Fi Display
|
||||||
|
* Copyright (c) 2011, Atheros Communications, Inc.
|
||||||
|
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "p2p/p2p.h"
|
||||||
|
#include "common/ieee802_11_defs.h"
|
||||||
|
#include "wpa_supplicant_i.h"
|
||||||
|
#include "wifi_display.h"
|
||||||
|
|
||||||
|
|
||||||
|
int wifi_display_init(struct wpa_global *global)
|
||||||
|
{
|
||||||
|
global->wifi_display = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wifi_display_deinit(struct wpa_global *global)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
|
||||||
|
wpabuf_free(global->wfd_subelem[i]);
|
||||||
|
global->wfd_subelem[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wifi_display_update_wfd_ie(struct wpa_global *global)
|
||||||
|
{
|
||||||
|
struct wpabuf *ie, *buf;
|
||||||
|
size_t len, plen;
|
||||||
|
|
||||||
|
wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
|
||||||
|
|
||||||
|
if (!global->wifi_display) {
|
||||||
|
wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
|
||||||
|
"include WFD IE");
|
||||||
|
p2p_set_wfd_ie_beacon(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_ie_probe_req(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_ie_invitation(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_ie_go_neg(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_dev_info(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_assoc_bssid(global->p2p, NULL);
|
||||||
|
p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p2p_set_wfd_dev_info(global->p2p,
|
||||||
|
global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
|
||||||
|
p2p_set_wfd_assoc_bssid(
|
||||||
|
global->p2p,
|
||||||
|
global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
|
||||||
|
p2p_set_wfd_coupled_sink_info(
|
||||||
|
global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* WFD IE is included in number of management frames. Two different
|
||||||
|
* sets of subelements are included depending on the frame:
|
||||||
|
*
|
||||||
|
* Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
|
||||||
|
* Provision Discovery Req:
|
||||||
|
* WFD Device Info
|
||||||
|
* [Associated BSSID]
|
||||||
|
* [Coupled Sink Info]
|
||||||
|
*
|
||||||
|
* Probe Request:
|
||||||
|
* WFD Device Info
|
||||||
|
* [Associated BSSID]
|
||||||
|
* [Coupled Sink Info]
|
||||||
|
* [WFD Extended Capability]
|
||||||
|
*
|
||||||
|
* Probe Response:
|
||||||
|
* WFD Device Info
|
||||||
|
* [Associated BSSID]
|
||||||
|
* [Coupled Sink Info]
|
||||||
|
* [WFD Extended Capability]
|
||||||
|
* [WFD Session Info]
|
||||||
|
*
|
||||||
|
* (Re)Association Response, P2P Invitation Req/Resp,
|
||||||
|
* Provision Discovery Resp:
|
||||||
|
* WFD Device Info
|
||||||
|
* [Associated BSSID]
|
||||||
|
* [Coupled Sink Info]
|
||||||
|
* [WFD Session Info]
|
||||||
|
*/
|
||||||
|
len = 0;
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
|
||||||
|
len += wpabuf_len(global->wfd_subelem[
|
||||||
|
WFD_SUBELEM_DEVICE_INFO]);
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
|
||||||
|
len += wpabuf_len(global->wfd_subelem[
|
||||||
|
WFD_SUBELEM_ASSOCIATED_BSSID]);
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
|
||||||
|
len += wpabuf_len(global->wfd_subelem[
|
||||||
|
WFD_SUBELEM_COUPLED_SINK]);
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
|
||||||
|
len += wpabuf_len(global->wfd_subelem[
|
||||||
|
WFD_SUBELEM_SESSION_INFO]);
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
|
||||||
|
len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
|
||||||
|
buf = wpabuf_alloc(len);
|
||||||
|
if (buf == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
|
||||||
|
wpabuf_put_buf(buf,
|
||||||
|
global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
|
||||||
|
wpabuf_put_buf(buf, global->wfd_subelem[
|
||||||
|
WFD_SUBELEM_ASSOCIATED_BSSID]);
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
|
||||||
|
wpabuf_put_buf(buf,
|
||||||
|
global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
|
||||||
|
|
||||||
|
ie = wifi_display_encaps(buf);
|
||||||
|
wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
|
||||||
|
p2p_set_wfd_ie_beacon(global->p2p, ie);
|
||||||
|
|
||||||
|
ie = wifi_display_encaps(buf);
|
||||||
|
wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
|
||||||
|
ie);
|
||||||
|
p2p_set_wfd_ie_assoc_req(global->p2p, ie);
|
||||||
|
|
||||||
|
ie = wifi_display_encaps(buf);
|
||||||
|
wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
|
||||||
|
p2p_set_wfd_ie_go_neg(global->p2p, ie);
|
||||||
|
|
||||||
|
ie = wifi_display_encaps(buf);
|
||||||
|
wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
|
||||||
|
"Request", ie);
|
||||||
|
p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
|
||||||
|
|
||||||
|
plen = buf->used;
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
|
||||||
|
wpabuf_put_buf(buf,
|
||||||
|
global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
|
||||||
|
|
||||||
|
ie = wifi_display_encaps(buf);
|
||||||
|
wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
|
||||||
|
p2p_set_wfd_ie_probe_req(global->p2p, ie);
|
||||||
|
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
|
||||||
|
wpabuf_put_buf(buf,
|
||||||
|
global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
|
||||||
|
ie = wifi_display_encaps(buf);
|
||||||
|
wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
|
||||||
|
p2p_set_wfd_ie_probe_resp(global->p2p, ie);
|
||||||
|
|
||||||
|
/* Remove WFD Extended Capability from buffer */
|
||||||
|
buf->used = plen;
|
||||||
|
if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
|
||||||
|
wpabuf_put_buf(buf,
|
||||||
|
global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
|
||||||
|
|
||||||
|
ie = wifi_display_encaps(buf);
|
||||||
|
wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
|
||||||
|
p2p_set_wfd_ie_invitation(global->p2p, ie);
|
||||||
|
|
||||||
|
ie = wifi_display_encaps(buf);
|
||||||
|
wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
|
||||||
|
"Response", ie);
|
||||||
|
p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
|
||||||
|
|
||||||
|
wpabuf_free(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wifi_display_enable(struct wpa_global *global, int enabled)
|
||||||
|
{
|
||||||
|
wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
|
||||||
|
enabled ? "enabled" : "disabled");
|
||||||
|
global->wifi_display = enabled;
|
||||||
|
wifi_display_update_wfd_ie(global);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
|
||||||
|
{
|
||||||
|
char *pos;
|
||||||
|
int subelem;
|
||||||
|
size_t len;
|
||||||
|
struct wpabuf *e;
|
||||||
|
|
||||||
|
pos = os_strchr(cmd, ' ');
|
||||||
|
if (pos == NULL)
|
||||||
|
return -1;
|
||||||
|
*pos++ = '\0';
|
||||||
|
subelem = atoi(cmd);
|
||||||
|
if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
len = os_strlen(pos);
|
||||||
|
if (len & 1)
|
||||||
|
return -1;
|
||||||
|
len /= 2;
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
/* Clear subelement */
|
||||||
|
e = NULL;
|
||||||
|
wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
|
||||||
|
} else {
|
||||||
|
e = wpabuf_alloc(1 + len);
|
||||||
|
if (e == NULL)
|
||||||
|
return -1;
|
||||||
|
wpabuf_put_u8(e, subelem);
|
||||||
|
if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
|
||||||
|
wpabuf_free(e);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpabuf_free(global->wfd_subelem[subelem]);
|
||||||
|
global->wfd_subelem[subelem] = e;
|
||||||
|
wifi_display_update_wfd_ie(global);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
|
||||||
|
char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
int subelem;
|
||||||
|
|
||||||
|
subelem = atoi(cmd);
|
||||||
|
if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (global->wfd_subelem[subelem] == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return wpa_snprintf_hex(buf, buflen,
|
||||||
|
wpabuf_head_u8(global->wfd_subelem[subelem]) +
|
||||||
|
1,
|
||||||
|
wpabuf_len(global->wfd_subelem[subelem]) - 1);
|
||||||
|
}
|
20
wpa_supplicant/wifi_display.h
Normal file
20
wpa_supplicant/wifi_display.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* wpa_supplicant - Wi-Fi Display
|
||||||
|
* Copyright (c) 2011, Atheros Communications, Inc.
|
||||||
|
* Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
|
||||||
|
*
|
||||||
|
* This software may be distributed under the terms of the BSD license.
|
||||||
|
* See README for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WIFI_DISPLAY_H
|
||||||
|
#define WIFI_DISPLAY_H
|
||||||
|
|
||||||
|
int wifi_display_init(struct wpa_global *global);
|
||||||
|
void wifi_display_deinit(struct wpa_global *global);
|
||||||
|
void wifi_display_enable(struct wpa_global *global, int enabled);
|
||||||
|
int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
|
||||||
|
int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
|
||||||
|
char *buf, size_t buflen);
|
||||||
|
|
||||||
|
#endif /* WIFI_DISPLAY_H */
|
|
@ -2014,6 +2014,50 @@ static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
|
||||||
|
static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
char cmd[100];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (argc != 1 && argc != 2) {
|
||||||
|
printf("Invalid WFD_SUBELEM_SET command: needs one or two "
|
||||||
|
"arguments (subelem, hexdump)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
|
||||||
|
argv[0], argc > 1 ? argv[1] : "");
|
||||||
|
if (res < 0 || (size_t) res >= sizeof(cmd))
|
||||||
|
return -1;
|
||||||
|
cmd[sizeof(cmd) - 1] = '\0';
|
||||||
|
return wpa_ctrl_command(ctrl, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
char *argv[])
|
||||||
|
{
|
||||||
|
char cmd[100];
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (argc != 1) {
|
||||||
|
printf("Invalid WFD_SUBELEM_GET command: needs one "
|
||||||
|
"argument (subelem)\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
|
||||||
|
argv[0]);
|
||||||
|
if (res < 0 || (size_t) res >= sizeof(cmd))
|
||||||
|
return -1;
|
||||||
|
cmd[sizeof(cmd) - 1] = '\0';
|
||||||
|
return wpa_ctrl_command(ctrl, cmd);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_INTERWORKING
|
#ifdef CONFIG_INTERWORKING
|
||||||
static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
|
static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
|
||||||
|
@ -2521,7 +2565,14 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
|
||||||
cli_cmd_flag_none,
|
cli_cmd_flag_none,
|
||||||
"[<period> <interval>] = set extended listen timing" },
|
"[<period> <interval>] = set extended listen timing" },
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
{ "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
|
||||||
|
cli_cmd_flag_none,
|
||||||
|
"<subelem> [contents] = set Wi-Fi Display subelement" },
|
||||||
|
{ "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL,
|
||||||
|
cli_cmd_flag_none,
|
||||||
|
"<subelem> = get Wi-Fi Display subelement" },
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
#ifdef CONFIG_INTERWORKING
|
#ifdef CONFIG_INTERWORKING
|
||||||
{ "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
|
{ "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
|
||||||
"= fetch ANQP information for all APs" },
|
"= fetch ANQP information for all APs" },
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "gas_query.h"
|
#include "gas_query.h"
|
||||||
#include "ap.h"
|
#include "ap.h"
|
||||||
#include "p2p_supplicant.h"
|
#include "p2p_supplicant.h"
|
||||||
|
#include "wifi_display.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "bgscan.h"
|
#include "bgscan.h"
|
||||||
#include "autoscan.h"
|
#include "autoscan.h"
|
||||||
|
@ -3190,6 +3191,14 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
if (wifi_display_init(global) < 0) {
|
||||||
|
wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
|
||||||
|
wpa_supplicant_deinit(global);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
|
|
||||||
return global;
|
return global;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3241,6 +3250,9 @@ void wpa_supplicant_deinit(struct wpa_global *global)
|
||||||
if (global == NULL)
|
if (global == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
wifi_display_deinit(global);
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_P2P
|
||||||
wpas_p2p_deinit_global(global);
|
wpas_p2p_deinit_global(global);
|
||||||
#endif /* CONFIG_P2P */
|
#endif /* CONFIG_P2P */
|
||||||
|
|
|
@ -239,6 +239,12 @@ struct wpa_global {
|
||||||
WPA_CONC_PREF_STA,
|
WPA_CONC_PREF_STA,
|
||||||
WPA_CONC_PREF_P2P
|
WPA_CONC_PREF_P2P
|
||||||
} conc_pref;
|
} conc_pref;
|
||||||
|
|
||||||
|
#ifdef CONFIG_WIFI_DISPLAY
|
||||||
|
int wifi_display;
|
||||||
|
#define MAX_WFD_SUBELEMS 10
|
||||||
|
struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
|
||||||
|
#endif /* CONFIG_WIFI_DISPLAY */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue