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