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
;