struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) { struct wpabuf *resp; u8 *rlen; size_t extra = 0; #ifdef CONFIG_WIFI_DISPLAY if (group->wfd_ie) extra = wpabuf_len(group->wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ /* * (Re)Association Response - P2P IE * Status attribute (shall be present when association request is * denied) * Extended Listen Timing (may be present) */ resp = wpabuf_alloc(20 + extra); if (resp == NULL) return NULL; #ifdef CONFIG_WIFI_DISPLAY if (group->wfd_ie) wpabuf_put_buf(resp, group->wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ rlen = p2p_buf_add_ie_hdr(resp); if (status != P2P_SC_SUCCESS) p2p_buf_add_status(resp, status); p2p_buf_update_ie_hdr(resp, rlen); return resp; }
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) { u8 *group_info; struct wpabuf *ie; struct p2p_group_member *m; u8 *len; ie = wpabuf_alloc(257); if (ie == NULL) return NULL; len = p2p_buf_add_ie_hdr(ie); p2p_group_add_common_ies(group, ie); p2p_group_add_noa(ie, group->noa); /* P2P Device Info */ p2p_buf_add_device_info(ie, group->p2p, NULL); /* P2P Group Info */ group_info = wpabuf_put(ie, 0); wpabuf_put_u8(ie, P2P_ATTR_GROUP_INFO); wpabuf_put_le16(ie, 0); /* Length to be filled */ for (m = group->members; m; m = m->next) p2p_client_info(ie, m); WPA_PUT_LE16(group_info + 1, (u8 *) wpabuf_put(ie, 0) - group_info - 3); p2p_buf_update_ie_hdr(ie, len); return ie; }
static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) { struct wpabuf *ie; u8 *len; size_t extra = 0; #ifdef CONFIG_WIFI_DISPLAY if (group->p2p->wfd_ie_beacon) extra = wpabuf_len(group->p2p->wfd_ie_beacon); #endif /* CONFIG_WIFI_DISPLAY */ ie = wpabuf_alloc(257 + extra); if (ie == NULL) return NULL; #ifdef CONFIG_WIFI_DISPLAY if (group->p2p->wfd_ie_beacon) wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon); #endif /* CONFIG_WIFI_DISPLAY */ len = p2p_buf_add_ie_hdr(ie); p2p_group_add_common_ies(group, ie); p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); p2p_group_add_noa(ie, group->noa); p2p_buf_update_ie_hdr(ie, len); return ie; }
static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, u8 dialog_token, u16 config_methods, struct p2p_device *go) { struct wpabuf *buf; u8 *len; buf = wpabuf_alloc(1000); if (buf == NULL) return NULL; p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token); len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_capability(buf, p2p->dev_capab, 0); p2p_buf_add_device_info(buf, p2p, NULL); if (go) { p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid, go->oper_ssid_len); } p2p_buf_update_ie_hdr(buf, len); /* WPS IE with Config Methods attribute */ p2p_build_wps_ie_config_methods(buf, config_methods); return buf; }
static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p, struct p2p_device *peer, u8 dialog_token, u8 status, const u8 *group_bssid, u8 reg_class, u8 channel, struct p2p_channels *channels) { struct wpabuf *buf; u8 *len; buf = wpabuf_alloc(1000); if (buf == NULL) return NULL; p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_RESP, dialog_token); len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_status(buf, status); p2p_buf_add_config_timeout(buf, 0, 0); /* FIX */ if (reg_class && channel) p2p_buf_add_operating_channel(buf, p2p->cfg->country, reg_class, channel); if (group_bssid) p2p_buf_add_group_bssid(buf, group_bssid); if (channels) p2p_buf_add_channel_list(buf, p2p->cfg->country, channels); p2p_buf_update_ie_hdr(buf, len); return buf; }
static struct wpabuf * p2p_build_invitation_resp(struct p2p_data *p2p, struct p2p_device *peer, u8 dialog_token, u8 status, const u8 *group_bssid, u8 reg_class, u8 channel, struct p2p_channels *channels) { struct wpabuf *buf; u8 *len; size_t extra = 0; #ifdef CONFIG_WIFI_DISPLAY struct wpabuf *wfd_ie = p2p->wfd_ie_invitation; if (wfd_ie && group_bssid) { 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_bssid, ETH_ALEN)) 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 */ buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_RESP, dialog_token); len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_status(buf, status); p2p_buf_add_config_timeout(buf, 0, 0); /* FIX */ if (reg_class && channel) p2p_buf_add_operating_channel(buf, p2p->cfg->country, reg_class, channel); if (group_bssid) p2p_buf_add_group_bssid(buf, group_bssid); if (channels) p2p_buf_add_channel_list(buf, p2p->cfg->country, channels); p2p_buf_update_ie_hdr(buf, len); #ifdef CONFIG_WIFI_DISPLAY if (wfd_ie) wpabuf_put_buf(buf, wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ return buf; }
static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) { struct wpabuf *ie; u8 *len; ie = wpabuf_alloc(257); if (ie == NULL) return NULL; len = p2p_buf_add_ie_hdr(ie); p2p_group_add_common_ies(group, ie); p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); p2p_group_add_noa(ie, group->noa); p2p_buf_update_ie_hdr(ie, len); return ie; }
static struct wpabuf * p2p_build_dev_disc_resp(u8 dialog_token, u8 status) { struct wpabuf *buf; u8 *len; buf = wpabuf_alloc(100); if (buf == NULL) return NULL; p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_RESP, dialog_token); len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_status(buf, status); p2p_buf_update_ie_hdr(buf, len); return buf; }
static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, u8 dialog_token, u16 config_methods, struct p2p_device *go) { struct wpabuf *buf; u8 *len; size_t extra = 0; #ifdef CONFIG_WIFI_DISPLAY if (p2p->wfd_ie_prov_disc_req) extra = wpabuf_len(p2p->wfd_ie_prov_disc_req); #endif /* CONFIG_WIFI_DISPLAY */ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token); len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_capability(buf, p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0); p2p_buf_add_device_info(buf, p2p, NULL); if (go) { p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid, go->oper_ssid_len); } 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 (p2p->wfd_ie_prov_disc_req) wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req); #endif /* CONFIG_WIFI_DISPLAY */ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); return buf; }
static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, struct p2p_device *peer, const u8 *go_dev_addr) { struct wpabuf *buf; u8 *len; const u8 *dev_addr; buf = wpabuf_alloc(1000); if (buf == NULL) return NULL; peer->dialog_token++; if (peer->dialog_token == 0) peer->dialog_token = 1; p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_REQ, peer->dialog_token); len = p2p_buf_add_ie_hdr(buf); if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent) p2p_buf_add_config_timeout(buf, 0, 0); else p2p_buf_add_config_timeout(buf, 100, 20); p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ? P2P_INVITATION_FLAGS_TYPE : 0); p2p_buf_add_operating_channel(buf, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); if (p2p->inv_bssid_set) p2p_buf_add_group_bssid(buf, p2p->inv_bssid); p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); if (go_dev_addr) dev_addr = go_dev_addr; else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT) dev_addr = peer->info.p2p_device_addr; else dev_addr = p2p->cfg->dev_addr; p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len); p2p_buf_add_device_info(buf, p2p, peer); p2p_buf_update_ie_hdr(buf, len); return buf; }
struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) { struct wpabuf *resp; u8 *rlen; /* * (Re)Association Response - P2P IE * Status attribute (shall be present when association request is * denied) * Extended Listen Timing (may be present) */ resp = wpabuf_alloc(20); if (resp == NULL) return NULL; rlen = p2p_buf_add_ie_hdr(resp); if (status != P2P_SC_SUCCESS) p2p_buf_add_status(resp, status); p2p_buf_update_ie_hdr(resp, rlen); return resp; }
static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) { struct wpabuf *ie; u8 *len; ie = wpabuf_alloc(257); if (ie == NULL) return NULL; len = p2p_buf_add_ie_hdr(ie); p2p_group_add_common_ies(group, ie); #ifdef ANDROID_BRCM_P2P_PATCH /* P2P_ADDR: Use p2p_dev_addr instead of own mac addr*/ p2p_buf_add_device_id(ie, group->p2p->cfg->p2p_dev_addr); #else p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); #endif p2p_group_add_noa(ie, group->noa); p2p_buf_update_ie_hdr(ie, len); return ie; }
static struct wpabuf * p2p_build_dev_disc_req(struct p2p_data *p2p, struct p2p_device *go, const u8 *dev_id) { struct wpabuf *buf; u8 *len; buf = wpabuf_alloc(100); if (buf == NULL) return NULL; go->dialog_token++; if (go->dialog_token == 0) go->dialog_token = 1; p2p_buf_add_public_action_hdr(buf, P2P_DEV_DISC_REQ, go->dialog_token); len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_device_id(buf, dev_id); p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid, go->oper_ssid_len); p2p_buf_update_ie_hdr(buf, len); return buf; }
static int p2p_buf_add_service_info(struct wpabuf *buf, struct p2p_data *p2p, u32 adv_id, u16 config_methods, const char *svc_name, u8 **ie_len, u8 **pos, size_t *total_len, u8 *attr_len) { size_t svc_len; size_t remaining; size_t info_len; p2p_dbg(p2p, "Add service info for %s (adv_id=%u)", svc_name, adv_id); svc_len = os_strlen(svc_name); info_len = sizeof(adv_id) + sizeof(config_methods) + sizeof(u8) + svc_len; if (info_len + *total_len > MAX_SVC_ADV_LEN) { p2p_dbg(p2p, "Unsufficient buffer, failed to add advertised service info"); return -1; } if (svc_len > 255) { p2p_dbg(p2p, "Invalid service name length (%u bytes), failed to add advertised service info", (unsigned int) svc_len); return -1; } if (*ie_len) { int ie_data_len = (*pos - *ie_len) - 1; if (ie_data_len < 0 || ie_data_len > 255) { p2p_dbg(p2p, "Invalid IE length, failed to add advertised service info"); return -1; } remaining = 255 - ie_data_len; } else { /* * Adding new P2P IE header takes 6 extra bytes: * - 2 byte IE header (1 byte IE id and 1 byte length) * - 4 bytes of IE_VENDOR_TYPE are reduced from 255 below */ *ie_len = p2p_buf_add_ie_hdr(buf); remaining = 255 - 4; } if (remaining < sizeof(u32) + sizeof(u16) + sizeof(u8)) { /* * Split adv_id, config_methods, and svc_name_len between two * IEs. */ size_t front = remaining; size_t back = sizeof(u32) + sizeof(u16) + sizeof(u8) - front; u8 holder[sizeof(u32) + sizeof(u16) + sizeof(u8)]; WPA_PUT_LE32(holder, adv_id); WPA_PUT_BE16(&holder[sizeof(u32)], config_methods); holder[sizeof(u32) + sizeof(u16)] = svc_len; if (front) wpabuf_put_data(buf, holder, front); p2p_buf_update_ie_hdr(buf, *ie_len); *ie_len = p2p_buf_add_ie_hdr(buf); wpabuf_put_data(buf, &holder[front], back); remaining = 255 - 4 - (sizeof(u32) + sizeof(u16) + sizeof(u8)) - back; } else { wpabuf_put_le32(buf, adv_id); wpabuf_put_be16(buf, config_methods); wpabuf_put_u8(buf, svc_len); remaining -= sizeof(adv_id) + sizeof(config_methods) + sizeof(u8); } if (remaining < svc_len) { /* split svc_name between two or three IEs */ size_t front = remaining; size_t back = svc_len - front; if (front) wpabuf_put_data(buf, svc_name, front); p2p_buf_update_ie_hdr(buf, *ie_len); *ie_len = p2p_buf_add_ie_hdr(buf); /* In rare cases, we must split across 3 attributes */ if (back > 255 - 4) { wpabuf_put_data(buf, &svc_name[front], 255 - 4); back -= 255 - 4; front += 255 - 4; p2p_buf_update_ie_hdr(buf, *ie_len); *ie_len = p2p_buf_add_ie_hdr(buf); } wpabuf_put_data(buf, &svc_name[front], back); remaining = 255 - 4 - back; } else { wpabuf_put_data(buf, svc_name, svc_len); remaining -= svc_len; } p2p_buf_update_ie_hdr(buf, *ie_len); /* set *ie_len to NULL if a new IE has to be added on the next call */ if (!remaining) *ie_len = NULL; /* set *pos to point to the next byte to update */ *pos = wpabuf_put(buf, 0); *total_len += info_len; WPA_PUT_LE16(attr_len, (u16) *total_len); return 0; }
static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, struct p2p_device *peer, const u8 *go_dev_addr, int dev_pw_id) { struct wpabuf *buf; u8 *len; const u8 *dev_addr; size_t extra = 0; #ifdef CONFIG_WIFI_DISPLAY struct wpabuf *wfd_ie = p2p->wfd_ie_invitation; if (wfd_ie && p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) { size_t i; for (i = 0; i < p2p->num_groups; i++) { struct p2p_group *g = p2p->groups[i]; struct wpabuf *ie; if (os_memcmp(p2p_group_get_interface_addr(g), p2p->inv_bssid, ETH_ALEN) != 0) 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_INV_REQ]) extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]); buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; peer->dialog_token++; if (peer->dialog_token == 0) peer->dialog_token = 1; p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_REQ, peer->dialog_token); len = p2p_buf_add_ie_hdr(buf); if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent) p2p_buf_add_config_timeout(buf, 0, 0); else p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout); p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ? P2P_INVITATION_FLAGS_TYPE : 0); if (p2p->inv_role != P2P_INVITE_ROLE_CLIENT || !(peer->flags & P2P_DEV_NO_PREF_CHAN)) p2p_buf_add_operating_channel(buf, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); if (p2p->inv_bssid_set) p2p_buf_add_group_bssid(buf, p2p->inv_bssid); p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); if (go_dev_addr) dev_addr = go_dev_addr; else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT) dev_addr = peer->info.p2p_device_addr; else dev_addr = p2p->cfg->dev_addr; p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len); p2p_buf_add_device_info(buf, p2p, peer); p2p_buf_update_ie_hdr(buf, len); p2p_buf_add_pref_channel_list(buf, p2p->pref_freq_list, p2p->num_pref_freq); #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_INV_REQ]) wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]); if (dev_pw_id >= 0) { /* WSC IE in Invitation Request for NFC static handover */ p2p_build_wps_ie(p2p, buf, dev_pw_id, 0); } return buf; }
static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, struct p2p_device *peer, const u8 *go_dev_addr) { struct wpabuf *buf; u8 *len; const u8 *dev_addr; size_t extra = 0; #ifdef CONFIG_WIFI_DISPLAY struct wpabuf *wfd_ie = p2p->wfd_ie_invitation; if (wfd_ie && p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) { size_t i; for (i = 0; i < p2p->num_groups; i++) { struct p2p_group *g = p2p->groups[i]; struct wpabuf *ie; 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 */ buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; peer->dialog_token++; if (peer->dialog_token == 0) peer->dialog_token = 1; p2p_buf_add_public_action_hdr(buf, P2P_INVITATION_REQ, peer->dialog_token); len = p2p_buf_add_ie_hdr(buf); if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent) p2p_buf_add_config_timeout(buf, 0, 0); else p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout); p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ? P2P_INVITATION_FLAGS_TYPE : 0); p2p_buf_add_operating_channel(buf, p2p->cfg->country, p2p->op_reg_class, p2p->op_channel); if (p2p->inv_bssid_set) p2p_buf_add_group_bssid(buf, p2p->inv_bssid); p2p_buf_add_channel_list(buf, p2p->cfg->country, &p2p->channels); if (go_dev_addr) dev_addr = go_dev_addr; else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT) dev_addr = peer->info.p2p_device_addr; else dev_addr = p2p->cfg->dev_addr; p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len); p2p_buf_add_device_info(buf, p2p, peer); p2p_buf_update_ie_hdr(buf, len); #ifdef CONFIG_WIFI_DISPLAY if (wfd_ie) wpabuf_put_buf(buf, wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ return buf; }
static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev, int join) { struct wpabuf *buf; u8 *len; size_t extra = 0; u8 dialog_token = dev->dialog_token; u16 config_methods = dev->req_config_methods; struct p2p_device *go = join ? dev : NULL; u8 group_capab; #ifdef CONFIG_WIFI_DISPLAY if (p2p->wfd_ie_prov_disc_req) extra = wpabuf_len(p2p->wfd_ie_prov_disc_req); #endif /* CONFIG_WIFI_DISPLAY */ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); if (p2p->p2ps_prov) extra += os_strlen(p2p->p2ps_prov->info) + 1 + sizeof(struct p2ps_provision); buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_REQ, dialog_token); len = p2p_buf_add_ie_hdr(buf); group_capab = 0; if (p2p->p2ps_prov) { group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP; group_capab |= 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 (p2p->p2ps_prov) { p2ps_add_pd_req_attrs(p2p, dev, buf, config_methods); } else if (go) { p2p_buf_add_group_id(buf, go->info.p2p_device_addr, go->oper_ssid, go->oper_ssid_len); } 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 (p2p->wfd_ie_prov_disc_req) wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req); #endif /* CONFIG_WIFI_DISPLAY */ if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); return buf; }
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; }
void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p, u8 hash_count, const u8 *hash, struct p2ps_advertisement *adv_list) { struct p2ps_advertisement *adv; int p2ps_wildcard; size_t total_len; struct wpabuf *tmp_buf = NULL; u8 *pos, *attr_len, *ie_len = NULL; if (!adv_list || !hash || !hash_count) return; wpa_hexdump(MSG_DEBUG, "P2PS: Probe Request service hash values", hash, hash_count * P2PS_HASH_LEN); p2ps_wildcard = p2ps_wildcard_hash(p2p, hash, hash_count) && p2p_wfa_service_adv(p2p); /* Allocate temp buffer, allowing for overflow of 1 instance */ tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN); if (!tmp_buf) return; /* * Attribute data can be split into a number of IEs. Start with the * first IE and the attribute headers here. */ ie_len = p2p_buf_add_ie_hdr(tmp_buf); total_len = 0; wpabuf_put_u8(tmp_buf, P2P_ATTR_ADVERTISED_SERVICE); attr_len = wpabuf_put(tmp_buf, sizeof(u16)); WPA_PUT_LE16(attr_len, (u16) total_len); p2p_buf_update_ie_hdr(tmp_buf, ie_len); pos = wpabuf_put(tmp_buf, 0); if (p2ps_wildcard) { /* org.wi-fi.wfds match found */ p2p_buf_add_service_info(tmp_buf, p2p, 0, 0, P2PS_WILD_HASH_STR, &ie_len, &pos, &total_len, attr_len); } /* add advertised service info of matching services */ for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN; adv = adv->next) { const u8 *test = hash; u8 i; for (i = 0; i < hash_count; i++) { /* exact name hash match */ if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0 && p2p_buf_add_service_info(tmp_buf, p2p, adv->id, adv->config_methods, adv->svc_name, &ie_len, &pos, &total_len, attr_len)) break; test += P2PS_HASH_LEN; } } if (total_len) wpabuf_put_buf(buf, tmp_buf); wpabuf_free(tmp_buf); }