2 * Wi-Fi Direct - P2P provision discovery
3 * Copyright (c) 2009-2010, Atheros Communications
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "common/ieee802_11_defs.h"
13 #include "wps/wps_defs.h"
19 * Number of retries to attempt for provision discovery requests during IDLE
20 * state in case the peer is not listening.
22 #define MAX_PROV_DISC_REQ_RETRIES 10
25 static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
29 wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
30 len = wpabuf_put(buf, 1);
31 wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
34 wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
35 wpabuf_put_be16(buf, 2);
36 wpabuf_put_be16(buf, config_methods);
38 p2p_buf_update_ie_hdr(buf, len);
42 static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p,
45 struct p2p_device *go)
50 buf = wpabuf_alloc(1000);
54 p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token);
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);
60 p2p_buf_add_group_id(buf, go->info.p2p_device_addr,
61 go->oper_ssid, go->oper_ssid_len);
63 p2p_buf_update_ie_hdr(buf, len);
65 /* WPS IE with Config Methods attribute */
66 p2p_build_wps_ie_config_methods(buf, config_methods);
72 static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
78 buf = wpabuf_alloc(100);
82 p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);
84 /* WPS IE with Config Methods attribute */
85 p2p_build_wps_ie_config_methods(buf, config_methods);
91 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
92 const u8 *data, size_t len, int rx_freq)
94 struct p2p_message msg;
95 struct p2p_device *dev;
100 if (p2p_parse(data, len, &msg))
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);
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))
115 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
116 "P2P: Provision Discovery Request add device "
117 "failed " MACSTR, MAC2STR(sa));
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");
131 for (i = 0; i < p2p->num_groups; i++) {
132 if (p2p_group_is_group_id_match(p2p->groups[i],
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");
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));
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",
157 dev->flags |= P2P_DEV_PD_PEER_DISPLAY;
163 resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
164 reject ? 0 : msg.wps_config_methods);
166 p2p_parse_free(&msg);
169 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
170 "P2P: Sending Provision Discovery Response");
174 freq = p2p_channel_to_freq(p2p->cfg->country,
178 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
179 "P2P: Unknown regulatory class/channel");
181 p2p_parse_free(&msg);
184 p2p->pending_action_state = P2P_NO_PENDING_ACTION;
185 if (p2p_send_action(p2p, freq, sa, 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");
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] :
205 msg.group_id, msg.group_id_len);
207 p2p_parse_free(&msg);
211 void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
212 const u8 *data, size_t len)
214 struct p2p_message msg;
215 struct p2p_device *dev;
216 u16 report_config_methods = 0;
219 if (p2p_parse(data, len, &msg))
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);
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);
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;
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);
251 * If the response is from the peer to whom a user initiated request
252 * was sent earlier, we reset that state info here.
254 if (p2p->user_initiated_pd &&
255 os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
256 p2p_reset_pending_pd(p2p);
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);
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",
279 dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
282 /* Store the provisioning info */
283 dev->wps_prov_info = msg.wps_config_methods;
285 p2p_parse_free(&msg);
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);
297 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
298 int join, int force_freq)
306 freq = dev->listen_freq > 0 ? dev->listen_freq :
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));
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));
325 /* TODO: use device discoverability request through GO */
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,
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");
349 os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
356 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
357 u16 config_methods, int join, int force_freq)
359 struct p2p_device *dev;
361 dev = p2p_get_device(p2p, peer_addr);
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));
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)
377 /* Reset provisioning info */
378 dev->wps_prov_info = 0;
380 dev->req_config_methods = config_methods;
382 dev->flags |= P2P_DEV_PD_FOR_JOIN;
384 dev->flags &= ~P2P_DEV_PD_FOR_JOIN;
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);
396 * We use the join param as a cue to differentiate between user
397 * initiated PD request and one issued during finds (internal).
399 p2p->user_initiated_pd = !join;
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;
405 return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
409 void p2p_reset_pending_pd(struct p2p_data *p2p)
411 struct p2p_device *dev;
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))
417 if (!dev->req_config_methods)
419 if (dev->flags & P2P_DEV_PD_FOR_JOIN)
421 /* Reset the config methods of the device */
422 dev->req_config_methods = 0;
425 p2p->user_initiated_pd = 0;
426 os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);