1 /* uuid.c - Bluetooth UUID handling */
2 
3 /*
4  * Copyright (c) 2015-2016 Intel Corporation
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <errno.h>
10 #include <stdbool.h>
11 #include <stdint.h>
12 #include <string.h>
13 
14 #include <zephyr/bluetooth/uuid.h>
15 #include <zephyr/sys/byteorder.h>
16 #include <zephyr/sys/printk.h>
17 
18 #define UUID_16_BASE_OFFSET 12
19 
20 /* TODO: Decide whether to continue using Bluetooth LE format or switch to RFC 4122 */
21 
22 /* Base UUID : 0000[0000]-0000-1000-8000-00805F9B34FB
23  * 0x2800    : 0000[2800]-0000-1000-8000-00805F9B34FB
24  *  little endian 0x2800 : [00 28] -> no swapping required
25  *  big endian 0x2800    : [28 00] -> swapping required
26  */
27 static const struct bt_uuid_128 uuid128_base = {
28 	.uuid = { BT_UUID_TYPE_128 },
29 	.val = { BT_UUID_128_ENCODE(
30 		0x00000000, 0x0000, 0x1000, 0x8000, 0x00805F9B34FB) }
31 };
32 
uuid_to_uuid128(const struct bt_uuid * src,struct bt_uuid_128 * dst)33 static void uuid_to_uuid128(const struct bt_uuid *src, struct bt_uuid_128 *dst)
34 {
35 	switch (src->type) {
36 	case BT_UUID_TYPE_16:
37 		*dst = uuid128_base;
38 		sys_put_le16(BT_UUID_16(src)->val,
39 			     &dst->val[UUID_16_BASE_OFFSET]);
40 		return;
41 	case BT_UUID_TYPE_32:
42 		*dst = uuid128_base;
43 		sys_put_le32(BT_UUID_32(src)->val,
44 			     &dst->val[UUID_16_BASE_OFFSET]);
45 		return;
46 	case BT_UUID_TYPE_128:
47 		memcpy(dst, src, sizeof(*dst));
48 		return;
49 	}
50 }
51 
uuid128_cmp(const struct bt_uuid * u1,const struct bt_uuid * u2)52 static int uuid128_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2)
53 {
54 	struct bt_uuid_128 uuid1, uuid2;
55 
56 	uuid_to_uuid128(u1, &uuid1);
57 	uuid_to_uuid128(u2, &uuid2);
58 
59 	return memcmp(uuid1.val, uuid2.val, 16);
60 }
61 
bt_uuid_cmp(const struct bt_uuid * u1,const struct bt_uuid * u2)62 int bt_uuid_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2)
63 {
64 	/* Convert to 128 bit if types don't match */
65 	if (u1->type != u2->type) {
66 		return uuid128_cmp(u1, u2);
67 	}
68 
69 	switch (u1->type) {
70 	case BT_UUID_TYPE_16:
71 		return (int)BT_UUID_16(u1)->val - (int)BT_UUID_16(u2)->val;
72 	case BT_UUID_TYPE_32:
73 		return (int)BT_UUID_32(u1)->val - (int)BT_UUID_32(u2)->val;
74 	case BT_UUID_TYPE_128:
75 		return memcmp(BT_UUID_128(u1)->val, BT_UUID_128(u2)->val, 16);
76 	}
77 
78 	return -EINVAL;
79 }
80 
bt_uuid_create(struct bt_uuid * uuid,const uint8_t * data,uint8_t data_len)81 bool bt_uuid_create(struct bt_uuid *uuid, const uint8_t *data, uint8_t data_len)
82 {
83 	/* Copy UUID from packet data/internal variable to internal bt_uuid */
84 	switch (data_len) {
85 	case BT_UUID_SIZE_16:
86 		uuid->type = BT_UUID_TYPE_16;
87 		BT_UUID_16(uuid)->val = sys_get_le16(data);
88 		break;
89 	case BT_UUID_SIZE_32:
90 		uuid->type = BT_UUID_TYPE_32;
91 		BT_UUID_32(uuid)->val = sys_get_le32(data);
92 		break;
93 	case BT_UUID_SIZE_128:
94 		uuid->type = BT_UUID_TYPE_128;
95 		memcpy(&BT_UUID_128(uuid)->val, data, 16);
96 		break;
97 	default:
98 		return false;
99 	}
100 	return true;
101 }
102 
bt_uuid_to_str(const struct bt_uuid * uuid,char * str,size_t len)103 void bt_uuid_to_str(const struct bt_uuid *uuid, char *str, size_t len)
104 {
105 	uint32_t tmp1, tmp5;
106 	uint16_t tmp0, tmp2, tmp3, tmp4;
107 
108 	switch (uuid->type) {
109 	case BT_UUID_TYPE_16:
110 		snprintk(str, len, "%04x", BT_UUID_16(uuid)->val);
111 		break;
112 	case BT_UUID_TYPE_32:
113 		snprintk(str, len, "%08x", BT_UUID_32(uuid)->val);
114 		break;
115 	case BT_UUID_TYPE_128:
116 		memcpy(&tmp0, &BT_UUID_128(uuid)->val[0], sizeof(tmp0));
117 		memcpy(&tmp1, &BT_UUID_128(uuid)->val[2], sizeof(tmp1));
118 		memcpy(&tmp2, &BT_UUID_128(uuid)->val[6], sizeof(tmp2));
119 		memcpy(&tmp3, &BT_UUID_128(uuid)->val[8], sizeof(tmp3));
120 		memcpy(&tmp4, &BT_UUID_128(uuid)->val[10], sizeof(tmp4));
121 		memcpy(&tmp5, &BT_UUID_128(uuid)->val[12], sizeof(tmp5));
122 
123 		snprintk(str, len, "%08x-%04x-%04x-%04x-%08x%04x",
124 			 sys_le32_to_cpu(tmp5), sys_le16_to_cpu(tmp4),
125 			 sys_le16_to_cpu(tmp3), sys_le16_to_cpu(tmp2),
126 			 sys_le32_to_cpu(tmp1), sys_le16_to_cpu(tmp0));
127 		break;
128 	default:
129 		(void)memset(str, 0, len);
130 		return;
131 	}
132 }
133