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