3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2011 Nokia Corporation
6 * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 #include "lib/bluetooth.h"
40 #include "src/shared/util.h"
41 #include "uuid-helper.h"
44 #define EIR_OOB_MIN (2 + 6)
46 void eir_data_free(struct eir_data *eir)
48 g_slist_free_full(eir->services, free);
54 g_free(eir->randomizer);
55 eir->randomizer = NULL;
56 g_slist_free_full(eir->msd_list, g_free);
58 #ifdef __TIZEN_PATCH__
59 g_free(eir->manufacturer_data);
60 eir->manufacturer_data = NULL;
64 static void eir_parse_uuid16(struct eir_data *eir, const void *data,
67 const uint16_t *uuid16 = data;
72 service.type = SDP_UUID16;
73 for (i = 0; i < len / 2; i++, uuid16++) {
74 service.value.uuid16 = get_le16(uuid16);
76 uuid_str = bt_uuid2string(&service);
79 eir->services = g_slist_append(eir->services, uuid_str);
83 static void eir_parse_uuid32(struct eir_data *eir, const void *data,
86 const uint32_t *uuid32 = data;
91 service.type = SDP_UUID32;
92 for (i = 0; i < len / 4; i++, uuid32++) {
93 service.value.uuid32 = get_le32(uuid32);
95 uuid_str = bt_uuid2string(&service);
98 eir->services = g_slist_append(eir->services, uuid_str);
102 static void eir_parse_uuid128(struct eir_data *eir, const uint8_t *data,
105 const uint8_t *uuid_ptr = data;
111 service.type = SDP_UUID128;
112 for (i = 0; i < len / 16; i++) {
113 for (k = 0; k < 16; k++)
114 service.value.uuid128.data[k] = uuid_ptr[16 - k - 1];
115 uuid_str = bt_uuid2string(&service);
118 eir->services = g_slist_append(eir->services, uuid_str);
123 static char *name2utf8(const uint8_t *name, uint8_t len)
125 #ifdef __TIZEN_PATCH__
130 in_name = g_malloc0(sizeof(char) * (len + 1));
131 /* Fix : NULL_RETURNS */
134 memcpy(in_name, name, sizeof(char) * len);
137 if (!g_utf8_validate(in_name, -1, (const char **)&ptr))
140 utf8_name = g_strdup(in_name);
145 char utf8_name[HCI_MAX_NAME_LENGTH + 2];
148 if (g_utf8_validate((const char *) name, len, NULL))
149 return g_strndup((char *) name, len);
151 memset(utf8_name, 0, sizeof(utf8_name));
152 strncpy(utf8_name, (char *) name, len);
154 /* Assume ASCII, and replace all non-ASCII with spaces */
155 for (i = 0; utf8_name[i] != '\0'; i++) {
156 if (!isascii(utf8_name[i]))
160 /* Remove leading and trailing whitespace characters */
161 g_strstrip(utf8_name);
163 return g_strdup(utf8_name);
167 static void eir_parse_msd(struct eir_data *eir, const uint8_t *data,
172 if (len < 2 || len > 2 + sizeof(msd->data))
175 msd = g_malloc(sizeof(*msd));
176 msd->company = get_le16(data);
177 msd->data_len = len - 2;
178 memcpy(&msd->data, data + 2, msd->data_len);
180 eir->msd_list = g_slist_append(eir->msd_list, msd);
183 void eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
190 /* No EIR data to parse */
191 if (eir_data == NULL)
194 while (len < eir_len - 1) {
195 uint8_t field_len = eir_data[0];
199 /* Check for the end of EIR */
203 len += field_len + 1;
205 /* Do not continue EIR Data parsing if got incorrect length */
210 data_len = field_len - 1;
212 switch (eir_data[1]) {
213 case EIR_UUID16_SOME:
215 eir_parse_uuid16(eir, data, data_len);
218 case EIR_UUID32_SOME:
220 eir_parse_uuid32(eir, data, data_len);
223 case EIR_UUID128_SOME:
224 case EIR_UUID128_ALL:
225 eir_parse_uuid128(eir, data, data_len);
234 case EIR_NAME_COMPLETE:
235 /* Some vendors put a NUL byte terminator into
237 while (data_len > 0 && data[data_len - 1] == '\0')
242 eir->name = name2utf8(data, data_len);
243 eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE;
249 eir->tx_power = (int8_t) data[0];
252 case EIR_CLASS_OF_DEV:
255 eir->class = data[0] | (data[1] << 8) |
259 case EIR_GAP_APPEARANCE:
262 eir->appearance = get_le16(data);
268 eir->hash = g_memdup(data, 16);
271 case EIR_SSP_RANDOMIZER:
274 eir->randomizer = g_memdup(data, 16);
281 eir->did_source = data[0] | (data[1] << 8);
282 eir->did_vendor = data[2] | (data[3] << 8);
283 eir->did_product = data[4] | (data[5] << 8);
284 eir->did_version = data[6] | (data[7] << 8);
287 case EIR_MANUFACTURER_DATA:
288 #ifdef __TIZEN_PATCH__
292 eir->manufacturer_data = g_memdup(data,
294 eir->manufacturer_data_len = data_len;
296 eir_parse_msd(eir, data, data_len);
301 eir_data += field_len + 1;
305 int eir_parse_oob(struct eir_data *eir, uint8_t *eir_data, uint16_t eir_len)
308 if (eir_len < EIR_OOB_MIN)
311 if (eir_len != get_le16(eir_data))
314 eir_data += sizeof(uint16_t);
315 eir_len -= sizeof(uint16_t);
317 memcpy(&eir->addr, eir_data, sizeof(bdaddr_t));
318 eir_data += sizeof(bdaddr_t);
319 eir_len -= sizeof(bdaddr_t);
321 /* optional OOB EIR data */
323 eir_parse(eir, eir_data, eir_len);
328 #define SIZEOF_UUID128 16
330 static void eir_generate_uuid128(sdp_list_t *list, uint8_t *ptr,
333 int i, k, uuid_count = 0;
334 uint16_t len = *eir_len;
336 bool truncated = false;
338 /* Store UUIDs in place, skip 2 bytes to write type and length later */
341 for (; list; list = list->next) {
342 sdp_record_t *rec = list->data;
343 uuid_t *uuid = &rec->svclass;
344 uint8_t *uuid128_data = uuid->value.uuid128.data;
346 if (uuid->type != SDP_UUID128)
349 /* Stop if not enough space to put next UUID128 */
350 if ((len + 2 + SIZEOF_UUID128) > HCI_MAX_EIR_LENGTH) {
355 /* Check for duplicates, EIR data is Little Endian */
356 for (i = 0; i < uuid_count; i++) {
357 for (k = 0; k < SIZEOF_UUID128; k++) {
358 if (uuid128[i * SIZEOF_UUID128 + k] !=
359 uuid128_data[SIZEOF_UUID128 - 1 - k])
362 if (k == SIZEOF_UUID128)
369 /* EIR data is Little Endian */
370 for (k = 0; k < SIZEOF_UUID128; k++)
371 uuid128[uuid_count * SIZEOF_UUID128 + k] =
372 uuid128_data[SIZEOF_UUID128 - 1 - k];
374 len += SIZEOF_UUID128;
378 if (uuid_count > 0 || truncated) {
379 /* EIR Data length */
380 ptr[0] = (uuid_count * SIZEOF_UUID128) + 1;
382 ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL;
388 int eir_create_oob(const bdaddr_t *addr, const char *name, uint32_t cod,
389 const uint8_t *hash, const uint8_t *randomizer,
390 uint16_t did_vendor, uint16_t did_product,
391 uint16_t did_version, uint16_t did_source,
392 sdp_list_t *uuids, uint8_t *data)
396 uint16_t eir_optional_len = 0;
397 uint16_t eir_total_len;
398 uint16_t uuid16[HCI_MAX_EIR_LENGTH / 2];
399 int i, uuid_count = 0;
400 bool truncated = false;
403 eir_total_len = sizeof(uint16_t) + sizeof(bdaddr_t);
404 ptr += sizeof(uint16_t);
406 memcpy(ptr, addr, sizeof(bdaddr_t));
407 ptr += sizeof(bdaddr_t);
412 class[0] = (uint8_t) cod;
413 class[1] = (uint8_t) (cod >> 8);
414 class[2] = (uint8_t) (cod >> 16);
417 *ptr++ = EIR_CLASS_OF_DEV;
419 memcpy(ptr, class, sizeof(class));
420 ptr += sizeof(class);
422 eir_optional_len += sizeof(class) + 2;
427 *ptr++ = EIR_SSP_HASH;
429 memcpy(ptr, hash, 16);
432 eir_optional_len += 16 + 2;
437 *ptr++ = EIR_SSP_RANDOMIZER;
439 memcpy(ptr, randomizer, 16);
442 eir_optional_len += 16 + 2;
445 name_len = strlen(name);
451 ptr[1] = EIR_NAME_SHORT;
453 ptr[1] = EIR_NAME_COMPLETE;
455 /* EIR Data length */
456 ptr[0] = name_len + 1;
458 memcpy(ptr + 2, name, name_len);
460 eir_optional_len += (name_len + 2);
461 ptr += (name_len + 2);
464 if (did_vendor != 0x0000) {
466 *ptr++ = EIR_DEVICE_ID;
467 *ptr++ = (did_source & 0x00ff);
468 *ptr++ = (did_source & 0xff00) >> 8;
469 *ptr++ = (did_vendor & 0x00ff);
470 *ptr++ = (did_vendor & 0xff00) >> 8;
471 *ptr++ = (did_product & 0x00ff);
472 *ptr++ = (did_product & 0xff00) >> 8;
473 *ptr++ = (did_version & 0x00ff);
474 *ptr++ = (did_version & 0xff00) >> 8;
475 eir_optional_len += 10;
478 /* Group all UUID16 types */
479 for (l = uuids; l != NULL; l = l->next) {
480 sdp_record_t *rec = l->data;
481 uuid_t *uuid = &rec->svclass;
483 if (uuid->type != SDP_UUID16)
486 if (uuid->value.uuid16 < 0x1100)
489 if (uuid->value.uuid16 == PNP_INFO_SVCLASS_ID)
492 /* Stop if not enough space to put next UUID16 */
493 if ((eir_optional_len + 2 + sizeof(uint16_t)) >
494 HCI_MAX_EIR_LENGTH) {
499 /* Check for duplicates */
500 for (i = 0; i < uuid_count; i++)
501 if (uuid16[i] == uuid->value.uuid16)
507 uuid16[uuid_count++] = uuid->value.uuid16;
508 eir_optional_len += sizeof(uint16_t);
511 if (uuid_count > 0) {
512 /* EIR Data length */
513 ptr[0] = (uuid_count * sizeof(uint16_t)) + 1;
515 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
518 eir_optional_len += 2;
520 for (i = 0; i < uuid_count; i++) {
521 *ptr++ = (uuid16[i] & 0x00ff);
522 *ptr++ = (uuid16[i] & 0xff00) >> 8;
526 /* Group all UUID128 types */
527 if (eir_optional_len <= HCI_MAX_EIR_LENGTH - 2)
528 eir_generate_uuid128(uuids, ptr, &eir_optional_len);
530 eir_total_len += eir_optional_len;
532 /* store total length */
533 put_le16(eir_total_len, data);
535 return eir_total_len;