]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/wpa/src/p2p/p2p_dev_disc.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / wpa / src / p2p / p2p_dev_disc.c
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 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         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
43 void 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
70 int 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
113 static 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
132 void 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
141 static 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
167 void 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
229 void 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
312 void 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
335 void 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 }