1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * P2P - IE builder
3e5b75505Sopenharmony_ci * Copyright (c) 2009-2010, Atheros Communications
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci
11e5b75505Sopenharmony_ci#include "common.h"
12e5b75505Sopenharmony_ci#include "common/ieee802_11_defs.h"
13e5b75505Sopenharmony_ci#include "common/qca-vendor.h"
14e5b75505Sopenharmony_ci#include "wps/wps_i.h"
15e5b75505Sopenharmony_ci#include "p2p_i.h"
16e5b75505Sopenharmony_ci
17e5b75505Sopenharmony_ci
18e5b75505Sopenharmony_civoid p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token)
19e5b75505Sopenharmony_ci{
20e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC);
21e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
22e5b75505Sopenharmony_ci
23e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, subtype); /* OUI Subtype */
24e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, dialog_token);
25e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token);
26e5b75505Sopenharmony_ci}
27e5b75505Sopenharmony_ci
28e5b75505Sopenharmony_ci
29e5b75505Sopenharmony_civoid p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype,
30e5b75505Sopenharmony_ci				   u8 dialog_token)
31e5b75505Sopenharmony_ci{
32e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
33e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC);
34e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
35e5b75505Sopenharmony_ci
36e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, subtype); /* OUI Subtype */
37e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, dialog_token);
38e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token);
39e5b75505Sopenharmony_ci}
40e5b75505Sopenharmony_ci
41e5b75505Sopenharmony_ci
42e5b75505Sopenharmony_ciu8 * p2p_buf_add_ie_hdr(struct wpabuf *buf)
43e5b75505Sopenharmony_ci{
44e5b75505Sopenharmony_ci	u8 *len;
45e5b75505Sopenharmony_ci
46e5b75505Sopenharmony_ci	/* P2P IE header */
47e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
48e5b75505Sopenharmony_ci	len = wpabuf_put(buf, 1); /* IE length to be filled */
49e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
50e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * P2P IE header");
51e5b75505Sopenharmony_ci	return len;
52e5b75505Sopenharmony_ci}
53e5b75505Sopenharmony_ci
54e5b75505Sopenharmony_ci
55e5b75505Sopenharmony_civoid p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len)
56e5b75505Sopenharmony_ci{
57e5b75505Sopenharmony_ci	/* Update P2P IE Length */
58e5b75505Sopenharmony_ci	*len = (u8 *) wpabuf_put(buf, 0) - len - 1;
59e5b75505Sopenharmony_ci}
60e5b75505Sopenharmony_ci
61e5b75505Sopenharmony_ci
62e5b75505Sopenharmony_civoid p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab)
63e5b75505Sopenharmony_ci{
64e5b75505Sopenharmony_ci	/* P2P Capability */
65e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY);
66e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 2);
67e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, dev_capab); /* Device Capabilities */
68e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, group_capab); /* Group Capabilities */
69e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Capability dev=%02x group=%02x",
70e5b75505Sopenharmony_ci		   dev_capab, group_capab);
71e5b75505Sopenharmony_ci}
72e5b75505Sopenharmony_ci
73e5b75505Sopenharmony_ci
74e5b75505Sopenharmony_civoid p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent)
75e5b75505Sopenharmony_ci{
76e5b75505Sopenharmony_ci	/* Group Owner Intent */
77e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_GROUP_OWNER_INTENT);
78e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 1);
79e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, go_intent);
80e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u Tie breaker %u",
81e5b75505Sopenharmony_ci		   go_intent >> 1, go_intent & 0x01);
82e5b75505Sopenharmony_ci}
83e5b75505Sopenharmony_ci
84e5b75505Sopenharmony_ci
85e5b75505Sopenharmony_civoid p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country,
86e5b75505Sopenharmony_ci				u8 reg_class, u8 channel)
87e5b75505Sopenharmony_ci{
88e5b75505Sopenharmony_ci	/* Listen Channel */
89e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_LISTEN_CHANNEL);
90e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 5);
91e5b75505Sopenharmony_ci	wpabuf_put_data(buf, country, 3);
92e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, reg_class); /* Regulatory Class */
93e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, channel); /* Channel Number */
94e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Regulatory Class %u "
95e5b75505Sopenharmony_ci		   "Channel %u", reg_class, channel);
96e5b75505Sopenharmony_ci}
97e5b75505Sopenharmony_ci
98e5b75505Sopenharmony_ci
99e5b75505Sopenharmony_civoid p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country,
100e5b75505Sopenharmony_ci				   u8 reg_class, u8 channel)
101e5b75505Sopenharmony_ci{
102e5b75505Sopenharmony_ci	/* Operating Channel */
103e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_OPERATING_CHANNEL);
104e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 5);
105e5b75505Sopenharmony_ci	wpabuf_put_data(buf, country, 3);
106e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, reg_class); /* Regulatory Class */
107e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, channel); /* Channel Number */
108e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: Regulatory Class %u "
109e5b75505Sopenharmony_ci		   "Channel %u", reg_class, channel);
110e5b75505Sopenharmony_ci}
111e5b75505Sopenharmony_ci
112e5b75505Sopenharmony_ci
113e5b75505Sopenharmony_civoid p2p_buf_add_pref_channel_list(struct wpabuf *buf,
114e5b75505Sopenharmony_ci				   const u32 *preferred_freq_list,
115e5b75505Sopenharmony_ci				   unsigned int size)
116e5b75505Sopenharmony_ci{
117e5b75505Sopenharmony_ci	unsigned int i, count = 0;
118e5b75505Sopenharmony_ci	u8 op_class, op_channel;
119e5b75505Sopenharmony_ci
120e5b75505Sopenharmony_ci	if (!size)
121e5b75505Sopenharmony_ci		return;
122e5b75505Sopenharmony_ci
123e5b75505Sopenharmony_ci	/*
124e5b75505Sopenharmony_ci	 * First, determine the number of P2P supported channels in the
125e5b75505Sopenharmony_ci	 * pref_freq_list returned from driver. This is needed for calculations
126e5b75505Sopenharmony_ci	 * of the vendor IE size.
127e5b75505Sopenharmony_ci	 */
128e5b75505Sopenharmony_ci	for (i = 0; i < size; i++) {
129e5b75505Sopenharmony_ci		if (p2p_freq_to_channel(preferred_freq_list[i], &op_class,
130e5b75505Sopenharmony_ci					&op_channel) == 0)
131e5b75505Sopenharmony_ci			count++;
132e5b75505Sopenharmony_ci	}
133e5b75505Sopenharmony_ci
134e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
135e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 4 + count * sizeof(u16));
136e5b75505Sopenharmony_ci	wpabuf_put_be24(buf, OUI_QCA);
137e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST);
138e5b75505Sopenharmony_ci	for (i = 0; i < size; i++) {
139e5b75505Sopenharmony_ci		if (p2p_freq_to_channel(preferred_freq_list[i], &op_class,
140e5b75505Sopenharmony_ci					&op_channel) < 0) {
141e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Unsupported frequency %u MHz",
142e5b75505Sopenharmony_ci				   preferred_freq_list[i]);
143e5b75505Sopenharmony_ci			continue;
144e5b75505Sopenharmony_ci		}
145e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, op_class);
146e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, op_channel);
147e5b75505Sopenharmony_ci	}
148e5b75505Sopenharmony_ci}
149e5b75505Sopenharmony_ci
150e5b75505Sopenharmony_ci
151e5b75505Sopenharmony_civoid p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
152e5b75505Sopenharmony_ci			      struct p2p_channels *chan)
153e5b75505Sopenharmony_ci{
154e5b75505Sopenharmony_ci	u8 *len;
155e5b75505Sopenharmony_ci	size_t i;
156e5b75505Sopenharmony_ci
157e5b75505Sopenharmony_ci	/* Channel List */
158e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST);
159e5b75505Sopenharmony_ci	len = wpabuf_put(buf, 2); /* IE length to be filled */
160e5b75505Sopenharmony_ci	wpabuf_put_data(buf, country, 3); /* Country String */
161e5b75505Sopenharmony_ci
162e5b75505Sopenharmony_ci	for (i = 0; i < chan->reg_classes; i++) {
163e5b75505Sopenharmony_ci		struct p2p_reg_class *c = &chan->reg_class[i];
164e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, c->reg_class);
165e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, c->channels);
166e5b75505Sopenharmony_ci		wpabuf_put_data(buf, c->channel, c->channels);
167e5b75505Sopenharmony_ci	}
168e5b75505Sopenharmony_ci
169e5b75505Sopenharmony_ci	/* Update attribute length */
170e5b75505Sopenharmony_ci	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
171e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "P2P: * Channel List",
172e5b75505Sopenharmony_ci		    len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2);
173e5b75505Sopenharmony_ci}
174e5b75505Sopenharmony_ci
175e5b75505Sopenharmony_ci
176e5b75505Sopenharmony_civoid p2p_buf_add_status(struct wpabuf *buf, u8 status)
177e5b75505Sopenharmony_ci{
178e5b75505Sopenharmony_ci	/* Status */
179e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_STATUS);
180e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 1);
181e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, status);
182e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Status: %d", status);
183e5b75505Sopenharmony_ci}
184e5b75505Sopenharmony_ci
185e5b75505Sopenharmony_ci
186e5b75505Sopenharmony_civoid p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
187e5b75505Sopenharmony_ci			     struct p2p_device *peer)
188e5b75505Sopenharmony_ci{
189e5b75505Sopenharmony_ci	u8 *len;
190e5b75505Sopenharmony_ci	u16 methods;
191e5b75505Sopenharmony_ci	size_t nlen, i;
192e5b75505Sopenharmony_ci
193e5b75505Sopenharmony_ci	/* P2P Device Info */
194e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO);
195e5b75505Sopenharmony_ci	len = wpabuf_put(buf, 2); /* IE length to be filled */
196e5b75505Sopenharmony_ci
197e5b75505Sopenharmony_ci	/* P2P Device address */
198e5b75505Sopenharmony_ci	wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
199e5b75505Sopenharmony_ci
200e5b75505Sopenharmony_ci	/* Config Methods */
201e5b75505Sopenharmony_ci	methods = 0;
202e5b75505Sopenharmony_ci	if (peer && peer->wps_method != WPS_NOT_READY) {
203e5b75505Sopenharmony_ci		if (peer->wps_method == WPS_PBC)
204e5b75505Sopenharmony_ci			methods |= WPS_CONFIG_PUSHBUTTON;
205e5b75505Sopenharmony_ci		else if (peer->wps_method == WPS_P2PS)
206e5b75505Sopenharmony_ci			methods |= WPS_CONFIG_P2PS;
207e5b75505Sopenharmony_ci		else if (peer->wps_method == WPS_PIN_DISPLAY ||
208e5b75505Sopenharmony_ci			 peer->wps_method == WPS_PIN_KEYPAD)
209e5b75505Sopenharmony_ci			methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
210e5b75505Sopenharmony_ci	} else if (p2p->cfg->config_methods) {
211e5b75505Sopenharmony_ci		methods |= p2p->cfg->config_methods &
212e5b75505Sopenharmony_ci			(WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
213e5b75505Sopenharmony_ci			 WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS);
214e5b75505Sopenharmony_ci	} else {
215e5b75505Sopenharmony_ci		methods |= WPS_CONFIG_PUSHBUTTON;
216e5b75505Sopenharmony_ci		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
217e5b75505Sopenharmony_ci		methods |= WPS_CONFIG_P2PS;
218e5b75505Sopenharmony_ci	}
219e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, methods);
220e5b75505Sopenharmony_ci
221e5b75505Sopenharmony_ci	/* Primary Device Type */
222e5b75505Sopenharmony_ci	wpabuf_put_data(buf, p2p->cfg->pri_dev_type,
223e5b75505Sopenharmony_ci			sizeof(p2p->cfg->pri_dev_type));
224e5b75505Sopenharmony_ci
225e5b75505Sopenharmony_ci	/* Number of Secondary Device Types */
226e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types);
227e5b75505Sopenharmony_ci
228e5b75505Sopenharmony_ci	/* Secondary Device Type List */
229e5b75505Sopenharmony_ci	for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
230e5b75505Sopenharmony_ci		wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i],
231e5b75505Sopenharmony_ci				WPS_DEV_TYPE_LEN);
232e5b75505Sopenharmony_ci
233e5b75505Sopenharmony_ci	/* Device Name */
234e5b75505Sopenharmony_ci	nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0;
235e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, ATTR_DEV_NAME);
236e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, nlen);
237e5b75505Sopenharmony_ci	wpabuf_put_data(buf, p2p->cfg->dev_name, nlen);
238e5b75505Sopenharmony_ci
239e5b75505Sopenharmony_ci	/* Update attribute length */
240e5b75505Sopenharmony_ci	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
241e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Device Info");
242e5b75505Sopenharmony_ci}
243e5b75505Sopenharmony_ci
244e5b75505Sopenharmony_ci
245e5b75505Sopenharmony_civoid p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr)
246e5b75505Sopenharmony_ci{
247e5b75505Sopenharmony_ci	/* P2P Device ID */
248e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_DEVICE_ID);
249e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, ETH_ALEN);
250e5b75505Sopenharmony_ci	wpabuf_put_data(buf, dev_addr, ETH_ALEN);
251e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Device ID: " MACSTR, MAC2STR(dev_addr));
252e5b75505Sopenharmony_ci}
253e5b75505Sopenharmony_ci
254e5b75505Sopenharmony_ci
255e5b75505Sopenharmony_civoid p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout,
256e5b75505Sopenharmony_ci				u8 client_timeout)
257e5b75505Sopenharmony_ci{
258e5b75505Sopenharmony_ci	/* Configuration Timeout */
259e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_CONFIGURATION_TIMEOUT);
260e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 2);
261e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, go_timeout);
262e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, client_timeout);
263e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout: GO %d (*10ms)  "
264e5b75505Sopenharmony_ci		   "client %d (*10ms)", go_timeout, client_timeout);
265e5b75505Sopenharmony_ci}
266e5b75505Sopenharmony_ci
267e5b75505Sopenharmony_ci
268e5b75505Sopenharmony_civoid p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr)
269e5b75505Sopenharmony_ci{
270e5b75505Sopenharmony_ci	/* Intended P2P Interface Address */
271e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_INTENDED_INTERFACE_ADDR);
272e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, ETH_ALEN);
273e5b75505Sopenharmony_ci	wpabuf_put_data(buf, interface_addr, ETH_ALEN);
274e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address " MACSTR,
275e5b75505Sopenharmony_ci		   MAC2STR(interface_addr));
276e5b75505Sopenharmony_ci}
277e5b75505Sopenharmony_ci
278e5b75505Sopenharmony_ci
279e5b75505Sopenharmony_civoid p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid)
280e5b75505Sopenharmony_ci{
281e5b75505Sopenharmony_ci	/* P2P Group BSSID */
282e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_GROUP_BSSID);
283e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, ETH_ALEN);
284e5b75505Sopenharmony_ci	wpabuf_put_data(buf, bssid, ETH_ALEN);
285e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID " MACSTR,
286e5b75505Sopenharmony_ci		   MAC2STR(bssid));
287e5b75505Sopenharmony_ci}
288e5b75505Sopenharmony_ci
289e5b75505Sopenharmony_ci
290e5b75505Sopenharmony_civoid p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr,
291e5b75505Sopenharmony_ci			  const u8 *ssid, size_t ssid_len)
292e5b75505Sopenharmony_ci{
293e5b75505Sopenharmony_ci	/* P2P Group ID */
294e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_GROUP_ID);
295e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
296e5b75505Sopenharmony_ci	wpabuf_put_data(buf, dev_addr, ETH_ALEN);
297e5b75505Sopenharmony_ci	wpabuf_put_data(buf, ssid, ssid_len);
298e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
299e5b75505Sopenharmony_ci		   MAC2STR(dev_addr));
300e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len);
301e5b75505Sopenharmony_ci}
302e5b75505Sopenharmony_ci
303e5b75505Sopenharmony_ci
304e5b75505Sopenharmony_civoid p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags)
305e5b75505Sopenharmony_ci{
306e5b75505Sopenharmony_ci	/* Invitation Flags */
307e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_INVITATION_FLAGS);
308e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 1);
309e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, flags);
310e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", flags);
311e5b75505Sopenharmony_ci}
312e5b75505Sopenharmony_ci
313e5b75505Sopenharmony_ci
314e5b75505Sopenharmony_cistatic void p2p_buf_add_noa_desc(struct wpabuf *buf, struct p2p_noa_desc *desc)
315e5b75505Sopenharmony_ci{
316e5b75505Sopenharmony_ci	if (desc == NULL)
317e5b75505Sopenharmony_ci		return;
318e5b75505Sopenharmony_ci
319e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, desc->count_type);
320e5b75505Sopenharmony_ci	wpabuf_put_le32(buf, desc->duration);
321e5b75505Sopenharmony_ci	wpabuf_put_le32(buf, desc->interval);
322e5b75505Sopenharmony_ci	wpabuf_put_le32(buf, desc->start_time);
323e5b75505Sopenharmony_ci}
324e5b75505Sopenharmony_ci
325e5b75505Sopenharmony_ci
326e5b75505Sopenharmony_civoid p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
327e5b75505Sopenharmony_ci		     struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2)
328e5b75505Sopenharmony_ci{
329e5b75505Sopenharmony_ci	/* Notice of Absence */
330e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_NOTICE_OF_ABSENCE);
331e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 2 + (desc1 ? 13 : 0) + (desc2 ? 13 : 0));
332e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, noa_index);
333e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, (opp_ps ? 0x80 : 0) | (ctwindow & 0x7f));
334e5b75505Sopenharmony_ci	p2p_buf_add_noa_desc(buf, desc1);
335e5b75505Sopenharmony_ci	p2p_buf_add_noa_desc(buf, desc2);
336e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence");
337e5b75505Sopenharmony_ci}
338e5b75505Sopenharmony_ci
339e5b75505Sopenharmony_ci
340e5b75505Sopenharmony_civoid p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
341e5b75505Sopenharmony_ci				   u16 interval)
342e5b75505Sopenharmony_ci{
343e5b75505Sopenharmony_ci	/* Extended Listen Timing */
344e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_EXT_LISTEN_TIMING);
345e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 4);
346e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, period);
347e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, interval);
348e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing (period %u msec  "
349e5b75505Sopenharmony_ci		   "interval %u msec)", period, interval);
350e5b75505Sopenharmony_ci}
351e5b75505Sopenharmony_ci
352e5b75505Sopenharmony_ci
353e5b75505Sopenharmony_civoid p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p)
354e5b75505Sopenharmony_ci{
355e5b75505Sopenharmony_ci	/* P2P Interface */
356e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_INTERFACE);
357e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, ETH_ALEN + 1 + ETH_ALEN);
358e5b75505Sopenharmony_ci	/* P2P Device address */
359e5b75505Sopenharmony_ci	wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
360e5b75505Sopenharmony_ci	/*
361e5b75505Sopenharmony_ci	 * FIX: Fetch interface address list from driver. Do not include
362e5b75505Sopenharmony_ci	 * the P2P Device address if it is never used as interface address.
363e5b75505Sopenharmony_ci	 */
364e5b75505Sopenharmony_ci	/* P2P Interface Address Count */
365e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 1);
366e5b75505Sopenharmony_ci	wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
367e5b75505Sopenharmony_ci}
368e5b75505Sopenharmony_ci
369e5b75505Sopenharmony_ci
370e5b75505Sopenharmony_civoid p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
371e5b75505Sopenharmony_ci				    u8 oper_class, u8 channel,
372e5b75505Sopenharmony_ci				    enum p2p_role_indication role)
373e5b75505Sopenharmony_ci{
374e5b75505Sopenharmony_ci	/* OOB Group Owner Negotiation Channel */
375e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_OOB_GO_NEG_CHANNEL);
376e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 6);
377e5b75505Sopenharmony_ci	wpabuf_put_data(buf, country, 3);
378e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, oper_class); /* Operating Class */
379e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, channel); /* Channel Number */
380e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, (u8) role); /* Role indication */
381e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * OOB GO Negotiation Channel: Operating "
382e5b75505Sopenharmony_ci		   "Class %u Channel %u Role %d",
383e5b75505Sopenharmony_ci		   oper_class, channel, role);
384e5b75505Sopenharmony_ci}
385e5b75505Sopenharmony_ci
386e5b75505Sopenharmony_ci
387e5b75505Sopenharmony_civoid p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p)
388e5b75505Sopenharmony_ci{
389e5b75505Sopenharmony_ci	if (!p2p)
390e5b75505Sopenharmony_ci		return;
391e5b75505Sopenharmony_ci
392e5b75505Sopenharmony_ci	/* Service Hash */
393e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH);
394e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, p2p->p2ps_seek_count * P2PS_HASH_LEN);
395e5b75505Sopenharmony_ci	wpabuf_put_data(buf, p2p->p2ps_seek_hash,
396e5b75505Sopenharmony_ci			p2p->p2ps_seek_count * P2PS_HASH_LEN);
397e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash",
398e5b75505Sopenharmony_ci		    p2p->p2ps_seek_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
399e5b75505Sopenharmony_ci}
400e5b75505Sopenharmony_ci
401e5b75505Sopenharmony_ci
402e5b75505Sopenharmony_civoid p2p_buf_add_session_info(struct wpabuf *buf, const char *info)
403e5b75505Sopenharmony_ci{
404e5b75505Sopenharmony_ci	size_t info_len = 0;
405e5b75505Sopenharmony_ci
406e5b75505Sopenharmony_ci	if (info && info[0])
407e5b75505Sopenharmony_ci		info_len = os_strlen(info);
408e5b75505Sopenharmony_ci
409e5b75505Sopenharmony_ci	/* Session Information Data Info */
410e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_SESSION_INFORMATION_DATA);
411e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, (u16) info_len);
412e5b75505Sopenharmony_ci
413e5b75505Sopenharmony_ci	if (info) {
414e5b75505Sopenharmony_ci		wpabuf_put_data(buf, info, info_len);
415e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: * Session Info Data (%s)", info);
416e5b75505Sopenharmony_ci	}
417e5b75505Sopenharmony_ci}
418e5b75505Sopenharmony_ci
419e5b75505Sopenharmony_ci
420e5b75505Sopenharmony_civoid p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap)
421e5b75505Sopenharmony_ci{
422e5b75505Sopenharmony_ci	/* Connection Capability Info */
423e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_CONNECTION_CAPABILITY);
424e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, 1);
425e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, connection_cap);
426e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
427e5b75505Sopenharmony_ci		   connection_cap);
428e5b75505Sopenharmony_ci}
429e5b75505Sopenharmony_ci
430e5b75505Sopenharmony_ci
431e5b75505Sopenharmony_civoid p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac)
432e5b75505Sopenharmony_ci{
433e5b75505Sopenharmony_ci	if (!buf || !mac)
434e5b75505Sopenharmony_ci		return;
435e5b75505Sopenharmony_ci
436e5b75505Sopenharmony_ci	/* Advertisement ID Info */
437e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_ADVERTISEMENT_ID);
438e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
439e5b75505Sopenharmony_ci	wpabuf_put_le32(buf, id);
440e5b75505Sopenharmony_ci	wpabuf_put_data(buf, mac, ETH_ALEN);
441e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID (%x) " MACSTR,
442e5b75505Sopenharmony_ci		   id, MAC2STR(mac));
443e5b75505Sopenharmony_ci}
444e5b75505Sopenharmony_ci
445e5b75505Sopenharmony_ci
446e5b75505Sopenharmony_cistatic int p2ps_wildcard_hash(struct p2p_data *p2p,
447e5b75505Sopenharmony_ci			      const u8 *hash, u8 hash_count)
448e5b75505Sopenharmony_ci{
449e5b75505Sopenharmony_ci	u8 i;
450e5b75505Sopenharmony_ci	const u8 *test = hash;
451e5b75505Sopenharmony_ci
452e5b75505Sopenharmony_ci	for (i = 0; i < hash_count; i++) {
453e5b75505Sopenharmony_ci		if (os_memcmp(test, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
454e5b75505Sopenharmony_ci			return 1;
455e5b75505Sopenharmony_ci		test += P2PS_HASH_LEN;
456e5b75505Sopenharmony_ci	}
457e5b75505Sopenharmony_ci
458e5b75505Sopenharmony_ci	return 0;
459e5b75505Sopenharmony_ci}
460e5b75505Sopenharmony_ci
461e5b75505Sopenharmony_ci
462e5b75505Sopenharmony_cistatic int p2p_wfa_service_adv(struct p2p_data *p2p)
463e5b75505Sopenharmony_ci{
464e5b75505Sopenharmony_ci	struct p2ps_advertisement *adv;
465e5b75505Sopenharmony_ci
466e5b75505Sopenharmony_ci	for (adv = p2p->p2ps_adv_list; adv; adv = adv->next) {
467e5b75505Sopenharmony_ci		if (os_strncmp(adv->svc_name, P2PS_WILD_HASH_STR,
468e5b75505Sopenharmony_ci			       os_strlen(P2PS_WILD_HASH_STR)) == 0)
469e5b75505Sopenharmony_ci			return 1;
470e5b75505Sopenharmony_ci	}
471e5b75505Sopenharmony_ci
472e5b75505Sopenharmony_ci	return 0;
473e5b75505Sopenharmony_ci}
474e5b75505Sopenharmony_ci
475e5b75505Sopenharmony_ci
476e5b75505Sopenharmony_cistatic int p2p_buf_add_service_info(struct wpabuf *buf, struct p2p_data *p2p,
477e5b75505Sopenharmony_ci				    u32 adv_id, u16 config_methods,
478e5b75505Sopenharmony_ci				    const char *svc_name, u8 **ie_len, u8 **pos,
479e5b75505Sopenharmony_ci				    size_t *total_len, u8 *attr_len)
480e5b75505Sopenharmony_ci{
481e5b75505Sopenharmony_ci	size_t svc_len;
482e5b75505Sopenharmony_ci	size_t remaining;
483e5b75505Sopenharmony_ci	size_t info_len;
484e5b75505Sopenharmony_ci
485e5b75505Sopenharmony_ci	p2p_dbg(p2p, "Add service info for %s (adv_id=%u)", svc_name, adv_id);
486e5b75505Sopenharmony_ci	svc_len = os_strlen(svc_name);
487e5b75505Sopenharmony_ci	info_len = sizeof(adv_id) + sizeof(config_methods) + sizeof(u8) +
488e5b75505Sopenharmony_ci		svc_len;
489e5b75505Sopenharmony_ci
490e5b75505Sopenharmony_ci	if (info_len + *total_len > MAX_SVC_ADV_LEN) {
491e5b75505Sopenharmony_ci		p2p_dbg(p2p,
492e5b75505Sopenharmony_ci			"Unsufficient buffer, failed to add advertised service info");
493e5b75505Sopenharmony_ci		return -1;
494e5b75505Sopenharmony_ci	}
495e5b75505Sopenharmony_ci
496e5b75505Sopenharmony_ci	if (svc_len > 255) {
497e5b75505Sopenharmony_ci		p2p_dbg(p2p,
498e5b75505Sopenharmony_ci			"Invalid service name length (%u bytes), failed to add advertised service info",
499e5b75505Sopenharmony_ci			(unsigned int) svc_len);
500e5b75505Sopenharmony_ci		return -1;
501e5b75505Sopenharmony_ci	}
502e5b75505Sopenharmony_ci
503e5b75505Sopenharmony_ci	if (*ie_len) {
504e5b75505Sopenharmony_ci		int ie_data_len = (*pos - *ie_len) - 1;
505e5b75505Sopenharmony_ci
506e5b75505Sopenharmony_ci		if (ie_data_len < 0 || ie_data_len > 255) {
507e5b75505Sopenharmony_ci			p2p_dbg(p2p,
508e5b75505Sopenharmony_ci				"Invalid IE length, failed to add advertised service info");
509e5b75505Sopenharmony_ci			return -1;
510e5b75505Sopenharmony_ci		}
511e5b75505Sopenharmony_ci		remaining = 255 - ie_data_len;
512e5b75505Sopenharmony_ci	} else {
513e5b75505Sopenharmony_ci		/*
514e5b75505Sopenharmony_ci		 * Adding new P2P IE header takes 6 extra bytes:
515e5b75505Sopenharmony_ci		 * - 2 byte IE header (1 byte IE id and 1 byte length)
516e5b75505Sopenharmony_ci		 * - 4 bytes of IE_VENDOR_TYPE are reduced from 255 below
517e5b75505Sopenharmony_ci		 */
518e5b75505Sopenharmony_ci		*ie_len = p2p_buf_add_ie_hdr(buf);
519e5b75505Sopenharmony_ci		remaining = 255 - 4;
520e5b75505Sopenharmony_ci	}
521e5b75505Sopenharmony_ci
522e5b75505Sopenharmony_ci	if (remaining < sizeof(u32) + sizeof(u16) + sizeof(u8)) {
523e5b75505Sopenharmony_ci		/*
524e5b75505Sopenharmony_ci		 * Split adv_id, config_methods, and svc_name_len between two
525e5b75505Sopenharmony_ci		 * IEs.
526e5b75505Sopenharmony_ci		 */
527e5b75505Sopenharmony_ci		size_t front = remaining;
528e5b75505Sopenharmony_ci		size_t back = sizeof(u32) + sizeof(u16) + sizeof(u8) - front;
529e5b75505Sopenharmony_ci		u8 holder[sizeof(u32) + sizeof(u16) + sizeof(u8)];
530e5b75505Sopenharmony_ci
531e5b75505Sopenharmony_ci		WPA_PUT_LE32(holder, adv_id);
532e5b75505Sopenharmony_ci		WPA_PUT_BE16(&holder[sizeof(u32)], config_methods);
533e5b75505Sopenharmony_ci		holder[sizeof(u32) + sizeof(u16)] = svc_len;
534e5b75505Sopenharmony_ci
535e5b75505Sopenharmony_ci		if (front)
536e5b75505Sopenharmony_ci			wpabuf_put_data(buf, holder, front);
537e5b75505Sopenharmony_ci
538e5b75505Sopenharmony_ci		p2p_buf_update_ie_hdr(buf, *ie_len);
539e5b75505Sopenharmony_ci		*ie_len = p2p_buf_add_ie_hdr(buf);
540e5b75505Sopenharmony_ci
541e5b75505Sopenharmony_ci		wpabuf_put_data(buf, &holder[front], back);
542e5b75505Sopenharmony_ci		remaining = 255 - 4 - (sizeof(u32) + sizeof(u16) + sizeof(u8)) -
543e5b75505Sopenharmony_ci			back;
544e5b75505Sopenharmony_ci	} else {
545e5b75505Sopenharmony_ci		wpabuf_put_le32(buf, adv_id);
546e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, config_methods);
547e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, svc_len);
548e5b75505Sopenharmony_ci		remaining -= sizeof(adv_id) + sizeof(config_methods) +
549e5b75505Sopenharmony_ci			sizeof(u8);
550e5b75505Sopenharmony_ci	}
551e5b75505Sopenharmony_ci
552e5b75505Sopenharmony_ci	if (remaining < svc_len) {
553e5b75505Sopenharmony_ci		/* split svc_name between two or three IEs */
554e5b75505Sopenharmony_ci		size_t front = remaining;
555e5b75505Sopenharmony_ci		size_t back = svc_len - front;
556e5b75505Sopenharmony_ci
557e5b75505Sopenharmony_ci		if (front)
558e5b75505Sopenharmony_ci			wpabuf_put_data(buf, svc_name, front);
559e5b75505Sopenharmony_ci
560e5b75505Sopenharmony_ci		p2p_buf_update_ie_hdr(buf, *ie_len);
561e5b75505Sopenharmony_ci		*ie_len = p2p_buf_add_ie_hdr(buf);
562e5b75505Sopenharmony_ci
563e5b75505Sopenharmony_ci		/* In rare cases, we must split across 3 attributes */
564e5b75505Sopenharmony_ci		if (back > 255 - 4) {
565e5b75505Sopenharmony_ci			wpabuf_put_data(buf, &svc_name[front], 255 - 4);
566e5b75505Sopenharmony_ci			back -= 255 - 4;
567e5b75505Sopenharmony_ci			front += 255 - 4;
568e5b75505Sopenharmony_ci			p2p_buf_update_ie_hdr(buf, *ie_len);
569e5b75505Sopenharmony_ci			*ie_len = p2p_buf_add_ie_hdr(buf);
570e5b75505Sopenharmony_ci		}
571e5b75505Sopenharmony_ci
572e5b75505Sopenharmony_ci		wpabuf_put_data(buf, &svc_name[front], back);
573e5b75505Sopenharmony_ci		remaining = 255 - 4 - back;
574e5b75505Sopenharmony_ci	} else {
575e5b75505Sopenharmony_ci		wpabuf_put_data(buf, svc_name, svc_len);
576e5b75505Sopenharmony_ci		remaining -= svc_len;
577e5b75505Sopenharmony_ci	}
578e5b75505Sopenharmony_ci
579e5b75505Sopenharmony_ci	p2p_buf_update_ie_hdr(buf, *ie_len);
580e5b75505Sopenharmony_ci
581e5b75505Sopenharmony_ci	/* set *ie_len to NULL if a new IE has to be added on the next call */
582e5b75505Sopenharmony_ci	if (!remaining)
583e5b75505Sopenharmony_ci		*ie_len = NULL;
584e5b75505Sopenharmony_ci
585e5b75505Sopenharmony_ci	/* set *pos to point to the next byte to update */
586e5b75505Sopenharmony_ci	*pos = wpabuf_put(buf, 0);
587e5b75505Sopenharmony_ci
588e5b75505Sopenharmony_ci	*total_len += info_len;
589e5b75505Sopenharmony_ci	WPA_PUT_LE16(attr_len, (u16) *total_len);
590e5b75505Sopenharmony_ci	return 0;
591e5b75505Sopenharmony_ci}
592e5b75505Sopenharmony_ci
593e5b75505Sopenharmony_ci
594e5b75505Sopenharmony_civoid p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
595e5b75505Sopenharmony_ci				  u8 hash_count, const u8 *hash,
596e5b75505Sopenharmony_ci				  struct p2ps_advertisement *adv_list)
597e5b75505Sopenharmony_ci{
598e5b75505Sopenharmony_ci	struct p2ps_advertisement *adv;
599e5b75505Sopenharmony_ci	int p2ps_wildcard;
600e5b75505Sopenharmony_ci	size_t total_len;
601e5b75505Sopenharmony_ci	struct wpabuf *tmp_buf = NULL;
602e5b75505Sopenharmony_ci	u8 *pos, *attr_len, *ie_len = NULL;
603e5b75505Sopenharmony_ci
604e5b75505Sopenharmony_ci	if (!adv_list || !hash || !hash_count)
605e5b75505Sopenharmony_ci		return;
606e5b75505Sopenharmony_ci
607e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "P2PS: Probe Request service hash values",
608e5b75505Sopenharmony_ci		    hash, hash_count * P2PS_HASH_LEN);
609e5b75505Sopenharmony_ci	p2ps_wildcard = p2ps_wildcard_hash(p2p, hash, hash_count) &&
610e5b75505Sopenharmony_ci		p2p_wfa_service_adv(p2p);
611e5b75505Sopenharmony_ci
612e5b75505Sopenharmony_ci	/* Allocate temp buffer, allowing for overflow of 1 instance */
613e5b75505Sopenharmony_ci	tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN);
614e5b75505Sopenharmony_ci	if (!tmp_buf)
615e5b75505Sopenharmony_ci		return;
616e5b75505Sopenharmony_ci
617e5b75505Sopenharmony_ci	/*
618e5b75505Sopenharmony_ci	 * Attribute data can be split into a number of IEs. Start with the
619e5b75505Sopenharmony_ci	 * first IE and the attribute headers here.
620e5b75505Sopenharmony_ci	 */
621e5b75505Sopenharmony_ci	ie_len = p2p_buf_add_ie_hdr(tmp_buf);
622e5b75505Sopenharmony_ci
623e5b75505Sopenharmony_ci	total_len = 0;
624e5b75505Sopenharmony_ci
625e5b75505Sopenharmony_ci	wpabuf_put_u8(tmp_buf, P2P_ATTR_ADVERTISED_SERVICE);
626e5b75505Sopenharmony_ci	attr_len = wpabuf_put(tmp_buf, sizeof(u16));
627e5b75505Sopenharmony_ci	WPA_PUT_LE16(attr_len, (u16) total_len);
628e5b75505Sopenharmony_ci	p2p_buf_update_ie_hdr(tmp_buf, ie_len);
629e5b75505Sopenharmony_ci	pos = wpabuf_put(tmp_buf, 0);
630e5b75505Sopenharmony_ci
631e5b75505Sopenharmony_ci	if (p2ps_wildcard) {
632e5b75505Sopenharmony_ci		/* org.wi-fi.wfds match found */
633e5b75505Sopenharmony_ci		p2p_buf_add_service_info(tmp_buf, p2p, 0, 0, P2PS_WILD_HASH_STR,
634e5b75505Sopenharmony_ci					 &ie_len, &pos, &total_len, attr_len);
635e5b75505Sopenharmony_ci	}
636e5b75505Sopenharmony_ci
637e5b75505Sopenharmony_ci	/* add advertised service info of matching services */
638e5b75505Sopenharmony_ci	for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN;
639e5b75505Sopenharmony_ci	     adv = adv->next) {
640e5b75505Sopenharmony_ci		const u8 *test = hash;
641e5b75505Sopenharmony_ci		u8 i;
642e5b75505Sopenharmony_ci
643e5b75505Sopenharmony_ci		for (i = 0; i < hash_count; i++) {
644e5b75505Sopenharmony_ci			/* exact name hash match */
645e5b75505Sopenharmony_ci			if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0 &&
646e5b75505Sopenharmony_ci			    p2p_buf_add_service_info(tmp_buf, p2p,
647e5b75505Sopenharmony_ci						     adv->id,
648e5b75505Sopenharmony_ci						     adv->config_methods,
649e5b75505Sopenharmony_ci						     adv->svc_name,
650e5b75505Sopenharmony_ci						     &ie_len, &pos,
651e5b75505Sopenharmony_ci						     &total_len,
652e5b75505Sopenharmony_ci						     attr_len))
653e5b75505Sopenharmony_ci				break;
654e5b75505Sopenharmony_ci
655e5b75505Sopenharmony_ci			test += P2PS_HASH_LEN;
656e5b75505Sopenharmony_ci		}
657e5b75505Sopenharmony_ci	}
658e5b75505Sopenharmony_ci
659e5b75505Sopenharmony_ci	if (total_len)
660e5b75505Sopenharmony_ci		wpabuf_put_buf(buf, tmp_buf);
661e5b75505Sopenharmony_ci	wpabuf_free(tmp_buf);
662e5b75505Sopenharmony_ci}
663e5b75505Sopenharmony_ci
664e5b75505Sopenharmony_ci
665e5b75505Sopenharmony_civoid p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac)
666e5b75505Sopenharmony_ci{
667e5b75505Sopenharmony_ci	if (!buf || !mac)
668e5b75505Sopenharmony_ci		return;
669e5b75505Sopenharmony_ci
670e5b75505Sopenharmony_ci	/* Session ID Info */
671e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_SESSION_ID);
672e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
673e5b75505Sopenharmony_ci	wpabuf_put_le32(buf, id);
674e5b75505Sopenharmony_ci	wpabuf_put_data(buf, mac, ETH_ALEN);
675e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Session ID Info (%x) " MACSTR,
676e5b75505Sopenharmony_ci		   id, MAC2STR(mac));
677e5b75505Sopenharmony_ci}
678e5b75505Sopenharmony_ci
679e5b75505Sopenharmony_ci
680e5b75505Sopenharmony_civoid p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len, const u8 *mask)
681e5b75505Sopenharmony_ci{
682e5b75505Sopenharmony_ci	if (!buf || !len || !mask)
683e5b75505Sopenharmony_ci		return;
684e5b75505Sopenharmony_ci
685e5b75505Sopenharmony_ci	/* Feature Capability */
686e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_FEATURE_CAPABILITY);
687e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, len);
688e5b75505Sopenharmony_ci	wpabuf_put_data(buf, mask, len);
689e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * Feature Capability (%d)", len);
690e5b75505Sopenharmony_ci}
691e5b75505Sopenharmony_ci
692e5b75505Sopenharmony_ci
693e5b75505Sopenharmony_civoid p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
694e5b75505Sopenharmony_ci				       const u8 *ssid, size_t ssid_len)
695e5b75505Sopenharmony_ci{
696e5b75505Sopenharmony_ci	/* P2P Group ID */
697e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, P2P_ATTR_PERSISTENT_GROUP);
698e5b75505Sopenharmony_ci	wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
699e5b75505Sopenharmony_ci	wpabuf_put_data(buf, dev_addr, ETH_ALEN);
700e5b75505Sopenharmony_ci	wpabuf_put_data(buf, ssid, ssid_len);
701e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
702e5b75505Sopenharmony_ci		   MAC2STR(dev_addr));
703e5b75505Sopenharmony_ci}
704e5b75505Sopenharmony_ci
705e5b75505Sopenharmony_ci
706e5b75505Sopenharmony_cistatic int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
707e5b75505Sopenharmony_ci			      const char *val)
708e5b75505Sopenharmony_ci{
709e5b75505Sopenharmony_ci	size_t len;
710e5b75505Sopenharmony_ci
711e5b75505Sopenharmony_ci	len = val ? os_strlen(val) : 0;
712e5b75505Sopenharmony_ci	if (wpabuf_tailroom(buf) < 4 + len)
713e5b75505Sopenharmony_ci		return -1;
714e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, attr);
715e5b75505Sopenharmony_ci#ifndef CONFIG_WPS_STRICT
716e5b75505Sopenharmony_ci	if (len == 0) {
717e5b75505Sopenharmony_ci		/*
718e5b75505Sopenharmony_ci		 * Some deployed WPS implementations fail to parse zeor-length
719e5b75505Sopenharmony_ci		 * attributes. As a workaround, send a space character if the
720e5b75505Sopenharmony_ci		 * device attribute string is empty.
721e5b75505Sopenharmony_ci		 */
722e5b75505Sopenharmony_ci		if (wpabuf_tailroom(buf) < 3)
723e5b75505Sopenharmony_ci			return -1;
724e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, 1);
725e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, ' ');
726e5b75505Sopenharmony_ci		return 0;
727e5b75505Sopenharmony_ci	}
728e5b75505Sopenharmony_ci#endif /* CONFIG_WPS_STRICT */
729e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, len);
730e5b75505Sopenharmony_ci	if (val)
731e5b75505Sopenharmony_ci		wpabuf_put_data(buf, val, len);
732e5b75505Sopenharmony_ci	return 0;
733e5b75505Sopenharmony_ci}
734e5b75505Sopenharmony_ci
735e5b75505Sopenharmony_ci
736e5b75505Sopenharmony_ciint p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
737e5b75505Sopenharmony_ci		     int all_attr)
738e5b75505Sopenharmony_ci{
739e5b75505Sopenharmony_ci	u8 *len;
740e5b75505Sopenharmony_ci	int i;
741e5b75505Sopenharmony_ci
742e5b75505Sopenharmony_ci	if (wpabuf_tailroom(buf) < 6)
743e5b75505Sopenharmony_ci		return -1;
744e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
745e5b75505Sopenharmony_ci	len = wpabuf_put(buf, 1);
746e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
747e5b75505Sopenharmony_ci
748e5b75505Sopenharmony_ci	if (wps_build_version(buf) < 0)
749e5b75505Sopenharmony_ci		return -1;
750e5b75505Sopenharmony_ci
751e5b75505Sopenharmony_ci	if (all_attr) {
752e5b75505Sopenharmony_ci		if (wpabuf_tailroom(buf) < 5)
753e5b75505Sopenharmony_ci			return -1;
754e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, ATTR_WPS_STATE);
755e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, 1);
756e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
757e5b75505Sopenharmony_ci	}
758e5b75505Sopenharmony_ci
759e5b75505Sopenharmony_ci	if (pw_id >= 0) {
760e5b75505Sopenharmony_ci		if (wpabuf_tailroom(buf) < 6)
761e5b75505Sopenharmony_ci			return -1;
762e5b75505Sopenharmony_ci		/* Device Password ID */
763e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
764e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, 2);
765e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d",
766e5b75505Sopenharmony_ci			   pw_id);
767e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, pw_id);
768e5b75505Sopenharmony_ci	}
769e5b75505Sopenharmony_ci
770e5b75505Sopenharmony_ci	if (all_attr) {
771e5b75505Sopenharmony_ci		if (wpabuf_tailroom(buf) < 5)
772e5b75505Sopenharmony_ci			return -1;
773e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
774e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, 1);
775e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
776e5b75505Sopenharmony_ci
777e5b75505Sopenharmony_ci		if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 ||
778e5b75505Sopenharmony_ci		    p2p_add_wps_string(buf, ATTR_MANUFACTURER,
779e5b75505Sopenharmony_ci				       p2p->cfg->manufacturer) < 0 ||
780e5b75505Sopenharmony_ci		    p2p_add_wps_string(buf, ATTR_MODEL_NAME,
781e5b75505Sopenharmony_ci				       p2p->cfg->model_name) < 0 ||
782e5b75505Sopenharmony_ci		    p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
783e5b75505Sopenharmony_ci				       p2p->cfg->model_number) < 0 ||
784e5b75505Sopenharmony_ci		    p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
785e5b75505Sopenharmony_ci				       p2p->cfg->serial_number) < 0)
786e5b75505Sopenharmony_ci			return -1;
787e5b75505Sopenharmony_ci
788e5b75505Sopenharmony_ci		if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN)
789e5b75505Sopenharmony_ci			return -1;
790e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
791e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
792e5b75505Sopenharmony_ci		wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
793e5b75505Sopenharmony_ci
794e5b75505Sopenharmony_ci		if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name)
795e5b75505Sopenharmony_ci		    < 0)
796e5b75505Sopenharmony_ci			return -1;
797e5b75505Sopenharmony_ci
798e5b75505Sopenharmony_ci		if (wpabuf_tailroom(buf) < 6)
799e5b75505Sopenharmony_ci			return -1;
800e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
801e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, 2);
802e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, p2p->cfg->config_methods);
803e5b75505Sopenharmony_ci	}
804e5b75505Sopenharmony_ci
805e5b75505Sopenharmony_ci	if (wps_build_wfa_ext(buf, 0, NULL, 0, 0) < 0)
806e5b75505Sopenharmony_ci		return -1;
807e5b75505Sopenharmony_ci
808e5b75505Sopenharmony_ci	if (all_attr && p2p->cfg->num_sec_dev_types) {
809e5b75505Sopenharmony_ci		if (wpabuf_tailroom(buf) <
810e5b75505Sopenharmony_ci		    4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types)
811e5b75505Sopenharmony_ci			return -1;
812e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
813e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
814e5b75505Sopenharmony_ci				p2p->cfg->num_sec_dev_types);
815e5b75505Sopenharmony_ci		wpabuf_put_data(buf, p2p->cfg->sec_dev_type,
816e5b75505Sopenharmony_ci				WPS_DEV_TYPE_LEN *
817e5b75505Sopenharmony_ci				p2p->cfg->num_sec_dev_types);
818e5b75505Sopenharmony_ci	}
819e5b75505Sopenharmony_ci
820e5b75505Sopenharmony_ci	/* Add the WPS vendor extensions */
821e5b75505Sopenharmony_ci	for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
822e5b75505Sopenharmony_ci		if (p2p->wps_vendor_ext[i] == NULL)
823e5b75505Sopenharmony_ci			break;
824e5b75505Sopenharmony_ci		if (wpabuf_tailroom(buf) <
825e5b75505Sopenharmony_ci		    4 + wpabuf_len(p2p->wps_vendor_ext[i]))
826e5b75505Sopenharmony_ci			continue;
827e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, ATTR_VENDOR_EXT);
828e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, wpabuf_len(p2p->wps_vendor_ext[i]));
829e5b75505Sopenharmony_ci		wpabuf_put_buf(buf, p2p->wps_vendor_ext[i]);
830e5b75505Sopenharmony_ci	}
831e5b75505Sopenharmony_ci
832e5b75505Sopenharmony_ci	p2p_buf_update_ie_hdr(buf, len);
833e5b75505Sopenharmony_ci
834e5b75505Sopenharmony_ci	return 0;
835e5b75505Sopenharmony_ci}
836