1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * Wi-Fi Direct - P2P provision discovery 3e5b75505Sopenharmony_ci * Copyright (c) 2009-2010, Atheros Communications 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h" 13e5b75505Sopenharmony_ci#include "common/wpa_ctrl.h" 14e5b75505Sopenharmony_ci#include "wps/wps_defs.h" 15e5b75505Sopenharmony_ci#include "p2p_i.h" 16e5b75505Sopenharmony_ci#include "p2p.h" 17e5b75505Sopenharmony_ci 18e5b75505Sopenharmony_ci 19e5b75505Sopenharmony_ci/* 20e5b75505Sopenharmony_ci * Number of retries to attempt for provision discovery requests 21e5b75505Sopenharmony_ci * in case the peer is not listening. 22e5b75505Sopenharmony_ci */ 23e5b75505Sopenharmony_ci#define MAX_PROV_DISC_REQ_RETRIES 120 24e5b75505Sopenharmony_ci 25e5b75505Sopenharmony_ci 26e5b75505Sopenharmony_cistatic void p2p_build_wps_ie_config_methods(struct wpabuf *buf, 27e5b75505Sopenharmony_ci u16 config_methods) 28e5b75505Sopenharmony_ci{ 29e5b75505Sopenharmony_ci u8 *len; 30e5b75505Sopenharmony_ci wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); 31e5b75505Sopenharmony_ci len = wpabuf_put(buf, 1); 32e5b75505Sopenharmony_ci wpabuf_put_be32(buf, WPS_DEV_OUI_WFA); 33e5b75505Sopenharmony_ci 34e5b75505Sopenharmony_ci /* Config Methods */ 35e5b75505Sopenharmony_ci wpabuf_put_be16(buf, ATTR_CONFIG_METHODS); 36e5b75505Sopenharmony_ci wpabuf_put_be16(buf, 2); 37e5b75505Sopenharmony_ci wpabuf_put_be16(buf, config_methods); 38e5b75505Sopenharmony_ci 39e5b75505Sopenharmony_ci p2p_buf_update_ie_hdr(buf, len); 40e5b75505Sopenharmony_ci} 41e5b75505Sopenharmony_ci 42e5b75505Sopenharmony_ci 43e5b75505Sopenharmony_cistatic void p2ps_add_new_group_info(struct p2p_data *p2p, 44e5b75505Sopenharmony_ci struct p2p_device *dev, 45e5b75505Sopenharmony_ci struct wpabuf *buf) 46e5b75505Sopenharmony_ci{ 47e5b75505Sopenharmony_ci int found; 48e5b75505Sopenharmony_ci u8 intended_addr[ETH_ALEN]; 49e5b75505Sopenharmony_ci u8 ssid[SSID_MAX_LEN]; 50e5b75505Sopenharmony_ci size_t ssid_len; 51e5b75505Sopenharmony_ci int group_iface; 52e5b75505Sopenharmony_ci unsigned int force_freq; 53e5b75505Sopenharmony_ci 54e5b75505Sopenharmony_ci if (!p2p->cfg->get_go_info) 55e5b75505Sopenharmony_ci return; 56e5b75505Sopenharmony_ci 57e5b75505Sopenharmony_ci found = p2p->cfg->get_go_info( 58e5b75505Sopenharmony_ci p2p->cfg->cb_ctx, intended_addr, ssid, 59e5b75505Sopenharmony_ci &ssid_len, &group_iface, &force_freq); 60e5b75505Sopenharmony_ci if (found) { 61e5b75505Sopenharmony_ci if (force_freq > 0) { 62e5b75505Sopenharmony_ci p2p->p2ps_prov->force_freq = force_freq; 63e5b75505Sopenharmony_ci p2p->p2ps_prov->pref_freq = 0; 64e5b75505Sopenharmony_ci 65e5b75505Sopenharmony_ci if (dev) 66e5b75505Sopenharmony_ci p2p_prepare_channel(p2p, dev, force_freq, 0, 0); 67e5b75505Sopenharmony_ci } 68e5b75505Sopenharmony_ci p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, 69e5b75505Sopenharmony_ci ssid, ssid_len); 70e5b75505Sopenharmony_ci 71e5b75505Sopenharmony_ci if (group_iface) 72e5b75505Sopenharmony_ci p2p_buf_add_intended_addr(buf, p2p->intended_addr); 73e5b75505Sopenharmony_ci else 74e5b75505Sopenharmony_ci p2p_buf_add_intended_addr(buf, intended_addr); 75e5b75505Sopenharmony_ci } else { 76e5b75505Sopenharmony_ci if (!p2p->ssid_set) { 77e5b75505Sopenharmony_ci p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len); 78e5b75505Sopenharmony_ci p2p->ssid_set = 1; 79e5b75505Sopenharmony_ci } 80e5b75505Sopenharmony_ci 81e5b75505Sopenharmony_ci /* Add pre-composed P2P Group ID */ 82e5b75505Sopenharmony_ci p2p_buf_add_group_id(buf, p2p->cfg->dev_addr, 83e5b75505Sopenharmony_ci p2p->ssid, p2p->ssid_len); 84e5b75505Sopenharmony_ci 85e5b75505Sopenharmony_ci if (group_iface) 86e5b75505Sopenharmony_ci p2p_buf_add_intended_addr( 87e5b75505Sopenharmony_ci buf, p2p->intended_addr); 88e5b75505Sopenharmony_ci else 89e5b75505Sopenharmony_ci p2p_buf_add_intended_addr( 90e5b75505Sopenharmony_ci buf, p2p->cfg->dev_addr); 91e5b75505Sopenharmony_ci } 92e5b75505Sopenharmony_ci} 93e5b75505Sopenharmony_ci 94e5b75505Sopenharmony_ci 95e5b75505Sopenharmony_cistatic void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev, 96e5b75505Sopenharmony_ci struct wpabuf *buf, u16 config_methods) 97e5b75505Sopenharmony_ci{ 98e5b75505Sopenharmony_ci struct p2ps_provision *prov = p2p->p2ps_prov; 99e5b75505Sopenharmony_ci struct p2ps_feature_capab fcap = { prov->cpt_mask, 0 }; 100e5b75505Sopenharmony_ci int shared_group = 0; 101e5b75505Sopenharmony_ci u8 ssid[SSID_MAX_LEN]; 102e5b75505Sopenharmony_ci size_t ssid_len; 103e5b75505Sopenharmony_ci u8 go_dev_addr[ETH_ALEN]; 104e5b75505Sopenharmony_ci u8 intended_addr[ETH_ALEN]; 105e5b75505Sopenharmony_ci int follow_on_req_fail = prov->status >= 0 && 106e5b75505Sopenharmony_ci prov->status != P2P_SC_SUCCESS_DEFERRED; 107e5b75505Sopenharmony_ci 108e5b75505Sopenharmony_ci /* If we might be explicite group owner, add GO details */ 109e5b75505Sopenharmony_ci if (!follow_on_req_fail && 110e5b75505Sopenharmony_ci (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW))) 111e5b75505Sopenharmony_ci p2ps_add_new_group_info(p2p, dev, buf); 112e5b75505Sopenharmony_ci 113e5b75505Sopenharmony_ci if (prov->status >= 0) 114e5b75505Sopenharmony_ci p2p_buf_add_status(buf, (u8) prov->status); 115e5b75505Sopenharmony_ci else 116e5b75505Sopenharmony_ci prov->method = config_methods; 117e5b75505Sopenharmony_ci 118e5b75505Sopenharmony_ci if (!follow_on_req_fail) { 119e5b75505Sopenharmony_ci if (p2p->cfg->get_persistent_group) { 120e5b75505Sopenharmony_ci shared_group = p2p->cfg->get_persistent_group( 121e5b75505Sopenharmony_ci p2p->cfg->cb_ctx, dev->info.p2p_device_addr, 122e5b75505Sopenharmony_ci NULL, 0, go_dev_addr, ssid, &ssid_len, 123e5b75505Sopenharmony_ci intended_addr); 124e5b75505Sopenharmony_ci } 125e5b75505Sopenharmony_ci 126e5b75505Sopenharmony_ci if (shared_group || 127e5b75505Sopenharmony_ci (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW))) 128e5b75505Sopenharmony_ci p2p_buf_add_channel_list(buf, p2p->cfg->country, 129e5b75505Sopenharmony_ci &p2p->channels); 130e5b75505Sopenharmony_ci 131e5b75505Sopenharmony_ci if ((shared_group && !is_zero_ether_addr(intended_addr)) || 132e5b75505Sopenharmony_ci (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW))) 133e5b75505Sopenharmony_ci p2p_buf_add_operating_channel(buf, p2p->cfg->country, 134e5b75505Sopenharmony_ci p2p->op_reg_class, 135e5b75505Sopenharmony_ci p2p->op_channel); 136e5b75505Sopenharmony_ci } 137e5b75505Sopenharmony_ci 138e5b75505Sopenharmony_ci if (prov->status < 0 && prov->info[0]) 139e5b75505Sopenharmony_ci p2p_buf_add_session_info(buf, prov->info); 140e5b75505Sopenharmony_ci 141e5b75505Sopenharmony_ci if (!follow_on_req_fail) 142e5b75505Sopenharmony_ci p2p_buf_add_connection_capability(buf, prov->conncap); 143e5b75505Sopenharmony_ci 144e5b75505Sopenharmony_ci p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac); 145e5b75505Sopenharmony_ci 146e5b75505Sopenharmony_ci if (!follow_on_req_fail) { 147e5b75505Sopenharmony_ci if (shared_group || prov->conncap == P2PS_SETUP_NEW || 148e5b75505Sopenharmony_ci prov->conncap == 149e5b75505Sopenharmony_ci (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) || 150e5b75505Sopenharmony_ci prov->conncap == 151e5b75505Sopenharmony_ci (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) { 152e5b75505Sopenharmony_ci /* Add Config Timeout */ 153e5b75505Sopenharmony_ci p2p_buf_add_config_timeout(buf, p2p->go_timeout, 154e5b75505Sopenharmony_ci p2p->client_timeout); 155e5b75505Sopenharmony_ci } 156e5b75505Sopenharmony_ci 157e5b75505Sopenharmony_ci p2p_buf_add_listen_channel(buf, p2p->cfg->country, 158e5b75505Sopenharmony_ci p2p->cfg->reg_class, 159e5b75505Sopenharmony_ci p2p->cfg->channel); 160e5b75505Sopenharmony_ci } 161e5b75505Sopenharmony_ci 162e5b75505Sopenharmony_ci p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac); 163e5b75505Sopenharmony_ci 164e5b75505Sopenharmony_ci p2p_buf_add_feature_capability(buf, sizeof(fcap), (const u8 *) &fcap); 165e5b75505Sopenharmony_ci 166e5b75505Sopenharmony_ci if (shared_group) { 167e5b75505Sopenharmony_ci p2p_buf_add_persistent_group_info(buf, go_dev_addr, 168e5b75505Sopenharmony_ci ssid, ssid_len); 169e5b75505Sopenharmony_ci /* Add intended interface address if it is not added yet */ 170e5b75505Sopenharmony_ci if ((prov->conncap == P2PS_SETUP_NONE || 171e5b75505Sopenharmony_ci prov->conncap == P2PS_SETUP_CLIENT) && 172e5b75505Sopenharmony_ci !is_zero_ether_addr(intended_addr)) 173e5b75505Sopenharmony_ci p2p_buf_add_intended_addr(buf, intended_addr); 174e5b75505Sopenharmony_ci } 175e5b75505Sopenharmony_ci} 176e5b75505Sopenharmony_ci 177e5b75505Sopenharmony_ci 178e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, 179e5b75505Sopenharmony_ci struct p2p_device *dev, 180e5b75505Sopenharmony_ci int join) 181e5b75505Sopenharmony_ci{ 182e5b75505Sopenharmony_ci struct wpabuf *buf; 183e5b75505Sopenharmony_ci u8 *len; 184e5b75505Sopenharmony_ci size_t extra = 0; 185e5b75505Sopenharmony_ci u8 dialog_token = dev->dialog_token; 186e5b75505Sopenharmony_ci u16 config_methods = dev->req_config_methods; 187e5b75505Sopenharmony_ci struct p2p_device *go = join ? dev : NULL; 188e5b75505Sopenharmony_ci u8 group_capab; 189e5b75505Sopenharmony_ci 190e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY 191e5b75505Sopenharmony_ci if (p2p->wfd_ie_prov_disc_req) 192e5b75505Sopenharmony_ci extra = wpabuf_len(p2p->wfd_ie_prov_disc_req); 193e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */ 194e5b75505Sopenharmony_ci 195e5b75505Sopenharmony_ci if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) 196e5b75505Sopenharmony_ci extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); 197e5b75505Sopenharmony_ci 198e5b75505Sopenharmony_ci if (p2p->p2ps_prov) 199e5b75505Sopenharmony_ci extra += os_strlen(p2p->p2ps_prov->info) + 1 + 200e5b75505Sopenharmony_ci sizeof(struct p2ps_provision); 201e5b75505Sopenharmony_ci 202e5b75505Sopenharmony_ci buf = wpabuf_alloc(1000 + extra); 203e5b75505Sopenharmony_ci if (buf == NULL) 204e5b75505Sopenharmony_ci return NULL; 205e5b75505Sopenharmony_ci 206e5b75505Sopenharmony_ci p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token); 207e5b75505Sopenharmony_ci 208e5b75505Sopenharmony_ci len = p2p_buf_add_ie_hdr(buf); 209e5b75505Sopenharmony_ci 210e5b75505Sopenharmony_ci group_capab = 0; 211e5b75505Sopenharmony_ci if (p2p->p2ps_prov) { 212e5b75505Sopenharmony_ci group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; 213e5b75505Sopenharmony_ci group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN; 214e5b75505Sopenharmony_ci if (p2p->cross_connect) 215e5b75505Sopenharmony_ci group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; 216e5b75505Sopenharmony_ci if (p2p->cfg->p2p_intra_bss) 217e5b75505Sopenharmony_ci group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; 218e5b75505Sopenharmony_ci } 219e5b75505Sopenharmony_ci p2p_buf_add_capability(buf, p2p->dev_capab & 220e5b75505Sopenharmony_ci ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 221e5b75505Sopenharmony_ci group_capab); 222e5b75505Sopenharmony_ci p2p_buf_add_device_info(buf, p2p, NULL); 223e5b75505Sopenharmony_ci if (p2p->p2ps_prov) { 224e5b75505Sopenharmony_ci p2ps_add_pd_req_attrs(p2p, dev, buf, config_methods); 225e5b75505Sopenharmony_ci } else if (go) { 226e5b75505Sopenharmony_ci p2p_buf_add_group_id(buf, go->info.p2p_device_addr, 227e5b75505Sopenharmony_ci go->oper_ssid, go->oper_ssid_len); 228e5b75505Sopenharmony_ci } 229e5b75505Sopenharmony_ci p2p_buf_update_ie_hdr(buf, len); 230e5b75505Sopenharmony_ci 231e5b75505Sopenharmony_ci /* WPS IE with Config Methods attribute */ 232e5b75505Sopenharmony_ci p2p_build_wps_ie_config_methods(buf, config_methods); 233e5b75505Sopenharmony_ci 234e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY 235e5b75505Sopenharmony_ci if (p2p->wfd_ie_prov_disc_req) 236e5b75505Sopenharmony_ci wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req); 237e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */ 238e5b75505Sopenharmony_ci 239e5b75505Sopenharmony_ci if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) 240e5b75505Sopenharmony_ci wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); 241e5b75505Sopenharmony_ci 242e5b75505Sopenharmony_ci return buf; 243e5b75505Sopenharmony_ci} 244e5b75505Sopenharmony_ci 245e5b75505Sopenharmony_ci 246e5b75505Sopenharmony_cistatic struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, 247e5b75505Sopenharmony_ci struct p2p_device *dev, 248e5b75505Sopenharmony_ci u8 dialog_token, 249e5b75505Sopenharmony_ci enum p2p_status_code status, 250e5b75505Sopenharmony_ci u16 config_methods, 251e5b75505Sopenharmony_ci u32 adv_id, 252e5b75505Sopenharmony_ci const u8 *group_id, 253e5b75505Sopenharmony_ci size_t group_id_len, 254e5b75505Sopenharmony_ci const u8 *persist_ssid, 255e5b75505Sopenharmony_ci size_t persist_ssid_len, 256e5b75505Sopenharmony_ci const u8 *fcap, 257e5b75505Sopenharmony_ci u16 fcap_len) 258e5b75505Sopenharmony_ci{ 259e5b75505Sopenharmony_ci struct wpabuf *buf; 260e5b75505Sopenharmony_ci size_t extra = 0; 261e5b75505Sopenharmony_ci int persist = 0; 262e5b75505Sopenharmony_ci 263e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY 264e5b75505Sopenharmony_ci struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp; 265e5b75505Sopenharmony_ci if (wfd_ie && group_id) { 266e5b75505Sopenharmony_ci size_t i; 267e5b75505Sopenharmony_ci for (i = 0; i < p2p->num_groups; i++) { 268e5b75505Sopenharmony_ci struct p2p_group *g = p2p->groups[i]; 269e5b75505Sopenharmony_ci struct wpabuf *ie; 270e5b75505Sopenharmony_ci if (!p2p_group_is_group_id_match(g, group_id, 271e5b75505Sopenharmony_ci group_id_len)) 272e5b75505Sopenharmony_ci continue; 273e5b75505Sopenharmony_ci ie = p2p_group_get_wfd_ie(g); 274e5b75505Sopenharmony_ci if (ie) { 275e5b75505Sopenharmony_ci wfd_ie = ie; 276e5b75505Sopenharmony_ci break; 277e5b75505Sopenharmony_ci } 278e5b75505Sopenharmony_ci } 279e5b75505Sopenharmony_ci } 280e5b75505Sopenharmony_ci if (wfd_ie) 281e5b75505Sopenharmony_ci extra = wpabuf_len(wfd_ie); 282e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */ 283e5b75505Sopenharmony_ci 284e5b75505Sopenharmony_ci if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]) 285e5b75505Sopenharmony_ci extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]); 286e5b75505Sopenharmony_ci 287e5b75505Sopenharmony_ci buf = wpabuf_alloc(1000 + extra); 288e5b75505Sopenharmony_ci if (buf == NULL) 289e5b75505Sopenharmony_ci return NULL; 290e5b75505Sopenharmony_ci 291e5b75505Sopenharmony_ci p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token); 292e5b75505Sopenharmony_ci 293e5b75505Sopenharmony_ci /* Add P2P IE for P2PS */ 294e5b75505Sopenharmony_ci if (p2p->p2ps_prov && p2p->p2ps_prov->adv_id == adv_id) { 295e5b75505Sopenharmony_ci u8 *len = p2p_buf_add_ie_hdr(buf); 296e5b75505Sopenharmony_ci struct p2ps_provision *prov = p2p->p2ps_prov; 297e5b75505Sopenharmony_ci u8 group_capab; 298e5b75505Sopenharmony_ci u8 conncap = 0; 299e5b75505Sopenharmony_ci 300e5b75505Sopenharmony_ci if (status == P2P_SC_SUCCESS || 301e5b75505Sopenharmony_ci status == P2P_SC_SUCCESS_DEFERRED) 302e5b75505Sopenharmony_ci conncap = prov->conncap; 303e5b75505Sopenharmony_ci 304e5b75505Sopenharmony_ci if (!status && prov->status != -1) 305e5b75505Sopenharmony_ci status = prov->status; 306e5b75505Sopenharmony_ci 307e5b75505Sopenharmony_ci p2p_buf_add_status(buf, status); 308e5b75505Sopenharmony_ci group_capab = P2P_GROUP_CAPAB_PERSISTENT_GROUP | 309e5b75505Sopenharmony_ci P2P_GROUP_CAPAB_PERSISTENT_RECONN; 310e5b75505Sopenharmony_ci if (p2p->cross_connect) 311e5b75505Sopenharmony_ci group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; 312e5b75505Sopenharmony_ci if (p2p->cfg->p2p_intra_bss) 313e5b75505Sopenharmony_ci group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; 314e5b75505Sopenharmony_ci p2p_buf_add_capability(buf, p2p->dev_capab & 315e5b75505Sopenharmony_ci ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 316e5b75505Sopenharmony_ci group_capab); 317e5b75505Sopenharmony_ci p2p_buf_add_device_info(buf, p2p, NULL); 318e5b75505Sopenharmony_ci 319e5b75505Sopenharmony_ci if (persist_ssid && p2p->cfg->get_persistent_group && dev && 320e5b75505Sopenharmony_ci (status == P2P_SC_SUCCESS || 321e5b75505Sopenharmony_ci status == P2P_SC_SUCCESS_DEFERRED)) { 322e5b75505Sopenharmony_ci u8 ssid[SSID_MAX_LEN]; 323e5b75505Sopenharmony_ci size_t ssid_len; 324e5b75505Sopenharmony_ci u8 go_dev_addr[ETH_ALEN]; 325e5b75505Sopenharmony_ci u8 intended_addr[ETH_ALEN]; 326e5b75505Sopenharmony_ci 327e5b75505Sopenharmony_ci persist = p2p->cfg->get_persistent_group( 328e5b75505Sopenharmony_ci p2p->cfg->cb_ctx, 329e5b75505Sopenharmony_ci dev->info.p2p_device_addr, 330e5b75505Sopenharmony_ci persist_ssid, persist_ssid_len, go_dev_addr, 331e5b75505Sopenharmony_ci ssid, &ssid_len, intended_addr); 332e5b75505Sopenharmony_ci if (persist) { 333e5b75505Sopenharmony_ci p2p_buf_add_persistent_group_info( 334e5b75505Sopenharmony_ci buf, go_dev_addr, ssid, ssid_len); 335e5b75505Sopenharmony_ci if (!is_zero_ether_addr(intended_addr)) 336e5b75505Sopenharmony_ci p2p_buf_add_intended_addr( 337e5b75505Sopenharmony_ci buf, intended_addr); 338e5b75505Sopenharmony_ci } 339e5b75505Sopenharmony_ci } 340e5b75505Sopenharmony_ci 341e5b75505Sopenharmony_ci if (!persist && (conncap & P2PS_SETUP_GROUP_OWNER)) 342e5b75505Sopenharmony_ci p2ps_add_new_group_info(p2p, dev, buf); 343e5b75505Sopenharmony_ci 344e5b75505Sopenharmony_ci /* Add Operating Channel if conncap indicates GO */ 345e5b75505Sopenharmony_ci if (persist || (conncap & P2PS_SETUP_GROUP_OWNER)) { 346e5b75505Sopenharmony_ci if (p2p->op_reg_class && p2p->op_channel) 347e5b75505Sopenharmony_ci p2p_buf_add_operating_channel( 348e5b75505Sopenharmony_ci buf, p2p->cfg->country, 349e5b75505Sopenharmony_ci p2p->op_reg_class, 350e5b75505Sopenharmony_ci p2p->op_channel); 351e5b75505Sopenharmony_ci else 352e5b75505Sopenharmony_ci p2p_buf_add_operating_channel( 353e5b75505Sopenharmony_ci buf, p2p->cfg->country, 354e5b75505Sopenharmony_ci p2p->cfg->op_reg_class, 355e5b75505Sopenharmony_ci p2p->cfg->op_channel); 356e5b75505Sopenharmony_ci } 357e5b75505Sopenharmony_ci 358e5b75505Sopenharmony_ci if (persist || 359e5b75505Sopenharmony_ci (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) 360e5b75505Sopenharmony_ci p2p_buf_add_channel_list(buf, p2p->cfg->country, 361e5b75505Sopenharmony_ci &p2p->channels); 362e5b75505Sopenharmony_ci 363e5b75505Sopenharmony_ci if (!persist && conncap) 364e5b75505Sopenharmony_ci p2p_buf_add_connection_capability(buf, conncap); 365e5b75505Sopenharmony_ci 366e5b75505Sopenharmony_ci p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac); 367e5b75505Sopenharmony_ci 368e5b75505Sopenharmony_ci if (persist || 369e5b75505Sopenharmony_ci (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) 370e5b75505Sopenharmony_ci p2p_buf_add_config_timeout(buf, p2p->go_timeout, 371e5b75505Sopenharmony_ci p2p->client_timeout); 372e5b75505Sopenharmony_ci 373e5b75505Sopenharmony_ci p2p_buf_add_session_id(buf, prov->session_id, 374e5b75505Sopenharmony_ci prov->session_mac); 375e5b75505Sopenharmony_ci 376e5b75505Sopenharmony_ci p2p_buf_add_feature_capability(buf, fcap_len, fcap); 377e5b75505Sopenharmony_ci p2p_buf_update_ie_hdr(buf, len); 378e5b75505Sopenharmony_ci } else if (status != P2P_SC_SUCCESS || adv_id) { 379e5b75505Sopenharmony_ci u8 *len = p2p_buf_add_ie_hdr(buf); 380e5b75505Sopenharmony_ci 381e5b75505Sopenharmony_ci p2p_buf_add_status(buf, status); 382e5b75505Sopenharmony_ci 383e5b75505Sopenharmony_ci if (p2p->p2ps_prov) 384e5b75505Sopenharmony_ci p2p_buf_add_advertisement_id(buf, adv_id, 385e5b75505Sopenharmony_ci p2p->p2ps_prov->adv_mac); 386e5b75505Sopenharmony_ci 387e5b75505Sopenharmony_ci p2p_buf_update_ie_hdr(buf, len); 388e5b75505Sopenharmony_ci } 389e5b75505Sopenharmony_ci 390e5b75505Sopenharmony_ci /* WPS IE with Config Methods attribute */ 391e5b75505Sopenharmony_ci p2p_build_wps_ie_config_methods(buf, config_methods); 392e5b75505Sopenharmony_ci 393e5b75505Sopenharmony_ci#ifdef CONFIG_WIFI_DISPLAY 394e5b75505Sopenharmony_ci if (wfd_ie) 395e5b75505Sopenharmony_ci wpabuf_put_buf(buf, wfd_ie); 396e5b75505Sopenharmony_ci#endif /* CONFIG_WIFI_DISPLAY */ 397e5b75505Sopenharmony_ci 398e5b75505Sopenharmony_ci if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]) 399e5b75505Sopenharmony_ci wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]); 400e5b75505Sopenharmony_ci 401e5b75505Sopenharmony_ci return buf; 402e5b75505Sopenharmony_ci} 403e5b75505Sopenharmony_ci 404e5b75505Sopenharmony_ci 405e5b75505Sopenharmony_cistatic int p2ps_setup_p2ps_prov(struct p2p_data *p2p, u32 adv_id, 406e5b75505Sopenharmony_ci u32 session_id, u16 method, 407e5b75505Sopenharmony_ci const u8 *session_mac, const u8 *adv_mac) 408e5b75505Sopenharmony_ci{ 409e5b75505Sopenharmony_ci struct p2ps_provision *tmp; 410e5b75505Sopenharmony_ci 411e5b75505Sopenharmony_ci if (!p2p->p2ps_prov) { 412e5b75505Sopenharmony_ci p2p->p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + 1); 413e5b75505Sopenharmony_ci if (!p2p->p2ps_prov) 414e5b75505Sopenharmony_ci return -1; 415e5b75505Sopenharmony_ci } else { 416e5b75505Sopenharmony_ci os_memset(p2p->p2ps_prov, 0, sizeof(struct p2ps_provision) + 1); 417e5b75505Sopenharmony_ci } 418e5b75505Sopenharmony_ci 419e5b75505Sopenharmony_ci tmp = p2p->p2ps_prov; 420e5b75505Sopenharmony_ci tmp->adv_id = adv_id; 421e5b75505Sopenharmony_ci tmp->session_id = session_id; 422e5b75505Sopenharmony_ci tmp->method = method; 423e5b75505Sopenharmony_ci os_memcpy(tmp->session_mac, session_mac, ETH_ALEN); 424e5b75505Sopenharmony_ci os_memcpy(tmp->adv_mac, adv_mac, ETH_ALEN); 425e5b75505Sopenharmony_ci tmp->info[0] = '\0'; 426e5b75505Sopenharmony_ci 427e5b75505Sopenharmony_ci return 0; 428e5b75505Sopenharmony_ci} 429e5b75505Sopenharmony_ci 430e5b75505Sopenharmony_ci 431e5b75505Sopenharmony_cistatic u8 p2ps_own_preferred_cpt(const u8 *cpt_priority, u8 req_cpt_mask) 432e5b75505Sopenharmony_ci{ 433e5b75505Sopenharmony_ci int i; 434e5b75505Sopenharmony_ci 435e5b75505Sopenharmony_ci for (i = 0; cpt_priority[i]; i++) 436e5b75505Sopenharmony_ci if (req_cpt_mask & cpt_priority[i]) 437e5b75505Sopenharmony_ci return cpt_priority[i]; 438e5b75505Sopenharmony_ci 439e5b75505Sopenharmony_ci return 0; 440e5b75505Sopenharmony_ci} 441e5b75505Sopenharmony_ci 442e5b75505Sopenharmony_ci 443e5b75505Sopenharmony_ci/* Check if the message contains a valid P2PS PD Request */ 444e5b75505Sopenharmony_cistatic int p2ps_validate_pd_req(struct p2p_data *p2p, struct p2p_message *msg, 445e5b75505Sopenharmony_ci const u8 *addr) 446e5b75505Sopenharmony_ci{ 447e5b75505Sopenharmony_ci u8 group_id = 0; 448e5b75505Sopenharmony_ci u8 intended_addr = 0; 449e5b75505Sopenharmony_ci u8 operating_channel = 0; 450e5b75505Sopenharmony_ci u8 channel_list = 0; 451e5b75505Sopenharmony_ci u8 config_timeout = 0; 452e5b75505Sopenharmony_ci u8 listen_channel = 0; 453e5b75505Sopenharmony_ci 454e5b75505Sopenharmony_ci#define P2PS_PD_REQ_CHECK(_val, _attr) \ 455e5b75505Sopenharmony_cido { \ 456e5b75505Sopenharmony_ci if ((_val) && !msg->_attr) { \ 457e5b75505Sopenharmony_ci p2p_dbg(p2p, "Not P2PS PD Request. Missing %s", #_attr); \ 458e5b75505Sopenharmony_ci return -1; \ 459e5b75505Sopenharmony_ci } \ 460e5b75505Sopenharmony_ci} while (0) 461e5b75505Sopenharmony_ci 462e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(1, adv_id); 463e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(1, session_id); 464e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(1, session_mac); 465e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(1, adv_mac); 466e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(1, capability); 467e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(1, p2p_device_info); 468e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(1, feature_cap); 469e5b75505Sopenharmony_ci 470e5b75505Sopenharmony_ci /* 471e5b75505Sopenharmony_ci * We don't need to check Connection Capability, Persistent Group, 472e5b75505Sopenharmony_ci * and related attributes for follow-on PD Request with a status 473e5b75505Sopenharmony_ci * other than SUCCESS_DEFERRED. 474e5b75505Sopenharmony_ci */ 475e5b75505Sopenharmony_ci if (msg->status && *msg->status != P2P_SC_SUCCESS_DEFERRED) 476e5b75505Sopenharmony_ci return 0; 477e5b75505Sopenharmony_ci 478e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(1, conn_cap); 479e5b75505Sopenharmony_ci 480e5b75505Sopenharmony_ci /* 481e5b75505Sopenharmony_ci * Note 1: A feature capability attribute structure can be changed 482e5b75505Sopenharmony_ci * in the future. The assumption is that such modifications are 483e5b75505Sopenharmony_ci * backward compatible, therefore we allow processing of msg.feature_cap 484e5b75505Sopenharmony_ci * exceeding the size of the p2ps_feature_capab structure. 485e5b75505Sopenharmony_ci * Note 2: Verification of msg.feature_cap_len below has to be changed 486e5b75505Sopenharmony_ci * to allow 2 byte feature capability processing if 487e5b75505Sopenharmony_ci * struct p2ps_feature_capab is extended to include additional fields 488e5b75505Sopenharmony_ci * and it affects the structure size. 489e5b75505Sopenharmony_ci */ 490e5b75505Sopenharmony_ci if (msg->feature_cap_len < sizeof(struct p2ps_feature_capab)) { 491e5b75505Sopenharmony_ci p2p_dbg(p2p, "P2PS: Invalid feature capability len"); 492e5b75505Sopenharmony_ci return -1; 493e5b75505Sopenharmony_ci } 494e5b75505Sopenharmony_ci 495e5b75505Sopenharmony_ci switch (*msg->conn_cap) { 496e5b75505Sopenharmony_ci case P2PS_SETUP_NEW: 497e5b75505Sopenharmony_ci group_id = 1; 498e5b75505Sopenharmony_ci intended_addr = 1; 499e5b75505Sopenharmony_ci operating_channel = 1; 500e5b75505Sopenharmony_ci channel_list = 1; 501e5b75505Sopenharmony_ci config_timeout = 1; 502e5b75505Sopenharmony_ci listen_channel = 1; 503e5b75505Sopenharmony_ci break; 504e5b75505Sopenharmony_ci case P2PS_SETUP_CLIENT: 505e5b75505Sopenharmony_ci channel_list = 1; 506e5b75505Sopenharmony_ci listen_channel = 1; 507e5b75505Sopenharmony_ci break; 508e5b75505Sopenharmony_ci case P2PS_SETUP_GROUP_OWNER: 509e5b75505Sopenharmony_ci group_id = 1; 510e5b75505Sopenharmony_ci intended_addr = 1; 511e5b75505Sopenharmony_ci operating_channel = 1; 512e5b75505Sopenharmony_ci break; 513e5b75505Sopenharmony_ci case P2PS_SETUP_NEW | P2PS_SETUP_GROUP_OWNER: 514e5b75505Sopenharmony_ci group_id = 1; 515e5b75505Sopenharmony_ci operating_channel = 1; 516e5b75505Sopenharmony_ci intended_addr = 1; 517e5b75505Sopenharmony_ci channel_list = 1; 518e5b75505Sopenharmony_ci config_timeout = 1; 519e5b75505Sopenharmony_ci break; 520e5b75505Sopenharmony_ci case P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER: 521e5b75505Sopenharmony_ci group_id = 1; 522e5b75505Sopenharmony_ci intended_addr = 1; 523e5b75505Sopenharmony_ci operating_channel = 1; 524e5b75505Sopenharmony_ci channel_list = 1; 525e5b75505Sopenharmony_ci config_timeout = 1; 526e5b75505Sopenharmony_ci break; 527e5b75505Sopenharmony_ci default: 528e5b75505Sopenharmony_ci p2p_dbg(p2p, "Invalid P2PS PD connection capability"); 529e5b75505Sopenharmony_ci return -1; 530e5b75505Sopenharmony_ci } 531e5b75505Sopenharmony_ci 532e5b75505Sopenharmony_ci if (msg->persistent_dev) { 533e5b75505Sopenharmony_ci channel_list = 1; 534e5b75505Sopenharmony_ci config_timeout = 1; 535e5b75505Sopenharmony_ci if (os_memcmp(msg->persistent_dev, addr, ETH_ALEN) == 0) { 536e5b75505Sopenharmony_ci intended_addr = 1; 537e5b75505Sopenharmony_ci operating_channel = 1; 538e5b75505Sopenharmony_ci } 539e5b75505Sopenharmony_ci } 540e5b75505Sopenharmony_ci 541e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(group_id, group_id); 542e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(intended_addr, intended_addr); 543e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(operating_channel, operating_channel); 544e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(channel_list, channel_list); 545e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(config_timeout, config_timeout); 546e5b75505Sopenharmony_ci P2PS_PD_REQ_CHECK(listen_channel, listen_channel); 547e5b75505Sopenharmony_ci 548e5b75505Sopenharmony_ci#undef P2PS_PD_REQ_CHECK 549e5b75505Sopenharmony_ci 550e5b75505Sopenharmony_ci return 0; 551e5b75505Sopenharmony_ci} 552e5b75505Sopenharmony_ci 553e5b75505Sopenharmony_ci 554e5b75505Sopenharmony_civoid p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa, 555e5b75505Sopenharmony_ci const u8 *data, size_t len, int rx_freq) 556e5b75505Sopenharmony_ci{ 557e5b75505Sopenharmony_ci struct p2p_message msg; 558e5b75505Sopenharmony_ci struct p2p_device *dev; 559e5b75505Sopenharmony_ci int freq; 560e5b75505Sopenharmony_ci enum p2p_status_code reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 561e5b75505Sopenharmony_ci struct wpabuf *resp; 562e5b75505Sopenharmony_ci u32 adv_id = 0; 563e5b75505Sopenharmony_ci struct p2ps_advertisement *p2ps_adv = NULL; 564e5b75505Sopenharmony_ci u8 conncap = P2PS_SETUP_NEW; 565e5b75505Sopenharmony_ci u8 auto_accept = 0; 566e5b75505Sopenharmony_ci u32 session_id = 0; 567e5b75505Sopenharmony_ci u8 session_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; 568e5b75505Sopenharmony_ci u8 adv_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; 569e5b75505Sopenharmony_ci const u8 *group_mac; 570e5b75505Sopenharmony_ci int passwd_id = DEV_PW_DEFAULT; 571e5b75505Sopenharmony_ci u16 config_methods; 572e5b75505Sopenharmony_ci u16 allowed_config_methods = WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD; 573e5b75505Sopenharmony_ci struct p2ps_feature_capab resp_fcap = { 0, 0 }; 574e5b75505Sopenharmony_ci struct p2ps_feature_capab *req_fcap = NULL; 575e5b75505Sopenharmony_ci u8 remote_conncap; 576e5b75505Sopenharmony_ci u16 method; 577e5b75505Sopenharmony_ci 578e5b75505Sopenharmony_ci if (p2p_parse(data, len, &msg)) 579e5b75505Sopenharmony_ci return; 580e5b75505Sopenharmony_ci 581e5b75505Sopenharmony_ci p2p_dbg(p2p, "Received Provision Discovery Request from " MACSTR 582e5b75505Sopenharmony_ci " with config methods 0x%x (freq=%d)", 583e5b75505Sopenharmony_ci MAC2STR(sa), msg.wps_config_methods, rx_freq); 584e5b75505Sopenharmony_ci group_mac = msg.intended_addr; 585e5b75505Sopenharmony_ci 586e5b75505Sopenharmony_ci dev = p2p_get_device(p2p, sa); 587e5b75505Sopenharmony_ci if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { 588e5b75505Sopenharmony_ci p2p_dbg(p2p, "Provision Discovery Request from unknown peer " 589e5b75505Sopenharmony_ci MACSTR, MAC2STR(sa)); 590e5b75505Sopenharmony_ci 591e5b75505Sopenharmony_ci if (p2p_add_device(p2p, sa, rx_freq, NULL, 0, data + 1, len - 1, 592e5b75505Sopenharmony_ci 0)) { 593e5b75505Sopenharmony_ci p2p_dbg(p2p, "Provision Discovery Request add device failed " 594e5b75505Sopenharmony_ci MACSTR, MAC2STR(sa)); 595e5b75505Sopenharmony_ci goto out; 596e5b75505Sopenharmony_ci } 597e5b75505Sopenharmony_ci 598e5b75505Sopenharmony_ci dev = p2p_get_device(p2p, sa); 599e5b75505Sopenharmony_ci if (!dev) { 600e5b75505Sopenharmony_ci p2p_dbg(p2p, 601e5b75505Sopenharmony_ci "Provision Discovery device not found " 602e5b75505Sopenharmony_ci MACSTR, MAC2STR(sa)); 603e5b75505Sopenharmony_ci goto out; 604e5b75505Sopenharmony_ci } 605e5b75505Sopenharmony_ci } else if (msg.wfd_subelems) { 606e5b75505Sopenharmony_ci wpabuf_free(dev->info.wfd_subelems); 607e5b75505Sopenharmony_ci dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); 608e5b75505Sopenharmony_ci } 609e5b75505Sopenharmony_ci 610e5b75505Sopenharmony_ci if (!msg.adv_id) { 611e5b75505Sopenharmony_ci allowed_config_methods |= WPS_CONFIG_PUSHBUTTON; 612e5b75505Sopenharmony_ci if (!(msg.wps_config_methods & allowed_config_methods)) { 613e5b75505Sopenharmony_ci p2p_dbg(p2p, 614e5b75505Sopenharmony_ci "Unsupported Config Methods in Provision Discovery Request"); 615e5b75505Sopenharmony_ci goto out; 616e5b75505Sopenharmony_ci } 617e5b75505Sopenharmony_ci 618e5b75505Sopenharmony_ci /* Legacy (non-P2PS) - Unknown groups allowed for P2PS */ 619e5b75505Sopenharmony_ci if (msg.group_id) { 620e5b75505Sopenharmony_ci size_t i; 621e5b75505Sopenharmony_ci 622e5b75505Sopenharmony_ci for (i = 0; i < p2p->num_groups; i++) { 623e5b75505Sopenharmony_ci if (p2p_group_is_group_id_match( 624e5b75505Sopenharmony_ci p2p->groups[i], 625e5b75505Sopenharmony_ci msg.group_id, msg.group_id_len)) 626e5b75505Sopenharmony_ci break; 627e5b75505Sopenharmony_ci } 628e5b75505Sopenharmony_ci if (i == p2p->num_groups) { 629e5b75505Sopenharmony_ci p2p_dbg(p2p, 630e5b75505Sopenharmony_ci "PD request for unknown P2P Group ID - reject"); 631e5b75505Sopenharmony_ci goto out; 632e5b75505Sopenharmony_ci } 633e5b75505Sopenharmony_ci } 634e5b75505Sopenharmony_ci } else { 635e5b75505Sopenharmony_ci allowed_config_methods |= WPS_CONFIG_P2PS; 636e5b75505Sopenharmony_ci 637e5b75505Sopenharmony_ci /* 638e5b75505Sopenharmony_ci * Set adv_id here, so in case of an error, a P2PS PD Response 639e5b75505Sopenharmony_ci * will be sent. 640e5b75505Sopenharmony_ci */ 641e5b75505Sopenharmony_ci adv_id = WPA_GET_LE32(msg.adv_id); 642e5b75505Sopenharmony_ci if (p2ps_validate_pd_req(p2p, &msg, sa) < 0) { 643e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INVALID_PARAMS; 644e5b75505Sopenharmony_ci goto out; 645e5b75505Sopenharmony_ci } 646e5b75505Sopenharmony_ci 647e5b75505Sopenharmony_ci req_fcap = (struct p2ps_feature_capab *) msg.feature_cap; 648e5b75505Sopenharmony_ci 649e5b75505Sopenharmony_ci os_memcpy(session_mac, msg.session_mac, ETH_ALEN); 650e5b75505Sopenharmony_ci os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); 651e5b75505Sopenharmony_ci 652e5b75505Sopenharmony_ci session_id = WPA_GET_LE32(msg.session_id); 653e5b75505Sopenharmony_ci 654e5b75505Sopenharmony_ci if (msg.conn_cap) 655e5b75505Sopenharmony_ci conncap = *msg.conn_cap; 656e5b75505Sopenharmony_ci 657e5b75505Sopenharmony_ci /* 658e5b75505Sopenharmony_ci * We need to verify a P2PS config methog in an initial PD 659e5b75505Sopenharmony_ci * request or in a follow-on PD request with the status 660e5b75505Sopenharmony_ci * SUCCESS_DEFERRED. 661e5b75505Sopenharmony_ci */ 662e5b75505Sopenharmony_ci if ((!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) && 663e5b75505Sopenharmony_ci !(msg.wps_config_methods & allowed_config_methods)) { 664e5b75505Sopenharmony_ci p2p_dbg(p2p, 665e5b75505Sopenharmony_ci "Unsupported Config Methods in Provision Discovery Request"); 666e5b75505Sopenharmony_ci goto out; 667e5b75505Sopenharmony_ci } 668e5b75505Sopenharmony_ci 669e5b75505Sopenharmony_ci /* 670e5b75505Sopenharmony_ci * TODO: since we don't support multiple PD, reject PD request 671e5b75505Sopenharmony_ci * if we are in the middle of P2PS PD with some other peer 672e5b75505Sopenharmony_ci */ 673e5b75505Sopenharmony_ci } 674e5b75505Sopenharmony_ci 675e5b75505Sopenharmony_ci dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | 676e5b75505Sopenharmony_ci P2P_DEV_PD_PEER_KEYPAD | 677e5b75505Sopenharmony_ci P2P_DEV_PD_PEER_P2PS); 678e5b75505Sopenharmony_ci 679e5b75505Sopenharmony_ci if (msg.wps_config_methods & WPS_CONFIG_DISPLAY) { 680e5b75505Sopenharmony_ci p2p_dbg(p2p, "Peer " MACSTR 681e5b75505Sopenharmony_ci " requested us to show a PIN on display", MAC2STR(sa)); 682e5b75505Sopenharmony_ci dev->flags |= P2P_DEV_PD_PEER_KEYPAD; 683e5b75505Sopenharmony_ci passwd_id = DEV_PW_USER_SPECIFIED; 684e5b75505Sopenharmony_ci } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { 685e5b75505Sopenharmony_ci p2p_dbg(p2p, "Peer " MACSTR 686e5b75505Sopenharmony_ci " requested us to write its PIN using keypad", 687e5b75505Sopenharmony_ci MAC2STR(sa)); 688e5b75505Sopenharmony_ci dev->flags |= P2P_DEV_PD_PEER_DISPLAY; 689e5b75505Sopenharmony_ci passwd_id = DEV_PW_REGISTRAR_SPECIFIED; 690e5b75505Sopenharmony_ci } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { 691e5b75505Sopenharmony_ci p2p_dbg(p2p, "Peer " MACSTR " requesting P2PS PIN", 692e5b75505Sopenharmony_ci MAC2STR(sa)); 693e5b75505Sopenharmony_ci dev->flags |= P2P_DEV_PD_PEER_P2PS; 694e5b75505Sopenharmony_ci passwd_id = DEV_PW_P2PS_DEFAULT; 695e5b75505Sopenharmony_ci } 696e5b75505Sopenharmony_ci 697e5b75505Sopenharmony_ci /* Remove stale persistent groups */ 698e5b75505Sopenharmony_ci if (p2p->cfg->remove_stale_groups) { 699e5b75505Sopenharmony_ci p2p->cfg->remove_stale_groups( 700e5b75505Sopenharmony_ci p2p->cfg->cb_ctx, dev->info.p2p_device_addr, 701e5b75505Sopenharmony_ci msg.persistent_dev, 702e5b75505Sopenharmony_ci msg.persistent_ssid, msg.persistent_ssid_len); 703e5b75505Sopenharmony_ci } 704e5b75505Sopenharmony_ci 705e5b75505Sopenharmony_ci reject = P2P_SC_SUCCESS; 706e5b75505Sopenharmony_ci 707e5b75505Sopenharmony_ci /* 708e5b75505Sopenharmony_ci * End of a legacy P2P PD Request processing, from this point continue 709e5b75505Sopenharmony_ci * with P2PS one. 710e5b75505Sopenharmony_ci */ 711e5b75505Sopenharmony_ci if (!msg.adv_id) 712e5b75505Sopenharmony_ci goto out; 713e5b75505Sopenharmony_ci 714e5b75505Sopenharmony_ci remote_conncap = conncap; 715e5b75505Sopenharmony_ci 716e5b75505Sopenharmony_ci if (!msg.status) { 717e5b75505Sopenharmony_ci unsigned int forced_freq, pref_freq; 718e5b75505Sopenharmony_ci 719e5b75505Sopenharmony_ci if (os_memcmp(p2p->cfg->dev_addr, msg.adv_mac, ETH_ALEN)) { 720e5b75505Sopenharmony_ci p2p_dbg(p2p, 721e5b75505Sopenharmony_ci "P2PS PD adv mac does not match the local one"); 722e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 723e5b75505Sopenharmony_ci goto out; 724e5b75505Sopenharmony_ci } 725e5b75505Sopenharmony_ci 726e5b75505Sopenharmony_ci p2ps_adv = p2p_service_p2ps_id(p2p, adv_id); 727e5b75505Sopenharmony_ci if (!p2ps_adv) { 728e5b75505Sopenharmony_ci p2p_dbg(p2p, "P2PS PD invalid adv_id=0x%X", adv_id); 729e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 730e5b75505Sopenharmony_ci goto out; 731e5b75505Sopenharmony_ci } 732e5b75505Sopenharmony_ci p2p_dbg(p2p, "adv_id: 0x%X, p2ps_adv: %p", adv_id, p2ps_adv); 733e5b75505Sopenharmony_ci 734e5b75505Sopenharmony_ci auto_accept = p2ps_adv->auto_accept; 735e5b75505Sopenharmony_ci conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx, 736e5b75505Sopenharmony_ci conncap, auto_accept, 737e5b75505Sopenharmony_ci &forced_freq, 738e5b75505Sopenharmony_ci &pref_freq); 739e5b75505Sopenharmony_ci 740e5b75505Sopenharmony_ci p2p_dbg(p2p, "Conncap: local:%d remote:%d result:%d", 741e5b75505Sopenharmony_ci auto_accept, remote_conncap, conncap); 742e5b75505Sopenharmony_ci 743e5b75505Sopenharmony_ci p2p_prepare_channel(p2p, dev, forced_freq, pref_freq, 0); 744e5b75505Sopenharmony_ci 745e5b75505Sopenharmony_ci resp_fcap.cpt = p2ps_own_preferred_cpt(p2ps_adv->cpt_priority, 746e5b75505Sopenharmony_ci req_fcap->cpt); 747e5b75505Sopenharmony_ci 748e5b75505Sopenharmony_ci p2p_dbg(p2p, "cpt: service:0x%x remote:0x%x result:0x%x", 749e5b75505Sopenharmony_ci p2ps_adv->cpt_mask, req_fcap->cpt, resp_fcap.cpt); 750e5b75505Sopenharmony_ci 751e5b75505Sopenharmony_ci if (!resp_fcap.cpt) { 752e5b75505Sopenharmony_ci p2p_dbg(p2p, 753e5b75505Sopenharmony_ci "Incompatible P2PS feature capability CPT bitmask"); 754e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 755e5b75505Sopenharmony_ci } else if (p2ps_adv->config_methods && 756e5b75505Sopenharmony_ci !(msg.wps_config_methods & 757e5b75505Sopenharmony_ci p2ps_adv->config_methods)) { 758e5b75505Sopenharmony_ci p2p_dbg(p2p, 759e5b75505Sopenharmony_ci "Unsupported config methods in Provision Discovery Request (own=0x%x peer=0x%x)", 760e5b75505Sopenharmony_ci p2ps_adv->config_methods, 761e5b75505Sopenharmony_ci msg.wps_config_methods); 762e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 763e5b75505Sopenharmony_ci } else if (!p2ps_adv->state) { 764e5b75505Sopenharmony_ci p2p_dbg(p2p, "P2PS state unavailable"); 765e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; 766e5b75505Sopenharmony_ci } else if (!conncap) { 767e5b75505Sopenharmony_ci p2p_dbg(p2p, "Conncap resolution failed"); 768e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 769e5b75505Sopenharmony_ci } 770e5b75505Sopenharmony_ci 771e5b75505Sopenharmony_ci if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { 772e5b75505Sopenharmony_ci p2p_dbg(p2p, "Keypad - always defer"); 773e5b75505Sopenharmony_ci auto_accept = 0; 774e5b75505Sopenharmony_ci } 775e5b75505Sopenharmony_ci 776e5b75505Sopenharmony_ci if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) || 777e5b75505Sopenharmony_ci msg.persistent_dev) && conncap != P2PS_SETUP_NEW && 778e5b75505Sopenharmony_ci msg.channel_list && msg.channel_list_len && 779e5b75505Sopenharmony_ci p2p_peer_channels_check(p2p, &p2p->channels, dev, 780e5b75505Sopenharmony_ci msg.channel_list, 781e5b75505Sopenharmony_ci msg.channel_list_len) < 0) { 782e5b75505Sopenharmony_ci p2p_dbg(p2p, 783e5b75505Sopenharmony_ci "No common channels - force deferred flow"); 784e5b75505Sopenharmony_ci auto_accept = 0; 785e5b75505Sopenharmony_ci } 786e5b75505Sopenharmony_ci 787e5b75505Sopenharmony_ci if (((remote_conncap & P2PS_SETUP_GROUP_OWNER) || 788e5b75505Sopenharmony_ci msg.persistent_dev) && msg.operating_channel) { 789e5b75505Sopenharmony_ci struct p2p_channels intersect; 790e5b75505Sopenharmony_ci 791e5b75505Sopenharmony_ci /* 792e5b75505Sopenharmony_ci * There are cases where only the operating channel is 793e5b75505Sopenharmony_ci * provided. This requires saving the channel as the 794e5b75505Sopenharmony_ci * supported channel list, and verifying that it is 795e5b75505Sopenharmony_ci * supported. 796e5b75505Sopenharmony_ci */ 797e5b75505Sopenharmony_ci if (dev->channels.reg_classes == 0 || 798e5b75505Sopenharmony_ci !p2p_channels_includes(&dev->channels, 799e5b75505Sopenharmony_ci msg.operating_channel[3], 800e5b75505Sopenharmony_ci msg.operating_channel[4])) { 801e5b75505Sopenharmony_ci struct p2p_channels *ch = &dev->channels; 802e5b75505Sopenharmony_ci 803e5b75505Sopenharmony_ci os_memset(ch, 0, sizeof(*ch)); 804e5b75505Sopenharmony_ci ch->reg_class[0].reg_class = 805e5b75505Sopenharmony_ci msg.operating_channel[3]; 806e5b75505Sopenharmony_ci ch->reg_class[0].channel[0] = 807e5b75505Sopenharmony_ci msg.operating_channel[4]; 808e5b75505Sopenharmony_ci ch->reg_class[0].channels = 1; 809e5b75505Sopenharmony_ci ch->reg_classes = 1; 810e5b75505Sopenharmony_ci } 811e5b75505Sopenharmony_ci 812e5b75505Sopenharmony_ci p2p_channels_intersect(&p2p->channels, &dev->channels, 813e5b75505Sopenharmony_ci &intersect); 814e5b75505Sopenharmony_ci 815e5b75505Sopenharmony_ci if (intersect.reg_classes == 0) { 816e5b75505Sopenharmony_ci p2p_dbg(p2p, 817e5b75505Sopenharmony_ci "No common channels - force deferred flow"); 818e5b75505Sopenharmony_ci auto_accept = 0; 819e5b75505Sopenharmony_ci } 820e5b75505Sopenharmony_ci } 821e5b75505Sopenharmony_ci 822e5b75505Sopenharmony_ci if (auto_accept || reject != P2P_SC_SUCCESS) { 823e5b75505Sopenharmony_ci struct p2ps_provision *tmp; 824e5b75505Sopenharmony_ci 825e5b75505Sopenharmony_ci if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, 826e5b75505Sopenharmony_ci msg.wps_config_methods, 827e5b75505Sopenharmony_ci session_mac, adv_mac) < 0) { 828e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; 829e5b75505Sopenharmony_ci goto out; 830e5b75505Sopenharmony_ci } 831e5b75505Sopenharmony_ci 832e5b75505Sopenharmony_ci tmp = p2p->p2ps_prov; 833e5b75505Sopenharmony_ci tmp->force_freq = forced_freq; 834e5b75505Sopenharmony_ci tmp->pref_freq = pref_freq; 835e5b75505Sopenharmony_ci if (conncap) { 836e5b75505Sopenharmony_ci tmp->conncap = conncap; 837e5b75505Sopenharmony_ci tmp->status = P2P_SC_SUCCESS; 838e5b75505Sopenharmony_ci } else { 839e5b75505Sopenharmony_ci tmp->conncap = auto_accept; 840e5b75505Sopenharmony_ci tmp->status = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 841e5b75505Sopenharmony_ci } 842e5b75505Sopenharmony_ci 843e5b75505Sopenharmony_ci if (reject != P2P_SC_SUCCESS) 844e5b75505Sopenharmony_ci goto out; 845e5b75505Sopenharmony_ci } 846e5b75505Sopenharmony_ci } 847e5b75505Sopenharmony_ci 848e5b75505Sopenharmony_ci if (!msg.status && !auto_accept && 849e5b75505Sopenharmony_ci (!p2p->p2ps_prov || p2p->p2ps_prov->adv_id != adv_id)) { 850e5b75505Sopenharmony_ci struct p2ps_provision *tmp; 851e5b75505Sopenharmony_ci 852e5b75505Sopenharmony_ci if (!conncap) { 853e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 854e5b75505Sopenharmony_ci goto out; 855e5b75505Sopenharmony_ci } 856e5b75505Sopenharmony_ci 857e5b75505Sopenharmony_ci if (p2ps_setup_p2ps_prov(p2p, adv_id, session_id, 858e5b75505Sopenharmony_ci msg.wps_config_methods, 859e5b75505Sopenharmony_ci session_mac, adv_mac) < 0) { 860e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE; 861e5b75505Sopenharmony_ci goto out; 862e5b75505Sopenharmony_ci } 863e5b75505Sopenharmony_ci tmp = p2p->p2ps_prov; 864e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE; 865e5b75505Sopenharmony_ci tmp->status = reject; 866e5b75505Sopenharmony_ci } 867e5b75505Sopenharmony_ci 868e5b75505Sopenharmony_ci /* Not a P2PS Follow-on PD */ 869e5b75505Sopenharmony_ci if (!msg.status) 870e5b75505Sopenharmony_ci goto out; 871e5b75505Sopenharmony_ci 872e5b75505Sopenharmony_ci if (*msg.status && *msg.status != P2P_SC_SUCCESS_DEFERRED) { 873e5b75505Sopenharmony_ci reject = *msg.status; 874e5b75505Sopenharmony_ci goto out; 875e5b75505Sopenharmony_ci } 876e5b75505Sopenharmony_ci 877e5b75505Sopenharmony_ci if (*msg.status != P2P_SC_SUCCESS_DEFERRED || !p2p->p2ps_prov) 878e5b75505Sopenharmony_ci goto out; 879e5b75505Sopenharmony_ci 880e5b75505Sopenharmony_ci if (p2p->p2ps_prov->adv_id != adv_id || 881e5b75505Sopenharmony_ci os_memcmp(p2p->p2ps_prov->adv_mac, msg.adv_mac, ETH_ALEN)) { 882e5b75505Sopenharmony_ci p2p_dbg(p2p, 883e5b75505Sopenharmony_ci "P2PS Follow-on PD with mismatch Advertisement ID/MAC"); 884e5b75505Sopenharmony_ci goto out; 885e5b75505Sopenharmony_ci } 886e5b75505Sopenharmony_ci 887e5b75505Sopenharmony_ci if (p2p->p2ps_prov->session_id != session_id || 888e5b75505Sopenharmony_ci os_memcmp(p2p->p2ps_prov->session_mac, msg.session_mac, ETH_ALEN)) { 889e5b75505Sopenharmony_ci p2p_dbg(p2p, "P2PS Follow-on PD with mismatch Session ID/MAC"); 890e5b75505Sopenharmony_ci goto out; 891e5b75505Sopenharmony_ci } 892e5b75505Sopenharmony_ci 893e5b75505Sopenharmony_ci method = p2p->p2ps_prov->method; 894e5b75505Sopenharmony_ci 895e5b75505Sopenharmony_ci conncap = p2p->cfg->p2ps_group_capability(p2p->cfg->cb_ctx, 896e5b75505Sopenharmony_ci remote_conncap, 897e5b75505Sopenharmony_ci p2p->p2ps_prov->conncap, 898e5b75505Sopenharmony_ci &p2p->p2ps_prov->force_freq, 899e5b75505Sopenharmony_ci &p2p->p2ps_prov->pref_freq); 900e5b75505Sopenharmony_ci 901e5b75505Sopenharmony_ci resp_fcap.cpt = p2ps_own_preferred_cpt(p2p->p2ps_prov->cpt_priority, 902e5b75505Sopenharmony_ci req_fcap->cpt); 903e5b75505Sopenharmony_ci 904e5b75505Sopenharmony_ci p2p_dbg(p2p, "cpt: local:0x%x remote:0x%x result:0x%x", 905e5b75505Sopenharmony_ci p2p->p2ps_prov->cpt_mask, req_fcap->cpt, resp_fcap.cpt); 906e5b75505Sopenharmony_ci 907e5b75505Sopenharmony_ci p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq, 908e5b75505Sopenharmony_ci p2p->p2ps_prov->pref_freq, 0); 909e5b75505Sopenharmony_ci 910e5b75505Sopenharmony_ci /* 911e5b75505Sopenharmony_ci * Ensure that if we asked for PIN originally, our method is consistent 912e5b75505Sopenharmony_ci * with original request. 913e5b75505Sopenharmony_ci */ 914e5b75505Sopenharmony_ci if (method & WPS_CONFIG_DISPLAY) 915e5b75505Sopenharmony_ci method = WPS_CONFIG_KEYPAD; 916e5b75505Sopenharmony_ci else if (method & WPS_CONFIG_KEYPAD) 917e5b75505Sopenharmony_ci method = WPS_CONFIG_DISPLAY; 918e5b75505Sopenharmony_ci 919e5b75505Sopenharmony_ci if (!conncap || !(msg.wps_config_methods & method)) { 920e5b75505Sopenharmony_ci /* 921e5b75505Sopenharmony_ci * Reject this "Deferred Accept* 922e5b75505Sopenharmony_ci * if incompatible conncap or method 923e5b75505Sopenharmony_ci */ 924e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 925e5b75505Sopenharmony_ci } else if (!resp_fcap.cpt) { 926e5b75505Sopenharmony_ci p2p_dbg(p2p, 927e5b75505Sopenharmony_ci "Incompatible P2PS feature capability CPT bitmask"); 928e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_INCOMPATIBLE_PARAMS; 929e5b75505Sopenharmony_ci } else if ((remote_conncap & (P2PS_SETUP_NEW | P2PS_SETUP_CLIENT) || 930e5b75505Sopenharmony_ci msg.persistent_dev) && conncap != P2PS_SETUP_NEW && 931e5b75505Sopenharmony_ci msg.channel_list && msg.channel_list_len && 932e5b75505Sopenharmony_ci p2p_peer_channels_check(p2p, &p2p->channels, dev, 933e5b75505Sopenharmony_ci msg.channel_list, 934e5b75505Sopenharmony_ci msg.channel_list_len) < 0) { 935e5b75505Sopenharmony_ci p2p_dbg(p2p, 936e5b75505Sopenharmony_ci "No common channels in Follow-On Provision Discovery Request"); 937e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_NO_COMMON_CHANNELS; 938e5b75505Sopenharmony_ci } else { 939e5b75505Sopenharmony_ci reject = P2P_SC_SUCCESS; 940e5b75505Sopenharmony_ci } 941e5b75505Sopenharmony_ci 942e5b75505Sopenharmony_ci dev->oper_freq = 0; 943e5b75505Sopenharmony_ci if (reject == P2P_SC_SUCCESS || reject == P2P_SC_SUCCESS_DEFERRED) { 944e5b75505Sopenharmony_ci u8 tmp; 945e5b75505Sopenharmony_ci 946e5b75505Sopenharmony_ci if (msg.operating_channel) 947e5b75505Sopenharmony_ci dev->oper_freq = 948e5b75505Sopenharmony_ci p2p_channel_to_freq(msg.operating_channel[3], 949e5b75505Sopenharmony_ci msg.operating_channel[4]); 950e5b75505Sopenharmony_ci 951e5b75505Sopenharmony_ci if ((conncap & P2PS_SETUP_GROUP_OWNER) && 952e5b75505Sopenharmony_ci p2p_go_select_channel(p2p, dev, &tmp) < 0) 953e5b75505Sopenharmony_ci reject = P2P_SC_FAIL_NO_COMMON_CHANNELS; 954e5b75505Sopenharmony_ci } 955e5b75505Sopenharmony_ci 956e5b75505Sopenharmony_ci p2p->p2ps_prov->status = reject; 957e5b75505Sopenharmony_ci p2p->p2ps_prov->conncap = conncap; 958e5b75505Sopenharmony_ci 959e5b75505Sopenharmony_ciout: 960e5b75505Sopenharmony_ci if (reject == P2P_SC_SUCCESS || 961e5b75505Sopenharmony_ci reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) 962e5b75505Sopenharmony_ci config_methods = msg.wps_config_methods; 963e5b75505Sopenharmony_ci else 964e5b75505Sopenharmony_ci config_methods = 0; 965e5b75505Sopenharmony_ci 966e5b75505Sopenharmony_ci /* 967e5b75505Sopenharmony_ci * Send PD Response for an initial PD Request or for follow-on 968e5b75505Sopenharmony_ci * PD Request with P2P_SC_SUCCESS_DEFERRED status. 969e5b75505Sopenharmony_ci */ 970e5b75505Sopenharmony_ci if (!msg.status || *msg.status == P2P_SC_SUCCESS_DEFERRED) { 971e5b75505Sopenharmony_ci resp = p2p_build_prov_disc_resp(p2p, dev, msg.dialog_token, 972e5b75505Sopenharmony_ci reject, config_methods, adv_id, 973e5b75505Sopenharmony_ci msg.group_id, msg.group_id_len, 974e5b75505Sopenharmony_ci msg.persistent_ssid, 975e5b75505Sopenharmony_ci msg.persistent_ssid_len, 976e5b75505Sopenharmony_ci (const u8 *) &resp_fcap, 977e5b75505Sopenharmony_ci sizeof(resp_fcap)); 978e5b75505Sopenharmony_ci if (!resp) { 979e5b75505Sopenharmony_ci p2p_parse_free(&msg); 980e5b75505Sopenharmony_ci return; 981e5b75505Sopenharmony_ci } 982e5b75505Sopenharmony_ci p2p_dbg(p2p, "Sending Provision Discovery Response"); 983e5b75505Sopenharmony_ci if (rx_freq > 0) 984e5b75505Sopenharmony_ci freq = rx_freq; 985e5b75505Sopenharmony_ci else 986e5b75505Sopenharmony_ci freq = p2p_channel_to_freq(p2p->cfg->reg_class, 987e5b75505Sopenharmony_ci p2p->cfg->channel); 988e5b75505Sopenharmony_ci if (freq < 0) { 989e5b75505Sopenharmony_ci p2p_dbg(p2p, "Unknown regulatory class/channel"); 990e5b75505Sopenharmony_ci wpabuf_free(resp); 991e5b75505Sopenharmony_ci p2p_parse_free(&msg); 992e5b75505Sopenharmony_ci return; 993e5b75505Sopenharmony_ci } 994e5b75505Sopenharmony_ci p2p->pending_action_state = P2P_PENDING_PD_RESPONSE; 995e5b75505Sopenharmony_ci if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr, 996e5b75505Sopenharmony_ci p2p->cfg->dev_addr, 997e5b75505Sopenharmony_ci wpabuf_head(resp), wpabuf_len(resp), 998e5b75505Sopenharmony_ci 50) < 0) 999e5b75505Sopenharmony_ci p2p_dbg(p2p, "Failed to send Action frame"); 1000e5b75505Sopenharmony_ci else 1001e5b75505Sopenharmony_ci p2p->send_action_in_progress = 1; 1002e5b75505Sopenharmony_ci 1003e5b75505Sopenharmony_ci wpabuf_free(resp); 1004e5b75505Sopenharmony_ci } 1005e5b75505Sopenharmony_ci 1006e5b75505Sopenharmony_ci if (!dev) { 1007e5b75505Sopenharmony_ci p2p_parse_free(&msg); 1008e5b75505Sopenharmony_ci return; 1009e5b75505Sopenharmony_ci } 1010e5b75505Sopenharmony_ci 1011e5b75505Sopenharmony_ci freq = 0; 1012e5b75505Sopenharmony_ci if (reject == P2P_SC_SUCCESS && conncap == P2PS_SETUP_GROUP_OWNER) { 1013e5b75505Sopenharmony_ci freq = p2p_channel_to_freq(p2p->op_reg_class, 1014e5b75505Sopenharmony_ci p2p->op_channel); 1015e5b75505Sopenharmony_ci if (freq < 0) 1016e5b75505Sopenharmony_ci freq = 0; 1017e5b75505Sopenharmony_ci } 1018e5b75505Sopenharmony_ci 1019e5b75505Sopenharmony_ci if (!p2p->cfg->p2ps_prov_complete) { 1020e5b75505Sopenharmony_ci /* Don't emit anything */ 1021e5b75505Sopenharmony_ci } else if (msg.status && *msg.status != P2P_SC_SUCCESS && 1022e5b75505Sopenharmony_ci *msg.status != P2P_SC_SUCCESS_DEFERRED) { 1023e5b75505Sopenharmony_ci reject = *msg.status; 1024e5b75505Sopenharmony_ci p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, 1025e5b75505Sopenharmony_ci sa, adv_mac, session_mac, 1026e5b75505Sopenharmony_ci NULL, adv_id, session_id, 1027e5b75505Sopenharmony_ci 0, 0, msg.persistent_ssid, 1028e5b75505Sopenharmony_ci msg.persistent_ssid_len, 1029e5b75505Sopenharmony_ci 0, 0, NULL, NULL, 0, freq, 1030e5b75505Sopenharmony_ci NULL, 0); 1031e5b75505Sopenharmony_ci } else if (msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && 1032e5b75505Sopenharmony_ci p2p->p2ps_prov) { 1033e5b75505Sopenharmony_ci p2p->p2ps_prov->status = reject; 1034e5b75505Sopenharmony_ci p2p->p2ps_prov->conncap = conncap; 1035e5b75505Sopenharmony_ci 1036e5b75505Sopenharmony_ci if (reject != P2P_SC_SUCCESS) 1037e5b75505Sopenharmony_ci p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, reject, 1038e5b75505Sopenharmony_ci sa, adv_mac, session_mac, 1039e5b75505Sopenharmony_ci NULL, adv_id, 1040e5b75505Sopenharmony_ci session_id, conncap, 0, 1041e5b75505Sopenharmony_ci msg.persistent_ssid, 1042e5b75505Sopenharmony_ci msg.persistent_ssid_len, 0, 1043e5b75505Sopenharmony_ci 0, NULL, NULL, 0, freq, 1044e5b75505Sopenharmony_ci NULL, 0); 1045e5b75505Sopenharmony_ci else 1046e5b75505Sopenharmony_ci p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, 1047e5b75505Sopenharmony_ci *msg.status, 1048e5b75505Sopenharmony_ci sa, adv_mac, session_mac, 1049e5b75505Sopenharmony_ci group_mac, adv_id, 1050e5b75505Sopenharmony_ci session_id, conncap, 1051e5b75505Sopenharmony_ci passwd_id, 1052e5b75505Sopenharmony_ci msg.persistent_ssid, 1053e5b75505Sopenharmony_ci msg.persistent_ssid_len, 0, 1054e5b75505Sopenharmony_ci 0, NULL, 1055e5b75505Sopenharmony_ci (const u8 *) &resp_fcap, 1056e5b75505Sopenharmony_ci sizeof(resp_fcap), freq, 1057e5b75505Sopenharmony_ci NULL, 0); 1058e5b75505Sopenharmony_ci } else if (msg.status && p2p->p2ps_prov) { 1059e5b75505Sopenharmony_ci p2p->p2ps_prov->status = P2P_SC_SUCCESS; 1060e5b75505Sopenharmony_ci p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, *msg.status, sa, 1061e5b75505Sopenharmony_ci adv_mac, session_mac, group_mac, 1062e5b75505Sopenharmony_ci adv_id, session_id, conncap, 1063e5b75505Sopenharmony_ci passwd_id, 1064e5b75505Sopenharmony_ci msg.persistent_ssid, 1065e5b75505Sopenharmony_ci msg.persistent_ssid_len, 1066e5b75505Sopenharmony_ci 0, 0, NULL, 1067e5b75505Sopenharmony_ci (const u8 *) &resp_fcap, 1068e5b75505Sopenharmony_ci sizeof(resp_fcap), freq, NULL, 0); 1069e5b75505Sopenharmony_ci } else if (msg.status) { 1070e5b75505Sopenharmony_ci } else if (auto_accept && reject == P2P_SC_SUCCESS) { 1071e5b75505Sopenharmony_ci p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, 1072e5b75505Sopenharmony_ci sa, adv_mac, session_mac, 1073e5b75505Sopenharmony_ci group_mac, adv_id, session_id, 1074e5b75505Sopenharmony_ci conncap, passwd_id, 1075e5b75505Sopenharmony_ci msg.persistent_ssid, 1076e5b75505Sopenharmony_ci msg.persistent_ssid_len, 1077e5b75505Sopenharmony_ci 0, 0, NULL, 1078e5b75505Sopenharmony_ci (const u8 *) &resp_fcap, 1079e5b75505Sopenharmony_ci sizeof(resp_fcap), freq, 1080e5b75505Sopenharmony_ci msg.group_id ? 1081e5b75505Sopenharmony_ci msg.group_id + ETH_ALEN : NULL, 1082e5b75505Sopenharmony_ci msg.group_id ? 1083e5b75505Sopenharmony_ci msg.group_id_len - ETH_ALEN : 0); 1084e5b75505Sopenharmony_ci } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && 1085e5b75505Sopenharmony_ci (!msg.session_info || !msg.session_info_len)) { 1086e5b75505Sopenharmony_ci p2p->p2ps_prov->method = msg.wps_config_methods; 1087e5b75505Sopenharmony_ci 1088e5b75505Sopenharmony_ci p2p->cfg->p2ps_prov_complete(p2p->cfg->cb_ctx, P2P_SC_SUCCESS, 1089e5b75505Sopenharmony_ci sa, adv_mac, session_mac, 1090e5b75505Sopenharmony_ci group_mac, adv_id, session_id, 1091e5b75505Sopenharmony_ci conncap, passwd_id, 1092e5b75505Sopenharmony_ci msg.persistent_ssid, 1093e5b75505Sopenharmony_ci msg.persistent_ssid_len, 1094e5b75505Sopenharmony_ci 0, 1, NULL, 1095e5b75505Sopenharmony_ci (const u8 *) &resp_fcap, 1096e5b75505Sopenharmony_ci sizeof(resp_fcap), freq, NULL, 0); 1097e5b75505Sopenharmony_ci } else if (reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { 1098e5b75505Sopenharmony_ci size_t buf_len = msg.session_info_len; 1099e5b75505Sopenharmony_ci char *buf = os_malloc(2 * buf_len + 1); 1100e5b75505Sopenharmony_ci 1101e5b75505Sopenharmony_ci if (buf) { 1102e5b75505Sopenharmony_ci p2p->p2ps_prov->method = msg.wps_config_methods; 1103e5b75505Sopenharmony_ci 1104e5b75505Sopenharmony_ci utf8_escape((char *) msg.session_info, buf_len, 1105e5b75505Sopenharmony_ci buf, 2 * buf_len + 1); 1106e5b75505Sopenharmony_ci 1107e5b75505Sopenharmony_ci p2p->cfg->p2ps_prov_complete( 1108e5b75505Sopenharmony_ci p2p->cfg->cb_ctx, P2P_SC_SUCCESS, sa, 1109e5b75505Sopenharmony_ci adv_mac, session_mac, group_mac, adv_id, 1110e5b75505Sopenharmony_ci session_id, conncap, passwd_id, 1111e5b75505Sopenharmony_ci msg.persistent_ssid, msg.persistent_ssid_len, 1112e5b75505Sopenharmony_ci 0, 1, buf, 1113e5b75505Sopenharmony_ci (const u8 *) &resp_fcap, sizeof(resp_fcap), 1114e5b75505Sopenharmony_ci freq, NULL, 0); 1115e5b75505Sopenharmony_ci 1116e5b75505Sopenharmony_ci os_free(buf); 1117e5b75505Sopenharmony_ci } 1118e5b75505Sopenharmony_ci } 1119e5b75505Sopenharmony_ci 1120e5b75505Sopenharmony_ci /* 1121e5b75505Sopenharmony_ci * prov_disc_req callback is used to generate P2P-PROV-DISC-ENTER-PIN, 1122e5b75505Sopenharmony_ci * P2P-PROV-DISC-SHOW-PIN, and P2P-PROV-DISC-PBC-REQ events. 1123e5b75505Sopenharmony_ci * Call it either on legacy P2P PD or on P2PS PD only if we need to 1124e5b75505Sopenharmony_ci * enter/show PIN. 1125e5b75505Sopenharmony_ci * 1126e5b75505Sopenharmony_ci * The callback is called in the following cases: 1127e5b75505Sopenharmony_ci * 1. Legacy P2P PD request, response status SUCCESS 1128e5b75505Sopenharmony_ci * 2. P2PS advertiser, method: DISPLAY, autoaccept: TRUE, 1129e5b75505Sopenharmony_ci * response status: SUCCESS 1130e5b75505Sopenharmony_ci * 3. P2PS advertiser, method DISPLAY, autoaccept: FALSE, 1131e5b75505Sopenharmony_ci * response status: INFO_CURRENTLY_UNAVAILABLE 1132e5b75505Sopenharmony_ci * 4. P2PS advertiser, method: KEYPAD, autoaccept==any, 1133e5b75505Sopenharmony_ci * response status: INFO_CURRENTLY_UNAVAILABLE 1134e5b75505Sopenharmony_ci * 5. P2PS follow-on with SUCCESS_DEFERRED, 1135e5b75505Sopenharmony_ci * advertiser role: DISPLAY, autoaccept: FALSE, 1136e5b75505Sopenharmony_ci * seeker: KEYPAD, response status: SUCCESS 1137e5b75505Sopenharmony_ci */ 1138e5b75505Sopenharmony_ci if (p2p->cfg->prov_disc_req && 1139e5b75505Sopenharmony_ci ((reject == P2P_SC_SUCCESS && !msg.adv_id) || 1140e5b75505Sopenharmony_ci (!msg.status && 1141e5b75505Sopenharmony_ci (reject == P2P_SC_SUCCESS || 1142e5b75505Sopenharmony_ci reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) && 1143e5b75505Sopenharmony_ci passwd_id == DEV_PW_USER_SPECIFIED) || 1144e5b75505Sopenharmony_ci (!msg.status && 1145e5b75505Sopenharmony_ci reject == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && 1146e5b75505Sopenharmony_ci passwd_id == DEV_PW_REGISTRAR_SPECIFIED) || 1147e5b75505Sopenharmony_ci (reject == P2P_SC_SUCCESS && 1148e5b75505Sopenharmony_ci msg.status && *msg.status == P2P_SC_SUCCESS_DEFERRED && 1149e5b75505Sopenharmony_ci passwd_id == DEV_PW_REGISTRAR_SPECIFIED))) { 1150e5b75505Sopenharmony_ci const u8 *dev_addr = sa; 1151e5b75505Sopenharmony_ci 1152e5b75505Sopenharmony_ci if (msg.p2p_device_addr) 1153e5b75505Sopenharmony_ci dev_addr = msg.p2p_device_addr; 1154e5b75505Sopenharmony_ci p2p->cfg->prov_disc_req(p2p->cfg->cb_ctx, sa, 1155e5b75505Sopenharmony_ci msg.wps_config_methods, 1156e5b75505Sopenharmony_ci dev_addr, msg.pri_dev_type, 1157e5b75505Sopenharmony_ci msg.device_name, msg.config_methods, 1158e5b75505Sopenharmony_ci msg.capability ? msg.capability[0] : 0, 1159e5b75505Sopenharmony_ci msg.capability ? msg.capability[1] : 1160e5b75505Sopenharmony_ci 0, 1161e5b75505Sopenharmony_ci msg.group_id, msg.group_id_len); 1162e5b75505Sopenharmony_ci } 1163e5b75505Sopenharmony_ci 1164e5b75505Sopenharmony_ci if (reject != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) 1165e5b75505Sopenharmony_ci p2ps_prov_free(p2p); 1166e5b75505Sopenharmony_ci 1167e5b75505Sopenharmony_ci if (reject == P2P_SC_SUCCESS) { 1168e5b75505Sopenharmony_ci switch (config_methods) { 1169e5b75505Sopenharmony_ci case WPS_CONFIG_DISPLAY: 1170e5b75505Sopenharmony_ci dev->wps_prov_info = WPS_CONFIG_KEYPAD; 1171e5b75505Sopenharmony_ci break; 1172e5b75505Sopenharmony_ci case WPS_CONFIG_KEYPAD: 1173e5b75505Sopenharmony_ci dev->wps_prov_info = WPS_CONFIG_DISPLAY; 1174e5b75505Sopenharmony_ci break; 1175e5b75505Sopenharmony_ci case WPS_CONFIG_PUSHBUTTON: 1176e5b75505Sopenharmony_ci dev->wps_prov_info = WPS_CONFIG_PUSHBUTTON; 1177e5b75505Sopenharmony_ci break; 1178e5b75505Sopenharmony_ci case WPS_CONFIG_P2PS: 1179e5b75505Sopenharmony_ci dev->wps_prov_info = WPS_CONFIG_P2PS; 1180e5b75505Sopenharmony_ci break; 1181e5b75505Sopenharmony_ci default: 1182e5b75505Sopenharmony_ci dev->wps_prov_info = 0; 1183e5b75505Sopenharmony_ci break; 1184e5b75505Sopenharmony_ci } 1185e5b75505Sopenharmony_ci 1186e5b75505Sopenharmony_ci if (msg.intended_addr) 1187e5b75505Sopenharmony_ci os_memcpy(dev->interface_addr, msg.intended_addr, 1188e5b75505Sopenharmony_ci ETH_ALEN); 1189e5b75505Sopenharmony_ci } 1190e5b75505Sopenharmony_ci p2p_parse_free(&msg); 1191e5b75505Sopenharmony_ci} 1192e5b75505Sopenharmony_ci 1193e5b75505Sopenharmony_ci 1194e5b75505Sopenharmony_cistatic int p2p_validate_p2ps_pd_resp(struct p2p_data *p2p, 1195e5b75505Sopenharmony_ci struct p2p_message *msg) 1196e5b75505Sopenharmony_ci{ 1197e5b75505Sopenharmony_ci u8 conn_cap_go = 0; 1198e5b75505Sopenharmony_ci u8 conn_cap_cli = 0; 1199e5b75505Sopenharmony_ci u32 session_id; 1200e5b75505Sopenharmony_ci u32 adv_id; 1201e5b75505Sopenharmony_ci 1202e5b75505Sopenharmony_ci#define P2PS_PD_RESP_CHECK(_val, _attr) \ 1203e5b75505Sopenharmony_ci do { \ 1204e5b75505Sopenharmony_ci if ((_val) && !msg->_attr) { \ 1205e5b75505Sopenharmony_ci p2p_dbg(p2p, "P2PS PD Response missing " #_attr); \ 1206e5b75505Sopenharmony_ci return -1; \ 1207e5b75505Sopenharmony_ci } \ 1208e5b75505Sopenharmony_ci } while (0) 1209e5b75505Sopenharmony_ci 1210e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(1, status); 1211e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(1, adv_id); 1212e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(1, adv_mac); 1213e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(1, capability); 1214e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(1, p2p_device_info); 1215e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(1, session_id); 1216e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(1, session_mac); 1217e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(1, feature_cap); 1218e5b75505Sopenharmony_ci 1219e5b75505Sopenharmony_ci session_id = WPA_GET_LE32(msg->session_id); 1220e5b75505Sopenharmony_ci adv_id = WPA_GET_LE32(msg->adv_id); 1221e5b75505Sopenharmony_ci 1222e5b75505Sopenharmony_ci if (p2p->p2ps_prov->session_id != session_id) { 1223e5b75505Sopenharmony_ci p2p_dbg(p2p, 1224e5b75505Sopenharmony_ci "Ignore PD Response with unexpected Session ID"); 1225e5b75505Sopenharmony_ci return -1; 1226e5b75505Sopenharmony_ci } 1227e5b75505Sopenharmony_ci 1228e5b75505Sopenharmony_ci if (os_memcmp(p2p->p2ps_prov->session_mac, msg->session_mac, 1229e5b75505Sopenharmony_ci ETH_ALEN)) { 1230e5b75505Sopenharmony_ci p2p_dbg(p2p, 1231e5b75505Sopenharmony_ci "Ignore PD Response with unexpected Session MAC"); 1232e5b75505Sopenharmony_ci return -1; 1233e5b75505Sopenharmony_ci } 1234e5b75505Sopenharmony_ci 1235e5b75505Sopenharmony_ci if (p2p->p2ps_prov->adv_id != adv_id) { 1236e5b75505Sopenharmony_ci p2p_dbg(p2p, 1237e5b75505Sopenharmony_ci "Ignore PD Response with unexpected Advertisement ID"); 1238e5b75505Sopenharmony_ci return -1; 1239e5b75505Sopenharmony_ci } 1240e5b75505Sopenharmony_ci 1241e5b75505Sopenharmony_ci if (os_memcmp(p2p->p2ps_prov->adv_mac, msg->adv_mac, ETH_ALEN) != 0) { 1242e5b75505Sopenharmony_ci p2p_dbg(p2p, 1243e5b75505Sopenharmony_ci "Ignore PD Response with unexpected Advertisement MAC"); 1244e5b75505Sopenharmony_ci return -1; 1245e5b75505Sopenharmony_ci } 1246e5b75505Sopenharmony_ci 1247e5b75505Sopenharmony_ci if (msg->listen_channel) { 1248e5b75505Sopenharmony_ci p2p_dbg(p2p, 1249e5b75505Sopenharmony_ci "Ignore malformed PD Response - unexpected Listen Channel"); 1250e5b75505Sopenharmony_ci return -1; 1251e5b75505Sopenharmony_ci } 1252e5b75505Sopenharmony_ci 1253e5b75505Sopenharmony_ci if (*msg->status == P2P_SC_SUCCESS && 1254e5b75505Sopenharmony_ci !(!!msg->conn_cap ^ !!msg->persistent_dev)) { 1255e5b75505Sopenharmony_ci p2p_dbg(p2p, 1256e5b75505Sopenharmony_ci "Ignore malformed PD Response - either conn_cap or persistent group should be present"); 1257e5b75505Sopenharmony_ci return -1; 1258e5b75505Sopenharmony_ci } 1259e5b75505Sopenharmony_ci 1260e5b75505Sopenharmony_ci if (msg->persistent_dev && *msg->status != P2P_SC_SUCCESS) { 1261e5b75505Sopenharmony_ci p2p_dbg(p2p, 1262e5b75505Sopenharmony_ci "Ignore malformed PD Response - persistent group is present, but the status isn't success"); 1263e5b75505Sopenharmony_ci return -1; 1264e5b75505Sopenharmony_ci } 1265e5b75505Sopenharmony_ci 1266e5b75505Sopenharmony_ci if (msg->conn_cap) { 1267e5b75505Sopenharmony_ci conn_cap_go = *msg->conn_cap == P2PS_SETUP_GROUP_OWNER; 1268e5b75505Sopenharmony_ci conn_cap_cli = *msg->conn_cap == P2PS_SETUP_CLIENT; 1269e5b75505Sopenharmony_ci } 1270e5b75505Sopenharmony_ci 1271e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli, 1272e5b75505Sopenharmony_ci channel_list); 1273e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(msg->persistent_dev || conn_cap_go || conn_cap_cli, 1274e5b75505Sopenharmony_ci config_timeout); 1275e5b75505Sopenharmony_ci 1276e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(conn_cap_go, group_id); 1277e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(conn_cap_go, intended_addr); 1278e5b75505Sopenharmony_ci P2PS_PD_RESP_CHECK(conn_cap_go, operating_channel); 1279e5b75505Sopenharmony_ci /* 1280e5b75505Sopenharmony_ci * TODO: Also validate that operating channel is present if the device 1281e5b75505Sopenharmony_ci * is a GO in a persistent group. We can't do it here since we don't 1282e5b75505Sopenharmony_ci * know what is the role of the peer. It should be probably done in 1283e5b75505Sopenharmony_ci * p2ps_prov_complete callback, but currently operating channel isn't 1284e5b75505Sopenharmony_ci * passed to it. 1285e5b75505Sopenharmony_ci */ 1286e5b75505Sopenharmony_ci 1287e5b75505Sopenharmony_ci#undef P2PS_PD_RESP_CHECK 1288e5b75505Sopenharmony_ci 1289e5b75505Sopenharmony_ci return 0; 1290e5b75505Sopenharmony_ci} 1291e5b75505Sopenharmony_ci 1292e5b75505Sopenharmony_ci 1293e5b75505Sopenharmony_civoid p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa, 1294e5b75505Sopenharmony_ci const u8 *data, size_t len) 1295e5b75505Sopenharmony_ci{ 1296e5b75505Sopenharmony_ci struct p2p_message msg; 1297e5b75505Sopenharmony_ci struct p2p_device *dev; 1298e5b75505Sopenharmony_ci u16 report_config_methods = 0, req_config_methods; 1299e5b75505Sopenharmony_ci u8 status = P2P_SC_SUCCESS; 1300e5b75505Sopenharmony_ci u32 adv_id = 0; 1301e5b75505Sopenharmony_ci u8 conncap = P2PS_SETUP_NEW; 1302e5b75505Sopenharmony_ci u8 adv_mac[ETH_ALEN]; 1303e5b75505Sopenharmony_ci const u8 *group_mac; 1304e5b75505Sopenharmony_ci int passwd_id = DEV_PW_DEFAULT; 1305e5b75505Sopenharmony_ci int p2ps_seeker; 1306e5b75505Sopenharmony_ci 1307e5b75505Sopenharmony_ci if (p2p_parse(data, len, &msg)) 1308e5b75505Sopenharmony_ci return; 1309e5b75505Sopenharmony_ci 1310e5b75505Sopenharmony_ci if (p2p->p2ps_prov && p2p_validate_p2ps_pd_resp(p2p, &msg)) { 1311e5b75505Sopenharmony_ci p2p_parse_free(&msg); 1312e5b75505Sopenharmony_ci return; 1313e5b75505Sopenharmony_ci } 1314e5b75505Sopenharmony_ci 1315e5b75505Sopenharmony_ci /* Parse the P2PS members present */ 1316e5b75505Sopenharmony_ci if (msg.status) 1317e5b75505Sopenharmony_ci status = *msg.status; 1318e5b75505Sopenharmony_ci 1319e5b75505Sopenharmony_ci group_mac = msg.intended_addr; 1320e5b75505Sopenharmony_ci 1321e5b75505Sopenharmony_ci if (msg.adv_mac) 1322e5b75505Sopenharmony_ci os_memcpy(adv_mac, msg.adv_mac, ETH_ALEN); 1323e5b75505Sopenharmony_ci else 1324e5b75505Sopenharmony_ci os_memset(adv_mac, 0, ETH_ALEN); 1325e5b75505Sopenharmony_ci 1326e5b75505Sopenharmony_ci if (msg.adv_id) 1327e5b75505Sopenharmony_ci adv_id = WPA_GET_LE32(msg.adv_id); 1328e5b75505Sopenharmony_ci 1329e5b75505Sopenharmony_ci if (msg.conn_cap) { 1330e5b75505Sopenharmony_ci conncap = *msg.conn_cap; 1331e5b75505Sopenharmony_ci 1332e5b75505Sopenharmony_ci /* Switch bits to local relative */ 1333e5b75505Sopenharmony_ci switch (conncap) { 1334e5b75505Sopenharmony_ci case P2PS_SETUP_GROUP_OWNER: 1335e5b75505Sopenharmony_ci conncap = P2PS_SETUP_CLIENT; 1336e5b75505Sopenharmony_ci break; 1337e5b75505Sopenharmony_ci case P2PS_SETUP_CLIENT: 1338e5b75505Sopenharmony_ci conncap = P2PS_SETUP_GROUP_OWNER; 1339e5b75505Sopenharmony_ci break; 1340e5b75505Sopenharmony_ci } 1341e5b75505Sopenharmony_ci } 1342e5b75505Sopenharmony_ci 1343e5b75505Sopenharmony_ci p2p_dbg(p2p, "Received Provision Discovery Response from " MACSTR 1344e5b75505Sopenharmony_ci " with config methods 0x%x", 1345e5b75505Sopenharmony_ci MAC2STR(sa), msg.wps_config_methods); 1346e5b75505Sopenharmony_ci 1347e5b75505Sopenharmony_ci dev = p2p_get_device(p2p, sa); 1348e5b75505Sopenharmony_ci if (dev == NULL || !dev->req_config_methods) { 1349e5b75505Sopenharmony_ci p2p_dbg(p2p, "Ignore Provision Discovery Response from " MACSTR 1350e5b75505Sopenharmony_ci " with no pending request", MAC2STR(sa)); 1351e5b75505Sopenharmony_ci p2p_parse_free(&msg); 1352e5b75505Sopenharmony_ci return; 1353e5b75505Sopenharmony_ci } else if (msg.wfd_subelems) { 1354e5b75505Sopenharmony_ci wpabuf_free(dev->info.wfd_subelems); 1355e5b75505Sopenharmony_ci dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems); 1356e5b75505Sopenharmony_ci } 1357e5b75505Sopenharmony_ci 1358e5b75505Sopenharmony_ci if (dev->dialog_token != msg.dialog_token) { 1359e5b75505Sopenharmony_ci p2p_dbg(p2p, "Ignore Provision Discovery Response with unexpected Dialog Token %u (expected %u)", 1360e5b75505Sopenharmony_ci msg.dialog_token, dev->dialog_token); 1361e5b75505Sopenharmony_ci p2p_parse_free(&msg); 1362e5b75505Sopenharmony_ci return; 1363e5b75505Sopenharmony_ci } 1364e5b75505Sopenharmony_ci 1365e5b75505Sopenharmony_ci if (p2p->pending_action_state == P2P_PENDING_PD) { 1366e5b75505Sopenharmony_ci os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN); 1367e5b75505Sopenharmony_ci p2p->pending_action_state = P2P_NO_PENDING_ACTION; 1368e5b75505Sopenharmony_ci } 1369e5b75505Sopenharmony_ci 1370e5b75505Sopenharmony_ci p2ps_seeker = p2p->p2ps_prov && p2p->p2ps_prov->pd_seeker; 1371e5b75505Sopenharmony_ci 1372e5b75505Sopenharmony_ci /* 1373e5b75505Sopenharmony_ci * Use a local copy of the requested config methods since 1374e5b75505Sopenharmony_ci * p2p_reset_pending_pd() can clear this in the peer entry. 1375e5b75505Sopenharmony_ci */ 1376e5b75505Sopenharmony_ci req_config_methods = dev->req_config_methods; 1377e5b75505Sopenharmony_ci 1378e5b75505Sopenharmony_ci /* 1379e5b75505Sopenharmony_ci * If the response is from the peer to whom a user initiated request 1380e5b75505Sopenharmony_ci * was sent earlier, we reset that state info here. 1381e5b75505Sopenharmony_ci */ 1382e5b75505Sopenharmony_ci if (p2p->user_initiated_pd && 1383e5b75505Sopenharmony_ci os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0) 1384e5b75505Sopenharmony_ci p2p_reset_pending_pd(p2p); 1385e5b75505Sopenharmony_ci 1386e5b75505Sopenharmony_ci if (msg.wps_config_methods != req_config_methods) { 1387e5b75505Sopenharmony_ci p2p_dbg(p2p, "Peer rejected our Provision Discovery Request (received config_methods 0x%x expected 0x%x", 1388e5b75505Sopenharmony_ci msg.wps_config_methods, req_config_methods); 1389e5b75505Sopenharmony_ci if (p2p->cfg->prov_disc_fail) 1390e5b75505Sopenharmony_ci p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, 1391e5b75505Sopenharmony_ci P2P_PROV_DISC_REJECTED, 1392e5b75505Sopenharmony_ci adv_id, adv_mac, NULL); 1393e5b75505Sopenharmony_ci p2p_parse_free(&msg); 1394e5b75505Sopenharmony_ci p2ps_prov_free(p2p); 1395e5b75505Sopenharmony_ci goto out; 1396e5b75505Sopenharmony_ci } 1397e5b75505Sopenharmony_ci 1398e5b75505Sopenharmony_ci report_config_methods = req_config_methods; 1399e5b75505Sopenharmony_ci dev->flags &= ~(P2P_DEV_PD_PEER_DISPLAY | 1400e5b75505Sopenharmony_ci P2P_DEV_PD_PEER_KEYPAD | 1401e5b75505Sopenharmony_ci P2P_DEV_PD_PEER_P2PS); 1402e5b75505Sopenharmony_ci if (req_config_methods & WPS_CONFIG_DISPLAY) { 1403e5b75505Sopenharmony_ci p2p_dbg(p2p, "Peer " MACSTR 1404e5b75505Sopenharmony_ci " accepted to show a PIN on display", MAC2STR(sa)); 1405e5b75505Sopenharmony_ci dev->flags |= P2P_DEV_PD_PEER_DISPLAY; 1406e5b75505Sopenharmony_ci passwd_id = DEV_PW_REGISTRAR_SPECIFIED; 1407e5b75505Sopenharmony_ci } else if (msg.wps_config_methods & WPS_CONFIG_KEYPAD) { 1408e5b75505Sopenharmony_ci p2p_dbg(p2p, "Peer " MACSTR 1409e5b75505Sopenharmony_ci " accepted to write our PIN using keypad", 1410e5b75505Sopenharmony_ci MAC2STR(sa)); 1411e5b75505Sopenharmony_ci dev->flags |= P2P_DEV_PD_PEER_KEYPAD; 1412e5b75505Sopenharmony_ci passwd_id = DEV_PW_USER_SPECIFIED; 1413e5b75505Sopenharmony_ci } else if (msg.wps_config_methods & WPS_CONFIG_P2PS) { 1414e5b75505Sopenharmony_ci p2p_dbg(p2p, "Peer " MACSTR " accepted P2PS PIN", 1415e5b75505Sopenharmony_ci MAC2STR(sa)); 1416e5b75505Sopenharmony_ci dev->flags |= P2P_DEV_PD_PEER_P2PS; 1417e5b75505Sopenharmony_ci passwd_id = DEV_PW_P2PS_DEFAULT; 1418e5b75505Sopenharmony_ci } 1419e5b75505Sopenharmony_ci 1420e5b75505Sopenharmony_ci if ((status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) && 1421e5b75505Sopenharmony_ci p2p->p2ps_prov) { 1422e5b75505Sopenharmony_ci dev->oper_freq = 0; 1423e5b75505Sopenharmony_ci 1424e5b75505Sopenharmony_ci /* 1425e5b75505Sopenharmony_ci * Save the reported channel list and operating frequency. 1426e5b75505Sopenharmony_ci * Note that the specification mandates that the responder 1427e5b75505Sopenharmony_ci * should include in the channel list only channels reported by 1428e5b75505Sopenharmony_ci * the initiator, so this is only a sanity check, and if this 1429e5b75505Sopenharmony_ci * fails the flow would continue, although it would probably 1430e5b75505Sopenharmony_ci * fail. Same is true for the operating channel. 1431e5b75505Sopenharmony_ci */ 1432e5b75505Sopenharmony_ci if (msg.channel_list && msg.channel_list_len && 1433e5b75505Sopenharmony_ci p2p_peer_channels_check(p2p, &p2p->channels, dev, 1434e5b75505Sopenharmony_ci msg.channel_list, 1435e5b75505Sopenharmony_ci msg.channel_list_len) < 0) 1436e5b75505Sopenharmony_ci p2p_dbg(p2p, "P2PS PD Response - no common channels"); 1437e5b75505Sopenharmony_ci 1438e5b75505Sopenharmony_ci if (msg.operating_channel) { 1439e5b75505Sopenharmony_ci if (p2p_channels_includes(&p2p->channels, 1440e5b75505Sopenharmony_ci msg.operating_channel[3], 1441e5b75505Sopenharmony_ci msg.operating_channel[4]) && 1442e5b75505Sopenharmony_ci p2p_channels_includes(&dev->channels, 1443e5b75505Sopenharmony_ci msg.operating_channel[3], 1444e5b75505Sopenharmony_ci msg.operating_channel[4])) { 1445e5b75505Sopenharmony_ci dev->oper_freq = 1446e5b75505Sopenharmony_ci p2p_channel_to_freq( 1447e5b75505Sopenharmony_ci msg.operating_channel[3], 1448e5b75505Sopenharmony_ci msg.operating_channel[4]); 1449e5b75505Sopenharmony_ci } else { 1450e5b75505Sopenharmony_ci p2p_dbg(p2p, 1451e5b75505Sopenharmony_ci "P2PS PD Response - invalid operating channel"); 1452e5b75505Sopenharmony_ci } 1453e5b75505Sopenharmony_ci } 1454e5b75505Sopenharmony_ci 1455e5b75505Sopenharmony_ci if (p2p->cfg->p2ps_prov_complete) { 1456e5b75505Sopenharmony_ci int freq = 0; 1457e5b75505Sopenharmony_ci 1458e5b75505Sopenharmony_ci if (conncap == P2PS_SETUP_GROUP_OWNER) { 1459e5b75505Sopenharmony_ci u8 tmp; 1460e5b75505Sopenharmony_ci 1461e5b75505Sopenharmony_ci /* 1462e5b75505Sopenharmony_ci * Re-select the operating channel as it is 1463e5b75505Sopenharmony_ci * possible that original channel is no longer 1464e5b75505Sopenharmony_ci * valid. This should not really fail. 1465e5b75505Sopenharmony_ci */ 1466e5b75505Sopenharmony_ci if (p2p_go_select_channel(p2p, dev, &tmp) < 0) 1467e5b75505Sopenharmony_ci p2p_dbg(p2p, 1468e5b75505Sopenharmony_ci "P2PS PD channel selection failed"); 1469e5b75505Sopenharmony_ci 1470e5b75505Sopenharmony_ci freq = p2p_channel_to_freq(p2p->op_reg_class, 1471e5b75505Sopenharmony_ci p2p->op_channel); 1472e5b75505Sopenharmony_ci if (freq < 0) 1473e5b75505Sopenharmony_ci freq = 0; 1474e5b75505Sopenharmony_ci } 1475e5b75505Sopenharmony_ci 1476e5b75505Sopenharmony_ci p2p->cfg->p2ps_prov_complete( 1477e5b75505Sopenharmony_ci p2p->cfg->cb_ctx, status, sa, adv_mac, 1478e5b75505Sopenharmony_ci p2p->p2ps_prov->session_mac, 1479e5b75505Sopenharmony_ci group_mac, adv_id, p2p->p2ps_prov->session_id, 1480e5b75505Sopenharmony_ci conncap, passwd_id, msg.persistent_ssid, 1481e5b75505Sopenharmony_ci msg.persistent_ssid_len, 1, 0, NULL, 1482e5b75505Sopenharmony_ci msg.feature_cap, msg.feature_cap_len, freq, 1483e5b75505Sopenharmony_ci msg.group_id ? msg.group_id + ETH_ALEN : NULL, 1484e5b75505Sopenharmony_ci msg.group_id ? msg.group_id_len - ETH_ALEN : 0); 1485e5b75505Sopenharmony_ci } 1486e5b75505Sopenharmony_ci p2ps_prov_free(p2p); 1487e5b75505Sopenharmony_ci } else if (status != P2P_SC_SUCCESS && 1488e5b75505Sopenharmony_ci status != P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && 1489e5b75505Sopenharmony_ci status != P2P_SC_SUCCESS_DEFERRED && p2p->p2ps_prov) { 1490e5b75505Sopenharmony_ci if (p2p->cfg->p2ps_prov_complete) 1491e5b75505Sopenharmony_ci p2p->cfg->p2ps_prov_complete( 1492e5b75505Sopenharmony_ci p2p->cfg->cb_ctx, status, sa, adv_mac, 1493e5b75505Sopenharmony_ci p2p->p2ps_prov->session_mac, 1494e5b75505Sopenharmony_ci group_mac, adv_id, p2p->p2ps_prov->session_id, 1495e5b75505Sopenharmony_ci 0, 0, NULL, 0, 1, 0, NULL, NULL, 0, 0, NULL, 0); 1496e5b75505Sopenharmony_ci p2ps_prov_free(p2p); 1497e5b75505Sopenharmony_ci } 1498e5b75505Sopenharmony_ci 1499e5b75505Sopenharmony_ci if (status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) { 1500e5b75505Sopenharmony_ci if (p2p->cfg->remove_stale_groups) { 1501e5b75505Sopenharmony_ci p2p->cfg->remove_stale_groups(p2p->cfg->cb_ctx, 1502e5b75505Sopenharmony_ci dev->info.p2p_device_addr, 1503e5b75505Sopenharmony_ci NULL, NULL, 0); 1504e5b75505Sopenharmony_ci } 1505e5b75505Sopenharmony_ci 1506e5b75505Sopenharmony_ci if (msg.session_info && msg.session_info_len) { 1507e5b75505Sopenharmony_ci size_t info_len = msg.session_info_len; 1508e5b75505Sopenharmony_ci char *deferred_sess_resp = os_malloc(2 * info_len + 1); 1509e5b75505Sopenharmony_ci 1510e5b75505Sopenharmony_ci if (!deferred_sess_resp) { 1511e5b75505Sopenharmony_ci p2p_parse_free(&msg); 1512e5b75505Sopenharmony_ci p2ps_prov_free(p2p); 1513e5b75505Sopenharmony_ci goto out; 1514e5b75505Sopenharmony_ci } 1515e5b75505Sopenharmony_ci utf8_escape((char *) msg.session_info, info_len, 1516e5b75505Sopenharmony_ci deferred_sess_resp, 2 * info_len + 1); 1517e5b75505Sopenharmony_ci 1518e5b75505Sopenharmony_ci if (p2p->cfg->prov_disc_fail) 1519e5b75505Sopenharmony_ci p2p->cfg->prov_disc_fail( 1520e5b75505Sopenharmony_ci p2p->cfg->cb_ctx, sa, 1521e5b75505Sopenharmony_ci P2P_PROV_DISC_INFO_UNAVAILABLE, 1522e5b75505Sopenharmony_ci adv_id, adv_mac, 1523e5b75505Sopenharmony_ci deferred_sess_resp); 1524e5b75505Sopenharmony_ci os_free(deferred_sess_resp); 1525e5b75505Sopenharmony_ci } else 1526e5b75505Sopenharmony_ci if (p2p->cfg->prov_disc_fail) 1527e5b75505Sopenharmony_ci p2p->cfg->prov_disc_fail( 1528e5b75505Sopenharmony_ci p2p->cfg->cb_ctx, sa, 1529e5b75505Sopenharmony_ci P2P_PROV_DISC_INFO_UNAVAILABLE, 1530e5b75505Sopenharmony_ci adv_id, adv_mac, NULL); 1531e5b75505Sopenharmony_ci } else if (status != P2P_SC_SUCCESS) { 1532e5b75505Sopenharmony_ci p2p_dbg(p2p, "Peer rejected our Provision Discovery Request"); 1533e5b75505Sopenharmony_ci if (p2p->cfg->prov_disc_fail) 1534e5b75505Sopenharmony_ci p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa, 1535e5b75505Sopenharmony_ci P2P_PROV_DISC_REJECTED, 1536e5b75505Sopenharmony_ci adv_id, adv_mac, NULL); 1537e5b75505Sopenharmony_ci p2p_parse_free(&msg); 1538e5b75505Sopenharmony_ci p2ps_prov_free(p2p); 1539e5b75505Sopenharmony_ci goto out; 1540e5b75505Sopenharmony_ci } 1541e5b75505Sopenharmony_ci 1542e5b75505Sopenharmony_ci /* Store the provisioning info */ 1543e5b75505Sopenharmony_ci dev->wps_prov_info = msg.wps_config_methods; 1544e5b75505Sopenharmony_ci if (msg.intended_addr) 1545e5b75505Sopenharmony_ci os_memcpy(dev->interface_addr, msg.intended_addr, ETH_ALEN); 1546e5b75505Sopenharmony_ci 1547e5b75505Sopenharmony_ci p2p_parse_free(&msg); 1548e5b75505Sopenharmony_ci 1549e5b75505Sopenharmony_ciout: 1550e5b75505Sopenharmony_ci dev->req_config_methods = 0; 1551e5b75505Sopenharmony_ci p2p->cfg->send_action_done(p2p->cfg->cb_ctx); 1552e5b75505Sopenharmony_ci if (dev->flags & P2P_DEV_PD_BEFORE_GO_NEG) { 1553e5b75505Sopenharmony_ci p2p_dbg(p2p, "Start GO Neg after the PD-before-GO-Neg workaround with " 1554e5b75505Sopenharmony_ci MACSTR, MAC2STR(dev->info.p2p_device_addr)); 1555e5b75505Sopenharmony_ci dev->flags &= ~P2P_DEV_PD_BEFORE_GO_NEG; 1556e5b75505Sopenharmony_ci p2p_connect_send(p2p, dev); 1557e5b75505Sopenharmony_ci return; 1558e5b75505Sopenharmony_ci } 1559e5b75505Sopenharmony_ci 1560e5b75505Sopenharmony_ci /* 1561e5b75505Sopenharmony_ci * prov_disc_resp callback is used to generate P2P-PROV-DISC-ENTER-PIN, 1562e5b75505Sopenharmony_ci * P2P-PROV-DISC-SHOW-PIN, and P2P-PROV-DISC-PBC-REQ events. 1563e5b75505Sopenharmony_ci * Call it only for a legacy P2P PD or for P2PS PD scenarios where 1564e5b75505Sopenharmony_ci * show/enter PIN events are needed. 1565e5b75505Sopenharmony_ci * 1566e5b75505Sopenharmony_ci * The callback is called in the following cases: 1567e5b75505Sopenharmony_ci * 1. Legacy P2P PD response with a status SUCCESS 1568e5b75505Sopenharmony_ci * 2. P2PS, advertiser method: DISPLAY, autoaccept: true, 1569e5b75505Sopenharmony_ci * response status: SUCCESS, local method KEYPAD 1570e5b75505Sopenharmony_ci * 3. P2PS, advertiser method: KEYPAD,Seeker side, 1571e5b75505Sopenharmony_ci * response status: INFO_CURRENTLY_UNAVAILABLE, 1572e5b75505Sopenharmony_ci * local method: DISPLAY 1573e5b75505Sopenharmony_ci */ 1574e5b75505Sopenharmony_ci if (p2p->cfg->prov_disc_resp && 1575e5b75505Sopenharmony_ci ((status == P2P_SC_SUCCESS && !adv_id) || 1576e5b75505Sopenharmony_ci (p2ps_seeker && status == P2P_SC_SUCCESS && 1577e5b75505Sopenharmony_ci passwd_id == DEV_PW_REGISTRAR_SPECIFIED) || 1578e5b75505Sopenharmony_ci (p2ps_seeker && 1579e5b75505Sopenharmony_ci status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE && 1580e5b75505Sopenharmony_ci passwd_id == DEV_PW_USER_SPECIFIED))) 1581e5b75505Sopenharmony_ci p2p->cfg->prov_disc_resp(p2p->cfg->cb_ctx, sa, 1582e5b75505Sopenharmony_ci report_config_methods); 1583e5b75505Sopenharmony_ci 1584e5b75505Sopenharmony_ci if (p2p->state == P2P_PD_DURING_FIND) { 1585e5b75505Sopenharmony_ci p2p_stop_listen_for_freq(p2p, 0); 1586e5b75505Sopenharmony_ci p2p_continue_find(p2p); 1587e5b75505Sopenharmony_ci } 1588e5b75505Sopenharmony_ci} 1589e5b75505Sopenharmony_ci 1590e5b75505Sopenharmony_ci 1591e5b75505Sopenharmony_ciint p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, 1592e5b75505Sopenharmony_ci int join, int force_freq) 1593e5b75505Sopenharmony_ci{ 1594e5b75505Sopenharmony_ci struct wpabuf *req; 1595e5b75505Sopenharmony_ci int freq; 1596e5b75505Sopenharmony_ci 1597e5b75505Sopenharmony_ci if (force_freq > 0) 1598e5b75505Sopenharmony_ci freq = force_freq; 1599e5b75505Sopenharmony_ci else 1600e5b75505Sopenharmony_ci freq = dev->listen_freq > 0 ? dev->listen_freq : 1601e5b75505Sopenharmony_ci dev->oper_freq; 1602e5b75505Sopenharmony_ci if (freq <= 0) { 1603e5b75505Sopenharmony_ci p2p_dbg(p2p, "No Listen/Operating frequency known for the peer " 1604e5b75505Sopenharmony_ci MACSTR " to send Provision Discovery Request", 1605e5b75505Sopenharmony_ci MAC2STR(dev->info.p2p_device_addr)); 1606e5b75505Sopenharmony_ci return -1; 1607e5b75505Sopenharmony_ci } 1608e5b75505Sopenharmony_ci 1609e5b75505Sopenharmony_ci if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) { 1610e5b75505Sopenharmony_ci if (!(dev->info.dev_capab & 1611e5b75505Sopenharmony_ci P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY)) { 1612e5b75505Sopenharmony_ci p2p_dbg(p2p, "Cannot use PD with P2P Device " MACSTR 1613e5b75505Sopenharmony_ci " that is in a group and is not discoverable", 1614e5b75505Sopenharmony_ci MAC2STR(dev->info.p2p_device_addr)); 1615e5b75505Sopenharmony_ci return -1; 1616e5b75505Sopenharmony_ci } 1617e5b75505Sopenharmony_ci /* TODO: use device discoverability request through GO */ 1618e5b75505Sopenharmony_ci } 1619e5b75505Sopenharmony_ci 1620e5b75505Sopenharmony_ci if (p2p->p2ps_prov) { 1621e5b75505Sopenharmony_ci if (p2p->p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED) { 1622e5b75505Sopenharmony_ci if (p2p->p2ps_prov->method == WPS_CONFIG_DISPLAY) 1623e5b75505Sopenharmony_ci dev->req_config_methods = WPS_CONFIG_KEYPAD; 1624e5b75505Sopenharmony_ci else if (p2p->p2ps_prov->method == WPS_CONFIG_KEYPAD) 1625e5b75505Sopenharmony_ci dev->req_config_methods = WPS_CONFIG_DISPLAY; 1626e5b75505Sopenharmony_ci else 1627e5b75505Sopenharmony_ci dev->req_config_methods = WPS_CONFIG_P2PS; 1628e5b75505Sopenharmony_ci } else { 1629e5b75505Sopenharmony_ci /* Order of preference, based on peer's capabilities */ 1630e5b75505Sopenharmony_ci if (p2p->p2ps_prov->method) 1631e5b75505Sopenharmony_ci dev->req_config_methods = 1632e5b75505Sopenharmony_ci p2p->p2ps_prov->method; 1633e5b75505Sopenharmony_ci else if (dev->info.config_methods & WPS_CONFIG_P2PS) 1634e5b75505Sopenharmony_ci dev->req_config_methods = WPS_CONFIG_P2PS; 1635e5b75505Sopenharmony_ci else if (dev->info.config_methods & WPS_CONFIG_DISPLAY) 1636e5b75505Sopenharmony_ci dev->req_config_methods = WPS_CONFIG_DISPLAY; 1637e5b75505Sopenharmony_ci else 1638e5b75505Sopenharmony_ci dev->req_config_methods = WPS_CONFIG_KEYPAD; 1639e5b75505Sopenharmony_ci } 1640e5b75505Sopenharmony_ci p2p_dbg(p2p, 1641e5b75505Sopenharmony_ci "Building PD Request based on P2PS config method 0x%x status %d --> req_config_methods 0x%x", 1642e5b75505Sopenharmony_ci p2p->p2ps_prov->method, p2p->p2ps_prov->status, 1643e5b75505Sopenharmony_ci dev->req_config_methods); 1644e5b75505Sopenharmony_ci 1645e5b75505Sopenharmony_ci if (p2p_prepare_channel(p2p, dev, p2p->p2ps_prov->force_freq, 1646e5b75505Sopenharmony_ci p2p->p2ps_prov->pref_freq, 1) < 0) 1647e5b75505Sopenharmony_ci return -1; 1648e5b75505Sopenharmony_ci } 1649e5b75505Sopenharmony_ci 1650e5b75505Sopenharmony_ci req = p2p_build_prov_disc_req(p2p, dev, join); 1651e5b75505Sopenharmony_ci if (req == NULL) 1652e5b75505Sopenharmony_ci return -1; 1653e5b75505Sopenharmony_ci 1654e5b75505Sopenharmony_ci if (p2p->state != P2P_IDLE) 1655e5b75505Sopenharmony_ci p2p_stop_listen_for_freq(p2p, freq); 1656e5b75505Sopenharmony_ci p2p->pending_action_state = P2P_PENDING_PD; 1657e5b75505Sopenharmony_ci if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, 1658e5b75505Sopenharmony_ci p2p->cfg->dev_addr, dev->info.p2p_device_addr, 1659e5b75505Sopenharmony_ci wpabuf_head(req), wpabuf_len(req), 200) < 0) { 1660e5b75505Sopenharmony_ci p2p_dbg(p2p, "Failed to send Action frame"); 1661e5b75505Sopenharmony_ci wpabuf_free(req); 1662e5b75505Sopenharmony_ci return -1; 1663e5b75505Sopenharmony_ci } 1664e5b75505Sopenharmony_ci 1665e5b75505Sopenharmony_ci os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN); 1666e5b75505Sopenharmony_ci 1667e5b75505Sopenharmony_ci wpabuf_free(req); 1668e5b75505Sopenharmony_ci return 0; 1669e5b75505Sopenharmony_ci} 1670e5b75505Sopenharmony_ci 1671e5b75505Sopenharmony_ci 1672e5b75505Sopenharmony_ciint p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr, 1673e5b75505Sopenharmony_ci struct p2ps_provision *p2ps_prov, 1674e5b75505Sopenharmony_ci u16 config_methods, int join, int force_freq, 1675e5b75505Sopenharmony_ci int user_initiated_pd) 1676e5b75505Sopenharmony_ci{ 1677e5b75505Sopenharmony_ci struct p2p_device *dev; 1678e5b75505Sopenharmony_ci 1679e5b75505Sopenharmony_ci dev = p2p_get_device(p2p, peer_addr); 1680e5b75505Sopenharmony_ci if (dev == NULL) 1681e5b75505Sopenharmony_ci dev = p2p_get_device_interface(p2p, peer_addr); 1682e5b75505Sopenharmony_ci if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) { 1683e5b75505Sopenharmony_ci p2p_dbg(p2p, "Provision Discovery Request destination " MACSTR 1684e5b75505Sopenharmony_ci " not yet known", MAC2STR(peer_addr)); 1685e5b75505Sopenharmony_ci os_free(p2ps_prov); 1686e5b75505Sopenharmony_ci return -1; 1687e5b75505Sopenharmony_ci } 1688e5b75505Sopenharmony_ci 1689e5b75505Sopenharmony_ci p2p_dbg(p2p, "Provision Discovery Request with " MACSTR 1690e5b75505Sopenharmony_ci " (config methods 0x%x)", 1691e5b75505Sopenharmony_ci MAC2STR(peer_addr), config_methods); 1692e5b75505Sopenharmony_ci if (config_methods == 0 && !p2ps_prov) { 1693e5b75505Sopenharmony_ci os_free(p2ps_prov); 1694e5b75505Sopenharmony_ci return -1; 1695e5b75505Sopenharmony_ci } 1696e5b75505Sopenharmony_ci 1697e5b75505Sopenharmony_ci if (p2ps_prov && p2ps_prov->status == P2P_SC_SUCCESS_DEFERRED && 1698e5b75505Sopenharmony_ci p2p->p2ps_prov) { 1699e5b75505Sopenharmony_ci /* Use cached method from deferred provisioning */ 1700e5b75505Sopenharmony_ci p2ps_prov->method = p2p->p2ps_prov->method; 1701e5b75505Sopenharmony_ci } 1702e5b75505Sopenharmony_ci 1703e5b75505Sopenharmony_ci /* Reset provisioning info */ 1704e5b75505Sopenharmony_ci dev->wps_prov_info = 0; 1705e5b75505Sopenharmony_ci p2ps_prov_free(p2p); 1706e5b75505Sopenharmony_ci p2p->p2ps_prov = p2ps_prov; 1707e5b75505Sopenharmony_ci 1708e5b75505Sopenharmony_ci dev->req_config_methods = config_methods; 1709e5b75505Sopenharmony_ci if (join) 1710e5b75505Sopenharmony_ci dev->flags |= P2P_DEV_PD_FOR_JOIN; 1711e5b75505Sopenharmony_ci else 1712e5b75505Sopenharmony_ci dev->flags &= ~P2P_DEV_PD_FOR_JOIN; 1713e5b75505Sopenharmony_ci 1714e5b75505Sopenharmony_ci if (p2p->state != P2P_IDLE && p2p->state != P2P_SEARCH && 1715e5b75505Sopenharmony_ci p2p->state != P2P_LISTEN_ONLY) { 1716e5b75505Sopenharmony_ci p2p_dbg(p2p, "Busy with other operations; postpone Provision Discovery Request with " 1717e5b75505Sopenharmony_ci MACSTR " (config methods 0x%x)", 1718e5b75505Sopenharmony_ci MAC2STR(peer_addr), config_methods); 1719e5b75505Sopenharmony_ci return 0; 1720e5b75505Sopenharmony_ci } 1721e5b75505Sopenharmony_ci 1722e5b75505Sopenharmony_ci p2p->user_initiated_pd = user_initiated_pd; 1723e5b75505Sopenharmony_ci p2p->pd_force_freq = force_freq; 1724e5b75505Sopenharmony_ci 1725e5b75505Sopenharmony_ci if (p2p->user_initiated_pd) 1726e5b75505Sopenharmony_ci p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES; 1727e5b75505Sopenharmony_ci 1728e5b75505Sopenharmony_ci /* 1729e5b75505Sopenharmony_ci * Assign dialog token here to use the same value in each retry within 1730e5b75505Sopenharmony_ci * the same PD exchange. 1731e5b75505Sopenharmony_ci */ 1732e5b75505Sopenharmony_ci dev->dialog_token++; 1733e5b75505Sopenharmony_ci if (dev->dialog_token == 0) 1734e5b75505Sopenharmony_ci dev->dialog_token = 1; 1735e5b75505Sopenharmony_ci 1736e5b75505Sopenharmony_ci return p2p_send_prov_disc_req(p2p, dev, join, force_freq); 1737e5b75505Sopenharmony_ci} 1738e5b75505Sopenharmony_ci 1739e5b75505Sopenharmony_ci 1740e5b75505Sopenharmony_civoid p2p_reset_pending_pd(struct p2p_data *p2p) 1741e5b75505Sopenharmony_ci{ 1742e5b75505Sopenharmony_ci struct p2p_device *dev; 1743e5b75505Sopenharmony_ci 1744e5b75505Sopenharmony_ci dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) { 1745e5b75505Sopenharmony_ci if (os_memcmp(p2p->pending_pd_devaddr, 1746e5b75505Sopenharmony_ci dev->info.p2p_device_addr, ETH_ALEN)) 1747e5b75505Sopenharmony_ci continue; 1748e5b75505Sopenharmony_ci if (!dev->req_config_methods) 1749e5b75505Sopenharmony_ci continue; 1750e5b75505Sopenharmony_ci if (dev->flags & P2P_DEV_PD_FOR_JOIN) 1751e5b75505Sopenharmony_ci continue; 1752e5b75505Sopenharmony_ci /* Reset the config methods of the device */ 1753e5b75505Sopenharmony_ci dev->req_config_methods = 0; 1754e5b75505Sopenharmony_ci } 1755e5b75505Sopenharmony_ci 1756e5b75505Sopenharmony_ci p2p->user_initiated_pd = 0; 1757e5b75505Sopenharmony_ci os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN); 1758e5b75505Sopenharmony_ci p2p->pd_retries = 0; 1759e5b75505Sopenharmony_ci p2p->pd_force_freq = 0; 1760e5b75505Sopenharmony_ci} 1761e5b75505Sopenharmony_ci 1762e5b75505Sopenharmony_ci 1763e5b75505Sopenharmony_civoid p2ps_prov_free(struct p2p_data *p2p) 1764e5b75505Sopenharmony_ci{ 1765e5b75505Sopenharmony_ci os_free(p2p->p2ps_prov); 1766e5b75505Sopenharmony_ci p2p->p2ps_prov = NULL; 1767e5b75505Sopenharmony_ci} 1768