p2p_dev_disc.c revision c5ec7f57ead87efa365800228aa0b09a12d9e6c4
1/*
2 * Wi-Fi Direct - P2P Device Discoverability procedure
3 * Copyright (c) 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 "p2p_i.h"
14#include "p2p.h"
15
16
17static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p,
18					      struct p2p_device *go,
19					      const u8 *dev_id)
20{
21	struct wpabuf *buf;
22	u8 *len;
23
24	buf = wpabuf_alloc(100);
25	if (buf == NULL)
26		return NULL;
27
28	go->dialog_token++;
29	if (go->dialog_token == 0)
30		go->dialog_token = 1;
31	p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_REQ, go->dialog_token);
32
33	len = p2p_buf_add_ie_hdr(buf);
34	p2p_buf_add_device_id(buf, dev_id);
35	p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid,
36			     go->oper_ssid_len);
37	p2p_buf_update_ie_hdr(buf, len);
38
39	return buf;
40}
41
42
43void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success)
44{
45	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
46		"P2P: Device Discoverability Request TX callback: success=%d",
47		success);
48
49	if (!success) {
50		/*
51		 * Use P2P find, if needed, to find the other device or to
52		 * retry device discoverability.
53		 */
54		p2p_set_state(p2p, P2P_CONNECT);
55		p2p_set_timeout(p2p, 0, 100000);
56		return;
57	}
58
59	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
60		"P2P: GO acknowledged Device Discoverability Request - wait "
61		"for response");
62	/*
63	 * TODO: is the remain-on-channel from Action frame TX long enough for
64	 * most cases or should we try to increase its duration and/or start
65	 * another remain-on-channel if needed once the previous one expires?
66	 */
67}
68
69
70int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev)
71{
72	struct p2p_device *go;
73	struct wpabuf *req;
74
75	go = p2p_get_device(p2p, dev->member_in_go_dev);
76	if (go == NULL || dev->oper_freq <= 0) {
77		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
78			"P2P: Could not find peer entry for GO and frequency "
79			"to send Device Discoverability Request");
80		return -1;
81	}
82
83	req = p2p_build_dev_disc_req(p2p, go, dev->info.p2p_device_addr);
84	if (req == NULL)
85		return -1;
86
87	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
88		"P2P: Sending Device Discoverability Request to GO " MACSTR
89		" for client " MACSTR,
90		MAC2STR(go->info.p2p_device_addr),
91		MAC2STR(dev->info.p2p_device_addr));
92
93	p2p->pending_client_disc_go = go;
94	os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr,
95		  ETH_ALEN);
96	p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST;
97	if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr,
98			    p2p->cfg->dev_addr, go->info.p2p_device_addr,
99			    wpabuf_head(req), wpabuf_len(req), 1000) < 0) {
100		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
101			"P2P: Failed to send Action frame");
102		wpabuf_free(req);
103		/* TODO: how to recover from failure? */
104		return -1;
105	}
106
107	wpabuf_free(req);
108
109	return 0;
110}
111
112
113static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status)
114{
115	struct wpabuf *buf;
116	u8 *len;
117
118	buf = wpabuf_alloc(100);
119	if (buf == NULL)
120		return NULL;
121
122	p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_RESP, dialog_token);
123
124	len = p2p_buf_add_ie_hdr(buf);
125	p2p_buf_add_status(buf, status);
126	p2p_buf_update_ie_hdr(buf, len);
127
128	return buf;
129}
130
131
132void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success)
133{
134	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
135		"P2P: Device Discoverability Response TX callback: success=%d",
136		success);
137	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
138}
139
140
141static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token,
142				   const u8 *addr, int freq, u8 status)
143{
144	struct wpabuf *resp;
145
146	resp = p2p_build_dev_disc_resp(dialog_token, status);
147	if (resp == NULL)
148		return;
149
150	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
151		"P2P: Sending Device Discoverability Response to " MACSTR
152		" (status %u freq %d)",
153		MAC2STR(addr), status, freq);
154
155	p2p->pending_action_state = P2P_PENDING_DEV_DISC_RESPONSE;
156	if (p2p_send_action(p2p, freq, addr, p2p->cfg->dev_addr,
157			    p2p->cfg->dev_addr,
158			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
159		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
160			"P2P: Failed to send Action frame");
161	}
162
163	wpabuf_free(resp);
164}
165
166
167void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa,
168			      const u8 *data, size_t len, int rx_freq)
169{
170	struct p2p_message msg;
171	size_t g;
172
173	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
174		"P2P: Received Device Discoverability Request from " MACSTR
175		" (freq=%d)", MAC2STR(sa), rx_freq);
176
177	if (p2p_parse(data, len, &msg))
178		return;
179
180	if (msg.dialog_token == 0) {
181		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
182			"P2P: Invalid Dialog Token 0 (must be nonzero) in "
183			"Device Discoverability Request");
184		p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
185				       P2P_SC_FAIL_INVALID_PARAMS);
186		p2p_parse_free(&msg);
187		return;
188	}
189
190	if (msg.device_id == NULL) {
191		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
192			"P2P: P2P Device ID attribute missing from Device "
193			"Discoverability Request");
194		p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
195				       P2P_SC_FAIL_INVALID_PARAMS);
196		p2p_parse_free(&msg);
197		return;
198	}
199
200	for (g = 0; g < p2p->num_groups; g++) {
201		if (p2p_group_go_discover(p2p->groups[g], msg.device_id, sa,
202					  rx_freq) == 0) {
203			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scheduled "
204				"GO Discoverability Request for the target "
205				"device");
206			/*
207			 * P2P group code will use a callback to indicate TX
208			 * status, so that we can reply to the request once the
209			 * target client has acknowledged the request or it has
210			 * timed out.
211			 */
212			p2p->pending_dev_disc_dialog_token = msg.dialog_token;
213			os_memcpy(p2p->pending_dev_disc_addr, sa, ETH_ALEN);
214			p2p->pending_dev_disc_freq = rx_freq;
215			p2p_parse_free(&msg);
216			return;
217		}
218	}
219
220	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Requested client "
221		"was not found in any group or did not support client "
222		"discoverability");
223	p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq,
224			       P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE);
225	p2p_parse_free(&msg);
226}
227
228
229void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa,
230			       const u8 *data, size_t len)
231{
232	struct p2p_message msg;
233	struct p2p_device *go;
234	u8 status;
235
236	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
237		"P2P: Received Device Discoverability Response from " MACSTR,
238		MAC2STR(sa));
239
240	go = p2p->pending_client_disc_go;
241	if (go == NULL ||
242	    os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) {
243		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected "
244			"Device Discoverability Response");
245		return;
246	}
247
248	if (p2p_parse(data, len, &msg))
249		return;
250
251	if (msg.status == NULL) {
252		p2p_parse_free(&msg);
253		return;
254	}
255
256	if (msg.dialog_token != go->dialog_token) {
257		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore Device "
258			"Discoverability Response with unexpected dialog "
259			"token %u (expected %u)",
260			msg.dialog_token, go->dialog_token);
261		p2p_parse_free(&msg);
262		return;
263	}
264
265	status = *msg.status;
266	p2p_parse_free(&msg);
267
268	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
269		"P2P: Device Discoverability Response status %u", status);
270
271	if (p2p->go_neg_peer == NULL ||
272	    os_memcmp(p2p->pending_client_disc_addr,
273		      p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 ||
274	    os_memcmp(p2p->go_neg_peer->member_in_go_dev,
275		      go->info.p2p_device_addr, ETH_ALEN) != 0) {
276		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending "
277			"operation with the client discoverability peer "
278			"anymore");
279		return;
280	}
281
282	if (status == 0) {
283		/*
284		 * Peer is expected to be awake for at least 100 TU; try to
285		 * connect immediately.
286		 */
287		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
288			"P2P: Client discoverability request succeeded");
289		if (p2p->state == P2P_CONNECT) {
290			/*
291			 * Change state to force the timeout to start in
292			 * P2P_CONNECT again without going through the short
293			 * Listen state.
294			 */
295			p2p_set_state(p2p, P2P_CONNECT_LISTEN);
296			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
297		}
298		p2p_set_timeout(p2p, 0, 0);
299	} else {
300		/*
301		 * Client discoverability request failed; try to connect from
302		 * timeout.
303		 */
304		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
305			"P2P: Client discoverability request failed");
306		p2p_set_timeout(p2p, 0, 500000);
307	}
308
309}
310
311
312void p2p_go_disc_req_cb(struct p2p_data *p2p, int success)
313{
314	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
315		"P2P: GO Discoverability Request TX callback: success=%d",
316		success);
317	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
318
319	if (p2p->pending_dev_disc_dialog_token == 0) {
320		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending Device "
321			"Discoverability Request");
322		return;
323	}
324
325	p2p_send_dev_disc_resp(p2p, p2p->pending_dev_disc_dialog_token,
326			       p2p->pending_dev_disc_addr,
327			       p2p->pending_dev_disc_freq,
328			       success ? P2P_SC_SUCCESS :
329			       P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE);
330
331	p2p->pending_dev_disc_dialog_token = 0;
332}
333
334
335void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa,
336			     const u8 *data, size_t len, int rx_freq)
337{
338	unsigned int tu;
339	struct wpabuf *ies;
340
341	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
342		"P2P: Received GO Discoverability Request - remain awake for "
343		"100 TU");
344
345	ies = p2p_build_probe_resp_ies(p2p);
346	if (ies == NULL)
347		return;
348
349	/* Remain awake 100 TU on operating channel */
350	p2p->pending_client_disc_freq = rx_freq;
351	tu = 100;
352	if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, rx_freq, 1024 * tu / 1000,
353		    ies) < 0) {
354		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
355			"P2P: Failed to start listen mode for client "
356			"discoverability");
357	}
358	wpabuf_free(ies);
359}
360