6e251c552f908f7e6e5da933db8eb28de40a3357
[mech_eap.git] / src / p2p / p2p_pd.c
1 /*
2  * Wi-Fi Direct - P2P provision discovery
3  * Copyright (c) 2009-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 "wps/wps_defs.h"
14 #include "p2p_i.h"
15 #include "p2p.h"
16
17
18 /*
19  * Number of retries to attempt for provision discovery requests during IDLE
20  * state in case the peer is not listening.
21  */
22 #define MAX_PROV_DISC_REQ_RETRIES 10
23
24
25 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
26                                             u16 config_methods)
27 {
28         u8 *len;
29         wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
30         len = wpabuf_put(buf, 1);
31         wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
32
33         /* Config Methods */
34         wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
35         wpabuf_put_be16(buf, 2);
36         wpabuf_put_be16(buf, config_methods);
37
38         p2p_buf_update_ie_hdr(buf, len);
39 }
40
41
42 static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
43                                                u8 dialog_token,
44                                                u16 config_methods,
45                                                struct p2p_device *go)
46 {
47         struct wpabuf *buf;
48         u8 *len;
49
50         buf = wpabuf_alloc(1000);
51         if (buf == NULL)
52                 return NULL;
53
54         p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
55
56         len = p2p_buf_add_ie_hdr(buf);
57         p2p_buf_add_capability(buf, p2p->dev_capab, 0);
58         p2p_buf_add_device_info(buf, p2p, NULL);
59         if (go) {
60                 p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
61                                      go->oper_ssid, go->oper_ssid_len);
62         }
63         p2p_buf_update_ie_hdr(buf, len);
64
65         /* WPS IE with Config Methods attribute */
66         p2p_build_wps_ie_config_methods(buf, config_methods);
67
68         return buf;
69 }
70
71
72 static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
73                                                 u8 dialog_token,
74                                                 u16 config_methods)
75 {
76         struct wpabuf *buf;
77
78         buf = wpabuf_alloc(100);
79         if (buf == NULL)
80                 return NULL;
81
82         p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
83
84         /* WPS IE with Config Methods attribute */
85         p2p_build_wps_ie_config_methods(buf, config_methods);
86
87         return buf;
88 }
89
90
91 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
92                                const u8 *data, size_t len, int rx_freq)
93 {
94         struct p2p_message msg;
95         struct p2p_device *dev;
96         int freq;
97         int reject = 1;
98         struct wpabuf *resp;
99
100         if (p2p_parse(data, len, &msg))
101                 return;
102
103         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
104                 "P2P: Received Provision Discovery Request from " MACSTR
105                 " with config methods 0x%x (freq=%d)",
106                 MAC2STR(sa), msg.wps_config_methods, rx_freq);
107
108         dev = p2p_get_device(p2p, sa);
109         if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
110                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
111                         "P2P: Provision Discovery Request from "
112                         "unknown peer " MACSTR, MAC2STR(sa));
113                 if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1, 0))
114                 {
115                         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
116                                 "P2P: Provision Discovery Request add device "
117                                 "failed " MACSTR, MAC2STR(sa));
118                 }
119         }
120
121         if (!(msg.wps_config_methods &
122               (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
123                WPS_CONFIG_PUSHBUTTON))) {
124                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported "
125                         "Config Methods in Provision Discovery Request");
126                 goto out;
127         }
128
129         if (msg.group_id) {
130                 size_t i;
131                 for (i = 0; i < p2p->num_groups; i++) {
132                         if (p2p_group_is_group_id_match(p2p->groups[i],
133                                                         msg.group_id,
134                                                         msg.group_id_len))
135                                 break;
136                 }
137                 if (i == p2p->num_groups) {
138                         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: PD "
139                                 "request for unknown P2P Group ID - reject");
140                         goto out;
141                 }
142         }
143
144         if (dev)
145                 dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
146                                 P2P_DEV_PD_PEER_KEYPAD);
147         if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
148                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
149                         " requested us to show a PIN on display", MAC2STR(sa));
150                 if (dev)
151                         dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
152         } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
153                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
154                         " requested us to write its PIN using keypad",
155                         MAC2STR(sa));
156                 if (dev)
157                         dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
158         }
159
160         reject = 0;
161
162 out:
163         resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
164                                         reject ? 0 : msg.wps_config_methods);
165         if (resp == NULL) {
166                 p2p_parse_free(&msg);
167                 return;
168         }
169         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
170                 "P2P: Sending Provision Discovery Response");
171         if (rx_freq > 0)
172                 freq = rx_freq;
173         else
174                 freq = p2p_channel_to_freq(p2p->cfg->country,
175                                            p2p->cfg->reg_class,
176                                            p2p->cfg->channel);
177         if (freq < 0) {
178                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
179                         "P2P: Unknown regulatory class/channel");
180                 wpabuf_free(resp);
181                 p2p_parse_free(&msg);
182                 return;
183         }
184         p2p->pending_action_state = P2P_NO_PENDING_ACTION;
185         if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
186                             p2p->cfg->dev_addr,
187                             wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
188                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
189                         "P2P: Failed to send Action frame");
190         }
191
192         wpabuf_free(resp);
193
194         if (!reject && p2p->cfg->prov_disc_req) {
195                 const u8 *dev_addr = sa;
196                 if (msg.p2p_device_addr)
197                         dev_addr = msg.p2p_device_addr;
198                 p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
199                                         msg.wps_config_methods,
200                                         dev_addr, msg.pri_dev_type,
201                                         msg.device_name, msg.config_methods,
202                                         msg.capability ? msg.capability[0] : 0,
203                                         msg.capability ? msg.capability[1] :
204                                         0,
205                                         msg.group_id, msg.group_id_len);
206         }
207         p2p_parse_free(&msg);
208 }
209
210
211 void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
212                                 const u8 *data, size_t len)
213 {
214         struct p2p_message msg;
215         struct p2p_device *dev;
216         u16 report_config_methods = 0;
217         int success = 0;
218
219         if (p2p_parse(data, len, &msg))
220                 return;
221
222         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
223                 "P2P: Received Provision Discovery Response from " MACSTR
224                 " with config methods 0x%x",
225                 MAC2STR(sa), msg.wps_config_methods);
226
227         dev = p2p_get_device(p2p, sa);
228         if (dev == NULL || !dev->req_config_methods) {
229                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
230                         "P2P: Ignore Provision Discovery Response from "
231                         MACSTR " with no pending request", MAC2STR(sa));
232                 p2p_parse_free(&msg);
233                 return;
234         }
235
236         if (p2p->pending_action_state == P2P_PENDING_PD) {
237                 os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
238                 p2p->pending_action_state = P2P_NO_PENDING_ACTION;
239         }
240
241         if (dev->dialog_token != msg.dialog_token) {
242                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
243                         "P2P: Ignore Provision Discovery Response with "
244                         "unexpected Dialog Token %u (expected %u)",
245                         msg.dialog_token, dev->dialog_token);
246                 p2p_parse_free(&msg);
247                 return;
248         }
249
250         /*
251          * If the response is from the peer to whom a user initiated request
252          * was sent earlier, we reset that state info here.
253          */
254         if (p2p->user_initiated_pd &&
255             os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
256                 p2p_reset_pending_pd(p2p);
257
258         if (msg.wps_config_methods != dev->req_config_methods) {
259                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
260                         "our Provision Discovery Request");
261                 if (p2p->cfg->prov_disc_fail)
262                         p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
263                                                  P2P_PROV_DISC_REJECTED);
264                 p2p_parse_free(&msg);
265                 goto out;
266         }
267
268         report_config_methods = dev->req_config_methods;
269         dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
270                         P2P_DEV_PD_PEER_KEYPAD);
271         if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
272                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
273                         " accepted to show a PIN on display", MAC2STR(sa));
274                 dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
275         } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
276                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
277                         " accepted to write our PIN using keypad",
278                         MAC2STR(sa));
279                 dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
280         }
281
282         /* Store the provisioning info */
283         dev->wps_prov_info = msg.wps_config_methods;
284
285         p2p_parse_free(&msg);
286         success = 1;
287
288 out:
289         dev->req_config_methods = 0;
290         p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
291         if (success && p2p->cfg->prov_disc_resp)
292                 p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
293                                          report_config_methods);
294 }
295
296
297 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
298                            int join, int force_freq)
299 {
300         struct wpabuf *req;
301         int freq;
302
303         if (force_freq > 0)
304                 freq = force_freq;
305         else
306                 freq = dev->listen_freq > 0 ? dev->listen_freq :
307                         dev->oper_freq;
308         if (freq <= 0) {
309                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
310                         "P2P: No Listen/Operating frequency known for the "
311                         "peer " MACSTR " to send Provision Discovery Request",
312                         MAC2STR(dev->info.p2p_device_addr));
313                 return -1;
314         }
315
316         if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
317                 if (!(dev->info.dev_capab &
318                       P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
319                         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
320                                 "P2P: Cannot use PD with P2P Device " MACSTR
321                                 " that is in a group and is not discoverable",
322                                 MAC2STR(dev->info.p2p_device_addr));
323                         return -1;
324                 }
325                 /* TODO: use device discoverability request through GO */
326         }
327
328         dev->dialog_token++;
329         if (dev->dialog_token == 0)
330                 dev->dialog_token = 1;
331         req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
332                                       dev->req_config_methods,
333                                       join ? dev : NULL);
334         if (req == NULL)
335                 return -1;
336
337         if (p2p->state != P2P_IDLE)
338                 p2p_stop_listen_for_freq(p2p, freq);
339         p2p->pending_action_state = P2P_PENDING_PD;
340         if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
341                             p2p->cfg->dev_addr, dev->info.p2p_device_addr,
342                             wpabuf_head(req), wpabuf_len(req), 200) < 0) {
343                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
344                         "P2P: Failed to send Action frame");
345                 wpabuf_free(req);
346                 return -1;
347         }
348
349         os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
350
351         wpabuf_free(req);
352         return 0;
353 }
354
355
356 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
357                       u16 config_methods, int join, int force_freq)
358 {
359         struct p2p_device *dev;
360
361         dev = p2p_get_device(p2p, peer_addr);
362         if (dev == NULL)
363                 dev = p2p_get_device_interface(p2p, peer_addr);
364         if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
365                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision "
366                         "Discovery Request destination " MACSTR
367                         " not yet known", MAC2STR(peer_addr));
368                 return -1;
369         }
370
371         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery "
372                 "Request with " MACSTR " (config methods 0x%x)",
373                 MAC2STR(peer_addr), config_methods);
374         if (config_methods == 0)
375                 return -1;
376
377         /* Reset provisioning info */
378         dev->wps_prov_info = 0;
379
380         dev->req_config_methods = config_methods;
381         if (join)
382                 dev->flags |= P2P_DEV_PD_FOR_JOIN;
383         else
384                 dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
385
386         if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
387             p2p->state != P2P_LISTEN_ONLY) {
388                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other "
389                         "operations; postpone Provision Discovery Request "
390                         "with " MACSTR " (config methods 0x%x)",
391                         MAC2STR(peer_addr), config_methods);
392                 return 0;
393         }
394
395         /*
396          * We use the join param as a cue to differentiate between user
397          * initiated PD request and one issued during finds (internal).
398          */
399         p2p->user_initiated_pd = !join;
400
401         /* Also set some retries to attempt in case of IDLE state */
402         if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
403                 p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
404
405         return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
406 }
407
408
409 void p2p_reset_pending_pd(struct p2p_data *p2p)
410 {
411         struct p2p_device *dev;
412
413         dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
414                 if (os_memcmp(p2p->pending_pd_devaddr,
415                               dev->info.p2p_device_addr, ETH_ALEN))
416                         continue;
417                 if (!dev->req_config_methods)
418                         continue;
419                 if (dev->flags & P2P_DEV_PD_FOR_JOIN)
420                         continue;
421                 /* Reset the config methods of the device */
422                 dev->req_config_methods = 0;
423         }
424
425         p2p->user_initiated_pd = 0;
426         os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
427         p2p->pd_retries = 0;
428 }