remove @EAP_LDFLAGS@, no longer exists
[mech_eap.orig] / libeap / src / p2p / p2p_pd.c
1 /*
2  * Wi-Fi Direct - P2P provision discovery
3  * Copyright (c) 2009-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 "wps/wps_defs.h"
20 #include "p2p_i.h"
21 #include "p2p.h"
22
23
24 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
25                                             u16 config_methods)
26 {
27         u8 *len;
28         wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
29         len = wpabuf_put(buf, 1);
30         wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
31
32         /* Config Methods */
33         wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
34         wpabuf_put_be16(buf, 2);
35         wpabuf_put_be16(buf, config_methods);
36
37         p2p_buf_update_ie_hdr(buf, len);
38 }
39
40
41 static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
42                                                u8 dialog_token,
43                                                u16 config_methods,
44                                                struct p2p_device *go)
45 {
46         struct wpabuf *buf;
47         u8 *len;
48
49         buf = wpabuf_alloc(1000);
50         if (buf == NULL)
51                 return NULL;
52
53         p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
54
55         len = p2p_buf_add_ie_hdr(buf);
56         p2p_buf_add_capability(buf, p2p->dev_capab, 0);
57         p2p_buf_add_device_info(buf, p2p, NULL);
58         if (go) {
59                 p2p_buf_add_group_id(buf, go->p2p_device_addr, go->oper_ssid,
60                                      go->oper_ssid_len);
61         }
62         p2p_buf_update_ie_hdr(buf, len);
63
64         /* WPS IE with Config Methods attribute */
65         p2p_build_wps_ie_config_methods(buf, config_methods);
66
67         return buf;
68 }
69
70
71 static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
72                                                 u8 dialog_token,
73                                                 u16 config_methods)
74 {
75         struct wpabuf *buf;
76
77         buf = wpabuf_alloc(100);
78         if (buf == NULL)
79                 return NULL;
80
81         p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
82
83         /* WPS IE with Config Methods attribute */
84         p2p_build_wps_ie_config_methods(buf, config_methods);
85
86         return buf;
87 }
88
89
90 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
91                                const u8 *data, size_t len, int rx_freq)
92 {
93         struct p2p_message msg;
94         struct p2p_device *dev;
95         int freq;
96         int reject = 1;
97         struct wpabuf *resp;
98
99         if (p2p_parse(data, len, &msg))
100                 return;
101
102         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
103                 "P2P: Received Provision Discovery Request from " MACSTR
104                 " with config methods 0x%x (freq=%d)",
105                 MAC2STR(sa), msg.wps_config_methods, rx_freq);
106
107         dev = p2p_get_device(p2p, sa);
108         if (dev == NULL || !(dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
109                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
110                         "P2P: Provision Discovery Request from "
111                         "unknown peer " MACSTR, MAC2STR(sa));
112                 if (p2p_add_device(p2p, sa, rx_freq, 0, data + 1, len - 1)) {
113                         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
114                                 "P2P: Provision Discovery Request add device "
115                                 "failed " MACSTR, MAC2STR(sa));
116                 }
117         }
118
119         if (!(msg.wps_config_methods &
120               (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD |
121                WPS_CONFIG_PUSHBUTTON))) {
122                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Unsupported "
123                         "Config Methods in Provision Discovery Request");
124                 goto out;
125         }
126
127         if (dev)
128                 dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
129                                 P2P_DEV_PD_PEER_KEYPAD);
130         if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) {
131                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
132                         " requested us to show a PIN on display", MAC2STR(sa));
133                 if (dev)
134                         dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
135         } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
136                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
137                         " requested us to write its PIN using keypad",
138                         MAC2STR(sa));
139                 if (dev)
140                         dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
141         }
142
143         reject = 0;
144
145 out:
146         resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
147                                         reject ? 0 : msg.wps_config_methods);
148         if (resp == NULL) {
149                 p2p_parse_free(&msg);
150                 return;
151         }
152         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
153                 "P2P: Sending Provision Discovery Response");
154         if (rx_freq > 0)
155                 freq = rx_freq;
156         else
157                 freq = p2p_channel_to_freq(p2p->cfg->country,
158                                            p2p->cfg->reg_class,
159                                            p2p->cfg->channel);
160         if (freq < 0) {
161                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
162                         "P2P: Unknown regulatory class/channel");
163                 wpabuf_free(resp);
164                 p2p_parse_free(&msg);
165                 return;
166         }
167         p2p->pending_action_state = P2P_NO_PENDING_ACTION;
168         if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, sa,
169                                   p2p->cfg->dev_addr, p2p->cfg->dev_addr,
170                                   wpabuf_head(resp), wpabuf_len(resp), 200) <
171             0) {
172                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
173                         "P2P: Failed to send Action frame");
174         }
175
176         wpabuf_free(resp);
177
178         if (!reject && p2p->cfg->prov_disc_req) {
179                 const u8 *dev_addr = sa;
180                 if (msg.p2p_device_addr)
181                         dev_addr = msg.p2p_device_addr;
182                 p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa,
183                                         msg.wps_config_methods,
184                                         dev_addr, msg.pri_dev_type,
185                                         msg.device_name, msg.config_methods,
186                                         msg.capability ? msg.capability[0] : 0,
187                                         msg.capability ? msg.capability[1] :
188                                         0);
189
190         }
191         p2p_parse_free(&msg);
192 }
193
194
195 void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
196                                 const u8 *data, size_t len)
197 {
198         struct p2p_message msg;
199         struct p2p_device *dev;
200         u16 report_config_methods = 0;
201
202         if (p2p_parse(data, len, &msg))
203                 return;
204
205         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
206                 "P2P: Received Provisioning Discovery Response from " MACSTR
207                 " with config methods 0x%x",
208                 MAC2STR(sa), msg.wps_config_methods);
209
210         dev = p2p_get_device(p2p, sa);
211         if (dev == NULL || !dev->req_config_methods) {
212                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
213                         "P2P: Ignore Provisioning Discovery Response from "
214                         MACSTR " with no pending request", MAC2STR(sa));
215                 p2p_parse_free(&msg);
216                 return;
217         }
218
219         if (dev->dialog_token != msg.dialog_token) {
220                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
221                         "P2P: Ignore Provisioning Discovery Response with "
222                         "unexpected Dialog Token %u (expected %u)",
223                         msg.dialog_token, dev->dialog_token);
224                 p2p_parse_free(&msg);
225                 return;
226         }
227
228         if (msg.wps_config_methods != dev->req_config_methods) {
229                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
230                         "our Provisioning Discovery Request");
231                 p2p_parse_free(&msg);
232                 goto out;
233         }
234
235         report_config_methods = dev->req_config_methods;
236         dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY |
237                         P2P_DEV_PD_PEER_KEYPAD);
238         if (dev->req_config_methods & WPS_CONFIG_DISPLAY) {
239                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
240                         " accepted to show a PIN on display", MAC2STR(sa));
241                 dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
242         } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) {
243                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer " MACSTR
244                         " accepted to write our PIN using keypad",
245                         MAC2STR(sa));
246                 dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
247         }
248         p2p_parse_free(&msg);
249
250 out:
251         dev->req_config_methods = 0;
252         p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
253         if (p2p->cfg->prov_disc_resp)
254                 p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa,
255                                          report_config_methods);
256 }
257
258
259 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
260                            int join)
261 {
262         struct wpabuf *req;
263         int freq;
264
265         freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
266         if (freq <= 0) {
267                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
268                         "P2P: No Listen/Operating frequency known for the "
269                         "peer " MACSTR " to send Provision Discovery Request",
270                         MAC2STR(dev->p2p_device_addr));
271                 return -1;
272         }
273
274         if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
275                 if (!(dev->dev_capab & P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) {
276                         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
277                                 "P2P: Cannot use PD with P2P Device " MACSTR
278                                 " that is in a group and is not discoverable",
279                                 MAC2STR(dev->p2p_device_addr));
280                         return -1;
281                 }
282                 /* TODO: use device discoverability request through GO */
283         }
284
285         dev->dialog_token++;
286         if (dev->dialog_token == 0)
287                 dev->dialog_token = 1;
288         req = p2p_build_prov_disc_req(p2p, dev->dialog_token,
289                                       dev->req_config_methods,
290                                       join ? dev : NULL);
291         if (req == NULL)
292                 return -1;
293
294         p2p->pending_action_state = P2P_PENDING_PD;
295         if (p2p->cfg->send_action(p2p->cfg->cb_ctx, freq,
296                                   dev->p2p_device_addr, p2p->cfg->dev_addr,
297                                   dev->p2p_device_addr,
298                                   wpabuf_head(req), wpabuf_len(req), 200) < 0)
299         {
300                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
301                         "P2P: Failed to send Action frame");
302                 wpabuf_free(req);
303                 return -1;
304         }
305
306         wpabuf_free(req);
307         return 0;
308 }
309
310
311 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
312                       u16 config_methods, int join)
313 {
314         struct p2p_device *dev;
315
316         dev = p2p_get_device(p2p, peer_addr);
317         if (dev == NULL)
318                 dev = p2p_get_device_interface(p2p, peer_addr);
319         if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
320                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision "
321                         "Discovery Request destination " MACSTR
322                         " not yet known", MAC2STR(peer_addr));
323                 return -1;
324         }
325
326         wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Provision Discovery "
327                 "Request with " MACSTR " (config methods 0x%x)",
328                 MAC2STR(peer_addr), config_methods);
329         if (config_methods == 0)
330                 return -1;
331
332         dev->req_config_methods = config_methods;
333
334         if (p2p->go_neg_peer ||
335             (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH &&
336              p2p->state != P2P_LISTEN_ONLY)) {
337                 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Busy with other "
338                         "operations; postpone Provision Discovery Request "
339                         "with " MACSTR " (config methods 0x%x)",
340                         MAC2STR(peer_addr), config_methods);
341                 return 0;
342         }
343
344         return p2p_send_prov_disc_req(p2p, dev, join);
345 }