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