1f05cddf9SRui Paulo /*
2f05cddf9SRui Paulo * P2P - IE builder
3f05cddf9SRui Paulo * Copyright (c) 2009-2010, Atheros Communications
4f05cddf9SRui Paulo *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
7f05cddf9SRui Paulo */
8f05cddf9SRui Paulo
9f05cddf9SRui Paulo #include "includes.h"
10f05cddf9SRui Paulo
11f05cddf9SRui Paulo #include "common.h"
12f05cddf9SRui Paulo #include "common/ieee802_11_defs.h"
13*a90b9d01SCy Schubert #include "common/ieee802_11_common.h"
14325151a3SRui Paulo #include "common/qca-vendor.h"
15f05cddf9SRui Paulo #include "wps/wps_i.h"
16f05cddf9SRui Paulo #include "p2p_i.h"
17f05cddf9SRui Paulo
18f05cddf9SRui Paulo
p2p_buf_add_action_hdr(struct wpabuf * buf,u8 subtype,u8 dialog_token)19f05cddf9SRui Paulo void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token)
20f05cddf9SRui Paulo {
21f05cddf9SRui Paulo wpabuf_put_u8(buf, WLAN_ACTION_VENDOR_SPECIFIC);
225b9c547cSRui Paulo wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
23f05cddf9SRui Paulo
24f05cddf9SRui Paulo wpabuf_put_u8(buf, subtype); /* OUI Subtype */
25f05cddf9SRui Paulo wpabuf_put_u8(buf, dialog_token);
26f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token);
27f05cddf9SRui Paulo }
28f05cddf9SRui Paulo
29f05cddf9SRui Paulo
p2p_buf_add_public_action_hdr(struct wpabuf * buf,u8 subtype,u8 dialog_token)30f05cddf9SRui Paulo void p2p_buf_add_public_action_hdr(struct wpabuf *buf, u8 subtype,
31f05cddf9SRui Paulo u8 dialog_token)
32f05cddf9SRui Paulo {
33f05cddf9SRui Paulo wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
34f05cddf9SRui Paulo wpabuf_put_u8(buf, WLAN_PA_VENDOR_SPECIFIC);
355b9c547cSRui Paulo wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
36f05cddf9SRui Paulo
37f05cddf9SRui Paulo wpabuf_put_u8(buf, subtype); /* OUI Subtype */
38f05cddf9SRui Paulo wpabuf_put_u8(buf, dialog_token);
39f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Dialog Token: %d", dialog_token);
40f05cddf9SRui Paulo }
41f05cddf9SRui Paulo
42f05cddf9SRui Paulo
p2p_buf_add_ie_hdr(struct wpabuf * buf)43f05cddf9SRui Paulo u8 * p2p_buf_add_ie_hdr(struct wpabuf *buf)
44f05cddf9SRui Paulo {
45f05cddf9SRui Paulo u8 *len;
46f05cddf9SRui Paulo
47f05cddf9SRui Paulo /* P2P IE header */
48f05cddf9SRui Paulo wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
49f05cddf9SRui Paulo len = wpabuf_put(buf, 1); /* IE length to be filled */
505b9c547cSRui Paulo wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE);
51f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * P2P IE header");
52f05cddf9SRui Paulo return len;
53f05cddf9SRui Paulo }
54f05cddf9SRui Paulo
55f05cddf9SRui Paulo
p2p_buf_update_ie_hdr(struct wpabuf * buf,u8 * len)56f05cddf9SRui Paulo void p2p_buf_update_ie_hdr(struct wpabuf *buf, u8 *len)
57f05cddf9SRui Paulo {
58f05cddf9SRui Paulo /* Update P2P IE Length */
59f05cddf9SRui Paulo *len = (u8 *) wpabuf_put(buf, 0) - len - 1;
60f05cddf9SRui Paulo }
61f05cddf9SRui Paulo
62f05cddf9SRui Paulo
p2p_buf_add_capability(struct wpabuf * buf,u8 dev_capab,u8 group_capab)63f05cddf9SRui Paulo void p2p_buf_add_capability(struct wpabuf *buf, u8 dev_capab, u8 group_capab)
64f05cddf9SRui Paulo {
65f05cddf9SRui Paulo /* P2P Capability */
66f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_CAPABILITY);
67f05cddf9SRui Paulo wpabuf_put_le16(buf, 2);
68f05cddf9SRui Paulo wpabuf_put_u8(buf, dev_capab); /* Device Capabilities */
69f05cddf9SRui Paulo wpabuf_put_u8(buf, group_capab); /* Group Capabilities */
70f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Capability dev=%02x group=%02x",
71f05cddf9SRui Paulo dev_capab, group_capab);
72f05cddf9SRui Paulo }
73f05cddf9SRui Paulo
74f05cddf9SRui Paulo
p2p_buf_add_go_intent(struct wpabuf * buf,u8 go_intent)75f05cddf9SRui Paulo void p2p_buf_add_go_intent(struct wpabuf *buf, u8 go_intent)
76f05cddf9SRui Paulo {
77f05cddf9SRui Paulo /* Group Owner Intent */
78f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_GROUP_OWNER_INTENT);
79f05cddf9SRui Paulo wpabuf_put_le16(buf, 1);
80f05cddf9SRui Paulo wpabuf_put_u8(buf, go_intent);
81f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * GO Intent: Intent %u Tie breaker %u",
82f05cddf9SRui Paulo go_intent >> 1, go_intent & 0x01);
83f05cddf9SRui Paulo }
84f05cddf9SRui Paulo
85f05cddf9SRui Paulo
p2p_buf_add_listen_channel(struct wpabuf * buf,const char * country,u8 reg_class,u8 channel)86f05cddf9SRui Paulo void p2p_buf_add_listen_channel(struct wpabuf *buf, const char *country,
87f05cddf9SRui Paulo u8 reg_class, u8 channel)
88f05cddf9SRui Paulo {
89f05cddf9SRui Paulo /* Listen Channel */
90f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_LISTEN_CHANNEL);
91f05cddf9SRui Paulo wpabuf_put_le16(buf, 5);
92f05cddf9SRui Paulo wpabuf_put_data(buf, country, 3);
93f05cddf9SRui Paulo wpabuf_put_u8(buf, reg_class); /* Regulatory Class */
94f05cddf9SRui Paulo wpabuf_put_u8(buf, channel); /* Channel Number */
95f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Listen Channel: Regulatory Class %u "
96f05cddf9SRui Paulo "Channel %u", reg_class, channel);
97f05cddf9SRui Paulo }
98f05cddf9SRui Paulo
99f05cddf9SRui Paulo
p2p_buf_add_operating_channel(struct wpabuf * buf,const char * country,u8 reg_class,u8 channel)100f05cddf9SRui Paulo void p2p_buf_add_operating_channel(struct wpabuf *buf, const char *country,
101f05cddf9SRui Paulo u8 reg_class, u8 channel)
102f05cddf9SRui Paulo {
103f05cddf9SRui Paulo /* Operating Channel */
104f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_OPERATING_CHANNEL);
105f05cddf9SRui Paulo wpabuf_put_le16(buf, 5);
106f05cddf9SRui Paulo wpabuf_put_data(buf, country, 3);
107f05cddf9SRui Paulo wpabuf_put_u8(buf, reg_class); /* Regulatory Class */
108f05cddf9SRui Paulo wpabuf_put_u8(buf, channel); /* Channel Number */
109f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Operating Channel: Regulatory Class %u "
110f05cddf9SRui Paulo "Channel %u", reg_class, channel);
111f05cddf9SRui Paulo }
112f05cddf9SRui Paulo
113f05cddf9SRui Paulo
p2p_buf_add_pref_channel_list(struct wpabuf * buf,const struct weighted_pcl * pref_freq_list,unsigned int size)114325151a3SRui Paulo void p2p_buf_add_pref_channel_list(struct wpabuf *buf,
115*a90b9d01SCy Schubert const struct weighted_pcl *pref_freq_list,
116325151a3SRui Paulo unsigned int size)
117325151a3SRui Paulo {
118325151a3SRui Paulo unsigned int i, count = 0;
119325151a3SRui Paulo u8 op_class, op_channel;
120325151a3SRui Paulo
121325151a3SRui Paulo if (!size)
122325151a3SRui Paulo return;
123325151a3SRui Paulo
124325151a3SRui Paulo /*
125325151a3SRui Paulo * First, determine the number of P2P supported channels in the
126325151a3SRui Paulo * pref_freq_list returned from driver. This is needed for calculations
127325151a3SRui Paulo * of the vendor IE size.
128325151a3SRui Paulo */
129325151a3SRui Paulo for (i = 0; i < size; i++) {
130*a90b9d01SCy Schubert if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class,
131*a90b9d01SCy Schubert &op_channel) == 0 &&
132*a90b9d01SCy Schubert !(pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE))
133325151a3SRui Paulo count++;
134325151a3SRui Paulo }
135325151a3SRui Paulo
136325151a3SRui Paulo wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
137325151a3SRui Paulo wpabuf_put_u8(buf, 4 + count * sizeof(u16));
138325151a3SRui Paulo wpabuf_put_be24(buf, OUI_QCA);
139325151a3SRui Paulo wpabuf_put_u8(buf, QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST);
140325151a3SRui Paulo for (i = 0; i < size; i++) {
141*a90b9d01SCy Schubert if (p2p_freq_to_channel(pref_freq_list[i].freq, &op_class,
142*a90b9d01SCy Schubert &op_channel) < 0 ||
143*a90b9d01SCy Schubert (pref_freq_list[i].flag & WEIGHTED_PCL_EXCLUDE)) {
144325151a3SRui Paulo wpa_printf(MSG_DEBUG, "Unsupported frequency %u MHz",
145*a90b9d01SCy Schubert pref_freq_list[i].freq);
146325151a3SRui Paulo continue;
147325151a3SRui Paulo }
148325151a3SRui Paulo wpabuf_put_u8(buf, op_class);
149325151a3SRui Paulo wpabuf_put_u8(buf, op_channel);
150325151a3SRui Paulo }
151325151a3SRui Paulo }
152325151a3SRui Paulo
153325151a3SRui Paulo
p2p_buf_add_channel_list(struct wpabuf * buf,const char * country,struct p2p_channels * chan,bool is_6ghz_capab)154f05cddf9SRui Paulo void p2p_buf_add_channel_list(struct wpabuf *buf, const char *country,
155*a90b9d01SCy Schubert struct p2p_channels *chan, bool is_6ghz_capab)
156f05cddf9SRui Paulo {
157f05cddf9SRui Paulo u8 *len;
158f05cddf9SRui Paulo size_t i;
159f05cddf9SRui Paulo
160f05cddf9SRui Paulo /* Channel List */
161f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_CHANNEL_LIST);
162f05cddf9SRui Paulo len = wpabuf_put(buf, 2); /* IE length to be filled */
163f05cddf9SRui Paulo wpabuf_put_data(buf, country, 3); /* Country String */
164f05cddf9SRui Paulo
165f05cddf9SRui Paulo for (i = 0; i < chan->reg_classes; i++) {
166f05cddf9SRui Paulo struct p2p_reg_class *c = &chan->reg_class[i];
167*a90b9d01SCy Schubert
168*a90b9d01SCy Schubert if (is_6ghz_op_class(c->reg_class) && !is_6ghz_capab)
169*a90b9d01SCy Schubert continue;
170f05cddf9SRui Paulo wpabuf_put_u8(buf, c->reg_class);
171f05cddf9SRui Paulo wpabuf_put_u8(buf, c->channels);
172f05cddf9SRui Paulo wpabuf_put_data(buf, c->channel, c->channels);
173f05cddf9SRui Paulo }
174f05cddf9SRui Paulo
175f05cddf9SRui Paulo /* Update attribute length */
176f05cddf9SRui Paulo WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
177f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "P2P: * Channel List",
178f05cddf9SRui Paulo len + 2, (u8 *) wpabuf_put(buf, 0) - len - 2);
179f05cddf9SRui Paulo }
180f05cddf9SRui Paulo
181f05cddf9SRui Paulo
p2p_buf_add_status(struct wpabuf * buf,u8 status)182f05cddf9SRui Paulo void p2p_buf_add_status(struct wpabuf *buf, u8 status)
183f05cddf9SRui Paulo {
184f05cddf9SRui Paulo /* Status */
185f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_STATUS);
186f05cddf9SRui Paulo wpabuf_put_le16(buf, 1);
187f05cddf9SRui Paulo wpabuf_put_u8(buf, status);
188f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Status: %d", status);
189f05cddf9SRui Paulo }
190f05cddf9SRui Paulo
191f05cddf9SRui Paulo
p2p_buf_add_device_info(struct wpabuf * buf,struct p2p_data * p2p,struct p2p_device * peer)192f05cddf9SRui Paulo void p2p_buf_add_device_info(struct wpabuf *buf, struct p2p_data *p2p,
193f05cddf9SRui Paulo struct p2p_device *peer)
194f05cddf9SRui Paulo {
195f05cddf9SRui Paulo u8 *len;
196f05cddf9SRui Paulo u16 methods;
197f05cddf9SRui Paulo size_t nlen, i;
198f05cddf9SRui Paulo
199f05cddf9SRui Paulo /* P2P Device Info */
200f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_DEVICE_INFO);
201f05cddf9SRui Paulo len = wpabuf_put(buf, 2); /* IE length to be filled */
202f05cddf9SRui Paulo
203f05cddf9SRui Paulo /* P2P Device address */
204f05cddf9SRui Paulo wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
205f05cddf9SRui Paulo
206f05cddf9SRui Paulo /* Config Methods */
207f05cddf9SRui Paulo methods = 0;
208f05cddf9SRui Paulo if (peer && peer->wps_method != WPS_NOT_READY) {
209f05cddf9SRui Paulo if (peer->wps_method == WPS_PBC)
210f05cddf9SRui Paulo methods |= WPS_CONFIG_PUSHBUTTON;
211780fb4a2SCy Schubert else if (peer->wps_method == WPS_P2PS)
2125b9c547cSRui Paulo methods |= WPS_CONFIG_P2PS;
213780fb4a2SCy Schubert else if (peer->wps_method == WPS_PIN_DISPLAY ||
214780fb4a2SCy Schubert peer->wps_method == WPS_PIN_KEYPAD)
215780fb4a2SCy Schubert methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
216f05cddf9SRui Paulo } else if (p2p->cfg->config_methods) {
217f05cddf9SRui Paulo methods |= p2p->cfg->config_methods &
218f05cddf9SRui Paulo (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
2195b9c547cSRui Paulo WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS);
220f05cddf9SRui Paulo } else {
221f05cddf9SRui Paulo methods |= WPS_CONFIG_PUSHBUTTON;
222f05cddf9SRui Paulo methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
2235b9c547cSRui Paulo methods |= WPS_CONFIG_P2PS;
224f05cddf9SRui Paulo }
225f05cddf9SRui Paulo wpabuf_put_be16(buf, methods);
226f05cddf9SRui Paulo
227f05cddf9SRui Paulo /* Primary Device Type */
228f05cddf9SRui Paulo wpabuf_put_data(buf, p2p->cfg->pri_dev_type,
229f05cddf9SRui Paulo sizeof(p2p->cfg->pri_dev_type));
230f05cddf9SRui Paulo
231f05cddf9SRui Paulo /* Number of Secondary Device Types */
232f05cddf9SRui Paulo wpabuf_put_u8(buf, p2p->cfg->num_sec_dev_types);
233f05cddf9SRui Paulo
234f05cddf9SRui Paulo /* Secondary Device Type List */
235f05cddf9SRui Paulo for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
236f05cddf9SRui Paulo wpabuf_put_data(buf, p2p->cfg->sec_dev_type[i],
237f05cddf9SRui Paulo WPS_DEV_TYPE_LEN);
238f05cddf9SRui Paulo
239f05cddf9SRui Paulo /* Device Name */
240f05cddf9SRui Paulo nlen = p2p->cfg->dev_name ? os_strlen(p2p->cfg->dev_name) : 0;
241f05cddf9SRui Paulo wpabuf_put_be16(buf, ATTR_DEV_NAME);
242f05cddf9SRui Paulo wpabuf_put_be16(buf, nlen);
243f05cddf9SRui Paulo wpabuf_put_data(buf, p2p->cfg->dev_name, nlen);
244f05cddf9SRui Paulo
245f05cddf9SRui Paulo /* Update attribute length */
246f05cddf9SRui Paulo WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
247f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Device Info");
248f05cddf9SRui Paulo }
249f05cddf9SRui Paulo
250f05cddf9SRui Paulo
p2p_buf_add_device_id(struct wpabuf * buf,const u8 * dev_addr)251f05cddf9SRui Paulo void p2p_buf_add_device_id(struct wpabuf *buf, const u8 *dev_addr)
252f05cddf9SRui Paulo {
253f05cddf9SRui Paulo /* P2P Device ID */
254f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_DEVICE_ID);
255f05cddf9SRui Paulo wpabuf_put_le16(buf, ETH_ALEN);
256f05cddf9SRui Paulo wpabuf_put_data(buf, dev_addr, ETH_ALEN);
257f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Device ID: " MACSTR, MAC2STR(dev_addr));
258f05cddf9SRui Paulo }
259f05cddf9SRui Paulo
260f05cddf9SRui Paulo
p2p_buf_add_config_timeout(struct wpabuf * buf,u8 go_timeout,u8 client_timeout)261f05cddf9SRui Paulo void p2p_buf_add_config_timeout(struct wpabuf *buf, u8 go_timeout,
262f05cddf9SRui Paulo u8 client_timeout)
263f05cddf9SRui Paulo {
264f05cddf9SRui Paulo /* Configuration Timeout */
265f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_CONFIGURATION_TIMEOUT);
266f05cddf9SRui Paulo wpabuf_put_le16(buf, 2);
267f05cddf9SRui Paulo wpabuf_put_u8(buf, go_timeout);
268f05cddf9SRui Paulo wpabuf_put_u8(buf, client_timeout);
269f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Configuration Timeout: GO %d (*10ms) "
270f05cddf9SRui Paulo "client %d (*10ms)", go_timeout, client_timeout);
271f05cddf9SRui Paulo }
272f05cddf9SRui Paulo
273f05cddf9SRui Paulo
p2p_buf_add_intended_addr(struct wpabuf * buf,const u8 * interface_addr)274f05cddf9SRui Paulo void p2p_buf_add_intended_addr(struct wpabuf *buf, const u8 *interface_addr)
275f05cddf9SRui Paulo {
276f05cddf9SRui Paulo /* Intended P2P Interface Address */
277f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_INTENDED_INTERFACE_ADDR);
278f05cddf9SRui Paulo wpabuf_put_le16(buf, ETH_ALEN);
279f05cddf9SRui Paulo wpabuf_put_data(buf, interface_addr, ETH_ALEN);
280f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Intended P2P Interface Address " MACSTR,
281f05cddf9SRui Paulo MAC2STR(interface_addr));
282f05cddf9SRui Paulo }
283f05cddf9SRui Paulo
284f05cddf9SRui Paulo
p2p_buf_add_group_bssid(struct wpabuf * buf,const u8 * bssid)285f05cddf9SRui Paulo void p2p_buf_add_group_bssid(struct wpabuf *buf, const u8 *bssid)
286f05cddf9SRui Paulo {
287f05cddf9SRui Paulo /* P2P Group BSSID */
288f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_GROUP_BSSID);
289f05cddf9SRui Paulo wpabuf_put_le16(buf, ETH_ALEN);
290f05cddf9SRui Paulo wpabuf_put_data(buf, bssid, ETH_ALEN);
291f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * P2P Group BSSID " MACSTR,
292f05cddf9SRui Paulo MAC2STR(bssid));
293f05cddf9SRui Paulo }
294f05cddf9SRui Paulo
295f05cddf9SRui Paulo
p2p_buf_add_group_id(struct wpabuf * buf,const u8 * dev_addr,const u8 * ssid,size_t ssid_len)296f05cddf9SRui Paulo void p2p_buf_add_group_id(struct wpabuf *buf, const u8 *dev_addr,
297f05cddf9SRui Paulo const u8 *ssid, size_t ssid_len)
298f05cddf9SRui Paulo {
299f05cddf9SRui Paulo /* P2P Group ID */
300f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_GROUP_ID);
301f05cddf9SRui Paulo wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
302f05cddf9SRui Paulo wpabuf_put_data(buf, dev_addr, ETH_ALEN);
303f05cddf9SRui Paulo wpabuf_put_data(buf, ssid, ssid_len);
304f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
305f05cddf9SRui Paulo MAC2STR(dev_addr));
3065b9c547cSRui Paulo wpa_hexdump_ascii(MSG_DEBUG, "P2P: P2P Group ID SSID", ssid, ssid_len);
307f05cddf9SRui Paulo }
308f05cddf9SRui Paulo
309f05cddf9SRui Paulo
p2p_buf_add_invitation_flags(struct wpabuf * buf,u8 flags)310f05cddf9SRui Paulo void p2p_buf_add_invitation_flags(struct wpabuf *buf, u8 flags)
311f05cddf9SRui Paulo {
312f05cddf9SRui Paulo /* Invitation Flags */
313f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_INVITATION_FLAGS);
314f05cddf9SRui Paulo wpabuf_put_le16(buf, 1);
315f05cddf9SRui Paulo wpabuf_put_u8(buf, flags);
316f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Invitation Flags: bitmap 0x%x", flags);
317f05cddf9SRui Paulo }
318f05cddf9SRui Paulo
319f05cddf9SRui Paulo
p2p_buf_add_noa_desc(struct wpabuf * buf,struct p2p_noa_desc * desc)320f05cddf9SRui Paulo static void p2p_buf_add_noa_desc(struct wpabuf *buf, struct p2p_noa_desc *desc)
321f05cddf9SRui Paulo {
322f05cddf9SRui Paulo if (desc == NULL)
323f05cddf9SRui Paulo return;
324f05cddf9SRui Paulo
325f05cddf9SRui Paulo wpabuf_put_u8(buf, desc->count_type);
326f05cddf9SRui Paulo wpabuf_put_le32(buf, desc->duration);
327f05cddf9SRui Paulo wpabuf_put_le32(buf, desc->interval);
328f05cddf9SRui Paulo wpabuf_put_le32(buf, desc->start_time);
329f05cddf9SRui Paulo }
330f05cddf9SRui Paulo
331f05cddf9SRui Paulo
p2p_buf_add_noa(struct wpabuf * buf,u8 noa_index,u8 opp_ps,u8 ctwindow,struct p2p_noa_desc * desc1,struct p2p_noa_desc * desc2)332f05cddf9SRui Paulo void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
333f05cddf9SRui Paulo struct p2p_noa_desc *desc1, struct p2p_noa_desc *desc2)
334f05cddf9SRui Paulo {
335f05cddf9SRui Paulo /* Notice of Absence */
336f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_NOTICE_OF_ABSENCE);
337f05cddf9SRui Paulo wpabuf_put_le16(buf, 2 + (desc1 ? 13 : 0) + (desc2 ? 13 : 0));
338f05cddf9SRui Paulo wpabuf_put_u8(buf, noa_index);
339f05cddf9SRui Paulo wpabuf_put_u8(buf, (opp_ps ? 0x80 : 0) | (ctwindow & 0x7f));
340f05cddf9SRui Paulo p2p_buf_add_noa_desc(buf, desc1);
341f05cddf9SRui Paulo p2p_buf_add_noa_desc(buf, desc2);
342f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Notice of Absence");
343f05cddf9SRui Paulo }
344f05cddf9SRui Paulo
345f05cddf9SRui Paulo
p2p_buf_add_ext_listen_timing(struct wpabuf * buf,u16 period,u16 interval)346f05cddf9SRui Paulo void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
347f05cddf9SRui Paulo u16 interval)
348f05cddf9SRui Paulo {
349f05cddf9SRui Paulo /* Extended Listen Timing */
350f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_EXT_LISTEN_TIMING);
351f05cddf9SRui Paulo wpabuf_put_le16(buf, 4);
352f05cddf9SRui Paulo wpabuf_put_le16(buf, period);
353f05cddf9SRui Paulo wpabuf_put_le16(buf, interval);
354f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Extended Listen Timing (period %u msec "
355f05cddf9SRui Paulo "interval %u msec)", period, interval);
356f05cddf9SRui Paulo }
357f05cddf9SRui Paulo
358f05cddf9SRui Paulo
p2p_buf_add_p2p_interface(struct wpabuf * buf,struct p2p_data * p2p)359f05cddf9SRui Paulo void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p)
360f05cddf9SRui Paulo {
361f05cddf9SRui Paulo /* P2P Interface */
362f05cddf9SRui Paulo wpabuf_put_u8(buf, P2P_ATTR_INTERFACE);
363f05cddf9SRui Paulo wpabuf_put_le16(buf, ETH_ALEN + 1 + ETH_ALEN);
364f05cddf9SRui Paulo /* P2P Device address */
365f05cddf9SRui Paulo wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
366f05cddf9SRui Paulo /*
367f05cddf9SRui Paulo * FIX: Fetch interface address list from driver. Do not include
368f05cddf9SRui Paulo * the P2P Device address if it is never used as interface address.
369f05cddf9SRui Paulo */
370f05cddf9SRui Paulo /* P2P Interface Address Count */
371f05cddf9SRui Paulo wpabuf_put_u8(buf, 1);
372f05cddf9SRui Paulo wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
373f05cddf9SRui Paulo }
374f05cddf9SRui Paulo
375f05cddf9SRui Paulo
p2p_buf_add_oob_go_neg_channel(struct wpabuf * buf,const char * country,u8 oper_class,u8 channel,enum p2p_role_indication role)3765b9c547cSRui Paulo void p2p_buf_add_oob_go_neg_channel(struct wpabuf *buf, const char *country,
3775b9c547cSRui Paulo u8 oper_class, u8 channel,
3785b9c547cSRui Paulo enum p2p_role_indication role)
3795b9c547cSRui Paulo {
3805b9c547cSRui Paulo /* OOB Group Owner Negotiation Channel */
3815b9c547cSRui Paulo wpabuf_put_u8(buf, P2P_ATTR_OOB_GO_NEG_CHANNEL);
3825b9c547cSRui Paulo wpabuf_put_le16(buf, 6);
3835b9c547cSRui Paulo wpabuf_put_data(buf, country, 3);
3845b9c547cSRui Paulo wpabuf_put_u8(buf, oper_class); /* Operating Class */
3855b9c547cSRui Paulo wpabuf_put_u8(buf, channel); /* Channel Number */
3865b9c547cSRui Paulo wpabuf_put_u8(buf, (u8) role); /* Role indication */
3875b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "P2P: * OOB GO Negotiation Channel: Operating "
3885b9c547cSRui Paulo "Class %u Channel %u Role %d",
3895b9c547cSRui Paulo oper_class, channel, role);
3905b9c547cSRui Paulo }
3915b9c547cSRui Paulo
3925b9c547cSRui Paulo
p2p_buf_add_service_hash(struct wpabuf * buf,struct p2p_data * p2p)3935b9c547cSRui Paulo void p2p_buf_add_service_hash(struct wpabuf *buf, struct p2p_data *p2p)
3945b9c547cSRui Paulo {
3955b9c547cSRui Paulo if (!p2p)
3965b9c547cSRui Paulo return;
3975b9c547cSRui Paulo
3985b9c547cSRui Paulo /* Service Hash */
3995b9c547cSRui Paulo wpabuf_put_u8(buf, P2P_ATTR_SERVICE_HASH);
4005b9c547cSRui Paulo wpabuf_put_le16(buf, p2p->p2ps_seek_count * P2PS_HASH_LEN);
401325151a3SRui Paulo wpabuf_put_data(buf, p2p->p2ps_seek_hash,
4025b9c547cSRui Paulo p2p->p2ps_seek_count * P2PS_HASH_LEN);
4035b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "P2P: * Service Hash",
404325151a3SRui Paulo p2p->p2ps_seek_hash, p2p->p2ps_seek_count * P2PS_HASH_LEN);
4055b9c547cSRui Paulo }
4065b9c547cSRui Paulo
4075b9c547cSRui Paulo
p2p_buf_add_session_info(struct wpabuf * buf,const char * info)4085b9c547cSRui Paulo void p2p_buf_add_session_info(struct wpabuf *buf, const char *info)
4095b9c547cSRui Paulo {
4105b9c547cSRui Paulo size_t info_len = 0;
4115b9c547cSRui Paulo
4125b9c547cSRui Paulo if (info && info[0])
4135b9c547cSRui Paulo info_len = os_strlen(info);
4145b9c547cSRui Paulo
4155b9c547cSRui Paulo /* Session Information Data Info */
4165b9c547cSRui Paulo wpabuf_put_u8(buf, P2P_ATTR_SESSION_INFORMATION_DATA);
4175b9c547cSRui Paulo wpabuf_put_le16(buf, (u16) info_len);
4185b9c547cSRui Paulo
4195b9c547cSRui Paulo if (info) {
4205b9c547cSRui Paulo wpabuf_put_data(buf, info, info_len);
4215b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Session Info Data (%s)", info);
4225b9c547cSRui Paulo }
4235b9c547cSRui Paulo }
4245b9c547cSRui Paulo
4255b9c547cSRui Paulo
p2p_buf_add_connection_capability(struct wpabuf * buf,u8 connection_cap)4265b9c547cSRui Paulo void p2p_buf_add_connection_capability(struct wpabuf *buf, u8 connection_cap)
4275b9c547cSRui Paulo {
4285b9c547cSRui Paulo /* Connection Capability Info */
4295b9c547cSRui Paulo wpabuf_put_u8(buf, P2P_ATTR_CONNECTION_CAPABILITY);
4305b9c547cSRui Paulo wpabuf_put_le16(buf, 1);
4315b9c547cSRui Paulo wpabuf_put_u8(buf, connection_cap);
4325b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Connection Capability: 0x%x",
4335b9c547cSRui Paulo connection_cap);
4345b9c547cSRui Paulo }
4355b9c547cSRui Paulo
4365b9c547cSRui Paulo
p2p_buf_add_advertisement_id(struct wpabuf * buf,u32 id,const u8 * mac)4375b9c547cSRui Paulo void p2p_buf_add_advertisement_id(struct wpabuf *buf, u32 id, const u8 *mac)
4385b9c547cSRui Paulo {
4395b9c547cSRui Paulo if (!buf || !mac)
4405b9c547cSRui Paulo return;
4415b9c547cSRui Paulo
4425b9c547cSRui Paulo /* Advertisement ID Info */
4435b9c547cSRui Paulo wpabuf_put_u8(buf, P2P_ATTR_ADVERTISEMENT_ID);
4445b9c547cSRui Paulo wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
4455b9c547cSRui Paulo wpabuf_put_le32(buf, id);
4465b9c547cSRui Paulo wpabuf_put_data(buf, mac, ETH_ALEN);
4475b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Advertisement ID (%x) " MACSTR,
4485b9c547cSRui Paulo id, MAC2STR(mac));
4495b9c547cSRui Paulo }
4505b9c547cSRui Paulo
4515b9c547cSRui Paulo
p2ps_wildcard_hash(struct p2p_data * p2p,const u8 * hash,u8 hash_count)452325151a3SRui Paulo static int p2ps_wildcard_hash(struct p2p_data *p2p,
453325151a3SRui Paulo const u8 *hash, u8 hash_count)
454325151a3SRui Paulo {
455325151a3SRui Paulo u8 i;
456325151a3SRui Paulo const u8 *test = hash;
457325151a3SRui Paulo
458325151a3SRui Paulo for (i = 0; i < hash_count; i++) {
459325151a3SRui Paulo if (os_memcmp(test, p2p->wild_card_hash, P2PS_HASH_LEN) == 0)
460325151a3SRui Paulo return 1;
461325151a3SRui Paulo test += P2PS_HASH_LEN;
462325151a3SRui Paulo }
463325151a3SRui Paulo
464325151a3SRui Paulo return 0;
465325151a3SRui Paulo }
466325151a3SRui Paulo
467325151a3SRui Paulo
p2p_wfa_service_adv(struct p2p_data * p2p)468325151a3SRui Paulo static int p2p_wfa_service_adv(struct p2p_data *p2p)
469325151a3SRui Paulo {
470325151a3SRui Paulo struct p2ps_advertisement *adv;
471325151a3SRui Paulo
472325151a3SRui Paulo for (adv = p2p->p2ps_adv_list; adv; adv = adv->next) {
473325151a3SRui Paulo if (os_strncmp(adv->svc_name, P2PS_WILD_HASH_STR,
474325151a3SRui Paulo os_strlen(P2PS_WILD_HASH_STR)) == 0)
475325151a3SRui Paulo return 1;
476325151a3SRui Paulo }
477325151a3SRui Paulo
478325151a3SRui Paulo return 0;
479325151a3SRui Paulo }
480325151a3SRui Paulo
481325151a3SRui Paulo
p2p_buf_add_service_info(struct wpabuf * buf,struct p2p_data * p2p,u32 adv_id,u16 config_methods,const char * svc_name,u8 ** ie_len,u8 ** pos,size_t * total_len,u8 * attr_len)482325151a3SRui Paulo static int p2p_buf_add_service_info(struct wpabuf *buf, struct p2p_data *p2p,
483325151a3SRui Paulo u32 adv_id, u16 config_methods,
484325151a3SRui Paulo const char *svc_name, u8 **ie_len, u8 **pos,
485325151a3SRui Paulo size_t *total_len, u8 *attr_len)
486325151a3SRui Paulo {
487325151a3SRui Paulo size_t svc_len;
488325151a3SRui Paulo size_t remaining;
489325151a3SRui Paulo size_t info_len;
490325151a3SRui Paulo
491325151a3SRui Paulo p2p_dbg(p2p, "Add service info for %s (adv_id=%u)", svc_name, adv_id);
492325151a3SRui Paulo svc_len = os_strlen(svc_name);
493325151a3SRui Paulo info_len = sizeof(adv_id) + sizeof(config_methods) + sizeof(u8) +
494325151a3SRui Paulo svc_len;
495325151a3SRui Paulo
496325151a3SRui Paulo if (info_len + *total_len > MAX_SVC_ADV_LEN) {
497325151a3SRui Paulo p2p_dbg(p2p,
498325151a3SRui Paulo "Unsufficient buffer, failed to add advertised service info");
499325151a3SRui Paulo return -1;
500325151a3SRui Paulo }
501325151a3SRui Paulo
502325151a3SRui Paulo if (svc_len > 255) {
503325151a3SRui Paulo p2p_dbg(p2p,
504325151a3SRui Paulo "Invalid service name length (%u bytes), failed to add advertised service info",
505325151a3SRui Paulo (unsigned int) svc_len);
506325151a3SRui Paulo return -1;
507325151a3SRui Paulo }
508325151a3SRui Paulo
509325151a3SRui Paulo if (*ie_len) {
510325151a3SRui Paulo int ie_data_len = (*pos - *ie_len) - 1;
511325151a3SRui Paulo
512325151a3SRui Paulo if (ie_data_len < 0 || ie_data_len > 255) {
513325151a3SRui Paulo p2p_dbg(p2p,
514325151a3SRui Paulo "Invalid IE length, failed to add advertised service info");
515325151a3SRui Paulo return -1;
516325151a3SRui Paulo }
517325151a3SRui Paulo remaining = 255 - ie_data_len;
518325151a3SRui Paulo } else {
519325151a3SRui Paulo /*
520325151a3SRui Paulo * Adding new P2P IE header takes 6 extra bytes:
521325151a3SRui Paulo * - 2 byte IE header (1 byte IE id and 1 byte length)
522325151a3SRui Paulo * - 4 bytes of IE_VENDOR_TYPE are reduced from 255 below
523325151a3SRui Paulo */
524325151a3SRui Paulo *ie_len = p2p_buf_add_ie_hdr(buf);
525325151a3SRui Paulo remaining = 255 - 4;
526325151a3SRui Paulo }
527325151a3SRui Paulo
528325151a3SRui Paulo if (remaining < sizeof(u32) + sizeof(u16) + sizeof(u8)) {
529325151a3SRui Paulo /*
530325151a3SRui Paulo * Split adv_id, config_methods, and svc_name_len between two
531325151a3SRui Paulo * IEs.
532325151a3SRui Paulo */
533325151a3SRui Paulo size_t front = remaining;
534325151a3SRui Paulo size_t back = sizeof(u32) + sizeof(u16) + sizeof(u8) - front;
535325151a3SRui Paulo u8 holder[sizeof(u32) + sizeof(u16) + sizeof(u8)];
536325151a3SRui Paulo
537325151a3SRui Paulo WPA_PUT_LE32(holder, adv_id);
538325151a3SRui Paulo WPA_PUT_BE16(&holder[sizeof(u32)], config_methods);
539325151a3SRui Paulo holder[sizeof(u32) + sizeof(u16)] = svc_len;
540325151a3SRui Paulo
541325151a3SRui Paulo if (front)
542325151a3SRui Paulo wpabuf_put_data(buf, holder, front);
543325151a3SRui Paulo
544325151a3SRui Paulo p2p_buf_update_ie_hdr(buf, *ie_len);
545325151a3SRui Paulo *ie_len = p2p_buf_add_ie_hdr(buf);
546325151a3SRui Paulo
547325151a3SRui Paulo wpabuf_put_data(buf, &holder[front], back);
548325151a3SRui Paulo remaining = 255 - 4 - (sizeof(u32) + sizeof(u16) + sizeof(u8)) -
549325151a3SRui Paulo back;
550325151a3SRui Paulo } else {
551325151a3SRui Paulo wpabuf_put_le32(buf, adv_id);
552325151a3SRui Paulo wpabuf_put_be16(buf, config_methods);
553325151a3SRui Paulo wpabuf_put_u8(buf, svc_len);
554325151a3SRui Paulo remaining -= sizeof(adv_id) + sizeof(config_methods) +
555325151a3SRui Paulo sizeof(u8);
556325151a3SRui Paulo }
557325151a3SRui Paulo
558325151a3SRui Paulo if (remaining < svc_len) {
559325151a3SRui Paulo /* split svc_name between two or three IEs */
560325151a3SRui Paulo size_t front = remaining;
561325151a3SRui Paulo size_t back = svc_len - front;
562325151a3SRui Paulo
563325151a3SRui Paulo if (front)
564325151a3SRui Paulo wpabuf_put_data(buf, svc_name, front);
565325151a3SRui Paulo
566325151a3SRui Paulo p2p_buf_update_ie_hdr(buf, *ie_len);
567325151a3SRui Paulo *ie_len = p2p_buf_add_ie_hdr(buf);
568325151a3SRui Paulo
569325151a3SRui Paulo /* In rare cases, we must split across 3 attributes */
570325151a3SRui Paulo if (back > 255 - 4) {
571325151a3SRui Paulo wpabuf_put_data(buf, &svc_name[front], 255 - 4);
572325151a3SRui Paulo back -= 255 - 4;
573325151a3SRui Paulo front += 255 - 4;
574325151a3SRui Paulo p2p_buf_update_ie_hdr(buf, *ie_len);
575325151a3SRui Paulo *ie_len = p2p_buf_add_ie_hdr(buf);
576325151a3SRui Paulo }
577325151a3SRui Paulo
578325151a3SRui Paulo wpabuf_put_data(buf, &svc_name[front], back);
579325151a3SRui Paulo remaining = 255 - 4 - back;
580325151a3SRui Paulo } else {
581325151a3SRui Paulo wpabuf_put_data(buf, svc_name, svc_len);
582325151a3SRui Paulo remaining -= svc_len;
583325151a3SRui Paulo }
584325151a3SRui Paulo
585325151a3SRui Paulo p2p_buf_update_ie_hdr(buf, *ie_len);
586325151a3SRui Paulo
587325151a3SRui Paulo /* set *ie_len to NULL if a new IE has to be added on the next call */
588325151a3SRui Paulo if (!remaining)
589325151a3SRui Paulo *ie_len = NULL;
590325151a3SRui Paulo
591325151a3SRui Paulo /* set *pos to point to the next byte to update */
592325151a3SRui Paulo *pos = wpabuf_put(buf, 0);
593325151a3SRui Paulo
594325151a3SRui Paulo *total_len += info_len;
595325151a3SRui Paulo WPA_PUT_LE16(attr_len, (u16) *total_len);
596325151a3SRui Paulo return 0;
597325151a3SRui Paulo }
598325151a3SRui Paulo
599325151a3SRui Paulo
p2p_buf_add_service_instance(struct wpabuf * buf,struct p2p_data * p2p,u8 hash_count,const u8 * hash,struct p2ps_advertisement * adv_list)6005b9c547cSRui Paulo void p2p_buf_add_service_instance(struct wpabuf *buf, struct p2p_data *p2p,
6015b9c547cSRui Paulo u8 hash_count, const u8 *hash,
6025b9c547cSRui Paulo struct p2ps_advertisement *adv_list)
6035b9c547cSRui Paulo {
6045b9c547cSRui Paulo struct p2ps_advertisement *adv;
605325151a3SRui Paulo int p2ps_wildcard;
606325151a3SRui Paulo size_t total_len;
607325151a3SRui Paulo struct wpabuf *tmp_buf = NULL;
608325151a3SRui Paulo u8 *pos, *attr_len, *ie_len = NULL;
6095b9c547cSRui Paulo
610325151a3SRui Paulo if (!adv_list || !hash || !hash_count)
6115b9c547cSRui Paulo return;
6125b9c547cSRui Paulo
613325151a3SRui Paulo wpa_hexdump(MSG_DEBUG, "P2PS: Probe Request service hash values",
614325151a3SRui Paulo hash, hash_count * P2PS_HASH_LEN);
615325151a3SRui Paulo p2ps_wildcard = p2ps_wildcard_hash(p2p, hash, hash_count) &&
616325151a3SRui Paulo p2p_wfa_service_adv(p2p);
617325151a3SRui Paulo
6185b9c547cSRui Paulo /* Allocate temp buffer, allowing for overflow of 1 instance */
6195b9c547cSRui Paulo tmp_buf = wpabuf_alloc(MAX_SVC_ADV_IE_LEN + 256 + P2PS_HASH_LEN);
6205b9c547cSRui Paulo if (!tmp_buf)
6215b9c547cSRui Paulo return;
6225b9c547cSRui Paulo
623325151a3SRui Paulo /*
624325151a3SRui Paulo * Attribute data can be split into a number of IEs. Start with the
625325151a3SRui Paulo * first IE and the attribute headers here.
626325151a3SRui Paulo */
627325151a3SRui Paulo ie_len = p2p_buf_add_ie_hdr(tmp_buf);
6285b9c547cSRui Paulo
629325151a3SRui Paulo total_len = 0;
630325151a3SRui Paulo
631325151a3SRui Paulo wpabuf_put_u8(tmp_buf, P2P_ATTR_ADVERTISED_SERVICE);
632325151a3SRui Paulo attr_len = wpabuf_put(tmp_buf, sizeof(u16));
633325151a3SRui Paulo WPA_PUT_LE16(attr_len, (u16) total_len);
634325151a3SRui Paulo p2p_buf_update_ie_hdr(tmp_buf, ie_len);
635325151a3SRui Paulo pos = wpabuf_put(tmp_buf, 0);
636325151a3SRui Paulo
637325151a3SRui Paulo if (p2ps_wildcard) {
638325151a3SRui Paulo /* org.wi-fi.wfds match found */
639325151a3SRui Paulo p2p_buf_add_service_info(tmp_buf, p2p, 0, 0, P2PS_WILD_HASH_STR,
640325151a3SRui Paulo &ie_len, &pos, &total_len, attr_len);
6415b9c547cSRui Paulo }
6425b9c547cSRui Paulo
643325151a3SRui Paulo /* add advertised service info of matching services */
644325151a3SRui Paulo for (adv = adv_list; adv && total_len <= MAX_SVC_ADV_LEN;
645325151a3SRui Paulo adv = adv->next) {
646325151a3SRui Paulo const u8 *test = hash;
647325151a3SRui Paulo u8 i;
648325151a3SRui Paulo
649325151a3SRui Paulo for (i = 0; i < hash_count; i++) {
650325151a3SRui Paulo /* exact name hash match */
651325151a3SRui Paulo if (os_memcmp(test, adv->hash, P2PS_HASH_LEN) == 0 &&
652325151a3SRui Paulo p2p_buf_add_service_info(tmp_buf, p2p,
653325151a3SRui Paulo adv->id,
654325151a3SRui Paulo adv->config_methods,
655325151a3SRui Paulo adv->svc_name,
656325151a3SRui Paulo &ie_len, &pos,
657325151a3SRui Paulo &total_len,
658325151a3SRui Paulo attr_len))
659325151a3SRui Paulo break;
6605b9c547cSRui Paulo
6615b9c547cSRui Paulo test += P2PS_HASH_LEN;
6625b9c547cSRui Paulo }
6635b9c547cSRui Paulo }
6645b9c547cSRui Paulo
665325151a3SRui Paulo if (total_len)
6665b9c547cSRui Paulo wpabuf_put_buf(buf, tmp_buf);
6675b9c547cSRui Paulo wpabuf_free(tmp_buf);
6685b9c547cSRui Paulo }
6695b9c547cSRui Paulo
6705b9c547cSRui Paulo
p2p_buf_add_session_id(struct wpabuf * buf,u32 id,const u8 * mac)6715b9c547cSRui Paulo void p2p_buf_add_session_id(struct wpabuf *buf, u32 id, const u8 *mac)
6725b9c547cSRui Paulo {
6735b9c547cSRui Paulo if (!buf || !mac)
6745b9c547cSRui Paulo return;
6755b9c547cSRui Paulo
6765b9c547cSRui Paulo /* Session ID Info */
6775b9c547cSRui Paulo wpabuf_put_u8(buf, P2P_ATTR_SESSION_ID);
6785b9c547cSRui Paulo wpabuf_put_le16(buf, (u16) (sizeof(u32) + ETH_ALEN));
6795b9c547cSRui Paulo wpabuf_put_le32(buf, id);
6805b9c547cSRui Paulo wpabuf_put_data(buf, mac, ETH_ALEN);
6815b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Session ID Info (%x) " MACSTR,
6825b9c547cSRui Paulo id, MAC2STR(mac));
6835b9c547cSRui Paulo }
6845b9c547cSRui Paulo
6855b9c547cSRui Paulo
p2p_buf_add_feature_capability(struct wpabuf * buf,u16 len,const u8 * mask)6865b9c547cSRui Paulo void p2p_buf_add_feature_capability(struct wpabuf *buf, u16 len, const u8 *mask)
6875b9c547cSRui Paulo {
6885b9c547cSRui Paulo if (!buf || !len || !mask)
6895b9c547cSRui Paulo return;
6905b9c547cSRui Paulo
6915b9c547cSRui Paulo /* Feature Capability */
6925b9c547cSRui Paulo wpabuf_put_u8(buf, P2P_ATTR_FEATURE_CAPABILITY);
6935b9c547cSRui Paulo wpabuf_put_le16(buf, len);
6945b9c547cSRui Paulo wpabuf_put_data(buf, mask, len);
6955b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "P2P: * Feature Capability (%d)", len);
6965b9c547cSRui Paulo }
6975b9c547cSRui Paulo
6985b9c547cSRui Paulo
p2p_buf_add_persistent_group_info(struct wpabuf * buf,const u8 * dev_addr,const u8 * ssid,size_t ssid_len)6995b9c547cSRui Paulo void p2p_buf_add_persistent_group_info(struct wpabuf *buf, const u8 *dev_addr,
7005b9c547cSRui Paulo const u8 *ssid, size_t ssid_len)
7015b9c547cSRui Paulo {
7025b9c547cSRui Paulo /* P2P Group ID */
7035b9c547cSRui Paulo wpabuf_put_u8(buf, P2P_ATTR_PERSISTENT_GROUP);
7045b9c547cSRui Paulo wpabuf_put_le16(buf, ETH_ALEN + ssid_len);
7055b9c547cSRui Paulo wpabuf_put_data(buf, dev_addr, ETH_ALEN);
7065b9c547cSRui Paulo wpabuf_put_data(buf, ssid, ssid_len);
7075b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "P2P: * P2P Group ID " MACSTR,
7085b9c547cSRui Paulo MAC2STR(dev_addr));
7095b9c547cSRui Paulo }
7105b9c547cSRui Paulo
7115b9c547cSRui Paulo
p2p_add_wps_string(struct wpabuf * buf,enum wps_attribute attr,const char * val)7125b9c547cSRui Paulo static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
713f05cddf9SRui Paulo const char *val)
714f05cddf9SRui Paulo {
715f05cddf9SRui Paulo size_t len;
716f05cddf9SRui Paulo
717f05cddf9SRui Paulo len = val ? os_strlen(val) : 0;
7185b9c547cSRui Paulo if (wpabuf_tailroom(buf) < 4 + len)
7195b9c547cSRui Paulo return -1;
7205b9c547cSRui Paulo wpabuf_put_be16(buf, attr);
721f05cddf9SRui Paulo #ifndef CONFIG_WPS_STRICT
722f05cddf9SRui Paulo if (len == 0) {
723f05cddf9SRui Paulo /*
724f05cddf9SRui Paulo * Some deployed WPS implementations fail to parse zeor-length
725f05cddf9SRui Paulo * attributes. As a workaround, send a space character if the
726f05cddf9SRui Paulo * device attribute string is empty.
727f05cddf9SRui Paulo */
7285b9c547cSRui Paulo if (wpabuf_tailroom(buf) < 3)
7295b9c547cSRui Paulo return -1;
730f05cddf9SRui Paulo wpabuf_put_be16(buf, 1);
731f05cddf9SRui Paulo wpabuf_put_u8(buf, ' ');
7325b9c547cSRui Paulo return 0;
733f05cddf9SRui Paulo }
734f05cddf9SRui Paulo #endif /* CONFIG_WPS_STRICT */
735f05cddf9SRui Paulo wpabuf_put_be16(buf, len);
736f05cddf9SRui Paulo if (val)
737f05cddf9SRui Paulo wpabuf_put_data(buf, val, len);
7385b9c547cSRui Paulo return 0;
739f05cddf9SRui Paulo }
740f05cddf9SRui Paulo
741f05cddf9SRui Paulo
p2p_build_wps_ie(struct p2p_data * p2p,struct wpabuf * buf,int pw_id,int all_attr)7425b9c547cSRui Paulo int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
743f05cddf9SRui Paulo int all_attr)
744f05cddf9SRui Paulo {
745f05cddf9SRui Paulo u8 *len;
746f05cddf9SRui Paulo int i;
747f05cddf9SRui Paulo
7485b9c547cSRui Paulo if (wpabuf_tailroom(buf) < 6)
7495b9c547cSRui Paulo return -1;
750f05cddf9SRui Paulo wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
751f05cddf9SRui Paulo len = wpabuf_put(buf, 1);
752f05cddf9SRui Paulo wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
753f05cddf9SRui Paulo
7545b9c547cSRui Paulo if (wps_build_version(buf) < 0)
7555b9c547cSRui Paulo return -1;
756f05cddf9SRui Paulo
757f05cddf9SRui Paulo if (all_attr) {
7585b9c547cSRui Paulo if (wpabuf_tailroom(buf) < 5)
7595b9c547cSRui Paulo return -1;
760f05cddf9SRui Paulo wpabuf_put_be16(buf, ATTR_WPS_STATE);
761f05cddf9SRui Paulo wpabuf_put_be16(buf, 1);
762f05cddf9SRui Paulo wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
763f05cddf9SRui Paulo }
764f05cddf9SRui Paulo
765f05cddf9SRui Paulo if (pw_id >= 0) {
7665b9c547cSRui Paulo if (wpabuf_tailroom(buf) < 6)
7675b9c547cSRui Paulo return -1;
768f05cddf9SRui Paulo /* Device Password ID */
769f05cddf9SRui Paulo wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
770f05cddf9SRui Paulo wpabuf_put_be16(buf, 2);
771f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "P2P: WPS IE Device Password ID: %d",
772f05cddf9SRui Paulo pw_id);
773f05cddf9SRui Paulo wpabuf_put_be16(buf, pw_id);
774f05cddf9SRui Paulo }
775f05cddf9SRui Paulo
776f05cddf9SRui Paulo if (all_attr) {
7775b9c547cSRui Paulo if (wpabuf_tailroom(buf) < 5)
7785b9c547cSRui Paulo return -1;
779f05cddf9SRui Paulo wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
780f05cddf9SRui Paulo wpabuf_put_be16(buf, 1);
781f05cddf9SRui Paulo wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
782f05cddf9SRui Paulo
7835b9c547cSRui Paulo if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 ||
784f05cddf9SRui Paulo p2p_add_wps_string(buf, ATTR_MANUFACTURER,
7855b9c547cSRui Paulo p2p->cfg->manufacturer) < 0 ||
7865b9c547cSRui Paulo p2p_add_wps_string(buf, ATTR_MODEL_NAME,
7875b9c547cSRui Paulo p2p->cfg->model_name) < 0 ||
788f05cddf9SRui Paulo p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
7895b9c547cSRui Paulo p2p->cfg->model_number) < 0 ||
790f05cddf9SRui Paulo p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
7915b9c547cSRui Paulo p2p->cfg->serial_number) < 0)
7925b9c547cSRui Paulo return -1;
793f05cddf9SRui Paulo
7945b9c547cSRui Paulo if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN)
7955b9c547cSRui Paulo return -1;
796f05cddf9SRui Paulo wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
797f05cddf9SRui Paulo wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
798f05cddf9SRui Paulo wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
799f05cddf9SRui Paulo
8005b9c547cSRui Paulo if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name)
8015b9c547cSRui Paulo < 0)
8025b9c547cSRui Paulo return -1;
803f05cddf9SRui Paulo
8045b9c547cSRui Paulo if (wpabuf_tailroom(buf) < 6)
8055b9c547cSRui Paulo return -1;
806f05cddf9SRui Paulo wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
807f05cddf9SRui Paulo wpabuf_put_be16(buf, 2);
808f05cddf9SRui Paulo wpabuf_put_be16(buf, p2p->cfg->config_methods);
809f05cddf9SRui Paulo }
810f05cddf9SRui Paulo
8114bc52338SCy Schubert if (wps_build_wfa_ext(buf, 0, NULL, 0, 0) < 0)
8125b9c547cSRui Paulo return -1;
813f05cddf9SRui Paulo
814f05cddf9SRui Paulo if (all_attr && p2p->cfg->num_sec_dev_types) {
8155b9c547cSRui Paulo if (wpabuf_tailroom(buf) <
8165b9c547cSRui Paulo 4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types)
8175b9c547cSRui Paulo return -1;
818f05cddf9SRui Paulo wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
819f05cddf9SRui Paulo wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
820f05cddf9SRui Paulo p2p->cfg->num_sec_dev_types);
821f05cddf9SRui Paulo wpabuf_put_data(buf, p2p->cfg->sec_dev_type,
822f05cddf9SRui Paulo WPS_DEV_TYPE_LEN *
823f05cddf9SRui Paulo p2p->cfg->num_sec_dev_types);
824f05cddf9SRui Paulo }
825f05cddf9SRui Paulo
826f05cddf9SRui Paulo /* Add the WPS vendor extensions */
827f05cddf9SRui Paulo for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
828f05cddf9SRui Paulo if (p2p->wps_vendor_ext[i] == NULL)
829f05cddf9SRui Paulo break;
830f05cddf9SRui Paulo if (wpabuf_tailroom(buf) <
831f05cddf9SRui Paulo 4 + wpabuf_len(p2p->wps_vendor_ext[i]))
832f05cddf9SRui Paulo continue;
833f05cddf9SRui Paulo wpabuf_put_be16(buf, ATTR_VENDOR_EXT);
834f05cddf9SRui Paulo wpabuf_put_be16(buf, wpabuf_len(p2p->wps_vendor_ext[i]));
835f05cddf9SRui Paulo wpabuf_put_buf(buf, p2p->wps_vendor_ext[i]);
836f05cddf9SRui Paulo }
837f05cddf9SRui Paulo
838f05cddf9SRui Paulo p2p_buf_update_ie_hdr(buf, len);
8395b9c547cSRui Paulo
8405b9c547cSRui Paulo return 0;
841f05cddf9SRui Paulo }
842