uuid.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2011 Nokia Corporation
  7. * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
  8. *
  9. *
  10. */
  11. #ifdef HAVE_CONFIG_H
  12. #include <config.h>
  13. #endif
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <errno.h>
  17. #include "lib/bluetooth.h"
  18. #include "uuid.h"
  19. static uint128_t bluetooth_base_uuid = {
  20. .data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
  21. 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }
  22. };
  23. #define BASE_UUID16_OFFSET 2
  24. #define BASE_UUID32_OFFSET 0
  25. static void bt_uuid16_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
  26. {
  27. uint16_t be16;
  28. dst->value.u128 = bluetooth_base_uuid;
  29. dst->type = BT_UUID128;
  30. /*
  31. * No matter the system: 128-bit UUIDs should be stored
  32. * as big-endian. 16-bit UUIDs are stored on host order.
  33. */
  34. be16 = htons(src->value.u16);
  35. memcpy(&dst->value.u128.data[BASE_UUID16_OFFSET], &be16, sizeof(be16));
  36. }
  37. static void bt_uuid32_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
  38. {
  39. uint32_t be32;
  40. dst->value.u128 = bluetooth_base_uuid;
  41. dst->type = BT_UUID128;
  42. /*
  43. * No matter the system: 128-bit UUIDs should be stored
  44. * as big-endian. 32-bit UUIDs are stored on host order.
  45. */
  46. be32 = htonl(src->value.u32);
  47. memcpy(&dst->value.u128.data[BASE_UUID32_OFFSET], &be32, sizeof(be32));
  48. }
  49. void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
  50. {
  51. switch (src->type) {
  52. case BT_UUID128:
  53. *dst = *src;
  54. break;
  55. case BT_UUID32:
  56. bt_uuid32_to_uuid128(src, dst);
  57. break;
  58. case BT_UUID16:
  59. bt_uuid16_to_uuid128(src, dst);
  60. break;
  61. case BT_UUID_UNSPEC:
  62. default:
  63. break;
  64. }
  65. }
  66. static int bt_uuid128_cmp(const bt_uuid_t *u1, const bt_uuid_t *u2)
  67. {
  68. return memcmp(&u1->value.u128, &u2->value.u128, sizeof(uint128_t));
  69. }
  70. int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value)
  71. {
  72. memset(btuuid, 0, sizeof(bt_uuid_t));
  73. btuuid->type = BT_UUID16;
  74. btuuid->value.u16 = value;
  75. return 0;
  76. }
  77. int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value)
  78. {
  79. memset(btuuid, 0, sizeof(bt_uuid_t));
  80. btuuid->type = BT_UUID32;
  81. btuuid->value.u32 = value;
  82. return 0;
  83. }
  84. int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value)
  85. {
  86. memset(btuuid, 0, sizeof(bt_uuid_t));
  87. btuuid->type = BT_UUID128;
  88. btuuid->value.u128 = value;
  89. return 0;
  90. }
  91. int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2)
  92. {
  93. bt_uuid_t u1, u2;
  94. bt_uuid_to_uuid128(uuid1, &u1);
  95. bt_uuid_to_uuid128(uuid2, &u2);
  96. return bt_uuid128_cmp(&u1, &u2);
  97. }
  98. /*
  99. * convert the UUID to string, copying a maximum of n characters.
  100. */
  101. int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
  102. {
  103. bt_uuid_t tmp;
  104. unsigned int data0;
  105. unsigned short data1;
  106. unsigned short data2;
  107. unsigned short data3;
  108. unsigned int data4;
  109. unsigned short data5;
  110. const uint8_t *data;
  111. if (!uuid || uuid->type == BT_UUID_UNSPEC) {
  112. snprintf(str, n, "NULL");
  113. return -EINVAL;
  114. }
  115. /* Convert to 128 Bit format */
  116. bt_uuid_to_uuid128(uuid, &tmp);
  117. data = (uint8_t *) &tmp.value.u128;
  118. memcpy(&data0, &data[0], 4);
  119. memcpy(&data1, &data[4], 2);
  120. memcpy(&data2, &data[6], 2);
  121. memcpy(&data3, &data[8], 2);
  122. memcpy(&data4, &data[10], 4);
  123. memcpy(&data5, &data[14], 2);
  124. snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
  125. ntohl(data0), ntohs(data1),
  126. ntohs(data2), ntohs(data3),
  127. ntohl(data4), ntohs(data5));
  128. return 0;
  129. }
  130. static inline int is_uuid128(const char *string)
  131. {
  132. return (strlen(string) == 36 &&
  133. string[8] == '-' &&
  134. string[13] == '-' &&
  135. string[18] == '-' &&
  136. string[23] == '-');
  137. }
  138. static inline int is_base_uuid128(const char *string)
  139. {
  140. uint16_t uuid;
  141. char dummy[2];
  142. if (!is_uuid128(string))
  143. return 0;
  144. return sscanf(string,
  145. "0000%04hx-0000-1000-8000-00805%1[fF]9%1[bB]34%1[fF]%1[bB]",
  146. &uuid, dummy, dummy, dummy, dummy) == 5;
  147. }
  148. static inline int is_uuid32(const char *string)
  149. {
  150. return (strlen(string) == 8 || strlen(string) == 10);
  151. }
  152. static inline int is_uuid16(const char *string)
  153. {
  154. return (strlen(string) == 4 || strlen(string) == 6);
  155. }
  156. static int bt_string_to_uuid16(bt_uuid_t *uuid, const char *string)
  157. {
  158. uint16_t u16;
  159. char *endptr = NULL;
  160. u16 = strtol(string, &endptr, 16);
  161. if (endptr && (*endptr == '\0' || *endptr == '-')) {
  162. bt_uuid16_create(uuid, u16);
  163. return 0;
  164. }
  165. return -EINVAL;
  166. }
  167. static int bt_string_to_uuid32(bt_uuid_t *uuid, const char *string)
  168. {
  169. uint32_t u32;
  170. char *endptr = NULL;
  171. u32 = strtoul(string, &endptr, 16);
  172. if (endptr && *endptr == '\0') {
  173. bt_uuid32_create(uuid, u32);
  174. return 0;
  175. }
  176. return -EINVAL;
  177. }
  178. static int bt_string_to_uuid128(bt_uuid_t *uuid, const char *string)
  179. {
  180. uint32_t data0, data4;
  181. uint16_t data1, data2, data3, data5;
  182. uint128_t u128;
  183. uint8_t *val = (uint8_t *) &u128;
  184. if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
  185. &data0, &data1, &data2,
  186. &data3, &data4, &data5) != 6)
  187. return -EINVAL;
  188. data0 = htonl(data0);
  189. data1 = htons(data1);
  190. data2 = htons(data2);
  191. data3 = htons(data3);
  192. data4 = htonl(data4);
  193. data5 = htons(data5);
  194. memcpy(&val[0], &data0, 4);
  195. memcpy(&val[4], &data1, 2);
  196. memcpy(&val[6], &data2, 2);
  197. memcpy(&val[8], &data3, 2);
  198. memcpy(&val[10], &data4, 4);
  199. memcpy(&val[14], &data5, 2);
  200. bt_uuid128_create(uuid, u128);
  201. return 0;
  202. }
  203. int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
  204. {
  205. if (is_base_uuid128(string))
  206. return bt_string_to_uuid16(uuid, string + 4);
  207. else if (is_uuid128(string))
  208. return bt_string_to_uuid128(uuid, string);
  209. else if (is_uuid32(string))
  210. return bt_string_to_uuid32(uuid, string);
  211. else if (is_uuid16(string))
  212. return bt_string_to_uuid16(uuid, string);
  213. return -EINVAL;
  214. }
  215. int bt_uuid_strcmp(const void *a, const void *b)
  216. {
  217. bt_uuid_t u1, u2;
  218. if (bt_string_to_uuid(&u1, a) < 0)
  219. return -EINVAL;
  220. if (bt_string_to_uuid(&u2, b) < 0)
  221. return -EINVAL;
  222. return bt_uuid_cmp(&u1, &u2);
  223. }
  224. int bt_uuid_to_le(const bt_uuid_t *src, void *dst)
  225. {
  226. bt_uuid_t uuid;
  227. switch (src->type) {
  228. case BT_UUID16:
  229. bt_put_le16(src->value.u16, dst);
  230. return 0;
  231. case BT_UUID32:
  232. bt_uuid32_to_uuid128(src, &uuid);
  233. src = &uuid;
  234. /* Fallthrough */
  235. case BT_UUID128:
  236. /* Convert from 128-bit BE to LE */
  237. bswap_128(&src->value.u128, dst);
  238. return 0;
  239. case BT_UUID_UNSPEC:
  240. default:
  241. return -EINVAL;
  242. }
  243. }