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
34 #include <bluetooth/bluetooth.h>
35 #include <bluetooth/hci.h>
36 #include <bluetooth/sdp.h>
38 #include "glib-helper.h"
41 void eir_data_free(struct eir_data *eir)
43 g_slist_free_full(eir->services, g_free);
49 static void eir_parse_uuid16(struct eir_data *eir, void *data, uint8_t len)
51 uint16_t *uuid16 = data;
56 service.type = SDP_UUID16;
57 for (i = 0; i < len / 2; i++, uuid16++) {
58 service.value.uuid16 = btohs(bt_get_unaligned(uuid16));
59 uuid_str = bt_uuid2string(&service);
60 eir->services = g_slist_append(eir->services, uuid_str);
64 static void eir_parse_uuid32(struct eir_data *eir, void *data, uint8_t len)
66 uint32_t *uuid32 = data;
71 service.type = SDP_UUID32;
72 for (i = 0; i < len / 4; i++, uuid32++) {
73 service.value.uuid32 = btohl(bt_get_unaligned(uuid32));
74 uuid_str = bt_uuid2string(&service);
75 eir->services = g_slist_append(eir->services, uuid_str);
79 static void eir_parse_uuid128(struct eir_data *eir, uint8_t *data, uint8_t len)
81 uint8_t *uuid_ptr = data;
87 service.type = SDP_UUID128;
88 for (i = 0; i < len / 16; i++) {
89 for (k = 0; k < 16; k++)
90 service.value.uuid128.data[k] = uuid_ptr[16 - k - 1];
91 uuid_str = bt_uuid2string(&service);
92 eir->services = g_slist_append(eir->services, uuid_str);
97 int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
103 /* No EIR data to parse */
104 if (eir_data == NULL)
107 while (len < eir_len - 1) {
108 uint8_t field_len = eir_data[0];
109 uint8_t data_len, *data = &eir_data[2];
111 /* Check for the end of EIR */
115 len += field_len + 1;
117 /* Do not continue EIR Data parsing if got incorrect length */
121 data_len = field_len - 1;
123 switch (eir_data[1]) {
124 case EIR_UUID16_SOME:
126 eir_parse_uuid16(eir, data, data_len);
129 case EIR_UUID32_SOME:
131 eir_parse_uuid32(eir, data, data_len);
134 case EIR_UUID128_SOME:
135 case EIR_UUID128_ALL:
136 eir_parse_uuid128(eir, data, data_len);
145 case EIR_NAME_COMPLETE:
146 /* Some vendors put a NUL byte terminator into
148 while (data_len > 0 && data[data_len - 1] == '\0')
151 if (!g_utf8_validate((char *) data, data_len, NULL))
156 eir->name = g_strndup((char *) data, data_len);
157 eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE;
160 case EIR_CLASS_OF_DEV:
163 memcpy(eir->dev_class, data, 3);
166 case EIR_GAP_APPEARANCE:
169 eir->appearance = bt_get_le16(data);
173 eir_data += field_len + 1;
179 #define SIZEOF_UUID128 16
181 static void eir_generate_uuid128(GSList *list, uint8_t *ptr, uint16_t *eir_len)
183 int i, k, uuid_count = 0;
184 uint16_t len = *eir_len;
186 gboolean truncated = FALSE;
188 /* Store UUIDs in place, skip 2 bytes to write type and length later */
191 for (; list; list = list->next) {
192 struct uuid_info *uuid = list->data;
193 uint8_t *uuid128_data = uuid->uuid.value.uuid128.data;
195 if (uuid->uuid.type != SDP_UUID128)
198 /* Stop if not enough space to put next UUID128 */
199 if ((len + 2 + SIZEOF_UUID128) > HCI_MAX_EIR_LENGTH) {
204 /* Check for duplicates, EIR data is Little Endian */
205 for (i = 0; i < uuid_count; i++) {
206 for (k = 0; k < SIZEOF_UUID128; k++) {
207 if (uuid128[i * SIZEOF_UUID128 + k] !=
208 uuid128_data[SIZEOF_UUID128 - 1 - k])
211 if (k == SIZEOF_UUID128)
218 /* EIR data is Little Endian */
219 for (k = 0; k < SIZEOF_UUID128; k++)
220 uuid128[uuid_count * SIZEOF_UUID128 + k] =
221 uuid128_data[SIZEOF_UUID128 - 1 - k];
223 len += SIZEOF_UUID128;
227 if (uuid_count > 0 || truncated) {
228 /* EIR Data length */
229 ptr[0] = (uuid_count * SIZEOF_UUID128) + 1;
231 ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL;
237 void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
238 uint16_t did_product, uint16_t did_version,
239 uint16_t did_source, GSList *uuids, uint8_t *data)
243 uint16_t eir_len = 0;
244 uint16_t uuid16[HCI_MAX_EIR_LENGTH / 2];
245 int i, uuid_count = 0;
246 gboolean truncated = FALSE;
249 name_len = strlen(name);
255 ptr[1] = EIR_NAME_SHORT;
257 ptr[1] = EIR_NAME_COMPLETE;
259 /* EIR Data length */
260 ptr[0] = name_len + 1;
262 memcpy(ptr + 2, name, name_len);
264 eir_len += (name_len + 2);
265 ptr += (name_len + 2);
270 *ptr++ = EIR_TX_POWER;
271 *ptr++ = (uint8_t) tx_power;
275 if (did_vendor != 0x0000) {
277 *ptr++ = EIR_DEVICE_ID;
278 *ptr++ = (did_source & 0x00ff);
279 *ptr++ = (did_source & 0xff00) >> 8;
280 *ptr++ = (did_vendor & 0x00ff);
281 *ptr++ = (did_vendor & 0xff00) >> 8;
282 *ptr++ = (did_product & 0x00ff);
283 *ptr++ = (did_product & 0xff00) >> 8;
284 *ptr++ = (did_version & 0x00ff);
285 *ptr++ = (did_version & 0xff00) >> 8;
289 /* Group all UUID16 types */
290 for (l = uuids; l != NULL; l = g_slist_next(l)) {
291 struct uuid_info *uuid = l->data;
293 if (uuid->uuid.type != SDP_UUID16)
296 if (uuid->uuid.value.uuid16 < 0x1100)
299 if (uuid->uuid.value.uuid16 == PNP_INFO_SVCLASS_ID)
302 /* Stop if not enough space to put next UUID16 */
303 if ((eir_len + 2 + sizeof(uint16_t)) > HCI_MAX_EIR_LENGTH) {
308 /* Check for duplicates */
309 for (i = 0; i < uuid_count; i++)
310 if (uuid16[i] == uuid->uuid.value.uuid16)
316 uuid16[uuid_count++] = uuid->uuid.value.uuid16;
317 eir_len += sizeof(uint16_t);
320 if (uuid_count > 0) {
321 /* EIR Data length */
322 ptr[0] = (uuid_count * sizeof(uint16_t)) + 1;
324 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
329 for (i = 0; i < uuid_count; i++) {
330 *ptr++ = (uuid16[i] & 0x00ff);
331 *ptr++ = (uuid16[i] & 0xff00) >> 8;
335 /* Group all UUID128 types */
336 if (eir_len <= HCI_MAX_EIR_LENGTH - 2)
337 eir_generate_uuid128(uuids, ptr, &eir_len);
340 gboolean eir_has_data_type(uint8_t *data, size_t len, uint8_t type)
344 #ifdef __TIZEN_PATCH__
348 while (parsed < len - 1) {
354 parsed += field_len + 1;
362 data += field_len + 1;
368 size_t eir_append_data(uint8_t *eir, size_t eir_len, uint8_t type,
369 uint8_t *data, size_t data_len)
371 eir[eir_len++] = sizeof(type) + data_len;
372 eir[eir_len++] = type;
373 memcpy(&eir[eir_len], data, data_len);
379 size_t eir_length(uint8_t *eir, size_t maxlen)
382 size_t parsed = 0, length = 0;
384 while (parsed < maxlen - 1) {
390 parsed += field_len + 1;
396 eir += field_len + 1;