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