Upgrade bluez5_37 :Merge the code from private
[platform/upstream/bluez.git] / lib / uuid.c
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 "lib/bluetooth.h"
34 #include "uuid.h"
35
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 static void bt_uuid16_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
45 {
46         uint16_t be16;
47
48         dst->value.u128 = bluetooth_base_uuid;
49         dst->type = BT_UUID128;
50
51         /*
52          * No matter the system: 128-bit UUIDs should be stored
53          * as big-endian. 16-bit UUIDs are stored on host order.
54          */
55
56         be16 = htons(src->value.u16);
57         memcpy(&dst->value.u128.data[BASE_UUID16_OFFSET], &be16, sizeof(be16));
58 }
59
60 static void bt_uuid32_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
61 {
62         uint32_t be32;
63
64         dst->value.u128 = bluetooth_base_uuid;
65         dst->type = BT_UUID128;
66
67         /*
68          * No matter the system: 128-bit UUIDs should be stored
69          * as big-endian. 32-bit UUIDs are stored on host order.
70          */
71
72         be32 = htonl(src->value.u32);
73         memcpy(&dst->value.u128.data[BASE_UUID32_OFFSET], &be32, sizeof(be32));
74 }
75
76 void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
77 {
78         switch (src->type) {
79         case BT_UUID128:
80                 *dst = *src;
81                 break;
82         case BT_UUID32:
83                 bt_uuid32_to_uuid128(src, dst);
84                 break;
85         case BT_UUID16:
86                 bt_uuid16_to_uuid128(src, dst);
87                 break;
88         case BT_UUID_UNSPEC:
89         default:
90                 break;
91         }
92 }
93
94 static int bt_uuid128_cmp(const bt_uuid_t *u1, const bt_uuid_t *u2)
95 {
96         return memcmp(&u1->value.u128, &u2->value.u128, sizeof(uint128_t));
97 }
98
99 int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value)
100 {
101         memset(btuuid, 0, sizeof(bt_uuid_t));
102         btuuid->type = BT_UUID16;
103         btuuid->value.u16 = value;
104
105         return 0;
106 }
107
108 int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value)
109 {
110         memset(btuuid, 0, sizeof(bt_uuid_t));
111         btuuid->type = BT_UUID32;
112         btuuid->value.u32 = value;
113
114         return 0;
115 }
116
117 int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value)
118 {
119         memset(btuuid, 0, sizeof(bt_uuid_t));
120         btuuid->type = BT_UUID128;
121         btuuid->value.u128 = value;
122
123         return 0;
124 }
125
126 int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2)
127 {
128         bt_uuid_t u1, u2;
129
130         bt_uuid_to_uuid128(uuid1, &u1);
131         bt_uuid_to_uuid128(uuid2, &u2);
132
133         return bt_uuid128_cmp(&u1, &u2);
134 }
135
136 /*
137  * convert the UUID to string, copying a maximum of n characters.
138  */
139 int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
140 {
141         bt_uuid_t tmp;
142         unsigned int   data0;
143         unsigned short data1;
144         unsigned short data2;
145         unsigned short data3;
146         unsigned int   data4;
147         unsigned short data5;
148         const uint8_t *data;
149
150         if (!uuid || uuid->type == BT_UUID_UNSPEC) {
151                 snprintf(str, n, "NULL");
152                 return -EINVAL;
153         }
154
155         /* Convert to 128 Bit format */
156         bt_uuid_to_uuid128(uuid, &tmp);
157         data = (uint8_t *) &tmp.value.u128;
158
159         memcpy(&data0, &data[0], 4);
160         memcpy(&data1, &data[4], 2);
161         memcpy(&data2, &data[6], 2);
162         memcpy(&data3, &data[8], 2);
163         memcpy(&data4, &data[10], 4);
164         memcpy(&data5, &data[14], 2);
165
166         snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
167                                 ntohl(data0), ntohs(data1),
168                                 ntohs(data2), ntohs(data3),
169                                 ntohl(data4), ntohs(data5));
170
171         return 0;
172 }
173
174 static inline int is_uuid128(const char *string)
175 {
176         return (strlen(string) == 36 &&
177                         string[8] == '-' &&
178                         string[13] == '-' &&
179                         string[18] == '-' &&
180                         string[23] == '-');
181 }
182
183 static inline int is_base_uuid128(const char *string)
184 {
185         uint16_t uuid;
186         char dummy;
187
188         if (!is_uuid128(string))
189                 return 0;
190
191         return sscanf(string,
192                 "0000%04hx-0000-1000-8000-00805%1[fF]9%1[bB]34%1[fF]%1[bB]",
193                 &uuid, &dummy, &dummy, &dummy, &dummy) == 5;
194 }
195
196 static inline int is_uuid32(const char *string)
197 {
198         return (strlen(string) == 8 || strlen(string) == 10);
199 }
200
201 static inline int is_uuid16(const char *string)
202 {
203         return (strlen(string) == 4 || strlen(string) == 6);
204 }
205
206 static int bt_string_to_uuid16(bt_uuid_t *uuid, const char *string)
207 {
208         uint16_t u16;
209         char *endptr = NULL;
210
211         u16 = strtol(string, &endptr, 16);
212         if (endptr && (*endptr == '\0' || *endptr == '-')) {
213                 bt_uuid16_create(uuid, u16);
214                 return 0;
215         }
216
217         return -EINVAL;
218 }
219
220 static int bt_string_to_uuid32(bt_uuid_t *uuid, const char *string)
221 {
222         uint32_t u32;
223         char *endptr = NULL;
224
225         u32 = strtol(string, &endptr, 16);
226         if (endptr && *endptr == '\0') {
227                 bt_uuid32_create(uuid, u32);
228                 return 0;
229         }
230
231         return -EINVAL;
232 }
233
234 static int bt_string_to_uuid128(bt_uuid_t *uuid, const char *string)
235 {
236         uint32_t data0, data4;
237         uint16_t data1, data2, data3, data5;
238         uint128_t u128;
239         uint8_t *val = (uint8_t *) &u128;
240
241         if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
242                                 &data0, &data1, &data2,
243                                 &data3, &data4, &data5) != 6)
244                 return -EINVAL;
245
246         data0 = htonl(data0);
247         data1 = htons(data1);
248         data2 = htons(data2);
249         data3 = htons(data3);
250         data4 = htonl(data4);
251         data5 = htons(data5);
252
253         memcpy(&val[0], &data0, 4);
254         memcpy(&val[4], &data1, 2);
255         memcpy(&val[6], &data2, 2);
256         memcpy(&val[8], &data3, 2);
257         memcpy(&val[10], &data4, 4);
258         memcpy(&val[14], &data5, 2);
259
260         bt_uuid128_create(uuid, u128);
261
262         return 0;
263 }
264
265 int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
266 {
267         if (is_base_uuid128(string))
268                 return bt_string_to_uuid16(uuid, string + 4);
269         else if (is_uuid128(string))
270                 return bt_string_to_uuid128(uuid, string);
271         else if (is_uuid32(string))
272                 return bt_string_to_uuid32(uuid, string);
273         else if (is_uuid16(string))
274                 return bt_string_to_uuid16(uuid, string);
275
276         return -EINVAL;
277 }
278
279 int bt_uuid_strcmp(const void *a, const void *b)
280 {
281         bt_uuid_t u1, u2;
282
283         bt_string_to_uuid(&u1, a);
284         bt_string_to_uuid(&u2, b);
285
286         return bt_uuid_cmp(&u1, &u2);
287 }
288
289 int bt_uuid_to_le(const bt_uuid_t *src, void *dst)
290 {
291         bt_uuid_t uuid;
292
293         switch (src->type) {
294         case BT_UUID16:
295                 bt_put_le16(src->value.u16, dst);
296                 return 0;
297         case BT_UUID32:
298                 bt_uuid32_to_uuid128(src, &uuid);
299                 src = &uuid;
300                 /* Fallthrough */
301         case BT_UUID128:
302                 /* Convert from 128-bit BE to LE */
303                 bswap_128(&src->value.u128, dst);
304                 return 0;
305         case BT_UUID_UNSPEC:
306         default:
307                 return -EINVAL;
308         }
309 }