161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/*
261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * wpa_supplicant - Wi-Fi Display
361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Copyright (c) 2011, Atheros Communications, Inc.
461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt *
661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * See README for more details.
861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */
961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "includes.h"
1161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "common.h"
1361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "p2p/p2p.h"
1461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "common/ieee802_11_defs.h"
1561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "wpa_supplicant_i.h"
1661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#include "wifi_display.h"
1761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
1904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt#define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
2004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
2104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
2261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint wifi_display_init(struct wpa_global *global)
2361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
2461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	global->wifi_display = 1;
2561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return 0;
2661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
2761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
2861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
2961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid wifi_display_deinit(struct wpa_global *global)
3061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
3161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int i;
3261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
3361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_free(global->wfd_subelem[i]);
3461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		global->wfd_subelem[i] = NULL;
3561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
3661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
3761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
3861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
39661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidtstruct wpabuf * wifi_display_get_wfd_ie(struct wpa_global *global)
40661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt{
41661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	struct wpabuf *ie;
42661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	size_t len;
43661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	int i;
44661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
45661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (global->p2p == NULL)
46661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		return NULL;
47661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
48661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	len = 0;
49661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
50661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		if (global->wfd_subelem[i])
51661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			len += wpabuf_len(global->wfd_subelem[i]);
52661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
53661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
54661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	ie = wpabuf_alloc(len);
55661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (ie == NULL)
56661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		return NULL;
57661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
58661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
59661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		if (global->wfd_subelem[i])
60661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			wpabuf_put_buf(ie, global->wfd_subelem[i]);
61661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
62661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
63661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	return ie;
64661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt}
65661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
66661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
6761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic int wifi_display_update_wfd_ie(struct wpa_global *global)
6861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
6961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct wpabuf *ie, *buf;
7061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	size_t len, plen;
7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
72ed003d2a93648e6201272d2fb8212cbc01085928Dmitry Shmidt	if (global->p2p == NULL)
73ed003d2a93648e6201272d2fb8212cbc01085928Dmitry Shmidt		return 0;
74ed003d2a93648e6201272d2fb8212cbc01085928Dmitry Shmidt
7561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!global->wifi_display) {
7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
7961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			   "include WFD IE");
8061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_ie_beacon(global->p2p, NULL);
8161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_ie_probe_req(global->p2p, NULL);
8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
8461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_ie_invitation(global->p2p, NULL);
8561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
8661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
8761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_ie_go_neg(global->p2p, NULL);
8861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_dev_info(global->p2p, NULL);
8961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_assoc_bssid(global->p2p, NULL);
9061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
9161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 0;
9261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
9361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
9461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_dev_info(global->p2p,
9561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			     global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
9661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_assoc_bssid(
9761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		global->p2p,
9861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
9961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_coupled_sink_info(
10061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
10161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
10261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/*
10361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * WFD IE is included in number of management frames. Two different
10461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * sets of subelements are included depending on the frame:
10561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 *
10661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
10761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * Provision Discovery Req:
10861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * WFD Device Info
10961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [Associated BSSID]
11061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [Coupled Sink Info]
11161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 *
11261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * Probe Request:
11361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * WFD Device Info
11461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [Associated BSSID]
11561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [Coupled Sink Info]
11661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [WFD Extended Capability]
11761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 *
11861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * Probe Response:
11961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * WFD Device Info
12061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [Associated BSSID]
12161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [Coupled Sink Info]
12261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [WFD Extended Capability]
12361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [WFD Session Info]
12461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 *
12561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * (Re)Association Response, P2P Invitation Req/Resp,
12661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * Provision Discovery Resp:
12761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * WFD Device Info
12861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [Associated BSSID]
12961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [Coupled Sink Info]
13061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * [WFD Session Info]
13161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 */
13261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	len = 0;
13361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		len += wpabuf_len(global->wfd_subelem[
13561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					  WFD_SUBELEM_DEVICE_INFO]);
13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		len += wpabuf_len(global->wfd_subelem[
13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					  WFD_SUBELEM_ASSOCIATED_BSSID]);
13961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
14061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		len += wpabuf_len(global->wfd_subelem[
14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					  WFD_SUBELEM_COUPLED_SINK]);
14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		len += wpabuf_len(global->wfd_subelem[
14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					  WFD_SUBELEM_SESSION_INFO]);
14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	buf = wpabuf_alloc(len);
14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (buf == NULL)
14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_buf(buf,
15361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
15461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
15561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_buf(buf, global->wfd_subelem[
15661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				       WFD_SUBELEM_ASSOCIATED_BSSID]);
15761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
15861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_buf(buf,
15961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
16061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
16161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ie = wifi_display_encaps(buf);
16261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
16361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_ie_beacon(global->p2p, ie);
16461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
16561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ie = wifi_display_encaps(buf);
16661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
16761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			ie);
16861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_ie_assoc_req(global->p2p, ie);
16961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
17061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ie = wifi_display_encaps(buf);
17161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
17261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_ie_go_neg(global->p2p, ie);
17361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
17461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ie = wifi_display_encaps(buf);
17561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
17661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			"Request", ie);
17761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
17861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
17961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	plen = buf->used;
18061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
18161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_buf(buf,
18261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
18361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
18461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ie = wifi_display_encaps(buf);
18561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
18661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_ie_probe_req(global->p2p, ie);
18761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
18861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
18961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_buf(buf,
19061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
19161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ie = wifi_display_encaps(buf);
19261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
19361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_ie_probe_resp(global->p2p, ie);
19461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
19561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/* Remove WFD Extended Capability from buffer */
19661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	buf->used = plen;
19761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
19861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_buf(buf,
19961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
20061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
20161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ie = wifi_display_encaps(buf);
20261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
20361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_ie_invitation(global->p2p, ie);
20461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
20561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ie = wifi_display_encaps(buf);
20661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
20761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			"Response", ie);
20861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
20961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
21061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_free(buf);
21161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
21261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return 0;
21361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
21461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
21561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
21661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid wifi_display_enable(struct wpa_global *global, int enabled)
21761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
21861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
21961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		   enabled ? "enabled" : "disabled");
22061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	global->wifi_display = enabled;
22161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wifi_display_update_wfd_ie(global);
22261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
22361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
22461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
22561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint wifi_display_subelem_set(struct wpa_global *global, char *cmd)
22661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
22761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	char *pos;
22861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int subelem;
22961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	size_t len;
23061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct wpabuf *e;
23161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
23261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	pos = os_strchr(cmd, ' ');
23361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (pos == NULL)
23461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
23561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	*pos++ = '\0';
23661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	subelem = atoi(cmd);
23761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
23861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
23961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
24061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	len = os_strlen(pos);
24161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (len & 1)
24261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
24361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	len /= 2;
24461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
24561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (len == 0) {
24661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/* Clear subelement */
24761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		e = NULL;
24861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
24961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	} else {
25061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		e = wpabuf_alloc(1 + len);
25161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (e == NULL)
25261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
25361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpabuf_put_u8(e, subelem);
25461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
25561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpabuf_free(e);
25661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return -1;
25761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
25861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
25961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
26061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
26161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wpabuf_free(global->wfd_subelem[subelem]);
26261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	global->wfd_subelem[subelem] = e;
26361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	wifi_display_update_wfd_ie(global);
26461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
26561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return 0;
26661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
26761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
26861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
269661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidtint wifi_display_subelem_set_from_ies(struct wpa_global *global,
270661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt				      struct wpabuf *ie)
271661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt{
272661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	int subelements[MAX_WFD_SUBELEMS] = {};
273661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	const u8 *pos, *end;
274661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	int len, subelem;
275661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	struct wpabuf *e;
276661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
277661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu",
278661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   ie, ie ? (unsigned long) wpabuf_len(ie) : 0);
279661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
280661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (ie == NULL || wpabuf_len(ie) < 6)
281661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		return -1;
282661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
283661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	pos = wpabuf_head(ie);
284661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	end = pos + wpabuf_len(ie);
285661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
286661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	while (end > pos) {
287661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		if (pos + 3 > end)
288661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			break;
289661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
290661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		len = WPA_GET_BE16(pos + 1) + 3;
291661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
292661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d",
293661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			   *pos, len - 3);
294661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
295661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		if (pos + len > end)
296661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			break;
297661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
298661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		subelem = *pos;
299661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		if (subelem < MAX_WFD_SUBELEMS && subelements[subelem] == 0) {
300661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			e = wpabuf_alloc_copy(pos, len);
301661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			if (e == NULL)
302661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt				return -1;
303661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
304661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			wpabuf_free(global->wfd_subelem[subelem]);
305661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			global->wfd_subelem[subelem] = e;
306661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			subelements[subelem] = 1;
307661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		}
308661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
309661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		pos += len;
310661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
311661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
312661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	for (subelem = 0; subelem < MAX_WFD_SUBELEMS; subelem++) {
313661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		if (subelements[subelem] == 0) {
314661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			wpabuf_free(global->wfd_subelem[subelem]);
315661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			global->wfd_subelem[subelem] = NULL;
316661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		}
317661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
318661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
319661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	return wifi_display_update_wfd_ie(global);
320661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt}
321661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
322661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
32361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint wifi_display_subelem_get(struct wpa_global *global, char *cmd,
32461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			     char *buf, size_t buflen)
32561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
32661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int subelem;
32761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
32861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	subelem = atoi(cmd);
32961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
33061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
33161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
33261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (global->wfd_subelem[subelem] == NULL)
33361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 0;
33461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
33561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return wpa_snprintf_hex(buf, buflen,
33661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				wpabuf_head_u8(global->wfd_subelem[subelem]) +
33761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				1,
33861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				wpabuf_len(global->wfd_subelem[subelem]) - 1);
33961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
34004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
34104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
34204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidtchar * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
34304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{
34404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	char *subelem = NULL;
34504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	const u8 *buf;
34604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	size_t buflen;
34704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	size_t i = 0;
34804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	u16 elen;
34904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
35004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!wfd_subelems)
35104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return NULL;
35204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
35304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	buf = wpabuf_head_u8(wfd_subelems);
35404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	if (!buf)
35504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return NULL;
35604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
35704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	buflen = wpabuf_len(wfd_subelems);
35804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
35904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
36004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		elen = WPA_GET_BE16(buf + i + 1);
361623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt		if (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN + elen > buflen)
362623d63a3a443027e50efdaaec027befcc3882527Dmitry Shmidt			break; /* truncated subelement */
36304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
36404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (buf[i] == id) {
365c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			/*
366c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			 * Limit explicitly to an arbitrary length to avoid
367c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			 * unnecessarily large allocations. In practice, this
368c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			 * is limited to maximum frame length anyway, so the
369c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			 * maximum memory allocation here is not really that
370c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			 * large. Anyway, the Wi-Fi Display subelements that
371c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			 * are fetched with this function are even shorter.
372c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			 */
373c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			if (elen > 1000)
374c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt				break;
37504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			subelem = os_zalloc(2 * elen + 1);
37604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			if (!subelem)
37704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt				return NULL;
37804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			wpa_snprintf_hex(subelem, 2 * elen + 1,
37904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					 buf + i +
38004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					 WIFI_DISPLAY_SUBELEM_HEADER_LEN,
38104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					 elen);
38204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt			break;
38304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		}
38404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
38504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
38604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
38704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
38804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	return subelem;
38904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt}
390