1991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi/*
2991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *
3991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  BlueZ - Bluetooth protocol stack for Linux
4991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *
5991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  Copyright (C) 2011  Nokia Corporation
6991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
7991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *
8991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *
9991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  This program is free software; you can redistribute it and/or modify
10991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  it under the terms of the GNU General Public License as published by
11991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  the Free Software Foundation; either version 2 of the License, or
12991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  (at your option) any later version.
13991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *
14991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  This program is distributed in the hope that it will be useful,
15991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  GNU General Public License for more details.
18991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *
19991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  You should have received a copy of the GNU General Public License
20991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  along with this program; if not, write to the Free Software
21991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi *
23991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi */
24991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#include <errno.h>
25991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#include <stdlib.h>
26991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#include <stdint.h>
27991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#include <glib.h>
28991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
29991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#include <bluetooth/bluetooth.h>
309d172c96a54a5417b4464e1bebe67bedf183a8baBruna Moreira#include <bluetooth/hci.h>
31991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#include <bluetooth/sdp.h>
32991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
33991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#include "glib-helper.h"
34991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#include "eir.h"
35991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
36991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_FLAGS                   0x01  /* flags */
37991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_UUID16_SOME             0x02  /* 16-bit UUID, more available */
38991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_UUID16_ALL              0x03  /* 16-bit UUID, all listed */
39991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_UUID32_SOME             0x04  /* 32-bit UUID, more available */
40991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_UUID32_ALL              0x05  /* 32-bit UUID, all listed */
41991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_UUID128_SOME            0x06  /* 128-bit UUID, more available */
42991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_UUID128_ALL             0x07  /* 128-bit UUID, all listed */
43991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_NAME_SHORT              0x08  /* shortened local name */
44991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_NAME_COMPLETE           0x09  /* complete local name */
45991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_TX_POWER                0x0A  /* transmit power level */
46991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define EIR_DEVICE_ID               0x10  /* device ID */
47991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
488b353b60e29a1d365c8db99a71583968cb004149Claudio Takahasivoid eir_data_free(struct eir_data *eir)
498b353b60e29a1d365c8db99a71583968cb004149Claudio Takahasi{
508b353b60e29a1d365c8db99a71583968cb004149Claudio Takahasi	g_slist_foreach(eir->services, (GFunc) g_free, NULL);
518b353b60e29a1d365c8db99a71583968cb004149Claudio Takahasi	g_slist_free(eir->services);
528b353b60e29a1d365c8db99a71583968cb004149Claudio Takahasi	g_free(eir->name);
538b353b60e29a1d365c8db99a71583968cb004149Claudio Takahasi}
548b353b60e29a1d365c8db99a71583968cb004149Claudio Takahasi
55f169bea7d5b30d84ccea7f687a2698b7a8894054Bruna Moreiraint eir_parse(struct eir_data *eir, uint8_t *eir_data)
56991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi{
57991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uint16_t len = 0;
58991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	size_t total;
59991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	size_t uuid16_count = 0;
60991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	size_t uuid32_count = 0;
61991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	size_t uuid128_count = 0;
62991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uint8_t *uuid16 = NULL;
63991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uint8_t *uuid32 = NULL;
64991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uint8_t *uuid128 = NULL;
65991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uuid_t service;
66991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	char *uuid_str;
67991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	unsigned int i;
68991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
69991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	eir->flags = -1;
70991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
71991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	/* No EIR data to parse */
72f169bea7d5b30d84ccea7f687a2698b7a8894054Bruna Moreira	if (eir_data == NULL)
73991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		return 0;
74991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
75f169bea7d5b30d84ccea7f687a2698b7a8894054Bruna Moreira	while (len < HCI_MAX_EIR_LENGTH - 1) {
76991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uint8_t field_len = eir_data[0];
77991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
78991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* Check for the end of EIR */
79991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		if (field_len == 0)
80991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			break;
81991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
82991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		switch (eir_data[1]) {
83991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		case EIR_UUID16_SOME:
84991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		case EIR_UUID16_ALL:
85991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			uuid16_count = field_len / 2;
86991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			uuid16 = &eir_data[2];
87991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			break;
88991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		case EIR_UUID32_SOME:
89991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		case EIR_UUID32_ALL:
90991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			uuid32_count = field_len / 4;
91991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			uuid32 = &eir_data[2];
92991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			break;
93991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		case EIR_UUID128_SOME:
94991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		case EIR_UUID128_ALL:
95991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			uuid128_count = field_len / 16;
96991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			uuid128 = &eir_data[2];
97991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			break;
98991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		case EIR_FLAGS:
99991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			eir->flags = eir_data[2];
100991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			break;
101991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		case EIR_NAME_SHORT:
102991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		case EIR_NAME_COMPLETE:
103991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			if (g_utf8_validate((char *) &eir_data[2],
104991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi							field_len - 1, NULL))
105991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi				eir->name = g_strndup((char *) &eir_data[2],
106991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi								field_len - 1);
107991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			else
108991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi				eir->name = g_strdup("");
109991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE;
110991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			break;
111991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		}
112991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
113991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		len += field_len + 1;
114991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir_data += field_len + 1;
115991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
116991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
117991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	/* Bail out if got incorrect length */
118f169bea7d5b30d84ccea7f687a2698b7a8894054Bruna Moreira	if (len > HCI_MAX_EIR_LENGTH)
119991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		return -EINVAL;
120991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
121991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	total = uuid16_count + uuid32_count + uuid128_count;
122991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
123991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	/* No UUIDs were parsed, so skip code below */
124991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	if (!total)
125991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		return 0;
126991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
127991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	/* Generate uuids in SDP format (EIR data is Little Endian) */
128991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	service.type = SDP_UUID16;
129991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	for (i = 0; i < uuid16_count; i++) {
130991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uint16_t val16 = uuid16[1];
131991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
132991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		val16 = (val16 << 8) + uuid16[0];
133991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		service.value.uuid16 = val16;
134991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uuid_str = bt_uuid2string(&service);
135991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir->services = g_slist_append(eir->services, uuid_str);
136991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uuid16 += 2;
137991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
138991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
139991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	service.type = SDP_UUID32;
140991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	for (i = uuid16_count; i < uuid32_count + uuid16_count; i++) {
141991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uint32_t val32 = uuid32[3];
142991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		int k;
143991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
144991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		for (k = 2; k >= 0; k--)
145991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			val32 = (val32 << 8) + uuid32[k];
146991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
147991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		service.value.uuid32 = val32;
148991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uuid_str = bt_uuid2string(&service);
149991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir->services = g_slist_append(eir->services, uuid_str);
150991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uuid32 += 4;
151991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
152991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
153991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	service.type = SDP_UUID128;
154991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	for (i = uuid32_count + uuid16_count; i < total; i++) {
155991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		int k;
156991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
157991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		for (k = 0; k < 16; k++)
158991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			service.value.uuid128.data[k] = uuid128[16 - k - 1];
159991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
160991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uuid_str = bt_uuid2string(&service);
161991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir->services = g_slist_append(eir->services, uuid_str);
162991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uuid128 += 16;
163991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
164991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
165991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	return 0;
166991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi}
167991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
168991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi#define SIZEOF_UUID128 16
169991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
170991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasistatic void eir_generate_uuid128(GSList *list, uint8_t *ptr, uint16_t *eir_len)
171991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi{
172991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	int i, k, uuid_count = 0;
173991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uint16_t len = *eir_len;
174991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uint8_t *uuid128;
175991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	gboolean truncated = FALSE;
176991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
177991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	/* Store UUIDs in place, skip 2 bytes to write type and length later */
178991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uuid128 = ptr + 2;
179991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
180991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	for (; list; list = list->next) {
181991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		struct uuid_info *uuid = list->data;
182991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uint8_t *uuid128_data = uuid->uuid.value.uuid128.data;
183991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
184991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		if (uuid->uuid.type != SDP_UUID128)
185991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			continue;
186991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
187991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* Stop if not enough space to put next UUID128 */
1889d172c96a54a5417b4464e1bebe67bedf183a8baBruna Moreira		if ((len + 2 + SIZEOF_UUID128) > HCI_MAX_EIR_LENGTH) {
189991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			truncated = TRUE;
190991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			break;
191991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		}
192991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
193991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* Check for duplicates, EIR data is Little Endian */
194991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		for (i = 0; i < uuid_count; i++) {
195991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			for (k = 0; k < SIZEOF_UUID128; k++) {
196991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi				if (uuid128[i * SIZEOF_UUID128 + k] !=
197991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi					uuid128_data[SIZEOF_UUID128 - 1 - k])
198991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi					break;
199991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			}
200991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			if (k == SIZEOF_UUID128)
201991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi				break;
202991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		}
203991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
204991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		if (i < uuid_count)
205991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			continue;
206991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
207991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* EIR data is Little Endian */
208991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		for (k = 0; k < SIZEOF_UUID128; k++)
209991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			uuid128[uuid_count * SIZEOF_UUID128 + k] =
210991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi				uuid128_data[SIZEOF_UUID128 - 1 - k];
211991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
212991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		len += SIZEOF_UUID128;
213991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uuid_count++;
214991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
215991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
216991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	if (uuid_count > 0 || truncated) {
217991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* EIR Data length */
218991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		ptr[0] = (uuid_count * SIZEOF_UUID128) + 1;
219991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* EIR Data type */
220991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL;
221991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		len += 2;
222991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*eir_len = len;
223991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
224991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi}
225991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
226991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasivoid eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
227991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			uint16_t did_product, uint16_t did_version,
228991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			GSList *uuids, uint8_t *data)
229991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi{
230991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	GSList *l;
231991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uint8_t *ptr = data;
232991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	uint16_t eir_len = 0;
2339d172c96a54a5417b4464e1bebe67bedf183a8baBruna Moreira	uint16_t uuid16[HCI_MAX_EIR_LENGTH / 2];
234991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	int i, uuid_count = 0;
235991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	gboolean truncated = FALSE;
236991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	size_t name_len;
237991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
238991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	name_len = strlen(name);
239991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
240991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	if (name_len > 0) {
241991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* EIR Data type */
242991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		if (name_len > 48) {
243991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			name_len = 48;
244991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			ptr[1] = EIR_NAME_SHORT;
245991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		} else
246991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			ptr[1] = EIR_NAME_COMPLETE;
247991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
248991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* EIR Data length */
249991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		ptr[0] = name_len + 1;
250991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
251991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		memcpy(ptr + 2, name, name_len);
252991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
253991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir_len += (name_len + 2);
254991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		ptr += (name_len + 2);
255991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
256991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
257991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	if (tx_power != 0) {
258991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = 2;
259991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = EIR_TX_POWER;
260991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = (uint8_t) tx_power;
261991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir_len += 3;
262991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
263991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
264991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	if (did_vendor != 0x0000) {
265991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uint16_t source = 0x0002;
266991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = 9;
267991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = EIR_DEVICE_ID;
268991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = (source & 0x00ff);
269991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = (source & 0xff00) >> 8;
270991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = (did_vendor & 0x00ff);
271991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = (did_vendor & 0xff00) >> 8;
272991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = (did_product & 0x00ff);
273991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = (did_product & 0xff00) >> 8;
274991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = (did_version & 0x00ff);
275991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		*ptr++ = (did_version & 0xff00) >> 8;
276991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir_len += 10;
277991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
278991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
279991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	/* Group all UUID16 types */
280991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	for (l = uuids; l != NULL; l = g_slist_next(l)) {
281991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		struct uuid_info *uuid = l->data;
282991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
283991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		if (uuid->uuid.type != SDP_UUID16)
284991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			continue;
285991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
286991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		if (uuid->uuid.value.uuid16 < 0x1100)
287991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			continue;
288991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
289991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		if (uuid->uuid.value.uuid16 == PNP_INFO_SVCLASS_ID)
290991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			continue;
291991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
292991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* Stop if not enough space to put next UUID16 */
2939d172c96a54a5417b4464e1bebe67bedf183a8baBruna Moreira		if ((eir_len + 2 + sizeof(uint16_t)) > HCI_MAX_EIR_LENGTH) {
294991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			truncated = TRUE;
295991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			break;
296991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		}
297991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
298991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* Check for duplicates */
299991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		for (i = 0; i < uuid_count; i++)
300991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			if (uuid16[i] == uuid->uuid.value.uuid16)
301991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi				break;
302991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
303991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		if (i < uuid_count)
304991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			continue;
305991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
306991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		uuid16[uuid_count++] = uuid->uuid.value.uuid16;
307991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir_len += sizeof(uint16_t);
308991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
309991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
310991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	if (uuid_count > 0) {
311991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* EIR Data length */
312991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		ptr[0] = (uuid_count * sizeof(uint16_t)) + 1;
313991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		/* EIR Data type */
314991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
315991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
316991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		ptr += 2;
317991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir_len += 2;
318991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
319991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		for (i = 0; i < uuid_count; i++) {
320991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			*ptr++ = (uuid16[i] & 0x00ff);
321991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi			*ptr++ = (uuid16[i] & 0xff00) >> 8;
322991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		}
323991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	}
324991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi
325991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi	/* Group all UUID128 types */
3269d172c96a54a5417b4464e1bebe67bedf183a8baBruna Moreira	if (eir_len <= HCI_MAX_EIR_LENGTH - 2)
327991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi		eir_generate_uuid128(uuids, ptr, &eir_len);
328991a7a4f09049c91297d74f9d28497fad166268eClaudio Takahasi}
329