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