1f05cddf9SRui Paulo /*
2f05cddf9SRui Paulo * wpa_supplicant - Wi-Fi Display
3f05cddf9SRui Paulo * Copyright (c) 2011, Atheros Communications, Inc.
4f05cddf9SRui Paulo * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
5f05cddf9SRui Paulo *
6f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
7f05cddf9SRui Paulo * See README for more details.
8f05cddf9SRui Paulo */
9f05cddf9SRui Paulo
10f05cddf9SRui Paulo #include "includes.h"
11f05cddf9SRui Paulo
12f05cddf9SRui Paulo #include "common.h"
13f05cddf9SRui Paulo #include "p2p/p2p.h"
14f05cddf9SRui Paulo #include "common/ieee802_11_defs.h"
15f05cddf9SRui Paulo #include "wpa_supplicant_i.h"
16f05cddf9SRui Paulo #include "wifi_display.h"
17f05cddf9SRui Paulo
18f05cddf9SRui Paulo
195b9c547cSRui Paulo #define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
205b9c547cSRui Paulo
215b9c547cSRui Paulo
wifi_display_init(struct wpa_global * global)22f05cddf9SRui Paulo int wifi_display_init(struct wpa_global *global)
23f05cddf9SRui Paulo {
24f05cddf9SRui Paulo global->wifi_display = 1;
25f05cddf9SRui Paulo return 0;
26f05cddf9SRui Paulo }
27f05cddf9SRui Paulo
28f05cddf9SRui Paulo
wifi_display_deinit(struct wpa_global * global)29f05cddf9SRui Paulo void wifi_display_deinit(struct wpa_global *global)
30f05cddf9SRui Paulo {
31f05cddf9SRui Paulo int i;
32f05cddf9SRui Paulo for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
33f05cddf9SRui Paulo wpabuf_free(global->wfd_subelem[i]);
34f05cddf9SRui Paulo global->wfd_subelem[i] = NULL;
35f05cddf9SRui Paulo }
36f05cddf9SRui Paulo }
37f05cddf9SRui Paulo
38f05cddf9SRui Paulo
wifi_display_get_wfd_ie(struct wpa_global * global)395b9c547cSRui Paulo struct wpabuf * wifi_display_get_wfd_ie(struct wpa_global *global)
405b9c547cSRui Paulo {
415b9c547cSRui Paulo struct wpabuf *ie;
425b9c547cSRui Paulo size_t len;
435b9c547cSRui Paulo int i;
445b9c547cSRui Paulo
455b9c547cSRui Paulo if (global->p2p == NULL)
465b9c547cSRui Paulo return NULL;
475b9c547cSRui Paulo
485b9c547cSRui Paulo len = 0;
495b9c547cSRui Paulo for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
505b9c547cSRui Paulo if (global->wfd_subelem[i])
515b9c547cSRui Paulo len += wpabuf_len(global->wfd_subelem[i]);
525b9c547cSRui Paulo }
535b9c547cSRui Paulo
545b9c547cSRui Paulo ie = wpabuf_alloc(len);
555b9c547cSRui Paulo if (ie == NULL)
565b9c547cSRui Paulo return NULL;
575b9c547cSRui Paulo
585b9c547cSRui Paulo for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
595b9c547cSRui Paulo if (global->wfd_subelem[i])
605b9c547cSRui Paulo wpabuf_put_buf(ie, global->wfd_subelem[i]);
615b9c547cSRui Paulo }
625b9c547cSRui Paulo
635b9c547cSRui Paulo return ie;
645b9c547cSRui Paulo }
655b9c547cSRui Paulo
665b9c547cSRui Paulo
wifi_display_update_wfd_ie(struct wpa_global * global)67f05cddf9SRui Paulo static int wifi_display_update_wfd_ie(struct wpa_global *global)
68f05cddf9SRui Paulo {
69f05cddf9SRui Paulo struct wpabuf *ie, *buf;
70f05cddf9SRui Paulo size_t len, plen;
71f05cddf9SRui Paulo
725b9c547cSRui Paulo if (global->p2p == NULL)
735b9c547cSRui Paulo return 0;
745b9c547cSRui Paulo
75f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
76f05cddf9SRui Paulo
77f05cddf9SRui Paulo if (!global->wifi_display) {
78f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
79f05cddf9SRui Paulo "include WFD IE");
80f05cddf9SRui Paulo p2p_set_wfd_ie_beacon(global->p2p, NULL);
81f05cddf9SRui Paulo p2p_set_wfd_ie_probe_req(global->p2p, NULL);
82f05cddf9SRui Paulo p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
83f05cddf9SRui Paulo p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
84f05cddf9SRui Paulo p2p_set_wfd_ie_invitation(global->p2p, NULL);
85f05cddf9SRui Paulo p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
86f05cddf9SRui Paulo p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
87f05cddf9SRui Paulo p2p_set_wfd_ie_go_neg(global->p2p, NULL);
88f05cddf9SRui Paulo p2p_set_wfd_dev_info(global->p2p, NULL);
89*85732ac8SCy Schubert p2p_set_wfd_r2_dev_info(global->p2p, NULL);
90f05cddf9SRui Paulo p2p_set_wfd_assoc_bssid(global->p2p, NULL);
91f05cddf9SRui Paulo p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
92f05cddf9SRui Paulo return 0;
93f05cddf9SRui Paulo }
94f05cddf9SRui Paulo
95f05cddf9SRui Paulo p2p_set_wfd_dev_info(global->p2p,
96f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
97*85732ac8SCy Schubert p2p_set_wfd_r2_dev_info(
98*85732ac8SCy Schubert global->p2p, global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]);
99f05cddf9SRui Paulo p2p_set_wfd_assoc_bssid(
100f05cddf9SRui Paulo global->p2p,
101f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
102f05cddf9SRui Paulo p2p_set_wfd_coupled_sink_info(
103f05cddf9SRui Paulo global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
104f05cddf9SRui Paulo
105f05cddf9SRui Paulo /*
106f05cddf9SRui Paulo * WFD IE is included in number of management frames. Two different
107f05cddf9SRui Paulo * sets of subelements are included depending on the frame:
108f05cddf9SRui Paulo *
109f05cddf9SRui Paulo * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
110f05cddf9SRui Paulo * Provision Discovery Req:
111f05cddf9SRui Paulo * WFD Device Info
112f05cddf9SRui Paulo * [Associated BSSID]
113f05cddf9SRui Paulo * [Coupled Sink Info]
114f05cddf9SRui Paulo *
115f05cddf9SRui Paulo * Probe Request:
116f05cddf9SRui Paulo * WFD Device Info
117f05cddf9SRui Paulo * [Associated BSSID]
118f05cddf9SRui Paulo * [Coupled Sink Info]
119f05cddf9SRui Paulo * [WFD Extended Capability]
120f05cddf9SRui Paulo *
121f05cddf9SRui Paulo * Probe Response:
122f05cddf9SRui Paulo * WFD Device Info
123f05cddf9SRui Paulo * [Associated BSSID]
124f05cddf9SRui Paulo * [Coupled Sink Info]
125f05cddf9SRui Paulo * [WFD Extended Capability]
126f05cddf9SRui Paulo * [WFD Session Info]
127f05cddf9SRui Paulo *
128f05cddf9SRui Paulo * (Re)Association Response, P2P Invitation Req/Resp,
129f05cddf9SRui Paulo * Provision Discovery Resp:
130f05cddf9SRui Paulo * WFD Device Info
131f05cddf9SRui Paulo * [Associated BSSID]
132f05cddf9SRui Paulo * [Coupled Sink Info]
133f05cddf9SRui Paulo * [WFD Session Info]
134f05cddf9SRui Paulo */
135f05cddf9SRui Paulo len = 0;
136f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
137f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[
138f05cddf9SRui Paulo WFD_SUBELEM_DEVICE_INFO]);
139*85732ac8SCy Schubert
140*85732ac8SCy Schubert if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO])
141*85732ac8SCy Schubert len += wpabuf_len(global->wfd_subelem[
142*85732ac8SCy Schubert WFD_SUBELEM_R2_DEVICE_INFO]);
143*85732ac8SCy Schubert
144f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
145f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[
146f05cddf9SRui Paulo WFD_SUBELEM_ASSOCIATED_BSSID]);
147f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
148f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[
149f05cddf9SRui Paulo WFD_SUBELEM_COUPLED_SINK]);
150f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
151f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[
152f05cddf9SRui Paulo WFD_SUBELEM_SESSION_INFO]);
153f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
154f05cddf9SRui Paulo len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
155f05cddf9SRui Paulo buf = wpabuf_alloc(len);
156f05cddf9SRui Paulo if (buf == NULL)
157f05cddf9SRui Paulo return -1;
158f05cddf9SRui Paulo
159f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
160f05cddf9SRui Paulo wpabuf_put_buf(buf,
161f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
162*85732ac8SCy Schubert
163*85732ac8SCy Schubert if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO])
164*85732ac8SCy Schubert wpabuf_put_buf(buf,
165*85732ac8SCy Schubert global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]);
166*85732ac8SCy Schubert
167f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
168f05cddf9SRui Paulo wpabuf_put_buf(buf, global->wfd_subelem[
169f05cddf9SRui Paulo WFD_SUBELEM_ASSOCIATED_BSSID]);
170f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
171f05cddf9SRui Paulo wpabuf_put_buf(buf,
172f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
173f05cddf9SRui Paulo
174f05cddf9SRui Paulo ie = wifi_display_encaps(buf);
175f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
176f05cddf9SRui Paulo p2p_set_wfd_ie_beacon(global->p2p, ie);
177f05cddf9SRui Paulo
178f05cddf9SRui Paulo ie = wifi_display_encaps(buf);
179f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
180f05cddf9SRui Paulo ie);
181f05cddf9SRui Paulo p2p_set_wfd_ie_assoc_req(global->p2p, ie);
182f05cddf9SRui Paulo
183f05cddf9SRui Paulo ie = wifi_display_encaps(buf);
184f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
185f05cddf9SRui Paulo p2p_set_wfd_ie_go_neg(global->p2p, ie);
186f05cddf9SRui Paulo
187f05cddf9SRui Paulo ie = wifi_display_encaps(buf);
188f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
189f05cddf9SRui Paulo "Request", ie);
190f05cddf9SRui Paulo p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
191f05cddf9SRui Paulo
192f05cddf9SRui Paulo plen = buf->used;
193f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
194f05cddf9SRui Paulo wpabuf_put_buf(buf,
195f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
196f05cddf9SRui Paulo
197f05cddf9SRui Paulo ie = wifi_display_encaps(buf);
198f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
199f05cddf9SRui Paulo p2p_set_wfd_ie_probe_req(global->p2p, ie);
200f05cddf9SRui Paulo
201f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
202f05cddf9SRui Paulo wpabuf_put_buf(buf,
203f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
204f05cddf9SRui Paulo ie = wifi_display_encaps(buf);
205f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
206f05cddf9SRui Paulo p2p_set_wfd_ie_probe_resp(global->p2p, ie);
207f05cddf9SRui Paulo
208f05cddf9SRui Paulo /* Remove WFD Extended Capability from buffer */
209f05cddf9SRui Paulo buf->used = plen;
210f05cddf9SRui Paulo if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
211f05cddf9SRui Paulo wpabuf_put_buf(buf,
212f05cddf9SRui Paulo global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
213f05cddf9SRui Paulo
214f05cddf9SRui Paulo ie = wifi_display_encaps(buf);
215f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
216f05cddf9SRui Paulo p2p_set_wfd_ie_invitation(global->p2p, ie);
217f05cddf9SRui Paulo
218f05cddf9SRui Paulo ie = wifi_display_encaps(buf);
219f05cddf9SRui Paulo wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
220f05cddf9SRui Paulo "Response", ie);
221f05cddf9SRui Paulo p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
222f05cddf9SRui Paulo
223f05cddf9SRui Paulo wpabuf_free(buf);
224f05cddf9SRui Paulo
225f05cddf9SRui Paulo return 0;
226f05cddf9SRui Paulo }
227f05cddf9SRui Paulo
228f05cddf9SRui Paulo
wifi_display_enable(struct wpa_global * global,int enabled)229f05cddf9SRui Paulo void wifi_display_enable(struct wpa_global *global, int enabled)
230f05cddf9SRui Paulo {
231f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
232f05cddf9SRui Paulo enabled ? "enabled" : "disabled");
233f05cddf9SRui Paulo global->wifi_display = enabled;
234f05cddf9SRui Paulo wifi_display_update_wfd_ie(global);
235f05cddf9SRui Paulo }
236f05cddf9SRui Paulo
237f05cddf9SRui Paulo
wifi_display_subelem_set(struct wpa_global * global,char * cmd)238f05cddf9SRui Paulo int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
239f05cddf9SRui Paulo {
240f05cddf9SRui Paulo char *pos;
241f05cddf9SRui Paulo int subelem;
242f05cddf9SRui Paulo size_t len;
243f05cddf9SRui Paulo struct wpabuf *e;
244f05cddf9SRui Paulo
245f05cddf9SRui Paulo pos = os_strchr(cmd, ' ');
246f05cddf9SRui Paulo if (pos == NULL)
247f05cddf9SRui Paulo return -1;
248f05cddf9SRui Paulo *pos++ = '\0';
249f05cddf9SRui Paulo
250f05cddf9SRui Paulo len = os_strlen(pos);
251f05cddf9SRui Paulo if (len & 1)
252f05cddf9SRui Paulo return -1;
253f05cddf9SRui Paulo len /= 2;
254f05cddf9SRui Paulo
2555b9c547cSRui Paulo if (os_strcmp(cmd, "all") == 0) {
2565b9c547cSRui Paulo int res;
2575b9c547cSRui Paulo
2585b9c547cSRui Paulo e = wpabuf_alloc(len);
2595b9c547cSRui Paulo if (e == NULL)
2605b9c547cSRui Paulo return -1;
2615b9c547cSRui Paulo if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
2625b9c547cSRui Paulo wpabuf_free(e);
2635b9c547cSRui Paulo return -1;
2645b9c547cSRui Paulo }
2655b9c547cSRui Paulo res = wifi_display_subelem_set_from_ies(global, e);
2665b9c547cSRui Paulo wpabuf_free(e);
2675b9c547cSRui Paulo return res;
2685b9c547cSRui Paulo }
2695b9c547cSRui Paulo
2705b9c547cSRui Paulo subelem = atoi(cmd);
2715b9c547cSRui Paulo if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
2725b9c547cSRui Paulo return -1;
2735b9c547cSRui Paulo
274f05cddf9SRui Paulo if (len == 0) {
275f05cddf9SRui Paulo /* Clear subelement */
276f05cddf9SRui Paulo e = NULL;
277f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
278f05cddf9SRui Paulo } else {
279f05cddf9SRui Paulo e = wpabuf_alloc(1 + len);
280f05cddf9SRui Paulo if (e == NULL)
281f05cddf9SRui Paulo return -1;
282f05cddf9SRui Paulo wpabuf_put_u8(e, subelem);
283f05cddf9SRui Paulo if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
284f05cddf9SRui Paulo wpabuf_free(e);
285f05cddf9SRui Paulo return -1;
286f05cddf9SRui Paulo }
287f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
288f05cddf9SRui Paulo }
289f05cddf9SRui Paulo
290f05cddf9SRui Paulo wpabuf_free(global->wfd_subelem[subelem]);
291f05cddf9SRui Paulo global->wfd_subelem[subelem] = e;
292f05cddf9SRui Paulo wifi_display_update_wfd_ie(global);
293f05cddf9SRui Paulo
294f05cddf9SRui Paulo return 0;
295f05cddf9SRui Paulo }
296f05cddf9SRui Paulo
297f05cddf9SRui Paulo
wifi_display_subelem_set_from_ies(struct wpa_global * global,struct wpabuf * ie)2985b9c547cSRui Paulo int wifi_display_subelem_set_from_ies(struct wpa_global *global,
2995b9c547cSRui Paulo struct wpabuf *ie)
3005b9c547cSRui Paulo {
3015b9c547cSRui Paulo int subelements[MAX_WFD_SUBELEMS] = {};
3025b9c547cSRui Paulo const u8 *pos, *end;
3035b9c547cSRui Paulo unsigned int len, subelem;
3045b9c547cSRui Paulo struct wpabuf *e;
3055b9c547cSRui Paulo
3065b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu",
3075b9c547cSRui Paulo ie, ie ? (unsigned long) wpabuf_len(ie) : 0);
3085b9c547cSRui Paulo
3095b9c547cSRui Paulo if (ie == NULL || wpabuf_len(ie) < 6)
3105b9c547cSRui Paulo return -1;
3115b9c547cSRui Paulo
3125b9c547cSRui Paulo pos = wpabuf_head(ie);
3135b9c547cSRui Paulo end = pos + wpabuf_len(ie);
3145b9c547cSRui Paulo
3155b9c547cSRui Paulo while (end > pos) {
3165b9c547cSRui Paulo if (pos + 3 > end)
3175b9c547cSRui Paulo break;
3185b9c547cSRui Paulo
3195b9c547cSRui Paulo len = WPA_GET_BE16(pos + 1) + 3;
3205b9c547cSRui Paulo
3215b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d",
3225b9c547cSRui Paulo *pos, len - 3);
3235b9c547cSRui Paulo
3245b9c547cSRui Paulo if (len > (unsigned int) (end - pos))
3255b9c547cSRui Paulo break;
3265b9c547cSRui Paulo
3275b9c547cSRui Paulo subelem = *pos;
3285b9c547cSRui Paulo if (subelem < MAX_WFD_SUBELEMS && subelements[subelem] == 0) {
3295b9c547cSRui Paulo e = wpabuf_alloc_copy(pos, len);
3305b9c547cSRui Paulo if (e == NULL)
3315b9c547cSRui Paulo return -1;
3325b9c547cSRui Paulo
3335b9c547cSRui Paulo wpabuf_free(global->wfd_subelem[subelem]);
3345b9c547cSRui Paulo global->wfd_subelem[subelem] = e;
3355b9c547cSRui Paulo subelements[subelem] = 1;
3365b9c547cSRui Paulo }
3375b9c547cSRui Paulo
3385b9c547cSRui Paulo pos += len;
3395b9c547cSRui Paulo }
3405b9c547cSRui Paulo
3415b9c547cSRui Paulo for (subelem = 0; subelem < MAX_WFD_SUBELEMS; subelem++) {
3425b9c547cSRui Paulo if (subelements[subelem] == 0) {
3435b9c547cSRui Paulo wpabuf_free(global->wfd_subelem[subelem]);
3445b9c547cSRui Paulo global->wfd_subelem[subelem] = NULL;
3455b9c547cSRui Paulo }
3465b9c547cSRui Paulo }
3475b9c547cSRui Paulo
3485b9c547cSRui Paulo return wifi_display_update_wfd_ie(global);
3495b9c547cSRui Paulo }
3505b9c547cSRui Paulo
3515b9c547cSRui Paulo
wifi_display_subelem_get(struct wpa_global * global,char * cmd,char * buf,size_t buflen)352f05cddf9SRui Paulo int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
353f05cddf9SRui Paulo char *buf, size_t buflen)
354f05cddf9SRui Paulo {
355f05cddf9SRui Paulo int subelem;
356f05cddf9SRui Paulo
3575b9c547cSRui Paulo if (os_strcmp(cmd, "all") == 0) {
3585b9c547cSRui Paulo struct wpabuf *ie;
3595b9c547cSRui Paulo int res;
3605b9c547cSRui Paulo
3615b9c547cSRui Paulo ie = wifi_display_get_wfd_ie(global);
3625b9c547cSRui Paulo if (ie == NULL)
3635b9c547cSRui Paulo return 0;
3645b9c547cSRui Paulo res = wpa_snprintf_hex(buf, buflen, wpabuf_head(ie),
3655b9c547cSRui Paulo wpabuf_len(ie));
3665b9c547cSRui Paulo wpabuf_free(ie);
3675b9c547cSRui Paulo return res;
3685b9c547cSRui Paulo }
3695b9c547cSRui Paulo
370f05cddf9SRui Paulo subelem = atoi(cmd);
371f05cddf9SRui Paulo if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
372f05cddf9SRui Paulo return -1;
373f05cddf9SRui Paulo
374f05cddf9SRui Paulo if (global->wfd_subelem[subelem] == NULL)
375f05cddf9SRui Paulo return 0;
376f05cddf9SRui Paulo
377f05cddf9SRui Paulo return wpa_snprintf_hex(buf, buflen,
378f05cddf9SRui Paulo wpabuf_head_u8(global->wfd_subelem[subelem]) +
379f05cddf9SRui Paulo 1,
380f05cddf9SRui Paulo wpabuf_len(global->wfd_subelem[subelem]) - 1);
381f05cddf9SRui Paulo }
3825b9c547cSRui Paulo
3835b9c547cSRui Paulo
wifi_display_subelem_hex(const struct wpabuf * wfd_subelems,u8 id)3845b9c547cSRui Paulo char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
3855b9c547cSRui Paulo {
3865b9c547cSRui Paulo char *subelem = NULL;
3875b9c547cSRui Paulo const u8 *buf;
3885b9c547cSRui Paulo size_t buflen;
3895b9c547cSRui Paulo size_t i = 0;
3905b9c547cSRui Paulo u16 elen;
3915b9c547cSRui Paulo
3925b9c547cSRui Paulo if (!wfd_subelems)
3935b9c547cSRui Paulo return NULL;
3945b9c547cSRui Paulo
3955b9c547cSRui Paulo buf = wpabuf_head_u8(wfd_subelems);
3965b9c547cSRui Paulo if (!buf)
3975b9c547cSRui Paulo return NULL;
3985b9c547cSRui Paulo
3995b9c547cSRui Paulo buflen = wpabuf_len(wfd_subelems);
4005b9c547cSRui Paulo
4015b9c547cSRui Paulo while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
4025b9c547cSRui Paulo elen = WPA_GET_BE16(buf + i + 1);
4035b9c547cSRui Paulo if (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN + elen > buflen)
4045b9c547cSRui Paulo break; /* truncated subelement */
4055b9c547cSRui Paulo
4065b9c547cSRui Paulo if (buf[i] == id) {
4075b9c547cSRui Paulo /*
4085b9c547cSRui Paulo * Limit explicitly to an arbitrary length to avoid
4095b9c547cSRui Paulo * unnecessarily large allocations. In practice, this
4105b9c547cSRui Paulo * is limited to maximum frame length anyway, so the
4115b9c547cSRui Paulo * maximum memory allocation here is not really that
4125b9c547cSRui Paulo * large. Anyway, the Wi-Fi Display subelements that
4135b9c547cSRui Paulo * are fetched with this function are even shorter.
4145b9c547cSRui Paulo */
4155b9c547cSRui Paulo if (elen > 1000)
4165b9c547cSRui Paulo break;
4175b9c547cSRui Paulo subelem = os_zalloc(2 * elen + 1);
4185b9c547cSRui Paulo if (!subelem)
4195b9c547cSRui Paulo return NULL;
4205b9c547cSRui Paulo wpa_snprintf_hex(subelem, 2 * elen + 1,
4215b9c547cSRui Paulo buf + i +
4225b9c547cSRui Paulo WIFI_DISPLAY_SUBELEM_HEADER_LEN,
4235b9c547cSRui Paulo elen);
4245b9c547cSRui Paulo break;
4255b9c547cSRui Paulo }
4265b9c547cSRui Paulo
4275b9c547cSRui Paulo i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
4285b9c547cSRui Paulo }
4295b9c547cSRui Paulo
4305b9c547cSRui Paulo return subelem;
4315b9c547cSRui Paulo }
432