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