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