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