p2p_pd.c revision 4582d2a5dd8180c52eb95b1100fb183b9a289708
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	} else
228		p2p->send_action_in_progress = 1;
229
230	wpabuf_free(resp);
231
232	if (!reject && p2p->cfg->prov_disc_req) {
233		const u8 *dev_addr = sa;
234		if (msg.p2p_device_addr)
235			dev_addr = msg.p2p_device_addr;
236		p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
237					msg.wps_config_methods,
238					dev_addr, msg.pri_dev_type,
239					msg.device_name, msg.config_methods,
240					msg.capability ? msg.capability[0] : 0,
241					msg.capability ? msg.capability[1] :
242					0,
243					msg.group_id, msg.group_id_len);
244	}
245	p2p_parse_free(&msg);
246}
247
248
249void 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	u16 report_config_methods = 0, req_config_methods;
255	int success = 0;
256
257	if (p2p_parse(data, len, &msg))
258		return;
259
260	p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR
261		" with config methods 0x%x",
262		MAC2STR(sa), msg.wps_config_methods);
263
264	dev = p2p_get_device(p2p, sa);
265	if (dev == NULL || !dev->req_config_methods) {
266		p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR
267			" with no pending request", MAC2STR(sa));
268		p2p_parse_free(&msg);
269		return;
270	}
271
272	if (dev->dialog_token != msg.dialog_token) {
273		p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)",
274			msg.dialog_token, dev->dialog_token);
275		p2p_parse_free(&msg);
276		return;
277	}
278
279	if (p2p->pending_action_state == P2P_PENDING_PD) {
280		os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
281		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	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	if (p2p->user_initiated_pd &&
295	    os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
296		p2p_reset_pending_pd(p2p);
297
298	if (msg.wps_config_methods != req_config_methods) {
299		p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x",
300			msg.wps_config_methods, req_config_methods);
301		if (p2p->cfg->prov_disc_fail)
302			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
303						 P2P_PROV_DISC_REJECTED);
304		p2p_parse_free(&msg);
305		goto out;
306	}
307
308	report_config_methods = req_config_methods;
309	dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
310			P2P_DEV_PD_PEER_KEYPAD);
311	if (req_config_methods & WPS_CONFIG_DISPLAY) {
312		p2p_dbg(p2p, "Peer " MACSTR
313			" accepted to show a PIN on display", MAC2STR(sa));
314		dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
315	} else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
316		p2p_dbg(p2p, "Peer " MACSTR
317			" accepted to write our PIN using keypad",
318			MAC2STR(sa));
319		dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
320	}
321
322	/* Store the provisioning info */
323	dev->wps_prov_info = msg.wps_config_methods;
324
325	p2p_parse_free(&msg);
326	success = 1;
327
328out:
329	dev->req_config_methods = 0;
330	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
331	if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) {
332		p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with "
333			MACSTR, MAC2STR(dev->info.p2p_device_addr));
334		dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG;
335		p2p_connect_send(p2p, dev);
336		return;
337	}
338	if (success && p2p->cfg->prov_disc_resp)
339		p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
340					 report_config_methods);
341
342	if (p2p->state == P2P_PD_DURING_FIND) {
343		p2p_clear_timeout(p2p);
344		p2p_continue_find(p2p);
345	}
346}
347
348
349int 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	if (force_freq > 0)
356		freq = force_freq;
357	else
358		freq = dev->listen_freq > 0 ? dev->listen_freq :
359			dev->oper_freq;
360	if (freq <= 0) {
361		p2p_dbg(p2p, "No Listen/Operating frequency known for the peer "
362			MACSTR " to send Provision Discovery Request",
363			MAC2STR(dev->info.p2p_device_addr));
364		return -1;
365	}
366
367	if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
368		if (!(dev->info.dev_capab &
369		      P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
370			p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR
371				" that is in a group and is not discoverable",
372				MAC2STR(dev->info.p2p_device_addr));
373			return -1;
374		}
375		/* TODO: use device discoverability request through GO */
376	}
377
378	req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
379				      dev->req_config_methods,
380				      join ? dev : NULL);
381	if (req == NULL)
382		return -1;
383
384	if (p2p->state != P2P_IDLE)
385		p2p_stop_listen_for_freq(p2p, freq);
386	p2p->pending_action_state = P2P_PENDING_PD;
387	if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
388			    p2p->cfg->dev_addr, dev->info.p2p_device_addr,
389			    wpabuf_head(req), wpabuf_len(req), 200) < 0) {
390		p2p_dbg(p2p, "Failed to send Action frame");
391		wpabuf_free(req);
392		return -1;
393	}
394
395	os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
396
397	wpabuf_free(req);
398	return 0;
399}
400
401
402int 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	dev = p2p_get_device(p2p, peer_addr);
409	if (dev == NULL)
410		dev = p2p_get_device_interface(p2p, peer_addr);
411	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
412		p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR
413			" not yet known", MAC2STR(peer_addr));
414		return -1;
415	}
416
417	p2p_dbg(p2p, "Provision Discovery Request with " MACSTR
418		" (config methods 0x%x)",
419		MAC2STR(peer_addr), config_methods);
420	if (config_methods == 0)
421		return -1;
422
423	/* Reset provisioning info */
424	dev->wps_prov_info = 0;
425
426	dev->req_config_methods = config_methods;
427	if (join)
428		dev->flags |= P2P_DEV_PD_FOR_JOIN;
429	else
430		dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
431
432	if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
433	    p2p->state != P2P_LISTEN_ONLY) {
434		p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with "
435			MACSTR " (config methods 0x%x)",
436			MAC2STR(peer_addr), config_methods);
437		return 0;
438	}
439
440	p2p->user_initiated_pd = user_initiated_pd;
441	p2p->pd_force_freq = force_freq;
442
443	if (p2p->user_initiated_pd)
444		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	dev->dialog_token++;
451	if (dev->dialog_token == 0)
452		dev->dialog_token = 1;
453
454	return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
455}
456
457
458void p2p_reset_pending_pd(struct p2p_data *p2p)
459{
460	struct p2p_device *dev;
461
462	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
463		if (os_memcmp(p2p->pending_pd_devaddr,
464			      dev->info.p2p_device_addr, ETH_ALEN))
465			continue;
466		if (!dev->req_config_methods)
467			continue;
468		if (dev->flags & P2P_DEV_PD_FOR_JOIN)
469			continue;
470		/* Reset the config methods of the device */
471		dev->req_config_methods = 0;
472	}
473
474	p2p->user_initiated_pd = 0;
475	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
476	p2p->pd_retries = 0;
477	p2p->pd_force_freq = 0;
478}
479