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