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