1 /* 2 * Wi-Fi Direct - P2P Device Discoverability procedure 3 * Copyright (c) 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 "p2p_i.h" 20 #include "p2p.h" 21 22 23 static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p, 24 struct p2p_device *go, 25 const u8 *dev_id) 26 { 27 struct wpabuf *buf; 28 u8 *len; 29 30 buf = wpabuf_alloc(100); 31 if (buf == NULL) 32 return NULL; 33 34 go->dialog_token++; 35 if (go->dialog_token == 0) 36 go->dialog_token = 1; 37 p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_REQ, go->dialog_token); 38 39 len = p2p_buf_add_ie_hdr(buf); 40 p2p_buf_add_device_id(buf, dev_id); 41 p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid, 42 go->oper_ssid_len); 43 p2p_buf_update_ie_hdr(buf, len); 44 45 return buf; 46 } 47 48 49 void p2p_dev_disc_req_cb(struct p2p_data *p2p, int success) 50 { 51 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 52 "P2P: Device Discoverability Request TX callback: success=%d", 53 success); 54 55 if (!success) { 56 /* 57 * Use P2P find, if needed, to find the other device or to 58 * retry device discoverability. 59 */ 60 p2p_set_state(p2p, P2P_CONNECT); 61 p2p_set_timeout(p2p, 0, 100000); 62 return; 63 } 64 65 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 66 "P2P: GO acknowledged Device Discoverability Request - wait " 67 "for response"); 68 /* 69 * TODO: is the remain-on-channel from Action frame TX long enough for 70 * most cases or should we try to increase its duration and/or start 71 * another remain-on-channel if needed once the previous one expires? 72 */ 73 } 74 75 76 int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev) 77 { 78 struct p2p_device *go; 79 struct wpabuf *req; 80 81 go = p2p_get_device(p2p, dev->member_in_go_dev); 82 if (go == NULL || dev->oper_freq <= 0) { 83 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 84 "P2P: Could not find peer entry for GO and frequency " 85 "to send Device Discoverability Request"); 86 return -1; 87 } 88 89 req = p2p_build_dev_disc_req(p2p, go, dev->info.p2p_device_addr); 90 if (req == NULL) 91 return -1; 92 93 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 94 "P2P: Sending Device Discoverability Request to GO " MACSTR 95 " for client " MACSTR, 96 MAC2STR(go->info.p2p_device_addr), 97 MAC2STR(dev->info.p2p_device_addr)); 98 99 p2p->pending_client_disc_go = go; 100 os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr, 101 ETH_ALEN); 102 p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST; 103 if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr, 104 p2p->cfg->dev_addr, go->info.p2p_device_addr, 105 wpabuf_head(req), wpabuf_len(req), 1000) < 0) { 106 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 107 "P2P: Failed to send Action frame"); 108 wpabuf_free(req); 109 /* TODO: how to recover from failure? */ 110 return -1; 111 } 112 113 wpabuf_free(req); 114 115 return 0; 116 } 117 118 119 static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status) 120 { 121 struct wpabuf *buf; 122 u8 *len; 123 124 buf = wpabuf_alloc(100); 125 if (buf == NULL) 126 return NULL; 127 128 p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_RESP, dialog_token); 129 130 len = p2p_buf_add_ie_hdr(buf); 131 p2p_buf_add_status(buf, status); 132 p2p_buf_update_ie_hdr(buf, len); 133 134 return buf; 135 } 136 137 138 void p2p_dev_disc_resp_cb(struct p2p_data *p2p, int success) 139 { 140 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 141 "P2P: Device Discoverability Response TX callback: success=%d", 142 success); 143 p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 144 } 145 146 147 static void p2p_send_dev_disc_resp(struct p2p_data *p2p, u8 dialog_token, 148 const u8 *addr, int freq, u8 status) 149 { 150 struct wpabuf *resp; 151 152 resp = p2p_build_dev_disc_resp(dialog_token, status); 153 if (resp == NULL) 154 return; 155 156 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 157 "P2P: Sending Device Discoverability Response to " MACSTR 158 " (status %u freq %d)", 159 MAC2STR(addr), status, freq); 160 161 p2p->pending_action_state = P2P_PENDING_DEV_DISC_RESPONSE; 162 if (p2p_send_action(p2p, freq, addr, p2p->cfg->dev_addr, 163 p2p->cfg->dev_addr, 164 wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { 165 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 166 "P2P: Failed to send Action frame"); 167 } 168 169 wpabuf_free(resp); 170 } 171 172 173 void p2p_process_dev_disc_req(struct p2p_data *p2p, const u8 *sa, 174 const u8 *data, size_t len, int rx_freq) 175 { 176 struct p2p_message msg; 177 size_t g; 178 179 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 180 "P2P: Received Device Discoverability Request from " MACSTR 181 " (freq=%d)", MAC2STR(sa), rx_freq); 182 183 if (p2p_parse(data, len, &msg)) 184 return; 185 186 if (msg.dialog_token == 0) { 187 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 188 "P2P: Invalid Dialog Token 0 (must be nonzero) in " 189 "Device Discoverability Request"); 190 p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq, 191 P2P_SC_FAIL_INVALID_PARAMS); 192 p2p_parse_free(&msg); 193 return; 194 } 195 196 if (msg.device_id == NULL) { 197 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 198 "P2P: P2P Device ID attribute missing from Device " 199 "Discoverability Request"); 200 p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq, 201 P2P_SC_FAIL_INVALID_PARAMS); 202 p2p_parse_free(&msg); 203 return; 204 } 205 206 for (g = 0; g < p2p->num_groups; g++) { 207 if (p2p_group_go_discover(p2p->groups[g], msg.device_id, sa, 208 rx_freq) == 0) { 209 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Scheduled " 210 "GO Discoverability Request for the target " 211 "device"); 212 /* 213 * P2P group code will use a callback to indicate TX 214 * status, so that we can reply to the request once the 215 * target client has acknowledged the request or it has 216 * timed out. 217 */ 218 p2p->pending_dev_disc_dialog_token = msg.dialog_token; 219 os_memcpy(p2p->pending_dev_disc_addr, sa, ETH_ALEN); 220 p2p->pending_dev_disc_freq = rx_freq; 221 p2p_parse_free(&msg); 222 return; 223 } 224 } 225 226 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Requested client " 227 "was not found in any group or did not support client " 228 "discoverability"); 229 p2p_send_dev_disc_resp(p2p, msg.dialog_token, sa, rx_freq, 230 P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE); 231 p2p_parse_free(&msg); 232 } 233 234 235 void p2p_process_dev_disc_resp(struct p2p_data *p2p, const u8 *sa, 236 const u8 *data, size_t len) 237 { 238 struct p2p_message msg; 239 struct p2p_device *go; 240 u8 status; 241 242 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 243 "P2P: Received Device Discoverability Response from " MACSTR, 244 MAC2STR(sa)); 245 246 go = p2p->pending_client_disc_go; 247 if (go == NULL || 248 os_memcmp(sa, go->info.p2p_device_addr, ETH_ALEN) != 0) { 249 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore unexpected " 250 "Device Discoverability Response"); 251 return; 252 } 253 254 if (p2p_parse(data, len, &msg)) 255 return; 256 257 if (msg.status == NULL) { 258 p2p_parse_free(&msg); 259 return; 260 } 261 262 if (msg.dialog_token != go->dialog_token) { 263 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Ignore Device " 264 "Discoverability Response with unexpected dialog " 265 "token %u (expected %u)", 266 msg.dialog_token, go->dialog_token); 267 p2p_parse_free(&msg); 268 return; 269 } 270 271 status = *msg.status; 272 p2p_parse_free(&msg); 273 274 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 275 "P2P: Device Discoverability Response status %u", status); 276 277 if (p2p->go_neg_peer == NULL || 278 os_memcmp(p2p->pending_client_disc_addr, 279 p2p->go_neg_peer->info.p2p_device_addr, ETH_ALEN) != 0 || 280 os_memcmp(p2p->go_neg_peer->member_in_go_dev, 281 go->info.p2p_device_addr, ETH_ALEN) != 0) { 282 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending " 283 "operation with the client discoverability peer " 284 "anymore"); 285 return; 286 } 287 288 if (status == 0) { 289 /* 290 * Peer is expected to be awake for at least 100 TU; try to 291 * connect immediately. 292 */ 293 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 294 "P2P: Client discoverability request succeeded"); 295 if (p2p->state == P2P_CONNECT) { 296 /* 297 * Change state to force the timeout to start in 298 * P2P_CONNECT again without going through the short 299 * Listen state. 300 */ 301 p2p_set_state(p2p, P2P_CONNECT_LISTEN); 302 p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 303 } 304 p2p_set_timeout(p2p, 0, 0); 305 } else { 306 /* 307 * Client discoverability request failed; try to connect from 308 * timeout. 309 */ 310 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 311 "P2P: Client discoverability request failed"); 312 p2p_set_timeout(p2p, 0, 500000); 313 } 314 315 } 316 317 318 void p2p_go_disc_req_cb(struct p2p_data *p2p, int success) 319 { 320 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 321 "P2P: GO Discoverability Request TX callback: success=%d", 322 success); 323 p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 324 325 if (p2p->pending_dev_disc_dialog_token == 0) { 326 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: No pending Device " 327 "Discoverability Request"); 328 return; 329 } 330 331 p2p_send_dev_disc_resp(p2p, p2p->pending_dev_disc_dialog_token, 332 p2p->pending_dev_disc_addr, 333 p2p->pending_dev_disc_freq, 334 success ? P2P_SC_SUCCESS : 335 P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE); 336 337 p2p->pending_dev_disc_dialog_token = 0; 338 } 339 340 341 void p2p_process_go_disc_req(struct p2p_data *p2p, const u8 *da, const u8 *sa, 342 const u8 *data, size_t len, int rx_freq) 343 { 344 unsigned int tu; 345 struct wpabuf *ies; 346 347 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 348 "P2P: Received GO Discoverability Request - remain awake for " 349 "100 TU"); 350 351 ies = p2p_build_probe_resp_ies(p2p); 352 if (ies == NULL) 353 return; 354 355 /* Remain awake 100 TU on operating channel */ 356 p2p->pending_client_disc_freq = rx_freq; 357 tu = 100; 358 if (p2p->cfg->start_listen(p2p->cfg->cb_ctx, rx_freq, 1024 * tu / 1000, 359 ies) < 0) { 360 wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, 361 "P2P: Failed to start listen mode for client " 362 "discoverability"); 363 } 364 wpabuf_free(ies); 365 } 366