Line data Source code
1 : /*
2 : * Wi-Fi Direct - P2P provision discovery
3 : * Copyright (c) 2009-2010, Atheros Communications
4 : *
5 : * This software may be distributed under the terms of the BSD license.
6 : * See README for more details.
7 : */
8 :
9 : #include "includes.h"
10 :
11 : #include "common.h"
12 : #include "common/ieee802_11_defs.h"
13 : #include "wps/wps_defs.h"
14 : #include "p2p_i.h"
15 : #include "p2p.h"
16 :
17 :
18 : /*
19 : * Number of retries to attempt for provision discovery requests
20 : * in case the peer is not listening.
21 : */
22 : #define MAX_PROV_DISC_REQ_RETRIES 120
23 :
24 :
25 207 : static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
26 : u16 config_methods)
27 : {
28 : u8 *len;
29 207 : wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
30 207 : len = wpabuf_put(buf, 1);
31 207 : wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
32 :
33 : /* Config Methods */
34 207 : wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
35 207 : wpabuf_put_be16(buf, 2);
36 207 : wpabuf_put_be16(buf, config_methods);
37 :
38 207 : p2p_buf_update_ie_hdr(buf, len);
39 207 : }
40 :
41 :
42 164 : static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
43 : u8 dialog_token,
44 : u16 config_methods,
45 : struct p2p_device *go)
46 : {
47 : struct wpabuf *buf;
48 : u8 *len;
49 164 : size_t extra = 0;
50 :
51 : #ifdef CONFIG_WIFI_DISPLAY
52 164 : if (p2p->wfd_ie_prov_disc_req)
53 0 : extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
54 : #endif /* CONFIG_WIFI_DISPLAY */
55 :
56 164 : buf = wpabuf_alloc(1000 + extra);
57 164 : if (buf == NULL)
58 0 : return NULL;
59 :
60 164 : p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
61 :
62 164 : len = p2p_buf_add_ie_hdr(buf);
63 164 : p2p_buf_add_capability(buf, p2p->dev_capab &
64 : ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
65 164 : p2p_buf_add_device_info(buf, p2p, NULL);
66 164 : if (go) {
67 66 : p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
68 33 : go->oper_ssid, go->oper_ssid_len);
69 : }
70 164 : p2p_buf_update_ie_hdr(buf, len);
71 :
72 : /* WPS IE with Config Methods attribute */
73 164 : p2p_build_wps_ie_config_methods(buf, config_methods);
74 :
75 : #ifdef CONFIG_WIFI_DISPLAY
76 164 : if (p2p->wfd_ie_prov_disc_req)
77 0 : wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
78 : #endif /* CONFIG_WIFI_DISPLAY */
79 :
80 164 : return buf;
81 : }
82 :
83 :
84 43 : static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
85 : u8 dialog_token,
86 : u16 config_methods,
87 : const u8 *group_id,
88 : size_t group_id_len)
89 : {
90 : struct wpabuf *buf;
91 43 : size_t extra = 0;
92 :
93 : #ifdef CONFIG_WIFI_DISPLAY
94 43 : struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
95 43 : if (wfd_ie && group_id) {
96 : size_t i;
97 0 : for (i = 0; i < p2p->num_groups; i++) {
98 0 : struct p2p_group *g = p2p->groups[i];
99 : struct wpabuf *ie;
100 0 : if (!p2p_group_is_group_id_match(g, group_id,
101 : group_id_len))
102 0 : continue;
103 0 : ie = p2p_group_get_wfd_ie(g);
104 0 : if (ie) {
105 0 : wfd_ie = ie;
106 0 : break;
107 : }
108 : }
109 : }
110 43 : if (wfd_ie)
111 0 : extra = wpabuf_len(wfd_ie);
112 : #endif /* CONFIG_WIFI_DISPLAY */
113 :
114 43 : buf = wpabuf_alloc(100 + extra);
115 43 : if (buf == NULL)
116 0 : return NULL;
117 :
118 43 : p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
119 :
120 : /* WPS IE with Config Methods attribute */
121 43 : p2p_build_wps_ie_config_methods(buf, config_methods);
122 :
123 : #ifdef CONFIG_WIFI_DISPLAY
124 43 : if (wfd_ie)
125 0 : wpabuf_put_buf(buf, wfd_ie);
126 : #endif /* CONFIG_WIFI_DISPLAY */
127 :
128 43 : return buf;
129 : }
130 :
131 :
132 44 : void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
133 : const u8 *data, size_t len, int rx_freq)
134 : {
135 : struct p2p_message msg;
136 : struct p2p_device *dev;
137 : int freq;
138 44 : int reject = 1;
139 : struct wpabuf *resp;
140 :
141 44 : if (p2p_parse(data, len, &msg))
142 2 : return;
143 :
144 301 : p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR
145 : " with config methods 0x%x (freq=%d)",
146 301 : MAC2STR(sa), msg.wps_config_methods, rx_freq);
147 :
148 43 : dev = p2p_get_device(p2p, sa);
149 43 : if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
150 216 : p2p_dbg(p2p, "Provision Discovery Request from unknown peer "
151 216 : MACSTR, MAC2STR(sa));
152 :
153 72 : if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1,
154 : 0)) {
155 6 : p2p_dbg(p2p, "Provision Discovery Request add device failed "
156 6 : MACSTR, MAC2STR(sa));
157 : }
158 7 : } else if (msg.wfd_subelems) {
159 0 : wpabuf_free(dev->info.wfd_subelems);
160 0 : dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
161 : }
162 :
163 43 : if (!(msg.wps_config_methods &
164 : (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
165 : WPS_CONFIG_PUSHBUTTON))) {
166 1 : p2p_dbg(p2p, "Unsupported Config Methods in Provision Discovery Request");
167 1 : goto out;
168 : }
169 :
170 42 : if (msg.group_id) {
171 : size_t i;
172 34 : for (i = 0; i < p2p->num_groups; i++) {
173 33 : if (p2p_group_is_group_id_match(p2p->groups[i],
174 : msg.group_id,
175 : msg.group_id_len))
176 33 : break;
177 : }
178 34 : if (i == p2p->num_groups) {
179 1 : p2p_dbg(p2p, "PD request for unknown P2P Group ID - reject");
180 1 : goto out;
181 : }
182 : }
183 :
184 41 : if (dev)
185 39 : dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
186 : P2P_DEV_PD_PEER_KEYPAD);
187 41 : if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
188 210 : p2p_dbg(p2p, "Peer " MACSTR
189 210 : " requested us to show a PIN on display", MAC2STR(sa));
190 35 : if (dev)
191 33 : dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
192 6 : } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
193 6 : p2p_dbg(p2p, "Peer " MACSTR
194 : " requested us to write its PIN using keypad",
195 6 : MAC2STR(sa));
196 1 : if (dev)
197 1 : dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
198 : }
199 :
200 41 : reject = 0;
201 :
202 : out:
203 84 : resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
204 41 : reject ? 0 : msg.wps_config_methods,
205 : msg.group_id, msg.group_id_len);
206 43 : if (resp == NULL) {
207 0 : p2p_parse_free(&msg);
208 0 : return;
209 : }
210 43 : p2p_dbg(p2p, "Sending Provision Discovery Response");
211 43 : if (rx_freq > 0)
212 43 : freq = rx_freq;
213 : else
214 0 : freq = p2p_channel_to_freq(p2p->cfg->reg_class,
215 0 : p2p->cfg->channel);
216 43 : if (freq < 0) {
217 0 : p2p_dbg(p2p, "Unknown regulatory class/channel");
218 0 : wpabuf_free(resp);
219 0 : p2p_parse_free(&msg);
220 0 : return;
221 : }
222 43 : p2p->pending_action_state = P2P_NO_PENDING_ACTION;
223 86 : if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
224 43 : p2p->cfg->dev_addr,
225 43 : wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
226 0 : p2p_dbg(p2p, "Failed to send Action frame");
227 : } else
228 43 : p2p->send_action_in_progress = 1;
229 :
230 43 : wpabuf_free(resp);
231 :
232 43 : if (!reject && p2p->cfg->prov_disc_req) {
233 41 : const u8 *dev_addr = sa;
234 41 : if (msg.p2p_device_addr)
235 41 : dev_addr = msg.p2p_device_addr;
236 287 : p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
237 41 : msg.wps_config_methods,
238 : dev_addr, msg.pri_dev_type,
239 41 : msg.device_name, msg.config_methods,
240 82 : msg.capability ? msg.capability[0] : 0,
241 82 : msg.capability ? msg.capability[1] :
242 : 0,
243 : msg.group_id, msg.group_id_len);
244 : }
245 43 : p2p_parse_free(&msg);
246 : }
247 :
248 :
249 41 : void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
250 : const u8 *data, size_t len)
251 : {
252 : struct p2p_message msg;
253 : struct p2p_device *dev;
254 41 : u16 report_config_methods = 0, req_config_methods;
255 41 : int success = 0;
256 :
257 41 : if (p2p_parse(data, len, &msg))
258 3 : return;
259 :
260 287 : p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
261 : " with config methods 0x%x",
262 287 : MAC2STR(sa), msg.wps_config_methods);
263 :
264 41 : dev = p2p_get_device(p2p, sa);
265 41 : if (dev == NULL || !dev->req_config_methods) {
266 0 : p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
267 0 : " with no pending request", MAC2STR(sa));
268 0 : p2p_parse_free(&msg);
269 0 : return;
270 : }
271 :
272 41 : if (dev->dialog_token != msg.dialog_token) {
273 2 : p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
274 2 : msg.dialog_token, dev->dialog_token);
275 1 : p2p_parse_free(&msg);
276 1 : return;
277 : }
278 :
279 40 : if (p2p->pending_action_state == P2P_PENDING_PD) {
280 39 : os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
281 39 : p2p->pending_action_state = P2P_NO_PENDING_ACTION;
282 : }
283 :
284 : /*
285 : * Use a local copy of the requested config methods since
286 : * p2p_reset_pending_pd() can clear this in the peer entry.
287 : */
288 40 : req_config_methods = dev->req_config_methods;
289 :
290 : /*
291 : * If the response is from the peer to whom a user initiated request
292 : * was sent earlier, we reset that state info here.
293 : */
294 79 : if (p2p->user_initiated_pd &&
295 39 : os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
296 0 : p2p_reset_pending_pd(p2p);
297 :
298 40 : if (msg.wps_config_methods != req_config_methods) {
299 2 : p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
300 1 : msg.wps_config_methods, req_config_methods);
301 1 : if (p2p->cfg->prov_disc_fail)
302 1 : p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
303 : P2P_PROV_DISC_REJECTED);
304 1 : p2p_parse_free(&msg);
305 1 : goto out;
306 : }
307 :
308 39 : report_config_methods = req_config_methods;
309 39 : dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
310 : P2P_DEV_PD_PEER_KEYPAD);
311 39 : if (req_config_methods & WPS_CONFIG_DISPLAY) {
312 198 : p2p_dbg(p2p, "Peer " MACSTR
313 198 : " accepted to show a PIN on display", MAC2STR(sa));
314 33 : dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
315 6 : } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
316 6 : p2p_dbg(p2p, "Peer " MACSTR
317 : " accepted to write our PIN using keypad",
318 6 : MAC2STR(sa));
319 1 : dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
320 : }
321 :
322 : /* Store the provisioning info */
323 39 : dev->wps_prov_info = msg.wps_config_methods;
324 :
325 39 : p2p_parse_free(&msg);
326 39 : success = 1;
327 :
328 : out:
329 40 : dev->req_config_methods = 0;
330 40 : p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
331 40 : if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
332 12 : p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
333 12 : MACSTR, MAC2STR(dev->info.p2p_device_addr));
334 2 : dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
335 2 : p2p_connect_send(p2p, dev);
336 2 : return;
337 : }
338 38 : if (success && p2p->cfg->prov_disc_resp)
339 37 : p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
340 : report_config_methods);
341 :
342 38 : if (p2p->state == P2P_PD_DURING_FIND) {
343 3 : p2p_clear_timeout(p2p);
344 3 : p2p_continue_find(p2p);
345 : }
346 : }
347 :
348 :
349 165 : int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
350 : int join, int force_freq)
351 : {
352 : struct wpabuf *req;
353 : int freq;
354 :
355 165 : if (force_freq > 0)
356 33 : freq = force_freq;
357 : else
358 132 : freq = dev->listen_freq > 0 ? dev->listen_freq :
359 : dev->oper_freq;
360 165 : if (freq <= 0) {
361 6 : p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
362 : MACSTR " to send Provision Discovery Request",
363 6 : MAC2STR(dev->info.p2p_device_addr));
364 1 : return -1;
365 : }
366 :
367 164 : if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
368 0 : if (!(dev->info.dev_capab &
369 : P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
370 0 : p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
371 : " that is in a group and is not discoverable",
372 0 : MAC2STR(dev->info.p2p_device_addr));
373 0 : return -1;
374 : }
375 : /* TODO: use device discoverability request through GO */
376 : }
377 :
378 328 : req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
379 164 : dev->req_config_methods,
380 : join ? dev : NULL);
381 164 : if (req == NULL)
382 0 : return -1;
383 :
384 164 : if (p2p->state != P2P_IDLE)
385 7 : p2p_stop_listen_for_freq(p2p, freq);
386 164 : p2p->pending_action_state = P2P_PENDING_PD;
387 328 : if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
388 164 : p2p->cfg->dev_addr, dev->info.p2p_device_addr,
389 164 : wpabuf_head(req), wpabuf_len(req), 200) < 0) {
390 0 : p2p_dbg(p2p, "Failed to send Action frame");
391 0 : wpabuf_free(req);
392 0 : return -1;
393 : }
394 :
395 164 : os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
396 :
397 164 : wpabuf_free(req);
398 164 : return 0;
399 : }
400 :
401 :
402 43 : int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
403 : u16 config_methods, int join, int force_freq,
404 : int user_initiated_pd)
405 : {
406 : struct p2p_device *dev;
407 :
408 43 : dev = p2p_get_device(p2p, peer_addr);
409 43 : if (dev == NULL)
410 1 : dev = p2p_get_device_interface(p2p, peer_addr);
411 43 : if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
412 6 : p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
413 6 : " not yet known", MAC2STR(peer_addr));
414 1 : return -1;
415 : }
416 :
417 294 : p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
418 : " (config methods 0x%x)",
419 252 : MAC2STR(peer_addr), config_methods);
420 42 : if (config_methods == 0)
421 0 : return -1;
422 :
423 : /* Reset provisioning info */
424 42 : dev->wps_prov_info = 0;
425 :
426 42 : dev->req_config_methods = config_methods;
427 42 : if (join)
428 33 : dev->flags |= P2P_DEV_PD_FOR_JOIN;
429 : else
430 9 : dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
431 :
432 44 : if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
433 2 : p2p->state != P2P_LISTEN_ONLY) {
434 0 : p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
435 : MACSTR " (config methods 0x%x)",
436 0 : MAC2STR(peer_addr), config_methods);
437 0 : return 0;
438 : }
439 :
440 42 : p2p->user_initiated_pd = user_initiated_pd;
441 42 : p2p->pd_force_freq = force_freq;
442 :
443 42 : if (p2p->user_initiated_pd)
444 41 : p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
445 :
446 : /*
447 : * Assign dialog token here to use the same value in each retry within
448 : * the same PD exchange.
449 : */
450 42 : dev->dialog_token++;
451 42 : if (dev->dialog_token == 0)
452 0 : dev->dialog_token = 1;
453 :
454 42 : return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
455 : }
456 :
457 :
458 1 : void p2p_reset_pending_pd(struct p2p_data *p2p)
459 : {
460 : struct p2p_device *dev;
461 :
462 2 : dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
463 1 : if (os_memcmp(p2p->pending_pd_devaddr,
464 : dev->info.p2p_device_addr, ETH_ALEN))
465 0 : continue;
466 1 : if (!dev->req_config_methods)
467 0 : continue;
468 1 : if (dev->flags & P2P_DEV_PD_FOR_JOIN)
469 0 : continue;
470 : /* Reset the config methods of the device */
471 1 : dev->req_config_methods = 0;
472 : }
473 :
474 1 : p2p->user_initiated_pd = 0;
475 1 : os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
476 1 : p2p->pd_retries = 0;
477 1 : p2p->pd_force_freq = 0;
478 1 : }
|