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