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_assoc_bssid(global
->p2p
, NULL
);
90 p2p_set_wfd_coupled_sink_info(global
->p2p
, NULL
);
94 p2p_set_wfd_dev_info(global
->p2p
,
95 global
->wfd_subelem
[WFD_SUBELEM_DEVICE_INFO
]);
96 p2p_set_wfd_assoc_bssid(
98 global
->wfd_subelem
[WFD_SUBELEM_ASSOCIATED_BSSID
]);
99 p2p_set_wfd_coupled_sink_info(
100 global
->p2p
, global
->wfd_subelem
[WFD_SUBELEM_COUPLED_SINK
]);
103 * WFD IE is included in number of management frames. Two different
104 * sets of subelements are included depending on the frame:
106 * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
107 * Provision Discovery Req:
110 * [Coupled Sink Info]
115 * [Coupled Sink Info]
116 * [WFD Extended Capability]
121 * [Coupled Sink Info]
122 * [WFD Extended Capability]
125 * (Re)Association Response, P2P Invitation Req/Resp,
126 * Provision Discovery Resp:
129 * [Coupled Sink Info]
133 if (global
->wfd_subelem
[WFD_SUBELEM_DEVICE_INFO
])
134 len
+= wpabuf_len(global
->wfd_subelem
[
135 WFD_SUBELEM_DEVICE_INFO
]);
136 if (global
->wfd_subelem
[WFD_SUBELEM_ASSOCIATED_BSSID
])
137 len
+= wpabuf_len(global
->wfd_subelem
[
138 WFD_SUBELEM_ASSOCIATED_BSSID
]);
139 if (global
->wfd_subelem
[WFD_SUBELEM_COUPLED_SINK
])
140 len
+= wpabuf_len(global
->wfd_subelem
[
141 WFD_SUBELEM_COUPLED_SINK
]);
142 if (global
->wfd_subelem
[WFD_SUBELEM_SESSION_INFO
])
143 len
+= wpabuf_len(global
->wfd_subelem
[
144 WFD_SUBELEM_SESSION_INFO
]);
145 if (global
->wfd_subelem
[WFD_SUBELEM_EXT_CAPAB
])
146 len
+= wpabuf_len(global
->wfd_subelem
[WFD_SUBELEM_EXT_CAPAB
]);
147 buf
= wpabuf_alloc(len
);
151 if (global
->wfd_subelem
[WFD_SUBELEM_DEVICE_INFO
])
153 global
->wfd_subelem
[WFD_SUBELEM_DEVICE_INFO
]);
154 if (global
->wfd_subelem
[WFD_SUBELEM_ASSOCIATED_BSSID
])
155 wpabuf_put_buf(buf
, global
->wfd_subelem
[
156 WFD_SUBELEM_ASSOCIATED_BSSID
]);
157 if (global
->wfd_subelem
[WFD_SUBELEM_COUPLED_SINK
])
159 global
->wfd_subelem
[WFD_SUBELEM_COUPLED_SINK
]);
161 ie
= wifi_display_encaps(buf
);
162 wpa_hexdump_buf(MSG_DEBUG
, "WFD: WFD IE for Beacon", ie
);
163 p2p_set_wfd_ie_beacon(global
->p2p
, ie
);
165 ie
= wifi_display_encaps(buf
);
166 wpa_hexdump_buf(MSG_DEBUG
, "WFD: WFD IE for (Re)Association Request",
168 p2p_set_wfd_ie_assoc_req(global
->p2p
, ie
);
170 ie
= wifi_display_encaps(buf
);
171 wpa_hexdump_buf(MSG_DEBUG
, "WFD: WFD IE for GO Negotiation", ie
);
172 p2p_set_wfd_ie_go_neg(global
->p2p
, ie
);
174 ie
= wifi_display_encaps(buf
);
175 wpa_hexdump_buf(MSG_DEBUG
, "WFD: WFD IE for Provision Discovery "
177 p2p_set_wfd_ie_prov_disc_req(global
->p2p
, ie
);
180 if (global
->wfd_subelem
[WFD_SUBELEM_EXT_CAPAB
])
182 global
->wfd_subelem
[WFD_SUBELEM_EXT_CAPAB
]);
184 ie
= wifi_display_encaps(buf
);
185 wpa_hexdump_buf(MSG_DEBUG
, "WFD: WFD IE for Probe Request", ie
);
186 p2p_set_wfd_ie_probe_req(global
->p2p
, ie
);
188 if (global
->wfd_subelem
[WFD_SUBELEM_SESSION_INFO
])
190 global
->wfd_subelem
[WFD_SUBELEM_SESSION_INFO
]);
191 ie
= wifi_display_encaps(buf
);
192 wpa_hexdump_buf(MSG_DEBUG
, "WFD: WFD IE for Probe Response", ie
);
193 p2p_set_wfd_ie_probe_resp(global
->p2p
, ie
);
195 /* Remove WFD Extended Capability from buffer */
197 if (global
->wfd_subelem
[WFD_SUBELEM_SESSION_INFO
])
199 global
->wfd_subelem
[WFD_SUBELEM_SESSION_INFO
]);
201 ie
= wifi_display_encaps(buf
);
202 wpa_hexdump_buf(MSG_DEBUG
, "WFD: WFD IE for P2P Invitation", ie
);
203 p2p_set_wfd_ie_invitation(global
->p2p
, ie
);
205 ie
= wifi_display_encaps(buf
);
206 wpa_hexdump_buf(MSG_DEBUG
, "WFD: WFD IE for Provision Discovery "
208 p2p_set_wfd_ie_prov_disc_resp(global
->p2p
, ie
);
216 void wifi_display_enable(struct wpa_global
*global
, int enabled
)
218 wpa_printf(MSG_DEBUG
, "WFD: Wi-Fi Display %s",
219 enabled
? "enabled" : "disabled");
220 global
->wifi_display
= enabled
;
221 wifi_display_update_wfd_ie(global
);
225 int wifi_display_subelem_set(struct wpa_global
*global
, char *cmd
)
232 pos
= os_strchr(cmd
, ' ');
237 if (subelem
< 0 || subelem
>= MAX_WFD_SUBELEMS
)
240 len
= os_strlen(pos
);
246 /* Clear subelement */
248 wpa_printf(MSG_DEBUG
, "WFD: Clear subelement %d", subelem
);
250 e
= wpabuf_alloc(1 + len
);
253 wpabuf_put_u8(e
, subelem
);
254 if (hexstr2bin(pos
, wpabuf_put(e
, len
), len
) < 0) {
258 wpa_printf(MSG_DEBUG
, "WFD: Set subelement %d", subelem
);
261 wpabuf_free(global
->wfd_subelem
[subelem
]);
262 global
->wfd_subelem
[subelem
] = e
;
263 wifi_display_update_wfd_ie(global
);
269 int wifi_display_subelem_set_from_ies(struct wpa_global
*global
,
272 int subelements
[MAX_WFD_SUBELEMS
] = {};
274 unsigned int len
, subelem
;
277 wpa_printf(MSG_DEBUG
, "WFD IEs set: %p - %lu",
278 ie
, ie
? (unsigned long) wpabuf_len(ie
) : 0);
280 if (ie
== NULL
|| wpabuf_len(ie
) < 6)
283 pos
= wpabuf_head(ie
);
284 end
= pos
+ wpabuf_len(ie
);
290 len
= WPA_GET_BE16(pos
+ 1) + 3;
292 wpa_printf(MSG_DEBUG
, "WFD Sub-Element ID %d - len %d",
295 if (len
> (unsigned int) (end
- pos
))
299 if (subelem
< MAX_WFD_SUBELEMS
&& subelements
[subelem
] == 0) {
300 e
= wpabuf_alloc_copy(pos
, len
);
304 wpabuf_free(global
->wfd_subelem
[subelem
]);
305 global
->wfd_subelem
[subelem
] = e
;
306 subelements
[subelem
] = 1;
312 for (subelem
= 0; subelem
< MAX_WFD_SUBELEMS
; subelem
++) {
313 if (subelements
[subelem
] == 0) {
314 wpabuf_free(global
->wfd_subelem
[subelem
]);
315 global
->wfd_subelem
[subelem
] = NULL
;
319 return wifi_display_update_wfd_ie(global
);
323 int wifi_display_subelem_get(struct wpa_global
*global
, char *cmd
,
324 char *buf
, size_t buflen
)
329 if (subelem
< 0 || subelem
>= MAX_WFD_SUBELEMS
)
332 if (global
->wfd_subelem
[subelem
] == NULL
)
335 return wpa_snprintf_hex(buf
, buflen
,
336 wpabuf_head_u8(global
->wfd_subelem
[subelem
]) +
338 wpabuf_len(global
->wfd_subelem
[subelem
]) - 1);
342 char * wifi_display_subelem_hex(const struct wpabuf
*wfd_subelems
, u8 id
)
344 char *subelem
= NULL
;
353 buf
= wpabuf_head_u8(wfd_subelems
);
357 buflen
= wpabuf_len(wfd_subelems
);
359 while (i
+ WIFI_DISPLAY_SUBELEM_HEADER_LEN
< buflen
) {
360 elen
= WPA_GET_BE16(buf
+ i
+ 1);
361 if (i
+ WIFI_DISPLAY_SUBELEM_HEADER_LEN
+ elen
> buflen
)
362 break; /* truncated subelement */
366 * Limit explicitly to an arbitrary length to avoid
367 * unnecessarily large allocations. In practice, this
368 * is limited to maximum frame length anyway, so the
369 * maximum memory allocation here is not really that
370 * large. Anyway, the Wi-Fi Display subelements that
371 * are fetched with this function are even shorter.
375 subelem
= os_zalloc(2 * elen
+ 1);
378 wpa_snprintf_hex(subelem
, 2 * elen
+ 1,
380 WIFI_DISPLAY_SUBELEM_HEADER_LEN
,
385 i
+= elen
+ WIFI_DISPLAY_SUBELEM_HEADER_LEN
;