1 /******************************************************************************
2 *
3 * Copyright 2018 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include "database.h"
20
21 #include <bluetooth/log.h>
22
23 #include <algorithm>
24 #include <list>
25 #include <sstream>
26
27 #include "crypto_toolbox/crypto_toolbox.h"
28 #include "internal_include/bt_trace.h"
29 #include "stack/include/bt_types.h"
30 #include "stack/include/gattdefs.h"
31 #include "types/bluetooth/uuid.h"
32
33 using bluetooth::Uuid;
34 using namespace bluetooth;
35
36 namespace gatt {
37
38 namespace {
39 const Uuid PRIMARY_SERVICE = Uuid::From16Bit(GATT_UUID_PRI_SERVICE);
40 const Uuid SECONDARY_SERVICE = Uuid::From16Bit(GATT_UUID_SEC_SERVICE);
41 const Uuid INCLUDE = Uuid::From16Bit(GATT_UUID_INCLUDE_SERVICE);
42 const Uuid CHARACTERISTIC = Uuid::From16Bit(GATT_UUID_CHAR_DECLARE);
43 const Uuid CHARACTERISTIC_EXTENDED_PROPERTIES = Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP);
44
HandleInRange(const Service & svc,uint16_t handle)45 bool HandleInRange(const Service& svc, uint16_t handle) {
46 return handle >= svc.handle && handle <= svc.end_handle;
47 }
48 } // namespace
49
UuidSize(const Uuid & uuid)50 static size_t UuidSize(const Uuid& uuid) {
51 size_t len = uuid.GetShortestRepresentationSize();
52 return (len == Uuid::kNumBytes32) ? Uuid::kNumBytes128 : len;
53 }
54
FindService(std::list<Service> & services,uint16_t handle)55 Service* FindService(std::list<Service>& services, uint16_t handle) {
56 for (Service& service : services) {
57 if (handle >= service.handle && handle <= service.end_handle) {
58 return &service;
59 }
60 }
61
62 return nullptr;
63 }
64
ToString() const65 std::string Database::ToString() const {
66 std::stringstream tmp;
67
68 for (const Service& service : services) {
69 tmp << "Service: handle=" << loghex(service.handle)
70 << ", end_handle=" << loghex(service.end_handle) << ", uuid=" << service.uuid << "\n";
71
72 for (const auto& is : service.included_services) {
73 tmp << "\t Included service: handle=" << loghex(is.handle)
74 << ", start_handle=" << loghex(is.start_handle)
75 << ", end_handle=" << loghex(is.end_handle) << ", uuid=" << is.uuid << "\n";
76 }
77
78 for (const Characteristic& c : service.characteristics) {
79 tmp << "\t Characteristic: declaration_handle=" << loghex(c.declaration_handle)
80 << ", value_handle=" << loghex(c.value_handle) << ", uuid=" << c.uuid
81 << ", prop=" << loghex(c.properties) << "\n";
82
83 for (const Descriptor& d : c.descriptors) {
84 tmp << "\t\t Descriptor: handle=" << loghex(d.handle) << ", uuid=" << d.uuid << "\n";
85 }
86 }
87 }
88 return tmp.str();
89 }
90
Serialize() const91 std::vector<StoredAttribute> Database::Serialize() const {
92 std::vector<StoredAttribute> nv_attr;
93
94 if (services.empty()) {
95 return std::vector<StoredAttribute>();
96 }
97
98 for (const Service& service : services) {
99 // TODO: add constructor to NV_ATTR, use emplace_back
100 nv_attr.push_back({service.handle,
101 service.is_primary ? PRIMARY_SERVICE : SECONDARY_SERVICE,
102 {.service = {.uuid = service.uuid, .end_handle = service.end_handle}}});
103 }
104
105 for (const Service& service : services) {
106 for (const IncludedService& p_isvc : service.included_services) {
107 nv_attr.push_back({p_isvc.handle,
108 INCLUDE,
109 {.included_service = {.handle = p_isvc.start_handle,
110 .end_handle = p_isvc.end_handle,
111 .uuid = p_isvc.uuid}}});
112 }
113
114 for (const Characteristic& charac : service.characteristics) {
115 nv_attr.push_back({charac.declaration_handle,
116 CHARACTERISTIC,
117 {.characteristic = {.properties = charac.properties,
118 .value_handle = charac.value_handle,
119 .uuid = charac.uuid}}});
120
121 for (const Descriptor& desc : charac.descriptors) {
122 if (desc.uuid == CHARACTERISTIC_EXTENDED_PROPERTIES) {
123 nv_attr.push_back({desc.handle,
124 desc.uuid,
125 {.characteristic_extended_properties =
126 desc.characteristic_extended_properties}});
127 } else {
128 nv_attr.push_back({desc.handle, desc.uuid, {}});
129 }
130 }
131 }
132 }
133
134 return nv_attr;
135 }
136
Deserialize(const std::vector<StoredAttribute> & nv_attr,bool * success)137 Database Database::Deserialize(const std::vector<StoredAttribute>& nv_attr, bool* success) {
138 // clear reallocating
139 Database result;
140 auto it = nv_attr.cbegin();
141
142 for (; it != nv_attr.cend(); ++it) {
143 const auto& attr = *it;
144 if (attr.type != PRIMARY_SERVICE && attr.type != SECONDARY_SERVICE) {
145 break;
146 }
147 result.services.emplace_back(Service{
148 .handle = attr.handle,
149 .uuid = attr.value.service.uuid,
150 .is_primary = (attr.type == PRIMARY_SERVICE),
151 .end_handle = attr.value.service.end_handle,
152 .included_services = {},
153 .characteristics = {},
154 });
155 }
156
157 auto current_service_it = result.services.begin();
158 for (; it != nv_attr.cend(); it++) {
159 const auto& attr = *it;
160
161 // go to the service this attribute belongs to; attributes are stored in
162 // order, so iterating just forward is enough
163 while (current_service_it != result.services.end() &&
164 current_service_it->end_handle < attr.handle) {
165 current_service_it++;
166 }
167
168 if (current_service_it == result.services.end() ||
169 !HandleInRange(*current_service_it, attr.handle)) {
170 log::error("Can't find service for attribute with handle: 0x{:x}", attr.handle);
171 *success = false;
172 return result;
173 }
174
175 if (attr.type == INCLUDE) {
176 Service* included_service = FindService(result.services, attr.value.included_service.handle);
177 if (!included_service) {
178 log::error("Non-existing included service!");
179 *success = false;
180 return result;
181 }
182 current_service_it->included_services.push_back(IncludedService{
183 .handle = attr.handle,
184 .uuid = attr.value.included_service.uuid,
185 .start_handle = attr.value.included_service.handle,
186 .end_handle = attr.value.included_service.end_handle,
187 });
188 } else if (attr.type == CHARACTERISTIC) {
189 current_service_it->characteristics.emplace_back(Characteristic{
190 .declaration_handle = attr.handle,
191 .uuid = attr.value.characteristic.uuid,
192 .value_handle = attr.value.characteristic.value_handle,
193 .properties = attr.value.characteristic.properties,
194 .descriptors = {},
195 });
196
197 } else {
198 if (attr.type == CHARACTERISTIC_EXTENDED_PROPERTIES) {
199 current_service_it->characteristics.back().descriptors.emplace_back(
200 Descriptor{.handle = attr.handle,
201 .uuid = attr.type,
202 .characteristic_extended_properties =
203 attr.value.characteristic_extended_properties});
204
205 } else {
206 current_service_it->characteristics.back().descriptors.emplace_back(Descriptor{
207 .handle = attr.handle,
208 .uuid = attr.type,
209 .characteristic_extended_properties = {},
210 });
211 }
212 }
213 }
214 *success = true;
215 return result;
216 }
217
Hash() const218 Octet16 Database::Hash() const {
219 int len = 0;
220 // Compute how much space we need to actually hold the data.
221 for (const Service& service : services) {
222 len += 4 + UuidSize(service.uuid);
223
224 for (const auto& is : service.included_services) {
225 len += 8 + UuidSize(is.uuid);
226 }
227
228 for (const Characteristic& c : service.characteristics) {
229 len += 7 + UuidSize(c.uuid);
230
231 for (const Descriptor& d : c.descriptors) {
232 if (UuidSize(d.uuid) != Uuid::kNumBytes16) {
233 continue;
234 }
235 uint16_t value = d.uuid.As16Bit();
236 if (value == GATT_UUID_CHAR_DESCRIPTION || value == GATT_UUID_CHAR_CLIENT_CONFIG ||
237 value == GATT_UUID_CHAR_SRVR_CONFIG || value == GATT_UUID_CHAR_PRESENT_FORMAT ||
238 value == GATT_UUID_CHAR_AGG_FORMAT) {
239 len += 2 + UuidSize(d.uuid);
240 } else if (value == GATT_UUID_CHAR_EXT_PROP) {
241 len += 4 + UuidSize(d.uuid);
242 }
243 }
244 }
245 }
246
247 std::vector<uint8_t> serialized(len);
248 uint8_t* p = serialized.data();
249 for (const Service& service : services) {
250 UINT16_TO_STREAM(p, service.handle);
251 if (service.is_primary) {
252 UINT16_TO_STREAM(p, GATT_UUID_PRI_SERVICE);
253 } else {
254 UINT16_TO_STREAM(p, GATT_UUID_SEC_SERVICE);
255 }
256
257 if (UuidSize(service.uuid) == Uuid::kNumBytes16) {
258 UINT16_TO_STREAM(p, service.uuid.As16Bit());
259 } else {
260 ARRAY_TO_STREAM(p, service.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
261 }
262
263 for (const auto& is : service.included_services) {
264 UINT16_TO_STREAM(p, is.handle);
265 UINT16_TO_STREAM(p, GATT_UUID_INCLUDE_SERVICE);
266 UINT16_TO_STREAM(p, is.start_handle);
267 UINT16_TO_STREAM(p, is.end_handle);
268
269 if (UuidSize(is.uuid) == Uuid::kNumBytes16) {
270 UINT16_TO_STREAM(p, is.uuid.As16Bit());
271 } else {
272 ARRAY_TO_STREAM(p, is.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
273 }
274 }
275
276 for (const Characteristic& c : service.characteristics) {
277 UINT16_TO_STREAM(p, c.declaration_handle);
278 UINT16_TO_STREAM(p, GATT_UUID_CHAR_DECLARE);
279 UINT8_TO_STREAM(p, c.properties);
280 UINT16_TO_STREAM(p, c.value_handle);
281
282 if (UuidSize(c.uuid) == Uuid::kNumBytes16) {
283 UINT16_TO_STREAM(p, c.uuid.As16Bit());
284 } else {
285 ARRAY_TO_STREAM(p, c.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
286 }
287
288 for (const Descriptor& d : c.descriptors) {
289 if (UuidSize(d.uuid) != Uuid::kNumBytes16) {
290 continue;
291 }
292 uint16_t value = d.uuid.As16Bit();
293 if (value == GATT_UUID_CHAR_DESCRIPTION || value == GATT_UUID_CHAR_CLIENT_CONFIG ||
294 value == GATT_UUID_CHAR_SRVR_CONFIG || value == GATT_UUID_CHAR_PRESENT_FORMAT ||
295 value == GATT_UUID_CHAR_AGG_FORMAT) {
296 UINT16_TO_STREAM(p, d.handle);
297 UINT16_TO_STREAM(p, d.uuid.As16Bit());
298 } else if (value == GATT_UUID_CHAR_EXT_PROP) {
299 UINT16_TO_STREAM(p, d.handle);
300 UINT16_TO_STREAM(p, d.uuid.As16Bit());
301 UINT16_TO_STREAM(p, d.characteristic_extended_properties);
302 }
303 }
304 }
305 }
306
307 std::reverse(serialized.begin(), serialized.end());
308 return crypto_toolbox::aes_cmac(Octet16{0}, serialized.data(), serialized.size());
309 }
310 } // namespace gatt
311