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