Example #1
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;
}
Example #2
0
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);
	}
}
Example #3
0
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);
	}
}