• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2011  Nokia Corporation
6  *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
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.
13  *
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.
18  *
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
22  *
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 
33 #include "uuid.h"
34 
35 #if __BYTE_ORDER == __BIG_ENDIAN
36 static uint128_t bluetooth_base_uuid = {
37 	.data = {	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
38 			0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }
39 };
40 
41 #define BASE_UUID16_OFFSET	2
42 #define BASE_UUID32_OFFSET	0
43 
44 #else
45 static uint128_t bluetooth_base_uuid = {
46 	.data = {	0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
47 			0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
48 };
49 
50 #define BASE_UUID16_OFFSET	12
51 #define BASE_UUID32_OFFSET	BASE_UUID16_OFFSET
52 
53 #endif
54 
bt_uuid16_to_uuid128(const bt_uuid_t * src,bt_uuid_t * dst)55 static void bt_uuid16_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
56 {
57 	dst->value.u128 = bluetooth_base_uuid;
58 	dst->type = BT_UUID128;
59 
60 	memcpy(&dst->value.u128.data[BASE_UUID16_OFFSET],
61 			&src->value.u16, sizeof(src->value.u16));
62 }
63 
bt_uuid32_to_uuid128(const bt_uuid_t * src,bt_uuid_t * dst)64 static void bt_uuid32_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
65 {
66 	dst->value.u128 = bluetooth_base_uuid;
67 	dst->type = BT_UUID128;
68 
69 	memcpy(&dst->value.u128.data[BASE_UUID32_OFFSET],
70 				&src->value.u32, sizeof(src->value.u32));
71 }
72 
bt_uuid_to_uuid128(const bt_uuid_t * src,bt_uuid_t * dst)73 void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
74 {
75 	switch (src->type) {
76 	case BT_UUID128:
77 		memcpy(dst, src, sizeof(bt_uuid_t));
78 		break;
79 	case BT_UUID32:
80 		bt_uuid32_to_uuid128(src, dst);
81 		break;
82 	case BT_UUID16:
83 		bt_uuid16_to_uuid128(src, dst);
84 		break;
85 	default:
86 		break;
87 	}
88 }
89 
bt_uuid128_cmp(const bt_uuid_t * u1,const bt_uuid_t * u2)90 static int bt_uuid128_cmp(const bt_uuid_t *u1, const bt_uuid_t *u2)
91 {
92 	return memcmp(&u1->value.u128, &u2->value.u128, sizeof(uint128_t));
93 }
94 
bt_uuid16_create(bt_uuid_t * btuuid,uint16_t value)95 int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value)
96 {
97 	memset(btuuid, 0, sizeof(bt_uuid_t));
98 	btuuid->type = BT_UUID16;
99 	btuuid->value.u16 = value;
100 
101 	return 0;
102 }
103 
bt_uuid32_create(bt_uuid_t * btuuid,uint32_t value)104 int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value)
105 {
106 	memset(btuuid, 0, sizeof(bt_uuid_t));
107 	btuuid->type = BT_UUID32;
108 	btuuid->value.u32 = value;
109 
110 	return 0;
111 }
112 
bt_uuid128_create(bt_uuid_t * btuuid,uint128_t value)113 int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value)
114 {
115 	memset(btuuid, 0, sizeof(bt_uuid_t));
116 	btuuid->type = BT_UUID128;
117 	btuuid->value.u128 = value;
118 
119 	return 0;
120 }
121 
bt_uuid_cmp(const bt_uuid_t * uuid1,const bt_uuid_t * uuid2)122 int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2)
123 {
124 	bt_uuid_t u1, u2;
125 
126 	bt_uuid_to_uuid128(uuid1, &u1);
127 	bt_uuid_to_uuid128(uuid2, &u2);
128 
129 	return bt_uuid128_cmp(&u1, &u2);
130 }
131 
132 /*
133  * convert the UUID to string, copying a maximum of n characters.
134  */
bt_uuid_to_string(const bt_uuid_t * uuid,char * str,size_t n)135 int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
136 {
137 	if (!uuid) {
138 		snprintf(str, n, "NULL");
139 		return -EINVAL;
140 	}
141 
142 	switch (uuid->type) {
143 	case BT_UUID16:
144 		snprintf(str, n, "%.4x", uuid->value.u16);
145 		break;
146 	case BT_UUID32:
147 		snprintf(str, n, "%.8x", uuid->value.u32);
148 		break;
149 	case BT_UUID128: {
150 		unsigned int   data0;
151 		unsigned short data1;
152 		unsigned short data2;
153 		unsigned short data3;
154 		unsigned int   data4;
155 		unsigned short data5;
156 
157 		uint128_t nvalue;
158 		const uint8_t *data = (uint8_t *) &nvalue;
159 
160 		hton128(&uuid->value.u128, &nvalue);
161 
162 		memcpy(&data0, &data[0], 4);
163 		memcpy(&data1, &data[4], 2);
164 		memcpy(&data2, &data[6], 2);
165 		memcpy(&data3, &data[8], 2);
166 		memcpy(&data4, &data[10], 4);
167 		memcpy(&data5, &data[14], 2);
168 
169 		snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
170 				ntohl(data0), ntohs(data1),
171 				ntohs(data2), ntohs(data3),
172 				ntohl(data4), ntohs(data5));
173 		}
174 		break;
175 	default:
176 		snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type);
177 		return -EINVAL;	/* Enum type of UUID not set */
178 	}
179 
180 	return 0;
181 }
182 
is_uuid128(const char * string)183 static inline int is_uuid128(const char *string)
184 {
185 	return (strlen(string) == 36 &&
186 			string[8] == '-' &&
187 			string[13] == '-' &&
188 			string[18] == '-' &&
189 			string[23] == '-');
190 }
191 
is_uuid32(const char * string)192 static inline int is_uuid32(const char *string)
193 {
194 	return (strlen(string) == 8 || strlen(string) == 10);
195 }
196 
is_uuid16(const char * string)197 static inline int is_uuid16(const char *string)
198 {
199 	return (strlen(string) == 4 || strlen(string) == 6);
200 }
201 
bt_string_to_uuid16(bt_uuid_t * uuid,const char * string)202 static int bt_string_to_uuid16(bt_uuid_t *uuid, const char *string)
203 {
204 	uint16_t u16;
205 	char *endptr = NULL;
206 
207 	u16 = strtol(string, &endptr, 16);
208 	if (endptr && *endptr == '\0') {
209 		bt_uuid16_create(uuid, u16);
210 		return 0;
211 	}
212 
213 	return -EINVAL;
214 }
215 
bt_string_to_uuid32(bt_uuid_t * uuid,const char * string)216 static int bt_string_to_uuid32(bt_uuid_t *uuid, const char *string)
217 {
218 	uint32_t u32;
219 	char *endptr = NULL;
220 
221 	u32 = strtol(string, &endptr, 16);
222 	if (endptr && *endptr == '\0') {
223 		bt_uuid32_create(uuid, u32);
224 		return 0;
225 	}
226 
227 	return -EINVAL;
228 }
229 
bt_string_to_uuid128(bt_uuid_t * uuid,const char * string)230 static int bt_string_to_uuid128(bt_uuid_t *uuid, const char *string)
231 {
232 	uint32_t data0, data4;
233 	uint16_t data1, data2, data3, data5;
234 	uint128_t n128, u128;
235 	uint8_t *val = (uint8_t *) &n128;
236 
237 	if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
238 				&data0, &data1, &data2,
239 				&data3, &data4, &data5) != 6)
240 		return -EINVAL;
241 
242 	data0 = htonl(data0);
243 	data1 = htons(data1);
244 	data2 = htons(data2);
245 	data3 = htons(data3);
246 	data4 = htonl(data4);
247 	data5 = htons(data5);
248 
249 	memcpy(&val[0], &data0, 4);
250 	memcpy(&val[4], &data1, 2);
251 	memcpy(&val[6], &data2, 2);
252 	memcpy(&val[8], &data3, 2);
253 	memcpy(&val[10], &data4, 4);
254 	memcpy(&val[14], &data5, 2);
255 
256 	ntoh128(&n128, &u128);
257 
258 	bt_uuid128_create(uuid, u128);
259 
260 	return 0;
261 }
262 
bt_string_to_uuid(bt_uuid_t * uuid,const char * string)263 int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
264 {
265 	if (is_uuid128(string))
266 		return bt_string_to_uuid128(uuid, string);
267 	else if (is_uuid32(string))
268 		return bt_string_to_uuid32(uuid, string);
269 	else if (is_uuid16(string))
270 		return bt_string_to_uuid16(uuid, string);
271 
272 	return -EINVAL;
273 }
274