p2p_build.c revision 289549
133965Sjdp/*
238889Sjdp * P2P - IE builder
338889Sjdp * Copyright (c) 2009-2010, Atheros Communications
433965Sjdp *
533965Sjdp * This software may be distributed under the terms of the BSD license.
633965Sjdp * See README for more details.
733965Sjdp */
833965Sjdp
933965Sjdp#include "includes.h"
1033965Sjdp
1133965Sjdp#include "common.h"
1233965Sjdp#include "common/ieee802_11_defs.h"
1333965Sjdp#include "common/qca-vendor.h"
1433965Sjdp#include "wps/wps_i.h"
1533965Sjdp#include "p2p_i.h"
1633965Sjdp
1733965Sjdp
1833965Sjdpvoid p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token)
1933965Sjdp{
2033965Sjdp	wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC);
2133965Sjdp	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
2233965Sjdp
2333965Sjdp	wpabuf_put_u8(buf, subtype); /* OUI Subtype */
2433965Sjdp	wpabuf_put_u8(buf, dialog_token);
2533965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token);
2633965Sjdp}
2733965Sjdp
2833965Sjdp
2933965Sjdpvoid p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype,
3033965Sjdp				   u8 dialog_token)
3133965Sjdp{
3233965Sjdp	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
3333965Sjdp	wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC);
3433965Sjdp	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
3533965Sjdp
3633965Sjdp	wpabuf_put_u8(buf, subtype); /* OUI Subtype */
3733965Sjdp	wpabuf_put_u8(buf, dialog_token);
3833965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token);
3933965Sjdp}
4033965Sjdp
4133965Sjdp
4233965Sjdpu8 * p2p_buf_add_ie_hdr(struct wpabuf *buf)
4333965Sjdp{
4433965Sjdp	u8 *len;
4533965Sjdp
4633965Sjdp	/* P2P IE header */
4733965Sjdp	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
4833965Sjdp	len = wpabuf_put(buf, 1); /* IE length to be filled */
4933965Sjdp	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
5033965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * P2P IE header");
5133965Sjdp	return len;
5238889Sjdp}
5333965Sjdp
5433965Sjdp
5533965Sjdpvoid p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len)
5633965Sjdp{
5733965Sjdp	/* Update P2P IE Length */
5833965Sjdp	*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
5960484Sobrien}
6033965Sjdp
6133965Sjdp
6233965Sjdpvoid p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab)
6333965Sjdp{
6433965Sjdp	/* P2P Capability */
6533965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY);
6633965Sjdp	wpabuf_put_le16(buf, 2);
6733965Sjdp	wpabuf_put_u8(buf, dev_capab); /* Device Capabilities */
6833965Sjdp	wpabuf_put_u8(buf, group_capab); /* Group Capabilities */
6933965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Capability dev=%02x group=%02x",
7033965Sjdp		   dev_capab, group_capab);
7133965Sjdp}
7238889Sjdp
7338889Sjdp
7438889Sjdpvoid p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent)
7538889Sjdp{
7638889Sjdp	/* Group Owner Intent */
7733965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_GROUP_OWNER_INTENT);
7833965Sjdp	wpabuf_put_le16(buf, 1);
7933965Sjdp	wpabuf_put_u8(buf, go_intent);
8033965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u Tie breaker %u",
8138889Sjdp		   go_intent >> 1, go_intent & 0x01);
8238889Sjdp}
8338889Sjdp
8438889Sjdp
8538889Sjdpvoid p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country,
8638889Sjdp				u8 reg_class, u8 channel)
8738889Sjdp{
8833965Sjdp	/* Listen Channel */
8933965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_LISTEN_CHANNEL);
9038889Sjdp	wpabuf_put_le16(buf, 5);
9138889Sjdp	wpabuf_put_data(buf, country, 3);
9238889Sjdp	wpabuf_put_u8(buf, reg_class); /* Regulatory Class */
9338889Sjdp	wpabuf_put_u8(buf, channel); /* Channel Number */
9438889Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Regulatory Class %u "
9538889Sjdp		   "Channel %u", reg_class, channel);
9638889Sjdp}
9738889Sjdp
9838889Sjdp
9938889Sjdpvoid p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country,
10038889Sjdp				   u8 reg_class, u8 channel)
10138889Sjdp{
10238889Sjdp	/* Operating Channel */
10338889Sjdp	wpabuf_put_u8(buf, P2P_ATTR_OPERATING_CHANNEL);
10438889Sjdp	wpabuf_put_le16(buf, 5);
10533965Sjdp	wpabuf_put_data(buf, country, 3);
10633965Sjdp	wpabuf_put_u8(buf, reg_class); /* Regulatory Class */
10733965Sjdp	wpabuf_put_u8(buf, channel); /* Channel Number */
10833965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: Regulatory Class %u "
10933965Sjdp		   "Channel %u", reg_class, channel);
11033965Sjdp}
11133965Sjdp
11233965Sjdp
11333965Sjdpvoid p2p_buf_add_pref_channel_list(struct wpabuf *buf,
11438889Sjdp				   const u32 *preferred_freq_list,
11538889Sjdp				   unsigned int size)
11638889Sjdp{
11738889Sjdp	unsigned int i, count = 0;
11838889Sjdp	u8 op_class, op_channel;
11938889Sjdp
12038889Sjdp	if (!size)
12138889Sjdp		return;
12233965Sjdp
12333965Sjdp	/*
12433965Sjdp	 * First, determine the number of P2P supported channels in the
12533965Sjdp	 * pref_freq_list returned from driver. This is needed for calculations
12633965Sjdp	 * of the vendor IE size.
12733965Sjdp	 */
12833965Sjdp	for (i = 0; i < size; i++) {
12933965Sjdp		if (p2p_freq_to_channel(preferred_freq_list[i], &op_class,
13033965Sjdp					&op_channel) == 0)
13133965Sjdp			count++;
13233965Sjdp	}
13333965Sjdp
13433965Sjdp	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
13533965Sjdp	wpabuf_put_u8(buf, 4 + count * sizeof(u16));
13633965Sjdp	wpabuf_put_be24(buf, OUI_QCA);
13733965Sjdp	wpabuf_put_u8(buf, QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST);
13833965Sjdp	for (i = 0; i < size; i++) {
13933965Sjdp		if (p2p_freq_to_channel(preferred_freq_list[i], &op_class,
14033965Sjdp					&op_channel) < 0) {
14133965Sjdp			wpa_printf(MSG_DEBUG, "Unsupported frequency %u MHz",
14238889Sjdp				   preferred_freq_list[i]);
14338889Sjdp			continue;
14438889Sjdp		}
14538889Sjdp		wpabuf_put_u8(buf, op_class);
14638889Sjdp		wpabuf_put_u8(buf, op_channel);
14738889Sjdp	}
14838889Sjdp}
14938889Sjdp
15038889Sjdp
15138889Sjdpvoid p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
15238889Sjdp			      struct p2p_channels *chan)
15338889Sjdp{
15438889Sjdp	u8 *len;
15538889Sjdp	size_t i;
15638889Sjdp
15738889Sjdp	/* Channel List */
15838889Sjdp	wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST);
15938889Sjdp	len = wpabuf_put(buf, 2); /* IE length to be filled */
16038889Sjdp	wpabuf_put_data(buf, country, 3); /* Country String */
16138889Sjdp
16233965Sjdp	for (i = 0; i < chan->reg_classes; i++) {
16333965Sjdp		struct p2p_reg_class *c = &chan->reg_class[i];
16433965Sjdp		wpabuf_put_u8(buf, c->reg_class);
16533965Sjdp		wpabuf_put_u8(buf, c->channels);
16633965Sjdp		wpabuf_put_data(buf, c->channel, c->channels);
16733965Sjdp	}
16833965Sjdp
16933965Sjdp	/* Update attribute length */
17033965Sjdp	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
17133965Sjdp	wpa_hexdump(MSG_DEBUG, "P2P: * Channel List",
17233965Sjdp		    len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2);
17333965Sjdp}
17433965Sjdp
17533965Sjdp
17633965Sjdpvoid p2p_buf_add_status(struct wpabuf *buf, u8 status)
17733965Sjdp{
17833965Sjdp	/* Status */
17933965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_STATUS);
18033965Sjdp	wpabuf_put_le16(buf, 1);
18133965Sjdp	wpabuf_put_u8(buf, status);
18233965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Status: %d", status);
18333965Sjdp}
18433965Sjdp
18533965Sjdp
18633965Sjdpvoid p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
18733965Sjdp			     struct p2p_device *peer)
18833965Sjdp{
18933965Sjdp	u8 *len;
19033965Sjdp	u16 methods;
19133965Sjdp	size_t nlen, i;
19233965Sjdp
19333965Sjdp	/* P2P Device Info */
19433965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO);
19560484Sobrien	len = wpabuf_put(buf, 2); /* IE length to be filled */
19633965Sjdp
19733965Sjdp	/* P2P Device address */
19833965Sjdp	wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
19933965Sjdp
20033965Sjdp	/* Config Methods */
20133965Sjdp	methods = 0;
20233965Sjdp	if (peer && peer->wps_method != WPS_NOT_READY) {
20333965Sjdp		if (peer->wps_method == WPS_PBC)
20433965Sjdp			methods |= WPS_CONFIG_PUSHBUTTON;
20533965Sjdp		else if (peer->wps_method == WPS_PIN_DISPLAY ||
20633965Sjdp			 peer->wps_method == WPS_PIN_KEYPAD) {
20733965Sjdp			methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
20833965Sjdp			methods |= WPS_CONFIG_P2PS;
20933965Sjdp		}
21033965Sjdp	} else if (p2p->cfg->config_methods) {
21133965Sjdp		methods |= p2p->cfg->config_methods &
21233965Sjdp			(WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
21333965Sjdp			 WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS);
21433965Sjdp	} else {
21533965Sjdp		methods |= WPS_CONFIG_PUSHBUTTON;
21633965Sjdp		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
21733965Sjdp		methods |= WPS_CONFIG_P2PS;
21833965Sjdp	}
21933965Sjdp	wpabuf_put_be16(buf, methods);
22033965Sjdp
22133965Sjdp	/* Primary Device Type */
22233965Sjdp	wpabuf_put_data(buf, p2p->cfg->pri_dev_type,
22333965Sjdp			sizeof(p2p->cfg->pri_dev_type));
22433965Sjdp
22533965Sjdp	/* Number of Secondary Device Types */
22633965Sjdp	wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types);
22733965Sjdp
22833965Sjdp	/* Secondary Device Type List */
22933965Sjdp	for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
23033965Sjdp		wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i],
23133965Sjdp				WPS_DEV_TYPE_LEN);
23233965Sjdp
23333965Sjdp	/* Device Name */
23433965Sjdp	nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0;
23533965Sjdp	wpabuf_put_be16(buf, ATTR_DEV_NAME);
23633965Sjdp	wpabuf_put_be16(buf, nlen);
23733965Sjdp	wpabuf_put_data(buf, p2p->cfg->dev_name, nlen);
23833965Sjdp
23933965Sjdp	/* Update attribute length */
24033965Sjdp	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
24133965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Device Info");
24233965Sjdp}
24333965Sjdp
24433965Sjdp
24533965Sjdpvoid p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr)
24633965Sjdp{
24733965Sjdp	/* P2P Device ID */
24833965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_DEVICE_ID);
24933965Sjdp	wpabuf_put_le16(buf, ETH_ALEN);
25033965Sjdp	wpabuf_put_data(buf, dev_addr, ETH_ALEN);
25133965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Device ID: " MACSTR, MAC2STR(dev_addr));
25233965Sjdp}
25333965Sjdp
25433965Sjdp
25533965Sjdpvoid p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout,
25633965Sjdp				u8 client_timeout)
25733965Sjdp{
25833965Sjdp	/* Configuration Timeout */
25933965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_CONFIGURATION_TIMEOUT);
26033965Sjdp	wpabuf_put_le16(buf, 2);
26133965Sjdp	wpabuf_put_u8(buf, go_timeout);
26233965Sjdp	wpabuf_put_u8(buf, client_timeout);
26333965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout: GO %d (*10ms)  "
26433965Sjdp		   "client %d (*10ms)", go_timeout, client_timeout);
26533965Sjdp}
26633965Sjdp
26733965Sjdp
26833965Sjdpvoid p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr)
26933965Sjdp{
27033965Sjdp	/* Intended P2P Interface Address */
27133965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_INTENDED_INTERFACE_ADDR);
27233965Sjdp	wpabuf_put_le16(buf, ETH_ALEN);
27333965Sjdp	wpabuf_put_data(buf, interface_addr, ETH_ALEN);
27433965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address " MACSTR,
27533965Sjdp		   MAC2STR(interface_addr));
27633965Sjdp}
27733965Sjdp
27833965Sjdp
27933965Sjdpvoid p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid)
28033965Sjdp{
28133965Sjdp	/* P2P Group BSSID */
28233965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_GROUP_BSSID);
28333965Sjdp	wpabuf_put_le16(buf, ETH_ALEN);
28433965Sjdp	wpabuf_put_data(buf, bssid, ETH_ALEN);
28533965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID " MACSTR,
28633965Sjdp		   MAC2STR(bssid));
28733965Sjdp}
28833965Sjdp
28933965Sjdp
29033965Sjdpvoid p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr,
29133965Sjdp			  const u8 *ssid, size_t ssid_len)
29233965Sjdp{
29333965Sjdp	/* P2P Group ID */
29433965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_GROUP_ID);
29533965Sjdp	wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
29633965Sjdp	wpabuf_put_data(buf, dev_addr, ETH_ALEN);
29733965Sjdp	wpabuf_put_data(buf, ssid, ssid_len);
29833965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
29933965Sjdp		   MAC2STR(dev_addr));
30033965Sjdp	wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len);
30133965Sjdp}
30233965Sjdp
30333965Sjdp
30433965Sjdpvoid p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags)
30533965Sjdp{
30633965Sjdp	/* Invitation Flags */
30733965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_INVITATION_FLAGS);
30833965Sjdp	wpabuf_put_le16(buf, 1);
30933965Sjdp	wpabuf_put_u8(buf, flags);
31033965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", flags);
31133965Sjdp}
31233965Sjdp
31333965Sjdp
31433965Sjdpstatic void p2p_buf_add_noa_desc(struct wpabuf *buf, struct p2p_noa_desc *desc)
31533965Sjdp{
31633965Sjdp	if (desc == NULL)
31733965Sjdp		return;
31833965Sjdp
31933965Sjdp	wpabuf_put_u8(buf, desc->count_type);
32033965Sjdp	wpabuf_put_le32(buf, desc->duration);
32133965Sjdp	wpabuf_put_le32(buf, desc->interval);
32233965Sjdp	wpabuf_put_le32(buf, desc->start_time);
32333965Sjdp}
32433965Sjdp
32533965Sjdp
32633965Sjdpvoid p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
32733965Sjdp		     struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2)
32833965Sjdp{
32933965Sjdp	/* Notice of Absence */
33033965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_NOTICE_OF_ABSENCE);
33133965Sjdp	wpabuf_put_le16(buf, 2 + (desc1 ? 13 : 0) + (desc2 ? 13 : 0));
33233965Sjdp	wpabuf_put_u8(buf, noa_index);
33333965Sjdp	wpabuf_put_u8(buf, (opp_ps ? 0x80 : 0) | (ctwindow & 0x7f));
33433965Sjdp	p2p_buf_add_noa_desc(buf, desc1);
33533965Sjdp	p2p_buf_add_noa_desc(buf, desc2);
33633965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence");
33733965Sjdp}
33833965Sjdp
33933965Sjdp
34033965Sjdpvoid p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
34133965Sjdp				   u16 interval)
34233965Sjdp{
34333965Sjdp	/* Extended Listen Timing */
34433965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_EXT_LISTEN_TIMING);
34533965Sjdp	wpabuf_put_le16(buf, 4);
34633965Sjdp	wpabuf_put_le16(buf, period);
34733965Sjdp	wpabuf_put_le16(buf, interval);
34833965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing (period %u msec  "
34933965Sjdp		   "interval %u msec)", period, interval);
35033965Sjdp}
35133965Sjdp
35233965Sjdp
35333965Sjdpvoid p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p)
35433965Sjdp{
35533965Sjdp	/* P2P Interface */
35633965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_INTERFACE);
35733965Sjdp	wpabuf_put_le16(buf, ETH_ALEN + 1 + ETH_ALEN);
35833965Sjdp	/* P2P Device address */
35933965Sjdp	wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
36033965Sjdp	/*
36133965Sjdp	 * FIX: Fetch interface address list from driver. Do not include
36233965Sjdp	 * the P2P Device address if it is never used as interface address.
36333965Sjdp	 */
36433965Sjdp	/* P2P Interface Address Count */
36560484Sobrien	wpabuf_put_u8(buf, 1);
36633965Sjdp	wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
36733965Sjdp}
36833965Sjdp
36933965Sjdp
37033965Sjdpvoid p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
37133965Sjdp				    u8 oper_class, u8 channel,
37233965Sjdp				    enum p2p_role_indication role)
37333965Sjdp{
37433965Sjdp	/* OOB Group Owner Negotiation Channel */
37533965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_OOB_GO_NEG_CHANNEL);
37633965Sjdp	wpabuf_put_le16(buf, 6);
37733965Sjdp	wpabuf_put_data(buf, country, 3);
37833965Sjdp	wpabuf_put_u8(buf, oper_class); /* Operating Class */
37933965Sjdp	wpabuf_put_u8(buf, channel); /* Channel Number */
38033965Sjdp	wpabuf_put_u8(buf, (u8) role); /* Role indication */
38133965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * OOB GO Negotiation Channel: Operating "
38233965Sjdp		   "Class %u Channel %u Role %d",
38333965Sjdp		   oper_class, channel, role);
38433965Sjdp}
38533965Sjdp
38633965Sjdp
38733965Sjdpvoid p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p)
38833965Sjdp{
38933965Sjdp	if (!p2p)
39033965Sjdp		return;
39133965Sjdp
39233965Sjdp	/* Service Hash */
39333965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH);
39433965Sjdp	wpabuf_put_le16(buf, p2p->p2ps_seek_count * P2PS_HASH_LEN);
39533965Sjdp	wpabuf_put_data(buf, p2p->p2ps_seek_hash,
39633965Sjdp			p2p->p2ps_seek_count * P2PS_HASH_LEN);
39733965Sjdp	wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash",
39833965Sjdp		    p2p->p2ps_seek_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
39933965Sjdp}
40033965Sjdp
40133965Sjdp
40233965Sjdpvoid p2p_buf_add_session_info(struct wpabuf *buf, const char *info)
40333965Sjdp{
40433965Sjdp	size_t info_len = 0;
40533965Sjdp
40633965Sjdp	if (info && info[0])
40733965Sjdp		info_len = os_strlen(info);
40833965Sjdp
40933965Sjdp	/* Session Information Data Info */
41033965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_SESSION_INFORMATION_DATA);
41133965Sjdp	wpabuf_put_le16(buf, (u16) info_len);
41233965Sjdp
41333965Sjdp	if (info) {
41433965Sjdp		wpabuf_put_data(buf, info, info_len);
41533965Sjdp		wpa_printf(MSG_DEBUG, "P2P: * Session Info Data (%s)", info);
41633965Sjdp	}
41733965Sjdp}
41833965Sjdp
41933965Sjdp
42033965Sjdpvoid p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap)
42133965Sjdp{
42233965Sjdp	/* Connection Capability Info */
42333965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_CONNECTION_CAPABILITY);
42433965Sjdp	wpabuf_put_le16(buf, 1);
42533965Sjdp	wpabuf_put_u8(buf, connection_cap);
42633965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
42733965Sjdp		   connection_cap);
42833965Sjdp}
42933965Sjdp
43033965Sjdp
43133965Sjdpvoid p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac)
43233965Sjdp{
43333965Sjdp	if (!buf || !mac)
43433965Sjdp		return;
43533965Sjdp
43633965Sjdp	/* Advertisement ID Info */
43733965Sjdp	wpabuf_put_u8(buf, P2P_ATTR_ADVERTISEMENT_ID);
43833965Sjdp	wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
43933965Sjdp	wpabuf_put_le32(buf, id);
44033965Sjdp	wpabuf_put_data(buf, mac, ETH_ALEN);
44133965Sjdp	wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID (%x) " MACSTR,
44233965Sjdp		   id, MAC2STR(mac));
44333965Sjdp}
44433965Sjdp
44533965Sjdp
44633965Sjdpstatic int p2ps_wildcard_hash(struct p2p_data *p2p,
44733965Sjdp			      const u8 *hash, u8 hash_count)
44833965Sjdp{
44933965Sjdp	u8 i;
45033965Sjdp	const u8 *test = hash;
45133965Sjdp
45233965Sjdp	for (i = 0; i < hash_count; i++) {
45333965Sjdp		if (os_memcmp(test, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
45433965Sjdp			return 1;
45533965Sjdp		test += P2PS_HASH_LEN;
45633965Sjdp	}
45733965Sjdp
45833965Sjdp	return 0;
45933965Sjdp}
46033965Sjdp
46133965Sjdp
46233965Sjdpstatic int p2p_wfa_service_adv(struct p2p_data *p2p)
46333965Sjdp{
46433965Sjdp	struct p2ps_advertisement *adv;
46533965Sjdp
46633965Sjdp	for (adv = p2p->p2ps_adv_list; adv; adv = adv->next) {
46733965Sjdp		if (os_strncmp(adv->svc_name, P2PS_WILD_HASH_STR,
46833965Sjdp			       os_strlen(P2PS_WILD_HASH_STR)) == 0)
46933965Sjdp			return 1;
47033965Sjdp	}
47133965Sjdp
47233965Sjdp	return 0;
47333965Sjdp}
47433965Sjdp
47533965Sjdp
47633965Sjdpstatic int p2p_buf_add_service_info(struct wpabuf *buf, struct p2p_data *p2p,
47733965Sjdp				    u32 adv_id, u16 config_methods,
47833965Sjdp				    const char *svc_name, u8 **ie_len, u8 **pos,
47933965Sjdp				    size_t *total_len, u8 *attr_len)
48033965Sjdp{
48133965Sjdp	size_t svc_len;
48233965Sjdp	size_t remaining;
48333965Sjdp	size_t info_len;
48433965Sjdp
48533965Sjdp	p2p_dbg(p2p, "Add service info for %s (adv_id=%u)", svc_name, adv_id);
48633965Sjdp	svc_len = os_strlen(svc_name);
48733965Sjdp	info_len = sizeof(adv_id) + sizeof(config_methods) + sizeof(u8) +
48833965Sjdp		svc_len;
48933965Sjdp
49033965Sjdp	if (info_len + *total_len > MAX_SVC_ADV_LEN) {
49133965Sjdp		p2p_dbg(p2p,
49233965Sjdp			"Unsufficient buffer, failed to add advertised service info");
49333965Sjdp		return -1;
49433965Sjdp	}
49533965Sjdp
49633965Sjdp	if (svc_len > 255) {
49733965Sjdp		p2p_dbg(p2p,
49833965Sjdp			"Invalid service name length (%u bytes), failed to add advertised service info",
49933965Sjdp			(unsigned int) svc_len);
50033965Sjdp		return -1;
50133965Sjdp	}
50233965Sjdp
50333965Sjdp	if (*ie_len) {
50433965Sjdp		int ie_data_len = (*pos - *ie_len) - 1;
50533965Sjdp
50633965Sjdp		if (ie_data_len < 0 || ie_data_len > 255) {
50733965Sjdp			p2p_dbg(p2p,
50833965Sjdp				"Invalid IE length, failed to add advertised service info");
50933965Sjdp			return -1;
51033965Sjdp		}
51133965Sjdp		remaining = 255 - ie_data_len;
51233965Sjdp	} else {
51333965Sjdp		/*
51433965Sjdp		 * Adding new P2P IE header takes 6 extra bytes:
51533965Sjdp		 * - 2 byte IE header (1 byte IE id and 1 byte length)
51633965Sjdp		 * - 4 bytes of IE_VENDOR_TYPE are reduced from 255 below
51733965Sjdp		 */
51833965Sjdp		*ie_len = p2p_buf_add_ie_hdr(buf);
51933965Sjdp		remaining = 255 - 4;
52033965Sjdp	}
52133965Sjdp
52233965Sjdp	if (remaining < sizeof(u32) + sizeof(u16) + sizeof(u8)) {
52333965Sjdp		/*
52433965Sjdp		 * Split adv_id, config_methods, and svc_name_len between two
52533965Sjdp		 * IEs.
52660484Sobrien		 */
52733965Sjdp		size_t front = remaining;
52833965Sjdp		size_t back = sizeof(u32) + sizeof(u16) + sizeof(u8) - front;
52933965Sjdp		u8 holder[sizeof(u32) + sizeof(u16) + sizeof(u8)];
53033965Sjdp
531		WPA_PUT_LE32(holder, adv_id);
532		WPA_PUT_BE16(&holder[sizeof(u32)], config_methods);
533		holder[sizeof(u32) + sizeof(u16)] = svc_len;
534
535		if (front)
536			wpabuf_put_data(buf, holder, front);
537
538		p2p_buf_update_ie_hdr(buf, *ie_len);
539		*ie_len = p2p_buf_add_ie_hdr(buf);
540
541		wpabuf_put_data(buf, &holder[front], back);
542		remaining = 255 - 4 - (sizeof(u32) + sizeof(u16) + sizeof(u8)) -
543			back;
544	} else {
545		wpabuf_put_le32(buf, adv_id);
546		wpabuf_put_be16(buf, config_methods);
547		wpabuf_put_u8(buf, svc_len);
548		remaining -= sizeof(adv_id) + sizeof(config_methods) +
549			sizeof(u8);
550	}
551
552	if (remaining < svc_len) {
553		/* split svc_name between two or three IEs */
554		size_t front = remaining;
555		size_t back = svc_len - front;
556
557		if (front)
558			wpabuf_put_data(buf, svc_name, front);
559
560		p2p_buf_update_ie_hdr(buf, *ie_len);
561		*ie_len = p2p_buf_add_ie_hdr(buf);
562
563		/* In rare cases, we must split across 3 attributes */
564		if (back > 255 - 4) {
565			wpabuf_put_data(buf, &svc_name[front], 255 - 4);
566			back -= 255 - 4;
567			front += 255 - 4;
568			p2p_buf_update_ie_hdr(buf, *ie_len);
569			*ie_len = p2p_buf_add_ie_hdr(buf);
570		}
571
572		wpabuf_put_data(buf, &svc_name[front], back);
573		remaining = 255 - 4 - back;
574	} else {
575		wpabuf_put_data(buf, svc_name, svc_len);
576		remaining -= svc_len;
577	}
578
579	p2p_buf_update_ie_hdr(buf, *ie_len);
580
581	/* set *ie_len to NULL if a new IE has to be added on the next call */
582	if (!remaining)
583		*ie_len = NULL;
584
585	/* set *pos to point to the next byte to update */
586	*pos = wpabuf_put(buf, 0);
587
588	*total_len += info_len;
589	WPA_PUT_LE16(attr_len, (u16) *total_len);
590	return 0;
591}
592
593
594void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
595				  u8 hash_count, const u8 *hash,
596				  struct p2ps_advertisement *adv_list)
597{
598	struct p2ps_advertisement *adv;
599	int p2ps_wildcard;
600	size_t total_len;
601	struct wpabuf *tmp_buf = NULL;
602	u8 *pos, *attr_len, *ie_len = NULL;
603
604	if (!adv_list || !hash || !hash_count)
605		return;
606
607	wpa_hexdump(MSG_DEBUG, "P2PS: Probe Request service hash values",
608		    hash, hash_count * P2PS_HASH_LEN);
609	p2ps_wildcard = p2ps_wildcard_hash(p2p, hash, hash_count) &&
610		p2p_wfa_service_adv(p2p);
611
612	/* Allocate temp buffer, allowing for overflow of 1 instance */
613	tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN);
614	if (!tmp_buf)
615		return;
616
617	/*
618	 * Attribute data can be split into a number of IEs. Start with the
619	 * first IE and the attribute headers here.
620	 */
621	ie_len = p2p_buf_add_ie_hdr(tmp_buf);
622
623	total_len = 0;
624
625	wpabuf_put_u8(tmp_buf, P2P_ATTR_ADVERTISED_SERVICE);
626	attr_len = wpabuf_put(tmp_buf, sizeof(u16));
627	WPA_PUT_LE16(attr_len, (u16) total_len);
628	p2p_buf_update_ie_hdr(tmp_buf, ie_len);
629	pos = wpabuf_put(tmp_buf, 0);
630
631	if (p2ps_wildcard) {
632		/* org.wi-fi.wfds match found */
633		p2p_buf_add_service_info(tmp_buf, p2p, 0, 0, P2PS_WILD_HASH_STR,
634					 &ie_len, &pos, &total_len, attr_len);
635	}
636
637	/* add advertised service info of matching services */
638	for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN;
639	     adv = adv->next) {
640		const u8 *test = hash;
641		u8 i;
642
643		for (i = 0; i < hash_count; i++) {
644			/* exact name hash match */
645			if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0 &&
646			    p2p_buf_add_service_info(tmp_buf, p2p,
647						     adv->id,
648						     adv->config_methods,
649						     adv->svc_name,
650						     &ie_len, &pos,
651						     &total_len,
652						     attr_len))
653				break;
654
655			test += P2PS_HASH_LEN;
656		}
657	}
658
659	if (total_len)
660		wpabuf_put_buf(buf, tmp_buf);
661	wpabuf_free(tmp_buf);
662}
663
664
665void p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac)
666{
667	if (!buf || !mac)
668		return;
669
670	/* Session ID Info */
671	wpabuf_put_u8(buf, P2P_ATTR_SESSION_ID);
672	wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
673	wpabuf_put_le32(buf, id);
674	wpabuf_put_data(buf, mac, ETH_ALEN);
675	wpa_printf(MSG_DEBUG, "P2P: * Session ID Info (%x) " MACSTR,
676		   id, MAC2STR(mac));
677}
678
679
680void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len, const u8 *mask)
681{
682	if (!buf || !len || !mask)
683		return;
684
685	/* Feature Capability */
686	wpabuf_put_u8(buf, P2P_ATTR_FEATURE_CAPABILITY);
687	wpabuf_put_le16(buf, len);
688	wpabuf_put_data(buf, mask, len);
689	wpa_printf(MSG_DEBUG, "P2P: * Feature Capability (%d)", len);
690}
691
692
693void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
694				       const u8 *ssid, size_t ssid_len)
695{
696	/* P2P Group ID */
697	wpabuf_put_u8(buf, P2P_ATTR_PERSISTENT_GROUP);
698	wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
699	wpabuf_put_data(buf, dev_addr, ETH_ALEN);
700	wpabuf_put_data(buf, ssid, ssid_len);
701	wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
702		   MAC2STR(dev_addr));
703}
704
705
706static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
707			      const char *val)
708{
709	size_t len;
710
711	len = val ? os_strlen(val) : 0;
712	if (wpabuf_tailroom(buf) < 4 + len)
713		return -1;
714	wpabuf_put_be16(buf, attr);
715#ifndef CONFIG_WPS_STRICT
716	if (len == 0) {
717		/*
718		 * Some deployed WPS implementations fail to parse zeor-length
719		 * attributes. As a workaround, send a space character if the
720		 * device attribute string is empty.
721		 */
722		if (wpabuf_tailroom(buf) < 3)
723			return -1;
724		wpabuf_put_be16(buf, 1);
725		wpabuf_put_u8(buf, ' ');
726		return 0;
727	}
728#endif /* CONFIG_WPS_STRICT */
729	wpabuf_put_be16(buf, len);
730	if (val)
731		wpabuf_put_data(buf, val, len);
732	return 0;
733}
734
735
736int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
737		     int all_attr)
738{
739	u8 *len;
740	int i;
741
742	if (wpabuf_tailroom(buf) < 6)
743		return -1;
744	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
745	len = wpabuf_put(buf, 1);
746	wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
747
748	if (wps_build_version(buf) < 0)
749		return -1;
750
751	if (all_attr) {
752		if (wpabuf_tailroom(buf) < 5)
753			return -1;
754		wpabuf_put_be16(buf, ATTR_WPS_STATE);
755		wpabuf_put_be16(buf, 1);
756		wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
757	}
758
759	if (pw_id >= 0) {
760		if (wpabuf_tailroom(buf) < 6)
761			return -1;
762		/* Device Password ID */
763		wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
764		wpabuf_put_be16(buf, 2);
765		wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d",
766			   pw_id);
767		wpabuf_put_be16(buf, pw_id);
768	}
769
770	if (all_attr) {
771		if (wpabuf_tailroom(buf) < 5)
772			return -1;
773		wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
774		wpabuf_put_be16(buf, 1);
775		wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
776
777		if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 ||
778		    p2p_add_wps_string(buf, ATTR_MANUFACTURER,
779				       p2p->cfg->manufacturer) < 0 ||
780		    p2p_add_wps_string(buf, ATTR_MODEL_NAME,
781				       p2p->cfg->model_name) < 0 ||
782		    p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
783				       p2p->cfg->model_number) < 0 ||
784		    p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
785				       p2p->cfg->serial_number) < 0)
786			return -1;
787
788		if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN)
789			return -1;
790		wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
791		wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
792		wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
793
794		if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name)
795		    < 0)
796			return -1;
797
798		if (wpabuf_tailroom(buf) < 6)
799			return -1;
800		wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
801		wpabuf_put_be16(buf, 2);
802		wpabuf_put_be16(buf, p2p->cfg->config_methods);
803	}
804
805	if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
806		return -1;
807
808	if (all_attr && p2p->cfg->num_sec_dev_types) {
809		if (wpabuf_tailroom(buf) <
810		    4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types)
811			return -1;
812		wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
813		wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
814				p2p->cfg->num_sec_dev_types);
815		wpabuf_put_data(buf, p2p->cfg->sec_dev_type,
816				WPS_DEV_TYPE_LEN *
817				p2p->cfg->num_sec_dev_types);
818	}
819
820	/* Add the WPS vendor extensions */
821	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
822		if (p2p->wps_vendor_ext[i] == NULL)
823			break;
824		if (wpabuf_tailroom(buf) <
825		    4 + wpabuf_len(p2p->wps_vendor_ext[i]))
826			continue;
827		wpabuf_put_be16(buf, ATTR_VENDOR_EXT);
828		wpabuf_put_be16(buf, wpabuf_len(p2p->wps_vendor_ext[i]));
829		wpabuf_put_buf(buf, p2p->wps_vendor_ext[i]);
830	}
831
832	p2p_buf_update_ie_hdr(buf, len);
833
834	return 0;
835}
836