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