Branch data 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 : 3 : 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 : 3 : 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 : 3 : 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 : 3 : p2p_dbg(p2p, "Received Device Discoverability Response from " MACSTR,
218 : 18 : MAC2STR(sa));
219 : :
220 : 3 : go = p2p->pending_client_disc_go;
221 [ + - ][ - + ]: 3 : 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 [ + - ][ + - ]: 3 : 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 : : }
|