Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}
Esempio n. 4
0
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
        u8 dialog_token,
        u16 config_methods,
        const u8 *group_id,
        size_t group_id_len)
{
    struct wpabuf *buf;
    size_t extra = 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(100 + extra);
    if (buf == NULL)
        return NULL;

    p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);

    /* 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;
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
						u8 dialog_token,
						u16 config_methods)
{
	struct wpabuf *buf;

	buf = wpabuf_alloc(100);
	if (buf == NULL)
		return NULL;

	p2p_buf_add_public_action_hdr(buf, P2P_PROV_DISC_RESP, dialog_token);

	/* WPS IE with Config Methods attribute */
	p2p_build_wps_ie_config_methods(buf, config_methods);

	return buf;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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_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;
}
Esempio n. 13
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;
}