2 * wpa_supplicant - Wi-Fi Display
3 * Copyright (c) 2011, Atheros Communications, Inc.
4 * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
14 #include "common/ieee802_11_defs.h"
15 #include "wpa_supplicant_i.h"
16 #include "wifi_display.h"
19 #define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
22 int wifi_display_init(struct wpa_global *global)
24 global->wifi_display = 1;
29 void wifi_display_deinit(struct wpa_global *global)
32 for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
33 wpabuf_free(global->wfd_subelem[i]);
34 global->wfd_subelem[i] = NULL;
39 struct wpabuf * wifi_display_get_wfd_ie(struct wpa_global *global)
45 if (global->p2p == NULL)
49 for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
50 if (global->wfd_subelem[i])
51 len += wpabuf_len(global->wfd_subelem[i]);
54 ie = wpabuf_alloc(len);
58 for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
59 if (global->wfd_subelem[i])
60 wpabuf_put_buf(ie, global->wfd_subelem[i]);
67 static int wifi_display_update_wfd_ie(struct wpa_global *global)
69 struct wpabuf *ie, *buf;
72 if (global->p2p == NULL)
75 wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
77 if (!global->wifi_display) {
78 wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
80 p2p_set_wfd_ie_beacon(global->p2p, NULL);
81 p2p_set_wfd_ie_probe_req(global->p2p, NULL);
82 p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
83 p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
84 p2p_set_wfd_ie_invitation(global->p2p, NULL);
85 p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
86 p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
87 p2p_set_wfd_ie_go_neg(global->p2p, NULL);
88 p2p_set_wfd_dev_info(global->p2p, NULL);
89 p2p_set_wfd_r2_dev_info(global->p2p, NULL);
90 p2p_set_wfd_assoc_bssid(global->p2p, NULL);
91 p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
95 p2p_set_wfd_dev_info(global->p2p,
96 global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
97 p2p_set_wfd_r2_dev_info(
98 global->p2p, global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]);
99 p2p_set_wfd_assoc_bssid(
101 global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
102 p2p_set_wfd_coupled_sink_info(
103 global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
106 * WFD IE is included in number of management frames. Two different
107 * sets of subelements are included depending on the frame:
109 * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
110 * Provision Discovery Req:
113 * [Coupled Sink Info]
118 * [Coupled Sink Info]
119 * [WFD Extended Capability]
124 * [Coupled Sink Info]
125 * [WFD Extended Capability]
128 * (Re)Association Response, P2P Invitation Req/Resp,
129 * Provision Discovery Resp:
132 * [Coupled Sink Info]
136 if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
137 len += wpabuf_len(global->wfd_subelem[
138 WFD_SUBELEM_DEVICE_INFO]);
140 if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO])
141 len += wpabuf_len(global->wfd_subelem[
142 WFD_SUBELEM_R2_DEVICE_INFO]);
144 if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
145 len += wpabuf_len(global->wfd_subelem[
146 WFD_SUBELEM_ASSOCIATED_BSSID]);
147 if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
148 len += wpabuf_len(global->wfd_subelem[
149 WFD_SUBELEM_COUPLED_SINK]);
150 if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
151 len += wpabuf_len(global->wfd_subelem[
152 WFD_SUBELEM_SESSION_INFO]);
153 if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
154 len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
155 buf = wpabuf_alloc(len);
159 if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
161 global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
163 if (global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO])
165 global->wfd_subelem[WFD_SUBELEM_R2_DEVICE_INFO]);
167 if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
168 wpabuf_put_buf(buf, global->wfd_subelem[
169 WFD_SUBELEM_ASSOCIATED_BSSID]);
170 if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
172 global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
174 ie = wifi_display_encaps(buf);
175 wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
176 p2p_set_wfd_ie_beacon(global->p2p, ie);
178 ie = wifi_display_encaps(buf);
179 wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
181 p2p_set_wfd_ie_assoc_req(global->p2p, ie);
183 ie = wifi_display_encaps(buf);
184 wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
185 p2p_set_wfd_ie_go_neg(global->p2p, ie);
187 ie = wifi_display_encaps(buf);
188 wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
190 p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
193 if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
195 global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
197 ie = wifi_display_encaps(buf);
198 wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
199 p2p_set_wfd_ie_probe_req(global->p2p, ie);
201 if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
203 global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
204 ie = wifi_display_encaps(buf);
205 wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
206 p2p_set_wfd_ie_probe_resp(global->p2p, ie);
208 /* Remove WFD Extended Capability from buffer */
210 if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
212 global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
214 ie = wifi_display_encaps(buf);
215 wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
216 p2p_set_wfd_ie_invitation(global->p2p, ie);
218 ie = wifi_display_encaps(buf);
219 wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
221 p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
229 void wifi_display_enable(struct wpa_global *global, int enabled)
231 wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
232 enabled ? "enabled" : "disabled");
233 global->wifi_display = enabled;
234 wifi_display_update_wfd_ie(global);
238 int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
245 pos = os_strchr(cmd, ' ');
250 len = os_strlen(pos);
255 if (os_strcmp(cmd, "all") == 0) {
258 e = wpabuf_alloc(len);
261 if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
265 res = wifi_display_subelem_set_from_ies(global, e);
271 if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
275 /* Clear subelement */
277 wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
279 e = wpabuf_alloc(1 + len);
282 wpabuf_put_u8(e, subelem);
283 if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
287 wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
290 wpabuf_free(global->wfd_subelem[subelem]);
291 global->wfd_subelem[subelem] = e;
292 wifi_display_update_wfd_ie(global);
298 int wifi_display_subelem_set_from_ies(struct wpa_global *global,
301 int subelements[MAX_WFD_SUBELEMS] = {};
303 unsigned int len, subelem;
306 wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu",
307 ie, ie ? (unsigned long) wpabuf_len(ie) : 0);
309 if (ie == NULL || wpabuf_len(ie) < 6)
312 pos = wpabuf_head(ie);
313 end = pos + wpabuf_len(ie);
319 len = WPA_GET_BE16(pos + 1) + 3;
321 wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d",
324 if (len > (unsigned int) (end - pos))
328 if (subelem < MAX_WFD_SUBELEMS && subelements[subelem] == 0) {
329 e = wpabuf_alloc_copy(pos, len);
333 wpabuf_free(global->wfd_subelem[subelem]);
334 global->wfd_subelem[subelem] = e;
335 subelements[subelem] = 1;
341 for (subelem = 0; subelem < MAX_WFD_SUBELEMS; subelem++) {
342 if (subelements[subelem] == 0) {
343 wpabuf_free(global->wfd_subelem[subelem]);
344 global->wfd_subelem[subelem] = NULL;
348 return wifi_display_update_wfd_ie(global);
352 int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
353 char *buf, size_t buflen)
357 if (os_strcmp(cmd, "all") == 0) {
361 ie = wifi_display_get_wfd_ie(global);
364 res = wpa_snprintf_hex(buf, buflen, wpabuf_head(ie),
371 if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
374 if (global->wfd_subelem[subelem] == NULL)
377 return wpa_snprintf_hex(buf, buflen,
378 wpabuf_head_u8(global->wfd_subelem[subelem]) +
380 wpabuf_len(global->wfd_subelem[subelem]) - 1);
384 char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
386 char *subelem = NULL;
395 buf = wpabuf_head_u8(wfd_subelems);
399 buflen = wpabuf_len(wfd_subelems);
401 while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
402 elen = WPA_GET_BE16(buf + i + 1);
403 if (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN + elen > buflen)
404 break; /* truncated subelement */
408 * Limit explicitly to an arbitrary length to avoid
409 * unnecessarily large allocations. In practice, this
410 * is limited to maximum frame length anyway, so the
411 * maximum memory allocation here is not really that
412 * large. Anyway, the Wi-Fi Display subelements that
413 * are fetched with this function are even shorter.
417 subelem = os_zalloc(2 * elen + 1);
420 wpa_snprintf_hex(subelem, 2 * elen + 1,
422 WIFI_DISPLAY_SUBELEM_HEADER_LEN,
427 i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;