static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, struct p2p_device *dev, u8 dialog_token, enum p2p_status_code status, u16 config_methods, u32 adv_id, const u8 *group_id, size_t group_id_len, const u8 *persist_ssid, size_t persist_ssid_len, const u8 *fcap, u16 fcap_len) { struct wpabuf *buf; size_t extra = 0; int persist = 0; #ifdef CONFIG_WIFI_DISPLAY struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp; if (wfd_ie && group_id) { size_t i; for (i = 0; i < p2p->num_groups; i++) { struct p2p_group *g = p2p->groups[i]; struct wpabuf *ie; if (!p2p_group_is_group_id_match(g, group_id, group_id_len)) continue; ie = p2p_group_get_wfd_ie(g); if (ie) { wfd_ie = ie; break; } } } if (wfd_ie) extra = wpabuf_len(wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]) extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]); buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token); /* Add P2P IE for P2PS */ if (p2p->p2ps_prov && p2p->p2ps_prov->adv_id == adv_id) { u8 *len = p2p_buf_add_ie_hdr(buf); struct p2ps_provision *prov = p2p->p2ps_prov; u8 group_capab; u8 conncap = 0; if (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED) conncap = prov->conncap; if (!status && prov->status != -1) status = prov->status; p2p_buf_add_status(buf, status); group_capab = P2P_GROUP_CAPAB_PERSISTENT_GROUP | P2P_GROUP_CAPAB_PERSISTENT_RECONN; if (p2p->cross_connect) group_capab |= P2P_GROUP_CAPAB_CROSS_CONN; if (p2p->cfg->p2p_intra_bss) group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST; p2p_buf_add_capability(buf, p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, group_capab); p2p_buf_add_device_info(buf, p2p, NULL); if (persist_ssid && p2p->cfg->get_persistent_group && dev && (status == P2P_SC_SUCCESS || status == P2P_SC_SUCCESS_DEFERRED)) { u8 ssid[SSID_MAX_LEN]; size_t ssid_len; u8 go_dev_addr[ETH_ALEN]; u8 intended_addr[ETH_ALEN]; persist = p2p->cfg->get_persistent_group( p2p->cfg->cb_ctx, dev->info.p2p_device_addr, persist_ssid, persist_ssid_len, go_dev_addr, ssid, &ssid_len, intended_addr); if (persist) { p2p_buf_add_persistent_group_info( buf, go_dev_addr, ssid, ssid_len); if (!is_zero_ether_addr(intended_addr)) p2p_buf_add_intended_addr( buf, intended_addr); } } if (!persist && (conncap & P2PS_SETUP_GROUP_OWNER)) p2ps_add_new_group_info(p2p, dev, buf); /* Add Operating Channel if conncap indicates GO */ if (persist || (conncap & P2PS_SETUP_GROUP_OWNER)) { if (p2p->op_reg_class && p2p->op_channel) p2p_buf_add_operating_channel( buf, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); else p2p_buf_add_operating_channel( buf, p2p->cfg->country, p2p->cfg->op_reg_class, p2p->cfg->op_channel); } if (persist || (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); if (!persist && conncap) p2p_buf_add_connection_capability(buf, conncap); p2p_buf_add_advertisement_id(buf, adv_id, prov->adv_mac); if (persist || (conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_GROUP_OWNER))) p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout); p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac); p2p_buf_add_feature_capability(buf, fcap_len, fcap); p2p_buf_update_ie_hdr(buf, len); } else if (status != P2P_SC_SUCCESS || adv_id) { u8 *len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_status(buf, status); if (p2p->p2ps_prov) p2p_buf_add_advertisement_id(buf, adv_id, p2p->p2ps_prov->adv_mac); p2p_buf_update_ie_hdr(buf, len); } /* WPS IE with Config Methods attribute */ p2p_build_wps_ie_config_methods(buf, config_methods); #ifdef CONFIG_WIFI_DISPLAY if (wfd_ie) wpabuf_put_buf(buf, wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]) wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]); return buf; }
static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev, struct wpabuf *buf, u16 config_methods) { struct p2ps_provision *prov = p2p->p2ps_prov; struct p2ps_feature_capab fcap = { prov->cpt_mask, 0 }; int shared_group = 0; u8 ssid[SSID_MAX_LEN]; size_t ssid_len; u8 go_dev_addr[ETH_ALEN]; u8 intended_addr[ETH_ALEN]; int follow_on_req_fail = prov->status >= 0 && prov->status != P2P_SC_SUCCESS_DEFERRED; /* If we might be explicite group owner, add GO details */ if (!follow_on_req_fail && (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW))) p2ps_add_new_group_info(p2p, dev, buf); if (prov->status >= 0) p2p_buf_add_status(buf, (u8) prov->status); else prov->method = config_methods; if (!follow_on_req_fail) { if (p2p->cfg->get_persistent_group) { shared_group = p2p->cfg->get_persistent_group( p2p->cfg->cb_ctx, dev->info.p2p_device_addr, NULL, 0, go_dev_addr, ssid, &ssid_len, intended_addr); } if (shared_group || (prov->conncap & (P2PS_SETUP_CLIENT | P2PS_SETUP_NEW))) p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); if ((shared_group && !is_zero_ether_addr(intended_addr)) || (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW))) p2p_buf_add_operating_channel(buf, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); } if (prov->status < 0 && prov->info[0]) p2p_buf_add_session_info(buf, prov->info); if (!follow_on_req_fail) p2p_buf_add_connection_capability(buf, prov->conncap); p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac); if (!follow_on_req_fail) { if (shared_group || prov->conncap == P2PS_SETUP_NEW || prov->conncap == (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) || prov->conncap == (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) { /* Add Config Timeout */ p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout); } p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class, p2p->cfg->channel); } p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac); p2p_buf_add_feature_capability(buf, sizeof(fcap), (const u8 *) &fcap); if (shared_group) { p2p_buf_add_persistent_group_info(buf, go_dev_addr, ssid, ssid_len); /* Add intended interface address if it is not added yet */ if ((prov->conncap == P2PS_SETUP_NONE || prov->conncap == P2PS_SETUP_CLIENT) && !is_zero_ether_addr(intended_addr)) p2p_buf_add_intended_addr(buf, intended_addr); } }
static void p2ps_add_pd_req_attrs(struct p2p_data *p2p, struct p2p_device *dev, struct wpabuf *buf, u16 config_methods) { struct p2ps_provision *prov = p2p->p2ps_prov; u8 feat_cap_mask[] = { 1, 0 }; int shared_group = 0; u8 ssid[SSID_MAX_LEN]; size_t ssid_len; u8 go_dev_addr[ETH_ALEN]; /* If we might be explicite group owner, add GO details */ if (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW)) { p2ps_add_new_group_info(p2p, buf); } if (prov->status >= 0) { p2p_buf_add_status(buf, (u8)prov->status); } else { prov->method = config_methods; } if (p2p->cfg->get_persistent_group) { shared_group = p2p->cfg->get_persistent_group(p2p->cfg->cb_ctx, dev->info.p2p_device_addr, NULL, 0, go_dev_addr, ssid, &ssid_len); } /* Add Operating Channel if conncap includes GO */ if (shared_group || (prov->conncap & (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW))) { u8 tmp; p2p_go_select_channel(p2p, dev, &tmp); if (p2p->op_reg_class && p2p->op_channel) { p2p_buf_add_operating_channel(buf, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); } else { p2p_buf_add_operating_channel(buf, p2p->cfg->country, p2p->cfg->op_reg_class, p2p->cfg->op_channel); } } p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->cfg->channels); if (prov->info[0]) { p2p_buf_add_session_info(buf, prov->info); } p2p_buf_add_connection_capability(buf, prov->conncap); p2p_buf_add_advertisement_id(buf, prov->adv_id, prov->adv_mac); if (shared_group || prov->conncap == P2PS_SETUP_NEW || prov->conncap == (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW) || prov->conncap == (P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT)) { /* Add Config Timeout */ p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout); } p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class, p2p->cfg->channel); p2p_buf_add_session_id(buf, prov->session_id, prov->session_mac); p2p_buf_add_feature_capability(buf, sizeof(feat_cap_mask), feat_cap_mask); if (shared_group) { p2p_buf_add_persistent_group_info(buf, go_dev_addr, ssid, ssid_len); } }