1f05cddf9SRui Paulo /* 2f05cddf9SRui Paulo * Wi-Fi Direct - P2P Invitation procedure 3f05cddf9SRui Paulo * Copyright (c) 2010, Atheros Communications 4f05cddf9SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7f05cddf9SRui Paulo */ 8f05cddf9SRui Paulo 9f05cddf9SRui Paulo #include "includes.h" 10f05cddf9SRui Paulo 11f05cddf9SRui Paulo #include "common.h" 12f05cddf9SRui Paulo #include "common/ieee802_11_defs.h" 13*5b9c547cSRui Paulo #include "common/wpa_ctrl.h" 14f05cddf9SRui Paulo #include "p2p_i.h" 15f05cddf9SRui Paulo #include "p2p.h" 16f05cddf9SRui Paulo 17f05cddf9SRui Paulo 18f05cddf9SRui Paulo static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, 19f05cddf9SRui Paulo struct p2p_device *peer, 20*5b9c547cSRui Paulo const u8 *go_dev_addr, 21*5b9c547cSRui Paulo int dev_pw_id) 22f05cddf9SRui Paulo { 23f05cddf9SRui Paulo struct wpabuf *buf; 24f05cddf9SRui Paulo u8 *len; 25f05cddf9SRui Paulo const u8 *dev_addr; 26f05cddf9SRui Paulo size_t extra = 0; 27f05cddf9SRui Paulo 28f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY 29f05cddf9SRui Paulo struct wpabuf *wfd_ie = p2p->wfd_ie_invitation; 30f05cddf9SRui Paulo if (wfd_ie && p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) { 31f05cddf9SRui Paulo size_t i; 32f05cddf9SRui Paulo for (i = 0; i < p2p->num_groups; i++) { 33f05cddf9SRui Paulo struct p2p_group *g = p2p->groups[i]; 34f05cddf9SRui Paulo struct wpabuf *ie; 35f05cddf9SRui Paulo if (os_memcmp(p2p_group_get_interface_addr(g), 36f05cddf9SRui Paulo p2p->inv_bssid, ETH_ALEN) != 0) 37f05cddf9SRui Paulo continue; 38f05cddf9SRui Paulo ie = p2p_group_get_wfd_ie(g); 39f05cddf9SRui Paulo if (ie) { 40f05cddf9SRui Paulo wfd_ie = ie; 41f05cddf9SRui Paulo break; 42f05cddf9SRui Paulo } 43f05cddf9SRui Paulo } 44f05cddf9SRui Paulo } 45f05cddf9SRui Paulo if (wfd_ie) 46f05cddf9SRui Paulo extra = wpabuf_len(wfd_ie); 47f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */ 48f05cddf9SRui Paulo 49*5b9c547cSRui Paulo if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]) 50*5b9c547cSRui Paulo extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]); 51*5b9c547cSRui Paulo 52f05cddf9SRui Paulo buf = wpabuf_alloc(1000 + extra); 53f05cddf9SRui Paulo if (buf == NULL) 54f05cddf9SRui Paulo return NULL; 55f05cddf9SRui Paulo 56f05cddf9SRui Paulo peer->dialog_token++; 57f05cddf9SRui Paulo if (peer->dialog_token == 0) 58f05cddf9SRui Paulo peer->dialog_token = 1; 59f05cddf9SRui Paulo p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_REQ, 60f05cddf9SRui Paulo peer->dialog_token); 61f05cddf9SRui Paulo 62f05cddf9SRui Paulo len = p2p_buf_add_ie_hdr(buf); 63f05cddf9SRui Paulo if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent) 64f05cddf9SRui Paulo p2p_buf_add_config_timeout(buf, 0, 0); 65f05cddf9SRui Paulo else 66f05cddf9SRui Paulo p2p_buf_add_config_timeout(buf, p2p->go_timeout, 67f05cddf9SRui Paulo p2p->client_timeout); 68f05cddf9SRui Paulo p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ? 69f05cddf9SRui Paulo P2P_INVITATION_FLAGS_TYPE : 0); 70*5b9c547cSRui Paulo if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT || 71*5b9c547cSRui Paulo !(peer->flags & P2P_DEV_NO_PREF_CHAN)) 72f05cddf9SRui Paulo p2p_buf_add_operating_channel(buf, p2p->cfg->country, 73*5b9c547cSRui Paulo p2p->op_reg_class, 74*5b9c547cSRui Paulo p2p->op_channel); 75f05cddf9SRui Paulo if (p2p->inv_bssid_set) 76f05cddf9SRui Paulo p2p_buf_add_group_bssid(buf, p2p->inv_bssid); 77f05cddf9SRui Paulo p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); 78f05cddf9SRui Paulo if (go_dev_addr) 79f05cddf9SRui Paulo dev_addr = go_dev_addr; 80f05cddf9SRui Paulo else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT) 81f05cddf9SRui Paulo dev_addr = peer->info.p2p_device_addr; 82f05cddf9SRui Paulo else 83f05cddf9SRui Paulo dev_addr = p2p->cfg->dev_addr; 84f05cddf9SRui Paulo p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len); 85f05cddf9SRui Paulo p2p_buf_add_device_info(buf, p2p, peer); 86f05cddf9SRui Paulo p2p_buf_update_ie_hdr(buf, len); 87f05cddf9SRui Paulo 88f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY 89f05cddf9SRui Paulo if (wfd_ie) 90f05cddf9SRui Paulo wpabuf_put_buf(buf, wfd_ie); 91f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */ 92f05cddf9SRui Paulo 93*5b9c547cSRui Paulo if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]) 94*5b9c547cSRui Paulo wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]); 95*5b9c547cSRui Paulo 96*5b9c547cSRui Paulo if (dev_pw_id >= 0) { 97*5b9c547cSRui Paulo /* WSC IE in Invitation Request for NFC static handover */ 98*5b9c547cSRui Paulo p2p_build_wps_ie(p2p, buf, dev_pw_id, 0); 99*5b9c547cSRui Paulo } 100*5b9c547cSRui Paulo 101f05cddf9SRui Paulo return buf; 102f05cddf9SRui Paulo } 103f05cddf9SRui Paulo 104f05cddf9SRui Paulo 105f05cddf9SRui Paulo static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p, 106f05cddf9SRui Paulo struct p2p_device *peer, 107f05cddf9SRui Paulo u8 dialog_token, u8 status, 108f05cddf9SRui Paulo const u8 *group_bssid, 109f05cddf9SRui Paulo u8 reg_class, u8 channel, 110f05cddf9SRui Paulo struct p2p_channels *channels) 111f05cddf9SRui Paulo { 112f05cddf9SRui Paulo struct wpabuf *buf; 113f05cddf9SRui Paulo u8 *len; 114f05cddf9SRui Paulo size_t extra = 0; 115f05cddf9SRui Paulo 116f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY 117f05cddf9SRui Paulo struct wpabuf *wfd_ie = p2p->wfd_ie_invitation; 118f05cddf9SRui Paulo if (wfd_ie && group_bssid) { 119f05cddf9SRui Paulo size_t i; 120f05cddf9SRui Paulo for (i = 0; i < p2p->num_groups; i++) { 121f05cddf9SRui Paulo struct p2p_group *g = p2p->groups[i]; 122f05cddf9SRui Paulo struct wpabuf *ie; 123f05cddf9SRui Paulo if (os_memcmp(p2p_group_get_interface_addr(g), 124f05cddf9SRui Paulo group_bssid, ETH_ALEN) != 0) 125f05cddf9SRui Paulo continue; 126f05cddf9SRui Paulo ie = p2p_group_get_wfd_ie(g); 127f05cddf9SRui Paulo if (ie) { 128f05cddf9SRui Paulo wfd_ie = ie; 129f05cddf9SRui Paulo break; 130f05cddf9SRui Paulo } 131f05cddf9SRui Paulo } 132f05cddf9SRui Paulo } 133f05cddf9SRui Paulo if (wfd_ie) 134f05cddf9SRui Paulo extra = wpabuf_len(wfd_ie); 135f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */ 136f05cddf9SRui Paulo 137f05cddf9SRui Paulo buf = wpabuf_alloc(1000 + extra); 138f05cddf9SRui Paulo if (buf == NULL) 139f05cddf9SRui Paulo return NULL; 140f05cddf9SRui Paulo 141f05cddf9SRui Paulo p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_RESP, 142f05cddf9SRui Paulo dialog_token); 143f05cddf9SRui Paulo 144f05cddf9SRui Paulo len = p2p_buf_add_ie_hdr(buf); 145f05cddf9SRui Paulo p2p_buf_add_status(buf, status); 146f05cddf9SRui Paulo p2p_buf_add_config_timeout(buf, 0, 0); /* FIX */ 147f05cddf9SRui Paulo if (reg_class && channel) 148f05cddf9SRui Paulo p2p_buf_add_operating_channel(buf, p2p->cfg->country, 149f05cddf9SRui Paulo reg_class, channel); 150f05cddf9SRui Paulo if (group_bssid) 151f05cddf9SRui Paulo p2p_buf_add_group_bssid(buf, group_bssid); 152f05cddf9SRui Paulo if (channels) 153f05cddf9SRui Paulo p2p_buf_add_channel_list(buf, p2p->cfg->country, channels); 154f05cddf9SRui Paulo p2p_buf_update_ie_hdr(buf, len); 155f05cddf9SRui Paulo 156f05cddf9SRui Paulo #ifdef CONFIG_WIFI_DISPLAY 157f05cddf9SRui Paulo if (wfd_ie) 158f05cddf9SRui Paulo wpabuf_put_buf(buf, wfd_ie); 159f05cddf9SRui Paulo #endif /* CONFIG_WIFI_DISPLAY */ 160f05cddf9SRui Paulo 161f05cddf9SRui Paulo return buf; 162f05cddf9SRui Paulo } 163f05cddf9SRui Paulo 164f05cddf9SRui Paulo 165f05cddf9SRui Paulo void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa, 166f05cddf9SRui Paulo const u8 *data, size_t len, int rx_freq) 167f05cddf9SRui Paulo { 168f05cddf9SRui Paulo struct p2p_device *dev; 169f05cddf9SRui Paulo struct p2p_message msg; 170f05cddf9SRui Paulo struct wpabuf *resp = NULL; 171f05cddf9SRui Paulo u8 status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; 172f05cddf9SRui Paulo int freq; 173f05cddf9SRui Paulo int go = 0; 174f05cddf9SRui Paulo u8 group_bssid[ETH_ALEN], *bssid; 175f05cddf9SRui Paulo int op_freq = 0; 176f05cddf9SRui Paulo u8 reg_class = 0, channel = 0; 177*5b9c547cSRui Paulo struct p2p_channels all_channels, intersection, *channels = NULL; 178f05cddf9SRui Paulo int persistent; 179f05cddf9SRui Paulo 180f05cddf9SRui Paulo os_memset(group_bssid, 0, sizeof(group_bssid)); 181f05cddf9SRui Paulo 182*5b9c547cSRui Paulo p2p_dbg(p2p, "Received Invitation Request from " MACSTR " (freq=%d)", 183f05cddf9SRui Paulo MAC2STR(sa), rx_freq); 184f05cddf9SRui Paulo 185f05cddf9SRui Paulo if (p2p_parse(data, len, &msg)) 186f05cddf9SRui Paulo return; 187f05cddf9SRui Paulo 188f05cddf9SRui Paulo dev = p2p_get_device(p2p, sa); 189f05cddf9SRui Paulo if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { 190*5b9c547cSRui Paulo p2p_dbg(p2p, "Invitation Request from unknown peer " MACSTR, 191*5b9c547cSRui Paulo MAC2STR(sa)); 192f05cddf9SRui Paulo 193*5b9c547cSRui Paulo if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1, 194f05cddf9SRui Paulo 0)) { 195*5b9c547cSRui Paulo p2p_dbg(p2p, "Invitation Request add device failed " 196f05cddf9SRui Paulo MACSTR, MAC2STR(sa)); 197f05cddf9SRui Paulo status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; 198f05cddf9SRui Paulo goto fail; 199f05cddf9SRui Paulo } 200f05cddf9SRui Paulo 201f05cddf9SRui Paulo dev = p2p_get_device(p2p, sa); 202f05cddf9SRui Paulo if (dev == NULL) { 203*5b9c547cSRui Paulo p2p_dbg(p2p, "Reject Invitation Request from unknown peer " 204*5b9c547cSRui Paulo MACSTR, MAC2STR(sa)); 205f05cddf9SRui Paulo status = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; 206f05cddf9SRui Paulo goto fail; 207f05cddf9SRui Paulo } 208f05cddf9SRui Paulo } 209f05cddf9SRui Paulo 210f05cddf9SRui Paulo if (!msg.group_id || !msg.channel_list) { 211*5b9c547cSRui Paulo p2p_dbg(p2p, "Mandatory attribute missing in Invitation Request from " 212*5b9c547cSRui Paulo MACSTR, MAC2STR(sa)); 213f05cddf9SRui Paulo status = P2P_SC_FAIL_INVALID_PARAMS; 214f05cddf9SRui Paulo goto fail; 215f05cddf9SRui Paulo } 216f05cddf9SRui Paulo 217f05cddf9SRui Paulo if (msg.invitation_flags) 218f05cddf9SRui Paulo persistent = *msg.invitation_flags & P2P_INVITATION_FLAGS_TYPE; 219f05cddf9SRui Paulo else { 220f05cddf9SRui Paulo /* Invitation Flags is a mandatory attribute starting from P2P 221f05cddf9SRui Paulo * spec 1.06. As a backwards compatibility mechanism, assume 222f05cddf9SRui Paulo * the request was for a persistent group if the attribute is 223f05cddf9SRui Paulo * missing. 224f05cddf9SRui Paulo */ 225*5b9c547cSRui Paulo p2p_dbg(p2p, "Mandatory Invitation Flags attribute missing from Invitation Request"); 226f05cddf9SRui Paulo persistent = 1; 227f05cddf9SRui Paulo } 228f05cddf9SRui Paulo 229*5b9c547cSRui Paulo p2p_channels_union(&p2p->cfg->channels, &p2p->cfg->cli_channels, 230*5b9c547cSRui Paulo &all_channels); 231*5b9c547cSRui Paulo 232*5b9c547cSRui Paulo if (p2p_peer_channels_check(p2p, &all_channels, dev, 233f05cddf9SRui Paulo msg.channel_list, msg.channel_list_len) < 234f05cddf9SRui Paulo 0) { 235*5b9c547cSRui Paulo p2p_dbg(p2p, "No common channels found"); 236f05cddf9SRui Paulo status = P2P_SC_FAIL_NO_COMMON_CHANNELS; 237f05cddf9SRui Paulo goto fail; 238f05cddf9SRui Paulo } 239f05cddf9SRui Paulo 240*5b9c547cSRui Paulo p2p_channels_dump(p2p, "own channels", &p2p->cfg->channels); 241*5b9c547cSRui Paulo p2p_channels_dump(p2p, "own client channels", &all_channels); 242*5b9c547cSRui Paulo p2p_channels_dump(p2p, "peer channels", &dev->channels); 243*5b9c547cSRui Paulo p2p_channels_intersect(&all_channels, &dev->channels, 244*5b9c547cSRui Paulo &intersection); 245*5b9c547cSRui Paulo p2p_channels_dump(p2p, "intersection", &intersection); 246*5b9c547cSRui Paulo 247f05cddf9SRui Paulo if (p2p->cfg->invitation_process) { 248f05cddf9SRui Paulo status = p2p->cfg->invitation_process( 249f05cddf9SRui Paulo p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id, 250f05cddf9SRui Paulo msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN, 251*5b9c547cSRui Paulo &go, group_bssid, &op_freq, persistent, &intersection, 252*5b9c547cSRui Paulo msg.dev_password_id_present ? msg.dev_password_id : -1); 253*5b9c547cSRui Paulo } 254*5b9c547cSRui Paulo 255*5b9c547cSRui Paulo if (go) { 256*5b9c547cSRui Paulo p2p_channels_intersect(&p2p->cfg->channels, &dev->channels, 257*5b9c547cSRui Paulo &intersection); 258*5b9c547cSRui Paulo p2p_channels_dump(p2p, "intersection(GO)", &intersection); 259*5b9c547cSRui Paulo if (intersection.reg_classes == 0) { 260*5b9c547cSRui Paulo p2p_dbg(p2p, "No common channels found (GO)"); 261*5b9c547cSRui Paulo status = P2P_SC_FAIL_NO_COMMON_CHANNELS; 262*5b9c547cSRui Paulo goto fail; 263*5b9c547cSRui Paulo } 264f05cddf9SRui Paulo } 265f05cddf9SRui Paulo 266f05cddf9SRui Paulo if (op_freq) { 267*5b9c547cSRui Paulo p2p_dbg(p2p, "Invitation processing forced frequency %d MHz", 268*5b9c547cSRui Paulo op_freq); 269*5b9c547cSRui Paulo if (p2p_freq_to_channel(op_freq, ®_class, &channel) < 0) { 270*5b9c547cSRui Paulo p2p_dbg(p2p, "Unknown forced freq %d MHz from invitation_process()", 271*5b9c547cSRui Paulo op_freq); 272f05cddf9SRui Paulo status = P2P_SC_FAIL_NO_COMMON_CHANNELS; 273f05cddf9SRui Paulo goto fail; 274f05cddf9SRui Paulo } 275f05cddf9SRui Paulo 276f05cddf9SRui Paulo if (!p2p_channels_includes(&intersection, reg_class, channel)) 277f05cddf9SRui Paulo { 278*5b9c547cSRui Paulo p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction", 279*5b9c547cSRui Paulo op_freq); 280f05cddf9SRui Paulo status = P2P_SC_FAIL_NO_COMMON_CHANNELS; 281f05cddf9SRui Paulo goto fail; 282f05cddf9SRui Paulo } 283f05cddf9SRui Paulo 284f05cddf9SRui Paulo if (status == P2P_SC_SUCCESS) 285f05cddf9SRui Paulo channels = &intersection; 286f05cddf9SRui Paulo } else { 287*5b9c547cSRui Paulo p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use"); 288f05cddf9SRui Paulo 289f05cddf9SRui Paulo /* Default to own configuration as a starting point */ 290f05cddf9SRui Paulo p2p->op_reg_class = p2p->cfg->op_reg_class; 291f05cddf9SRui Paulo p2p->op_channel = p2p->cfg->op_channel; 292*5b9c547cSRui Paulo p2p_dbg(p2p, "Own default op_class %d channel %d", 293f05cddf9SRui Paulo p2p->op_reg_class, p2p->op_channel); 294f05cddf9SRui Paulo 295f05cddf9SRui Paulo /* Use peer preference if specified and compatible */ 296f05cddf9SRui Paulo if (msg.operating_channel) { 297f05cddf9SRui Paulo int req_freq; 298f05cddf9SRui Paulo req_freq = p2p_channel_to_freq( 299f05cddf9SRui Paulo msg.operating_channel[3], 300f05cddf9SRui Paulo msg.operating_channel[4]); 301*5b9c547cSRui Paulo p2p_dbg(p2p, "Peer operating channel preference: %d MHz", 302f05cddf9SRui Paulo req_freq); 303f05cddf9SRui Paulo if (req_freq > 0 && 304f05cddf9SRui Paulo p2p_channels_includes(&intersection, 305f05cddf9SRui Paulo msg.operating_channel[3], 306f05cddf9SRui Paulo msg.operating_channel[4])) { 307f05cddf9SRui Paulo p2p->op_reg_class = msg.operating_channel[3]; 308f05cddf9SRui Paulo p2p->op_channel = msg.operating_channel[4]; 309*5b9c547cSRui Paulo p2p_dbg(p2p, "Use peer preference op_class %d channel %d", 310f05cddf9SRui Paulo p2p->op_reg_class, p2p->op_channel); 311f05cddf9SRui Paulo } else { 312*5b9c547cSRui Paulo p2p_dbg(p2p, "Cannot use peer channel preference"); 313f05cddf9SRui Paulo } 314f05cddf9SRui Paulo } 315f05cddf9SRui Paulo 316*5b9c547cSRui Paulo /* Reselect the channel only for the case of the GO */ 317*5b9c547cSRui Paulo if (go && 318*5b9c547cSRui Paulo !p2p_channels_includes(&intersection, p2p->op_reg_class, 319f05cddf9SRui Paulo p2p->op_channel)) { 320*5b9c547cSRui Paulo p2p_dbg(p2p, "Initially selected channel (op_class %d channel %d) not in channel intersection - try to reselect", 321f05cddf9SRui Paulo p2p->op_reg_class, p2p->op_channel); 322f05cddf9SRui Paulo p2p_reselect_channel(p2p, &intersection); 323*5b9c547cSRui Paulo p2p_dbg(p2p, "Re-selection result: op_class %d channel %d", 324f05cddf9SRui Paulo p2p->op_reg_class, p2p->op_channel); 325f05cddf9SRui Paulo if (!p2p_channels_includes(&intersection, 326f05cddf9SRui Paulo p2p->op_reg_class, 327f05cddf9SRui Paulo p2p->op_channel)) { 328*5b9c547cSRui Paulo p2p_dbg(p2p, "Peer does not support selected operating channel (reg_class=%u channel=%u)", 329f05cddf9SRui Paulo p2p->op_reg_class, p2p->op_channel); 330f05cddf9SRui Paulo status = P2P_SC_FAIL_NO_COMMON_CHANNELS; 331f05cddf9SRui Paulo goto fail; 332f05cddf9SRui Paulo } 333*5b9c547cSRui Paulo } else if (go && !(dev->flags & P2P_DEV_FORCE_FREQ) && 334*5b9c547cSRui Paulo !p2p->cfg->cfg_op_channel) { 335*5b9c547cSRui Paulo p2p_dbg(p2p, "Try to reselect channel selection with peer information received; previously selected op_class %u channel %u", 336*5b9c547cSRui Paulo p2p->op_reg_class, p2p->op_channel); 337*5b9c547cSRui Paulo p2p_reselect_channel(p2p, &intersection); 338f05cddf9SRui Paulo } 339f05cddf9SRui Paulo 340*5b9c547cSRui Paulo op_freq = p2p_channel_to_freq(p2p->op_reg_class, 341f05cddf9SRui Paulo p2p->op_channel); 342f05cddf9SRui Paulo if (op_freq < 0) { 343*5b9c547cSRui Paulo p2p_dbg(p2p, "Unknown operational channel (country=%c%c reg_class=%u channel=%u)", 344f05cddf9SRui Paulo p2p->cfg->country[0], p2p->cfg->country[1], 345f05cddf9SRui Paulo p2p->op_reg_class, p2p->op_channel); 346f05cddf9SRui Paulo status = P2P_SC_FAIL_NO_COMMON_CHANNELS; 347f05cddf9SRui Paulo goto fail; 348f05cddf9SRui Paulo } 349*5b9c547cSRui Paulo p2p_dbg(p2p, "Selected operating channel - %d MHz", op_freq); 350f05cddf9SRui Paulo 351f05cddf9SRui Paulo if (status == P2P_SC_SUCCESS) { 352f05cddf9SRui Paulo reg_class = p2p->op_reg_class; 353f05cddf9SRui Paulo channel = p2p->op_channel; 354f05cddf9SRui Paulo channels = &intersection; 355f05cddf9SRui Paulo } 356f05cddf9SRui Paulo } 357f05cddf9SRui Paulo 358f05cddf9SRui Paulo fail: 359f05cddf9SRui Paulo if (go && status == P2P_SC_SUCCESS && !is_zero_ether_addr(group_bssid)) 360f05cddf9SRui Paulo bssid = group_bssid; 361f05cddf9SRui Paulo else 362f05cddf9SRui Paulo bssid = NULL; 363f05cddf9SRui Paulo resp = p2p_build_invitation_resp(p2p, dev, msg.dialog_token, status, 364f05cddf9SRui Paulo bssid, reg_class, channel, channels); 365f05cddf9SRui Paulo 366f05cddf9SRui Paulo if (resp == NULL) 367f05cddf9SRui Paulo goto out; 368f05cddf9SRui Paulo 369f05cddf9SRui Paulo if (rx_freq > 0) 370f05cddf9SRui Paulo freq = rx_freq; 371f05cddf9SRui Paulo else 372*5b9c547cSRui Paulo freq = p2p_channel_to_freq(p2p->cfg->reg_class, 373f05cddf9SRui Paulo p2p->cfg->channel); 374f05cddf9SRui Paulo if (freq < 0) { 375*5b9c547cSRui Paulo p2p_dbg(p2p, "Unknown regulatory class/channel"); 376f05cddf9SRui Paulo goto out; 377f05cddf9SRui Paulo } 378f05cddf9SRui Paulo 379f05cddf9SRui Paulo /* 380f05cddf9SRui Paulo * Store copy of invitation data to be used when processing TX status 381f05cddf9SRui Paulo * callback for the Acton frame. 382f05cddf9SRui Paulo */ 383f05cddf9SRui Paulo os_memcpy(p2p->inv_sa, sa, ETH_ALEN); 384f05cddf9SRui Paulo if (msg.group_bssid) { 385f05cddf9SRui Paulo os_memcpy(p2p->inv_group_bssid, msg.group_bssid, ETH_ALEN); 386f05cddf9SRui Paulo p2p->inv_group_bssid_ptr = p2p->inv_group_bssid; 387f05cddf9SRui Paulo } else 388f05cddf9SRui Paulo p2p->inv_group_bssid_ptr = NULL; 389*5b9c547cSRui Paulo if (msg.group_id) { 390f05cddf9SRui Paulo if (msg.group_id_len - ETH_ALEN <= 32) { 391f05cddf9SRui Paulo os_memcpy(p2p->inv_ssid, msg.group_id + ETH_ALEN, 392f05cddf9SRui Paulo msg.group_id_len - ETH_ALEN); 393f05cddf9SRui Paulo p2p->inv_ssid_len = msg.group_id_len - ETH_ALEN; 394f05cddf9SRui Paulo } 395f05cddf9SRui Paulo os_memcpy(p2p->inv_go_dev_addr, msg.group_id, ETH_ALEN); 396*5b9c547cSRui Paulo } else { 397*5b9c547cSRui Paulo p2p->inv_ssid_len = 0; 398*5b9c547cSRui Paulo os_memset(p2p->inv_go_dev_addr, 0, ETH_ALEN); 399*5b9c547cSRui Paulo } 400f05cddf9SRui Paulo p2p->inv_status = status; 401f05cddf9SRui Paulo p2p->inv_op_freq = op_freq; 402f05cddf9SRui Paulo 403f05cddf9SRui Paulo p2p->pending_action_state = P2P_PENDING_INVITATION_RESPONSE; 404f05cddf9SRui Paulo if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, 405f05cddf9SRui Paulo p2p->cfg->dev_addr, 406f05cddf9SRui Paulo wpabuf_head(resp), wpabuf_len(resp), 200) < 0) { 407*5b9c547cSRui Paulo p2p_dbg(p2p, "Failed to send Action frame"); 408f05cddf9SRui Paulo } 409f05cddf9SRui Paulo 410f05cddf9SRui Paulo out: 411f05cddf9SRui Paulo wpabuf_free(resp); 412f05cddf9SRui Paulo p2p_parse_free(&msg); 413f05cddf9SRui Paulo } 414f05cddf9SRui Paulo 415f05cddf9SRui Paulo 416f05cddf9SRui Paulo void p2p_process_invitation_resp(struct p2p_data *p2p, const u8 *sa, 417f05cddf9SRui Paulo const u8 *data, size_t len) 418f05cddf9SRui Paulo { 419f05cddf9SRui Paulo struct p2p_device *dev; 420f05cddf9SRui Paulo struct p2p_message msg; 421*5b9c547cSRui Paulo struct p2p_channels intersection, *channels = NULL; 422f05cddf9SRui Paulo 423*5b9c547cSRui Paulo p2p_dbg(p2p, "Received Invitation Response from " MACSTR, 424f05cddf9SRui Paulo MAC2STR(sa)); 425f05cddf9SRui Paulo 426f05cddf9SRui Paulo dev = p2p_get_device(p2p, sa); 427f05cddf9SRui Paulo if (dev == NULL) { 428*5b9c547cSRui Paulo p2p_dbg(p2p, "Ignore Invitation Response from unknown peer " 429f05cddf9SRui Paulo MACSTR, MAC2STR(sa)); 430*5b9c547cSRui Paulo p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 431f05cddf9SRui Paulo return; 432f05cddf9SRui Paulo } 433f05cddf9SRui Paulo 434f05cddf9SRui Paulo if (dev != p2p->invite_peer) { 435*5b9c547cSRui Paulo p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer " 436f05cddf9SRui Paulo MACSTR, MAC2STR(sa)); 437*5b9c547cSRui Paulo p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 438f05cddf9SRui Paulo return; 439f05cddf9SRui Paulo } 440f05cddf9SRui Paulo 441*5b9c547cSRui Paulo if (p2p_parse(data, len, &msg)) { 442*5b9c547cSRui Paulo p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 443f05cddf9SRui Paulo return; 444*5b9c547cSRui Paulo } 445f05cddf9SRui Paulo 446f05cddf9SRui Paulo if (!msg.status) { 447*5b9c547cSRui Paulo p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from " 448*5b9c547cSRui Paulo MACSTR, MAC2STR(sa)); 449*5b9c547cSRui Paulo p2p_parse_free(&msg); 450*5b9c547cSRui Paulo p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 451*5b9c547cSRui Paulo return; 452*5b9c547cSRui Paulo } 453*5b9c547cSRui Paulo 454*5b9c547cSRui Paulo /* 455*5b9c547cSRui Paulo * We should not really receive a replayed response twice since 456*5b9c547cSRui Paulo * duplicate frames are supposed to be dropped. However, not all drivers 457*5b9c547cSRui Paulo * do that for pre-association frames. We did not use to verify dialog 458*5b9c547cSRui Paulo * token matches for invitation response frames, but that check can be 459*5b9c547cSRui Paulo * safely used to drop a replayed response to the previous Invitation 460*5b9c547cSRui Paulo * Request in case the suggested operating channel was changed. This 461*5b9c547cSRui Paulo * allows a duplicated reject frame to be dropped with the assumption 462*5b9c547cSRui Paulo * that the real response follows after it. 463*5b9c547cSRui Paulo */ 464*5b9c547cSRui Paulo if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS && 465*5b9c547cSRui Paulo p2p->retry_invite_req_sent && 466*5b9c547cSRui Paulo msg.dialog_token != dev->dialog_token) { 467*5b9c547cSRui Paulo p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)", 468*5b9c547cSRui Paulo msg.dialog_token, dev->dialog_token); 469f05cddf9SRui Paulo p2p_parse_free(&msg); 470f05cddf9SRui Paulo return; 471f05cddf9SRui Paulo } 472f05cddf9SRui Paulo 473*5b9c547cSRui Paulo if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS && 474*5b9c547cSRui Paulo p2p->retry_invite_req && 475*5b9c547cSRui Paulo p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class, 476*5b9c547cSRui Paulo &p2p->op_channel) == 0) { 477*5b9c547cSRui Paulo p2p->retry_invite_req = 0; 478*5b9c547cSRui Paulo p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 479*5b9c547cSRui Paulo p2p->cfg->stop_listen(p2p->cfg->cb_ctx); 480*5b9c547cSRui Paulo p2p_set_state(p2p, P2P_INVITE); 481*5b9c547cSRui Paulo p2p_dbg(p2p, "Resend Invitation Request setting op_class %u channel %u as operating channel", 482*5b9c547cSRui Paulo p2p->op_reg_class, p2p->op_channel); 483*5b9c547cSRui Paulo p2p->retry_invite_req_sent = 1; 484*5b9c547cSRui Paulo p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr, 485*5b9c547cSRui Paulo p2p->invite_dev_pw_id); 486*5b9c547cSRui Paulo p2p_parse_free(&msg); 487*5b9c547cSRui Paulo return; 488*5b9c547cSRui Paulo } 489*5b9c547cSRui Paulo p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 490*5b9c547cSRui Paulo p2p->retry_invite_req = 0; 491*5b9c547cSRui Paulo 492*5b9c547cSRui Paulo if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) { 493*5b9c547cSRui Paulo p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from " 494*5b9c547cSRui Paulo MACSTR, MAC2STR(sa)); 495*5b9c547cSRui Paulo #ifdef CONFIG_P2P_STRICT 496*5b9c547cSRui Paulo p2p_parse_free(&msg); 497*5b9c547cSRui Paulo return; 498*5b9c547cSRui Paulo #endif /* CONFIG_P2P_STRICT */ 499*5b9c547cSRui Paulo /* Try to survive without peer channel list */ 500*5b9c547cSRui Paulo channels = &p2p->channels; 501*5b9c547cSRui Paulo } else if (!msg.channel_list) { 502*5b9c547cSRui Paulo /* Non-success cases are not required to include Channel List */ 503*5b9c547cSRui Paulo channels = &p2p->channels; 504*5b9c547cSRui Paulo } else if (p2p_peer_channels_check(p2p, &p2p->channels, dev, 505*5b9c547cSRui Paulo msg.channel_list, 506*5b9c547cSRui Paulo msg.channel_list_len) < 0) { 507*5b9c547cSRui Paulo p2p_dbg(p2p, "No common channels found"); 508*5b9c547cSRui Paulo p2p_parse_free(&msg); 509*5b9c547cSRui Paulo return; 510*5b9c547cSRui Paulo } else { 511*5b9c547cSRui Paulo p2p_channels_intersect(&p2p->channels, &dev->channels, 512*5b9c547cSRui Paulo &intersection); 513*5b9c547cSRui Paulo channels = &intersection; 514*5b9c547cSRui Paulo } 515*5b9c547cSRui Paulo 516*5b9c547cSRui Paulo if (p2p->cfg->invitation_result) { 517*5b9c547cSRui Paulo int peer_oper_freq = 0; 518*5b9c547cSRui Paulo int freq = p2p_channel_to_freq(p2p->op_reg_class, 519*5b9c547cSRui Paulo p2p->op_channel); 520*5b9c547cSRui Paulo if (freq < 0) 521*5b9c547cSRui Paulo freq = 0; 522*5b9c547cSRui Paulo 523*5b9c547cSRui Paulo if (msg.operating_channel) { 524*5b9c547cSRui Paulo peer_oper_freq = p2p_channel_to_freq( 525*5b9c547cSRui Paulo msg.operating_channel[3], 526*5b9c547cSRui Paulo msg.operating_channel[4]); 527*5b9c547cSRui Paulo if (peer_oper_freq < 0) 528*5b9c547cSRui Paulo peer_oper_freq = 0; 529*5b9c547cSRui Paulo } 530*5b9c547cSRui Paulo 531f05cddf9SRui Paulo p2p->cfg->invitation_result(p2p->cfg->cb_ctx, *msg.status, 532*5b9c547cSRui Paulo msg.group_bssid, channels, sa, 533*5b9c547cSRui Paulo freq, peer_oper_freq); 534*5b9c547cSRui Paulo } 535f05cddf9SRui Paulo 536f05cddf9SRui Paulo p2p_parse_free(&msg); 537f05cddf9SRui Paulo 538f05cddf9SRui Paulo p2p_clear_timeout(p2p); 539f05cddf9SRui Paulo p2p_set_state(p2p, P2P_IDLE); 540f05cddf9SRui Paulo p2p->invite_peer = NULL; 541f05cddf9SRui Paulo } 542f05cddf9SRui Paulo 543f05cddf9SRui Paulo 544f05cddf9SRui Paulo int p2p_invite_send(struct p2p_data *p2p, struct p2p_device *dev, 545*5b9c547cSRui Paulo const u8 *go_dev_addr, int dev_pw_id) 546f05cddf9SRui Paulo { 547f05cddf9SRui Paulo struct wpabuf *req; 548f05cddf9SRui Paulo int freq; 549f05cddf9SRui Paulo 550f05cddf9SRui Paulo freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; 551*5b9c547cSRui Paulo if (freq <= 0) 552*5b9c547cSRui Paulo freq = dev->oob_go_neg_freq; 553f05cddf9SRui Paulo if (freq <= 0) { 554*5b9c547cSRui Paulo p2p_dbg(p2p, "No Listen/Operating frequency known for the peer " 555*5b9c547cSRui Paulo MACSTR " to send Invitation Request", 556f05cddf9SRui Paulo MAC2STR(dev->info.p2p_device_addr)); 557f05cddf9SRui Paulo return -1; 558f05cddf9SRui Paulo } 559f05cddf9SRui Paulo 560*5b9c547cSRui Paulo req = p2p_build_invitation_req(p2p, dev, go_dev_addr, dev_pw_id); 561f05cddf9SRui Paulo if (req == NULL) 562f05cddf9SRui Paulo return -1; 563f05cddf9SRui Paulo if (p2p->state != P2P_IDLE) 564f05cddf9SRui Paulo p2p_stop_listen_for_freq(p2p, freq); 565*5b9c547cSRui Paulo p2p_dbg(p2p, "Sending Invitation Request"); 566f05cddf9SRui Paulo p2p_set_state(p2p, P2P_INVITE); 567f05cddf9SRui Paulo p2p->pending_action_state = P2P_PENDING_INVITATION_REQUEST; 568f05cddf9SRui Paulo p2p->invite_peer = dev; 569f05cddf9SRui Paulo dev->invitation_reqs++; 570f05cddf9SRui Paulo if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, 571f05cddf9SRui Paulo p2p->cfg->dev_addr, dev->info.p2p_device_addr, 572*5b9c547cSRui Paulo wpabuf_head(req), wpabuf_len(req), 500) < 0) { 573*5b9c547cSRui Paulo p2p_dbg(p2p, "Failed to send Action frame"); 574f05cddf9SRui Paulo /* Use P2P find to recover and retry */ 575f05cddf9SRui Paulo p2p_set_timeout(p2p, 0, 0); 576*5b9c547cSRui Paulo } else { 577*5b9c547cSRui Paulo dev->flags |= P2P_DEV_WAIT_INV_REQ_ACK; 578f05cddf9SRui Paulo } 579f05cddf9SRui Paulo 580f05cddf9SRui Paulo wpabuf_free(req); 581f05cddf9SRui Paulo 582f05cddf9SRui Paulo return 0; 583f05cddf9SRui Paulo } 584f05cddf9SRui Paulo 585f05cddf9SRui Paulo 586f05cddf9SRui Paulo void p2p_invitation_req_cb(struct p2p_data *p2p, int success) 587f05cddf9SRui Paulo { 588*5b9c547cSRui Paulo p2p_dbg(p2p, "Invitation Request TX callback: success=%d", success); 589f05cddf9SRui Paulo 590f05cddf9SRui Paulo if (p2p->invite_peer == NULL) { 591*5b9c547cSRui Paulo p2p_dbg(p2p, "No pending Invite"); 592f05cddf9SRui Paulo return; 593f05cddf9SRui Paulo } 594f05cddf9SRui Paulo 595*5b9c547cSRui Paulo if (success) 596*5b9c547cSRui Paulo p2p->invite_peer->flags &= ~P2P_DEV_WAIT_INV_REQ_ACK; 597*5b9c547cSRui Paulo 598f05cddf9SRui Paulo /* 599f05cddf9SRui Paulo * Use P2P find, if needed, to find the other device from its listen 600f05cddf9SRui Paulo * channel. 601f05cddf9SRui Paulo */ 602f05cddf9SRui Paulo p2p_set_state(p2p, P2P_INVITE); 603*5b9c547cSRui Paulo p2p_set_timeout(p2p, 0, success ? 500000 : 100000); 604f05cddf9SRui Paulo } 605f05cddf9SRui Paulo 606f05cddf9SRui Paulo 607f05cddf9SRui Paulo void p2p_invitation_resp_cb(struct p2p_data *p2p, int success) 608f05cddf9SRui Paulo { 609*5b9c547cSRui Paulo p2p_dbg(p2p, "Invitation Response TX callback: success=%d", success); 610f05cddf9SRui Paulo p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 611f05cddf9SRui Paulo 612*5b9c547cSRui Paulo if (!success) 613*5b9c547cSRui Paulo p2p_dbg(p2p, "Assume Invitation Response was actually received by the peer even though Ack was not reported"); 614*5b9c547cSRui Paulo 615*5b9c547cSRui Paulo if (p2p->cfg->invitation_received) { 616f05cddf9SRui Paulo p2p->cfg->invitation_received(p2p->cfg->cb_ctx, 617f05cddf9SRui Paulo p2p->inv_sa, 618f05cddf9SRui Paulo p2p->inv_group_bssid_ptr, 619f05cddf9SRui Paulo p2p->inv_ssid, p2p->inv_ssid_len, 620f05cddf9SRui Paulo p2p->inv_go_dev_addr, 621f05cddf9SRui Paulo p2p->inv_status, 622f05cddf9SRui Paulo p2p->inv_op_freq); 623f05cddf9SRui Paulo } 624f05cddf9SRui Paulo } 625f05cddf9SRui Paulo 626f05cddf9SRui Paulo 627f05cddf9SRui Paulo int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role, 628f05cddf9SRui Paulo const u8 *bssid, const u8 *ssid, size_t ssid_len, 629f05cddf9SRui Paulo unsigned int force_freq, const u8 *go_dev_addr, 630*5b9c547cSRui Paulo int persistent_group, unsigned int pref_freq, int dev_pw_id) 631f05cddf9SRui Paulo { 632f05cddf9SRui Paulo struct p2p_device *dev; 633f05cddf9SRui Paulo 634*5b9c547cSRui Paulo p2p_dbg(p2p, "Request to invite peer " MACSTR " role=%d persistent=%d " 635f05cddf9SRui Paulo "force_freq=%u", 636f05cddf9SRui Paulo MAC2STR(peer), role, persistent_group, force_freq); 637f05cddf9SRui Paulo if (bssid) 638*5b9c547cSRui Paulo p2p_dbg(p2p, "Invitation for BSSID " MACSTR, MAC2STR(bssid)); 639f05cddf9SRui Paulo if (go_dev_addr) { 640*5b9c547cSRui Paulo p2p_dbg(p2p, "Invitation for GO Device Address " MACSTR, 641f05cddf9SRui Paulo MAC2STR(go_dev_addr)); 642f05cddf9SRui Paulo os_memcpy(p2p->invite_go_dev_addr_buf, go_dev_addr, ETH_ALEN); 643f05cddf9SRui Paulo p2p->invite_go_dev_addr = p2p->invite_go_dev_addr_buf; 644f05cddf9SRui Paulo } else 645f05cddf9SRui Paulo p2p->invite_go_dev_addr = NULL; 646*5b9c547cSRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "Invitation for SSID", 647f05cddf9SRui Paulo ssid, ssid_len); 648*5b9c547cSRui Paulo if (dev_pw_id >= 0) { 649*5b9c547cSRui Paulo p2p_dbg(p2p, "Invitation to use Device Password ID %d", 650*5b9c547cSRui Paulo dev_pw_id); 651*5b9c547cSRui Paulo } 652*5b9c547cSRui Paulo p2p->invite_dev_pw_id = dev_pw_id; 653*5b9c547cSRui Paulo p2p->retry_invite_req = role == P2P_INVITE_ROLE_GO && 654*5b9c547cSRui Paulo persistent_group && !force_freq; 655*5b9c547cSRui Paulo p2p->retry_invite_req_sent = 0; 656f05cddf9SRui Paulo 657f05cddf9SRui Paulo dev = p2p_get_device(p2p, peer); 658*5b9c547cSRui Paulo if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 && 659*5b9c547cSRui Paulo dev->oob_go_neg_freq <= 0)) { 660*5b9c547cSRui Paulo p2p_dbg(p2p, "Cannot invite unknown P2P Device " MACSTR, 661f05cddf9SRui Paulo MAC2STR(peer)); 662f05cddf9SRui Paulo return -1; 663f05cddf9SRui Paulo } 664f05cddf9SRui Paulo 665*5b9c547cSRui Paulo if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, 666*5b9c547cSRui Paulo role != P2P_INVITE_ROLE_CLIENT) < 0) 667*5b9c547cSRui Paulo return -1; 668*5b9c547cSRui Paulo 669*5b9c547cSRui Paulo if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq && 670*5b9c547cSRui Paulo !pref_freq) 671*5b9c547cSRui Paulo dev->flags |= P2P_DEV_NO_PREF_CHAN; 672*5b9c547cSRui Paulo else 673*5b9c547cSRui Paulo dev->flags &= ~P2P_DEV_NO_PREF_CHAN; 674*5b9c547cSRui Paulo 675f05cddf9SRui Paulo if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { 676f05cddf9SRui Paulo if (!(dev->info.dev_capab & 677f05cddf9SRui Paulo P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { 678*5b9c547cSRui Paulo p2p_dbg(p2p, "Cannot invite a P2P Device " MACSTR 679f05cddf9SRui Paulo " that is in a group and is not discoverable", 680f05cddf9SRui Paulo MAC2STR(peer)); 681f05cddf9SRui Paulo } 682f05cddf9SRui Paulo /* TODO: use device discoverability request through GO */ 683f05cddf9SRui Paulo } 684f05cddf9SRui Paulo 685f05cddf9SRui Paulo dev->invitation_reqs = 0; 686f05cddf9SRui Paulo 687f05cddf9SRui Paulo if (p2p->state != P2P_IDLE) 688f05cddf9SRui Paulo p2p_stop_find(p2p); 689f05cddf9SRui Paulo 690f05cddf9SRui Paulo p2p->inv_role = role; 691f05cddf9SRui Paulo p2p->inv_bssid_set = bssid != NULL; 692f05cddf9SRui Paulo if (bssid) 693f05cddf9SRui Paulo os_memcpy(p2p->inv_bssid, bssid, ETH_ALEN); 694f05cddf9SRui Paulo os_memcpy(p2p->inv_ssid, ssid, ssid_len); 695f05cddf9SRui Paulo p2p->inv_ssid_len = ssid_len; 696f05cddf9SRui Paulo p2p->inv_persistent = persistent_group; 697*5b9c547cSRui Paulo return p2p_invite_send(p2p, dev, go_dev_addr, dev_pw_id); 698f05cddf9SRui Paulo } 699