Branch data 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 : 6 : static int wifi_display_update_wfd_ie(struct wpa_global *global)
40 : : {
41 : : struct wpabuf *ie, *buf;
42 : : size_t len, plen;
43 : :
44 [ - + ]: 6 : if (global->p2p == NULL)
45 : 0 : return 0;
46 : :
47 : 6 : wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
48 : :
49 [ - + ]: 6 : if (!global->wifi_display) {
50 : 0 : wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
51 : : "include WFD IE");
52 : 0 : p2p_set_wfd_ie_beacon(global->p2p, NULL);
53 : 0 : p2p_set_wfd_ie_probe_req(global->p2p, NULL);
54 : 0 : p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
55 : 0 : p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
56 : 0 : p2p_set_wfd_ie_invitation(global->p2p, NULL);
57 : 0 : p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
58 : 0 : p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
59 : 0 : p2p_set_wfd_ie_go_neg(global->p2p, NULL);
60 : 0 : p2p_set_wfd_dev_info(global->p2p, NULL);
61 : 0 : p2p_set_wfd_assoc_bssid(global->p2p, NULL);
62 : 0 : p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
63 : 0 : return 0;
64 : : }
65 : :
66 : 6 : p2p_set_wfd_dev_info(global->p2p,
67 : 6 : global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
68 : 6 : p2p_set_wfd_assoc_bssid(
69 : : global->p2p,
70 : 6 : global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
71 : 6 : p2p_set_wfd_coupled_sink_info(
72 : 6 : 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 : 6 : len = 0;
105 [ + + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
106 : 3 : len += wpabuf_len(global->wfd_subelem[
107 : : WFD_SUBELEM_DEVICE_INFO]);
108 [ - + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
109 : 0 : len += wpabuf_len(global->wfd_subelem[
110 : : WFD_SUBELEM_ASSOCIATED_BSSID]);
111 [ - + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
112 : 0 : len += wpabuf_len(global->wfd_subelem[
113 : : WFD_SUBELEM_COUPLED_SINK]);
114 [ - + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
115 : 0 : len += wpabuf_len(global->wfd_subelem[
116 : : WFD_SUBELEM_SESSION_INFO]);
117 [ - + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
118 : 0 : len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
119 : 6 : buf = wpabuf_alloc(len);
120 [ - + ]: 6 : if (buf == NULL)
121 : 0 : return -1;
122 : :
123 [ + + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
124 : 3 : wpabuf_put_buf(buf,
125 : 3 : global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
126 [ - + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
127 : 0 : wpabuf_put_buf(buf, global->wfd_subelem[
128 : : WFD_SUBELEM_ASSOCIATED_BSSID]);
129 [ - + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
130 : 0 : wpabuf_put_buf(buf,
131 : 0 : global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
132 : :
133 : 6 : ie = wifi_display_encaps(buf);
134 : 6 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
135 : 6 : p2p_set_wfd_ie_beacon(global->p2p, ie);
136 : :
137 : 6 : ie = wifi_display_encaps(buf);
138 : 6 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
139 : : ie);
140 : 6 : p2p_set_wfd_ie_assoc_req(global->p2p, ie);
141 : :
142 : 6 : ie = wifi_display_encaps(buf);
143 : 6 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
144 : 6 : p2p_set_wfd_ie_go_neg(global->p2p, ie);
145 : :
146 : 6 : ie = wifi_display_encaps(buf);
147 : 6 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
148 : : "Request", ie);
149 : 6 : p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
150 : :
151 : 6 : plen = buf->used;
152 [ - + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
153 : 0 : wpabuf_put_buf(buf,
154 : 0 : global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
155 : :
156 : 6 : ie = wifi_display_encaps(buf);
157 : 6 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
158 : 6 : p2p_set_wfd_ie_probe_req(global->p2p, ie);
159 : :
160 [ - + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
161 : 0 : wpabuf_put_buf(buf,
162 : 0 : global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
163 : 6 : ie = wifi_display_encaps(buf);
164 : 6 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
165 : 6 : p2p_set_wfd_ie_probe_resp(global->p2p, ie);
166 : :
167 : : /* Remove WFD Extended Capability from buffer */
168 : 6 : buf->used = plen;
169 [ - + ]: 6 : if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
170 : 0 : wpabuf_put_buf(buf,
171 : 0 : global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
172 : :
173 : 6 : ie = wifi_display_encaps(buf);
174 : 6 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
175 : 6 : p2p_set_wfd_ie_invitation(global->p2p, ie);
176 : :
177 : 6 : ie = wifi_display_encaps(buf);
178 : 6 : wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
179 : : "Response", ie);
180 : 6 : p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
181 : :
182 : 6 : wpabuf_free(buf);
183 : :
184 : 6 : return 0;
185 : : }
186 : :
187 : :
188 : 3 : void wifi_display_enable(struct wpa_global *global, int enabled)
189 : : {
190 [ + - ]: 3 : wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
191 : : enabled ? "enabled" : "disabled");
192 : 3 : global->wifi_display = enabled;
193 : 3 : wifi_display_update_wfd_ie(global);
194 : 3 : }
195 : :
196 : :
197 : 3 : 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 : 3 : pos = os_strchr(cmd, ' ');
205 [ - + ]: 3 : if (pos == NULL)
206 : 0 : return -1;
207 : 3 : *pos++ = '\0';
208 : 3 : subelem = atoi(cmd);
209 [ + - ][ - + ]: 3 : if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
210 : 0 : return -1;
211 : :
212 : 3 : len = os_strlen(pos);
213 [ - + ]: 3 : if (len & 1)
214 : 0 : return -1;
215 : 3 : len /= 2;
216 : :
217 [ - + ]: 3 : if (len == 0) {
218 : : /* Clear subelement */
219 : 0 : e = NULL;
220 : 0 : wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
221 : : } else {
222 : 3 : e = wpabuf_alloc(1 + len);
223 [ - + ]: 3 : if (e == NULL)
224 : 0 : return -1;
225 : 3 : wpabuf_put_u8(e, subelem);
226 [ - + ]: 3 : if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
227 : 0 : wpabuf_free(e);
228 : 0 : return -1;
229 : : }
230 : 3 : wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
231 : : }
232 : :
233 : 3 : wpabuf_free(global->wfd_subelem[subelem]);
234 : 3 : global->wfd_subelem[subelem] = e;
235 : 3 : wifi_display_update_wfd_ie(global);
236 : :
237 : 3 : return 0;
238 : : }
239 : :
240 : :
241 : 2 : int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
242 : : char *buf, size_t buflen)
243 : : {
244 : : int subelem;
245 : :
246 : 2 : subelem = atoi(cmd);
247 [ + - ][ - + ]: 2 : if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
248 : 0 : return -1;
249 : :
250 [ - + ]: 2 : if (global->wfd_subelem[subelem] == NULL)
251 : 0 : return 0;
252 : :
253 : 2 : return wpa_snprintf_hex(buf, buflen,
254 : 2 : wpabuf_head_u8(global->wfd_subelem[subelem]) +
255 : : 1,
256 : 2 : wpabuf_len(global->wfd_subelem[subelem]) - 1);
257 : : }
258 : :
259 : :
260 : 241 : char * wifi_display_subelem_hex(const struct wpabuf *wfd_subelems, u8 id)
261 : : {
262 : 241 : char *subelem = NULL;
263 : : const u8 *buf;
264 : : size_t buflen;
265 : 241 : size_t i = 0;
266 : : u16 elen;
267 : :
268 [ + + ]: 241 : if (!wfd_subelems)
269 : 59 : return NULL;
270 : :
271 : 182 : buf = wpabuf_head_u8(wfd_subelems);
272 [ - + ]: 182 : if (!buf)
273 : 0 : return NULL;
274 : :
275 : 182 : buflen = wpabuf_len(wfd_subelems);
276 : :
277 [ + - ]: 182 : while (i + WIFI_DISPLAY_SUBELEM_HEADER_LEN < buflen) {
278 : 182 : elen = WPA_GET_BE16(buf + i + 1);
279 : :
280 [ + - ]: 182 : if (buf[i] == id) {
281 : 182 : subelem = os_zalloc(2 * elen + 1);
282 [ - + ]: 182 : if (!subelem)
283 : 0 : return NULL;
284 : 182 : wpa_snprintf_hex(subelem, 2 * elen + 1,
285 : 182 : buf + i +
286 : : WIFI_DISPLAY_SUBELEM_HEADER_LEN,
287 : : elen);
288 : 182 : break;
289 : : }
290 : :
291 : 0 : i += elen + WIFI_DISPLAY_SUBELEM_HEADER_LEN;
292 : : }
293 : :
294 : 241 : return subelem;
295 : : }
|