Home | History | Annotate | Download | only in lib
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2011  Nokia Corporation
      6  *  Copyright (C) 2011  Marcel Holtmann <marcel (at) 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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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  */
    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 
    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 
    192 static inline int is_uuid32(const char *string)
    193 {
    194 	return (strlen(string) == 8 || strlen(string) == 10);
    195 }
    196 
    197 static inline int is_uuid16(const char *string)
    198 {
    199 	return (strlen(string) == 4 || strlen(string) == 6);
    200 }
    201 
    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 
    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 
    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 
    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