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 =
44 Uuid::From16Bit(GATT_UUID_CHAR_EXT_PROP);
45
HandleInRange(const Service & svc,uint16_t handle)46 bool HandleInRange(const Service& svc, uint16_t handle) {
47 return handle >= svc.handle && handle <= svc.end_handle;
48 }
49 } // namespace
50
UuidSize(const Uuid & uuid)51 static size_t UuidSize(const Uuid& uuid) {
52 size_t len = uuid.GetShortestRepresentationSize();
53 return (len == Uuid::kNumBytes32) ? Uuid::kNumBytes128 : len;
54 }
55
FindService(std::list<Service> & services,uint16_t handle)56 Service* FindService(std::list<Service>& services, uint16_t handle) {
57 for (Service& service : services) {
58 if (handle >= service.handle && handle <= service.end_handle)
59 return &service;
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)
71 << ", uuid=" << service.uuid << "\n";
72
73 for (const auto& is : service.included_services) {
74 tmp << "\t Included service: handle=" << loghex(is.handle)
75 << ", start_handle=" << loghex(is.start_handle)
76 << ", end_handle=" << loghex(is.end_handle) << ", uuid=" << is.uuid
77 << "\n";
78 }
79
80 for (const Characteristic& c : service.characteristics) {
81 tmp << "\t Characteristic: declaration_handle="
82 << loghex(c.declaration_handle)
83 << ", value_handle=" << loghex(c.value_handle) << ", uuid=" << c.uuid
84 << ", prop=" << loghex(c.properties) << "\n";
85
86 for (const Descriptor& d : c.descriptors) {
87 tmp << "\t\t Descriptor: handle=" << loghex(d.handle)
88 << ", uuid=" << d.uuid << "\n";
89 }
90 }
91 }
92 return tmp.str();
93 }
94
Serialize() const95 std::vector<StoredAttribute> Database::Serialize() const {
96 std::vector<StoredAttribute> nv_attr;
97
98 if (services.empty()) return std::vector<StoredAttribute>();
99
100 for (const Service& service : services) {
101 // TODO: add constructor to NV_ATTR, use emplace_back
102 nv_attr.push_back({service.handle,
103 service.is_primary ? PRIMARY_SERVICE : SECONDARY_SERVICE,
104 {.service = {.uuid = service.uuid,
105 .end_handle = service.end_handle}}});
106 }
107
108 for (const Service& service : services) {
109 for (const IncludedService& p_isvc : service.included_services) {
110 nv_attr.push_back({p_isvc.handle,
111 INCLUDE,
112 {.included_service = {.handle = p_isvc.start_handle,
113 .end_handle = p_isvc.end_handle,
114 .uuid = p_isvc.uuid}}});
115 }
116
117 for (const Characteristic& charac : service.characteristics) {
118 nv_attr.push_back(
119 {charac.declaration_handle,
120 CHARACTERISTIC,
121 {.characteristic = {.properties = charac.properties,
122 .value_handle = charac.value_handle,
123 .uuid = charac.uuid}}});
124
125 for (const Descriptor& desc : charac.descriptors) {
126 if (desc.uuid == CHARACTERISTIC_EXTENDED_PROPERTIES) {
127 nv_attr.push_back({desc.handle,
128 desc.uuid,
129 {.characteristic_extended_properties =
130 desc.characteristic_extended_properties}});
131 } else {
132 nv_attr.push_back({desc.handle, desc.uuid, {}});
133 }
134 }
135 }
136 }
137
138 return nv_attr;
139 }
140
Deserialize(const std::vector<StoredAttribute> & nv_attr,bool * success)141 Database Database::Deserialize(const std::vector<StoredAttribute>& nv_attr,
142 bool* success) {
143 // clear reallocating
144 Database result;
145 auto it = nv_attr.cbegin();
146
147 for (; it != nv_attr.cend(); ++it) {
148 const auto& attr = *it;
149 if (attr.type != PRIMARY_SERVICE && attr.type != SECONDARY_SERVICE) break;
150 result.services.emplace_back(Service{
151 .handle = attr.handle,
152 .uuid = attr.value.service.uuid,
153 .is_primary = (attr.type == PRIMARY_SERVICE),
154 .end_handle = attr.value.service.end_handle,
155 .included_services = {},
156 .characteristics = {},
157 });
158 }
159
160 auto current_service_it = result.services.begin();
161 for (; it != nv_attr.cend(); it++) {
162 const auto& attr = *it;
163
164 // go to the service this attribute belongs to; attributes are stored in
165 // order, so iterating just forward is enough
166 while (current_service_it != result.services.end() &&
167 current_service_it->end_handle < attr.handle) {
168 current_service_it++;
169 }
170
171 if (current_service_it == result.services.end() ||
172 !HandleInRange(*current_service_it, attr.handle)) {
173 log::error("Can't find service for attribute with handle: 0x{:x}",
174 attr.handle);
175 *success = false;
176 return result;
177 }
178
179 if (attr.type == INCLUDE) {
180 Service* included_service =
181 FindService(result.services, attr.value.included_service.handle);
182 if (!included_service) {
183 log::error("Non-existing included service!");
184 *success = false;
185 return result;
186 }
187 current_service_it->included_services.push_back(IncludedService{
188 .handle = attr.handle,
189 .uuid = attr.value.included_service.uuid,
190 .start_handle = attr.value.included_service.handle,
191 .end_handle = attr.value.included_service.end_handle,
192 });
193 } else if (attr.type == CHARACTERISTIC) {
194 current_service_it->characteristics.emplace_back(Characteristic{
195 .declaration_handle = attr.handle,
196 .uuid = attr.value.characteristic.uuid,
197 .value_handle = attr.value.characteristic.value_handle,
198 .properties = attr.value.characteristic.properties,
199 .descriptors = {},
200 });
201
202 } else {
203 if (attr.type == CHARACTERISTIC_EXTENDED_PROPERTIES) {
204 current_service_it->characteristics.back().descriptors.emplace_back(
205 Descriptor{.handle = attr.handle,
206 .uuid = attr.type,
207 .characteristic_extended_properties =
208 attr.value.characteristic_extended_properties});
209
210 } else {
211 current_service_it->characteristics.back().descriptors.emplace_back(
212 Descriptor{
213 .handle = attr.handle,
214 .uuid = attr.type,
215 .characteristic_extended_properties = {},
216 });
217 }
218 }
219 }
220 *success = true;
221 return result;
222 }
223
Hash() const224 Octet16 Database::Hash() const {
225 int len = 0;
226 // Compute how much space we need to actually hold the data.
227 for (const Service& service : services) {
228 len += 4 + UuidSize(service.uuid);
229
230 for (const auto& is : service.included_services) {
231 len += 8 + UuidSize(is.uuid);
232 }
233
234 for (const Characteristic& c : service.characteristics) {
235 len += 7 + UuidSize(c.uuid);
236
237 for (const Descriptor& d : c.descriptors) {
238 if (UuidSize(d.uuid) != Uuid::kNumBytes16) {
239 continue;
240 }
241 uint16_t value = d.uuid.As16Bit();
242 if (value == GATT_UUID_CHAR_DESCRIPTION ||
243 value == GATT_UUID_CHAR_CLIENT_CONFIG ||
244 value == GATT_UUID_CHAR_SRVR_CONFIG ||
245 value == GATT_UUID_CHAR_PRESENT_FORMAT ||
246 value == GATT_UUID_CHAR_AGG_FORMAT) {
247 len += 2 + UuidSize(d.uuid);
248 } else if (value == GATT_UUID_CHAR_EXT_PROP) {
249 len += 4 + UuidSize(d.uuid);
250 }
251 }
252 }
253 }
254
255 std::vector<uint8_t> serialized(len);
256 uint8_t* p = serialized.data();
257 for (const Service& service : services) {
258 UINT16_TO_STREAM(p, service.handle);
259 if (service.is_primary) {
260 UINT16_TO_STREAM(p, GATT_UUID_PRI_SERVICE);
261 } else {
262 UINT16_TO_STREAM(p, GATT_UUID_SEC_SERVICE);
263 }
264
265 if (UuidSize(service.uuid) == Uuid::kNumBytes16) {
266 UINT16_TO_STREAM(p, service.uuid.As16Bit());
267 } else {
268 ARRAY_TO_STREAM(p, service.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
269 }
270
271 for (const auto& is : service.included_services) {
272 UINT16_TO_STREAM(p, is.handle);
273 UINT16_TO_STREAM(p, GATT_UUID_INCLUDE_SERVICE);
274 UINT16_TO_STREAM(p, is.start_handle);
275 UINT16_TO_STREAM(p, is.end_handle);
276
277 if (UuidSize(is.uuid) == Uuid::kNumBytes16) {
278 UINT16_TO_STREAM(p, is.uuid.As16Bit());
279 } else {
280 ARRAY_TO_STREAM(p, is.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
281 }
282 }
283
284 for (const Characteristic& c : service.characteristics) {
285 UINT16_TO_STREAM(p, c.declaration_handle);
286 UINT16_TO_STREAM(p, GATT_UUID_CHAR_DECLARE);
287 UINT8_TO_STREAM(p, c.properties);
288 UINT16_TO_STREAM(p, c.value_handle);
289
290 if (UuidSize(c.uuid) == Uuid::kNumBytes16) {
291 UINT16_TO_STREAM(p, c.uuid.As16Bit());
292 } else {
293 ARRAY_TO_STREAM(p, c.uuid.To128BitLE(), (int)Uuid::kNumBytes128);
294 }
295
296 for (const Descriptor& d : c.descriptors) {
297 if (UuidSize(d.uuid) != Uuid::kNumBytes16) continue;
298 uint16_t value = d.uuid.As16Bit();
299 if (value == GATT_UUID_CHAR_DESCRIPTION ||
300 value == GATT_UUID_CHAR_CLIENT_CONFIG ||
301 value == GATT_UUID_CHAR_SRVR_CONFIG ||
302 value == GATT_UUID_CHAR_PRESENT_FORMAT ||
303 value == GATT_UUID_CHAR_AGG_FORMAT) {
304 UINT16_TO_STREAM(p, d.handle);
305 UINT16_TO_STREAM(p, d.uuid.As16Bit());
306 } else if (value == GATT_UUID_CHAR_EXT_PROP) {
307 UINT16_TO_STREAM(p, d.handle);
308 UINT16_TO_STREAM(p, d.uuid.As16Bit());
309 UINT16_TO_STREAM(p, d.characteristic_extended_properties);
310 }
311 }
312 }
313 }
314
315 std::reverse(serialized.begin(), serialized.end());
316 return crypto_toolbox::aes_cmac(Octet16{0}, serialized.data(),
317 serialized.size());
318 }
319 } // namespace gatt
320