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