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