Line data Source code
1 : /*
2 : * wpa_supplicant - Wi-Fi Display
3 : * Copyright (c) 2011, Atheros Communications, Inc.
4 : * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
5 : *
6 : * This software may be distributed under the terms of the BSD license.
7 : * See README for more details.
8 : */
9 :
10 : #include "includes.h"
11 :
12 : #include "common.h"
13 : #include "p2p/p2p.h"
14 : #include "common/ieee802_11_defs.h"
15 : #include "wpa_supplicant_i.h"
16 : #include "wifi_display.h"
17 :
18 :
19 : #define WIFI_DISPLAY_SUBELEM_HEADER_LEN 3
20 :
21 :
22 4 : int wifi_display_init(struct wpa_global *global)
23 : {
24 4 : global->wifi_display = 1;
25 4 : return 0;
26 : }
27 :
28 :
29 4 : void wifi_display_deinit(struct wpa_global *global)
30 : {
31 : int i;
32 44 : for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
33 40 : wpabuf_free(global->wfd_subelem[i]);
34 40 : global->wfd_subelem[i] = NULL;
35 : }
36 4 : }
37 :
38 :
39 21 : static int wifi_display_update_wfd_ie(struct wpa_global *global)
40 : {
41 : struct wpabuf *ie, *buf;
42 : size_t len, plen;
43 :
44 21 : if (global->p2p == NULL)
45 0 : return 0;
46 :
47 21 : wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
48 :
49 21 : if (!global->wifi_display) {
50 4 : wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
51 : "include WFD IE");
52 4 : p2p_set_wfd_ie_beacon(global->p2p, NULL);
53 4 : p2p_set_wfd_ie_probe_req(global->p2p, NULL);
54 4 : p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
55 4 : p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
56 4 : p2p_set_wfd_ie_invitation(global->p2p, NULL);
57 4 : p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
58 4 : p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
59 4 : p2p_set_wfd_ie_go_neg(global->p2p, NULL);
60 4 : p2p_set_wfd_dev_info(global->p2p, NULL);
61 4 : p2p_set_wfd_assoc_bssid(global->p2p, NULL);
62 4 : p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
63 4 : return 0;
64 : }
65 :
66 17 : p2p_set_wfd_dev_info(global->p2p,
67 17 : global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
68 17 : p2p_set_wfd_assoc_bssid(
69 : global->p2p,
70 17 : global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
71 17 : p2p_set_wfd_coupled_sink_info(
72 17 : global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
73 :
74 : /*
75 : * WFD IE is included in number of management frames. Two different
76 : * sets of subelements are included depending on the frame:
77 : *
78 : * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
79 : * Provision Discovery Req:
80 : * WFD Device Info
81 : * [Associated BSSID]
82 : * [Coupled Sink Info]
83 : *
84 : * Probe Request:
85 : * WFD Device Info
86 : * [Associated BSSID]
87 : * [Coupled Sink Info]
88 : * [WFD Extended Capability]
89 : *
90 : * Probe Response:
91 : * WFD Device Info
92 : * [Associated BSSID]
93 : * [Coupled Sink Info]
94 : * [WFD Extended Capability]
95 : * [WFD Session Info]
96 : *
97 : * (Re)Association Response, P2P Invitation Req/Resp,
98 : * Provision Discovery Resp:
99 : * WFD Device Info
100 : * [Associated BSSID]
101 : * [Coupled Sink Info]
102 : * [WFD Session Info]
103 : */
104 17 : len = 0;
105 17 : if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
106 13 : len += wpabuf_len(global->wfd_subelem[
107 : WFD_SUBELEM_DEVICE_INFO]);
108 17 : if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
109 10 : len += wpabuf_len(global->wfd_subelem[
110 : WFD_SUBELEM_ASSOCIATED_BSSID]);
111 17 : if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
112 7 : len += wpabuf_len(global->wfd_subelem[
113 : WFD_SUBELEM_COUPLED_SINK]);
114 17 : if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
115 8 : len += wpabuf_len(global->wfd_subelem[
116 : WFD_SUBELEM_SESSION_INFO]);
117 17 : if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
118 7 : len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
119 17 : buf = wpabuf_alloc(len);
120 17 : if (buf == NULL)
121 0 : return -1;
122 :
123 17 : if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
124 13 : wpabuf_put_buf(buf,
125 13 : global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
126 17 : if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
127 10 : wpabuf_put_buf(buf, global->wfd_subelem[
128 : WFD_SUBELEM_ASSOCIATED_BSSID]);
129 17 : if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
130 7 : wpabuf_put_buf(buf,
131 7 : global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
132 :
133 17 : ie = wifi_display_encaps(buf);
134 17 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
135 17 : p2p_set_wfd_ie_beacon(global->p2p, ie);
136 :
137 17 : ie = wifi_display_encaps(buf);
138 17 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
139 : ie);
140 17 : p2p_set_wfd_ie_assoc_req(global->p2p, ie);
141 :
142 17 : ie = wifi_display_encaps(buf);
143 17 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
144 17 : p2p_set_wfd_ie_go_neg(global->p2p, ie);
145 :
146 17 : ie = wifi_display_encaps(buf);
147 17 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
148 : "Request", ie);
149 17 : p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
150 :
151 17 : plen = buf->used;
152 17 : if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
153 7 : wpabuf_put_buf(buf,
154 7 : global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
155 :
156 17 : ie = wifi_display_encaps(buf);
157 17 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
158 17 : p2p_set_wfd_ie_probe_req(global->p2p, ie);
159 :
160 17 : if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
161 8 : wpabuf_put_buf(buf,
162 8 : global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
163 17 : ie = wifi_display_encaps(buf);
164 17 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
165 17 : p2p_set_wfd_ie_probe_resp(global->p2p, ie);
166 :
167 : /* Remove WFD Extended Capability from buffer */
168 17 : buf->used = plen;
169 17 : if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
170 8 : wpabuf_put_buf(buf,
171 8 : global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
172 :
173 17 : ie = wifi_display_encaps(buf);
174 17 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
175 17 : p2p_set_wfd_ie_invitation(global->p2p, ie);
176 :
177 17 : ie = wifi_display_encaps(buf);
178 17 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
179 : "Response", ie);
180 17 : p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
181 :
182 17 : wpabuf_free(buf);
183 :
184 17 : return 0;
185 : }
186 :
187 :
188 8 : void wifi_display_enable(struct wpa_global *global, int enabled)
189 : {
190 8 : wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
191 : enabled ? "enabled" : "disabled");
192 8 : global->wifi_display = enabled;
193 8 : wifi_display_update_wfd_ie(global);
194 8 : }
195 :
196 :
197 17 : int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
198 : {
199 : char *pos;
200 : int subelem;
201 : size_t len;
202 : struct wpabuf *e;
203 :
204 17 : pos = os_strchr(cmd, ' ');
205 17 : if (pos == NULL)
206 2 : return -1;
207 15 : *pos++ = '\0';
208 15 : subelem = atoi(cmd);
209 15 : if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
210 0 : return -1;
211 :
212 15 : len = os_strlen(pos);
213 15 : if (len & 1)
214 1 : return -1;
215 14 : len /= 2;
216 :
217 14 : if (len == 0) {
218 : /* Clear subelement */
219 1 : e = NULL;
220 1 : wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
221 : } else {
222 13 : e = wpabuf_alloc(1 + len);
223 13 : if (e == NULL)
224 0 : return -1;
225 13 : wpabuf_put_u8(e, subelem);
226 13 : if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
227 1 : wpabuf_free(e);
228 1 : return -1;
229 : }
230 12 : wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
231 : }
232 :
233 13 : wpabuf_free(global->wfd_subelem[subelem]);
234 13 : global->wfd_subelem[subelem] = e;
235 13 : wifi_display_update_wfd_ie(global);
236 :
237 13 : return 0;
238 : }
239 :
240 :
241 10 : int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
242 : char *buf, size_t buflen)
243 : {
244 : int subelem;
245 :
246 10 : subelem = atoi(cmd);
247 10 : if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
248 0 : return -1;
249 :
250 10 : if (global->wfd_subelem[subelem] == NULL)
251 2 : return 0;
252 :
253 16 : return wpa_snprintf_hex(buf, buflen,
254 8 : wpabuf_head_u8(global->wfd_subelem[subelem]) +
255 : 1,
256 8 : wpabuf_len(global->wfd_subelem[subelem]) - 1);
257 : }
258 :
259 :
260 313 : char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
261 : {
262 313 : char *subelem = NULL;
263 : const u8 *buf;
264 : size_t buflen;
265 313 : size_t i = 0;
266 : u16 elen;
267 :
268 313 : if (!wfd_subelems)
269 310 : return NULL;
270 :
271 3 : buf = wpabuf_head_u8(wfd_subelems);
272 3 : if (!buf)
273 0 : return NULL;
274 :
275 3 : buflen = wpabuf_len(wfd_subelems);
276 :
277 6 : while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
278 3 : elen = WPA_GET_BE16(buf + i + 1);
279 :
280 3 : if (buf[i] == id) {
281 3 : subelem = os_zalloc(2 * elen + 1);
282 3 : if (!subelem)
283 0 : return NULL;
284 6 : wpa_snprintf_hex(subelem, 2 * elen + 1,
285 3 : buf + i +
286 : WIFI_DISPLAY_SUBELEM_HEADER_LEN,
287 : elen);
288 3 : break;
289 : }
290 :
291 0 : i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
292 : }
293 :
294 3 : return subelem;
295 : }
|