1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 
17 #include "gatt_database.h"
18 #include <algorithm>
19 #include <functional>
20 #include <optional>
21 #include "bt_def.h"
22 #include "gatt_defines.h"
23 #include "openssl/md4.h"
24 
25 namespace OHOS {
26 namespace bluetooth {
27 using GattAttributeEntity = std::optional<std::reference_wrapper<GattDatabase::AttributeEntity>>;
28 
GattDatabase()29 GattDatabase::GattDatabase()
30 {
31     availableHandles_.emplace_front(MIN_ATTRIBUTE_HANDLE, MAX_ATTRIBUTE_HANDLE);
32 }
33 
AddService(bluetooth::Service & service)34 int GattDatabase::AddService(bluetooth::Service &service)
35 {
36     std::pair<uint16_t, uint16_t> availableHandlePair = CalculateAndAssignHandle(service);
37     if (availableHandlePair == std::pair<uint16_t, uint16_t>(0, 0)) {
38         return GattStatus::NOT_ENOUGH_HANDLES;
39     }
40 
41     uint32_t currentHandle = availableHandlePair.first;
42     service.handle_ = currentHandle++;
43     service.endHandle_ = availableHandlePair.second;
44     // copy service
45     Service dbService(service);
46 
47     // copy includeService
48     for (auto &includeService : service.includeServices_) {
49         includeService.handle_ = currentHandle++;
50         dbService.includeServices_.push_back(GattDatabase::IncludeService(includeService));
51     }
52 
53     for (auto &ccc : service.characteristics_) {
54         ccc.handle_ = currentHandle++;
55         ccc.valueHandle_ = currentHandle++;
56         // copy characteristic
57         Characteristic dbCharacteristic(ccc);
58         AttributeEntity cccAttributeValue(ccc.permissions_, ccc.valueHandle_, ccc.uuid_);
59         cccAttributeValue.SetValue(ccc.value_.get(), ccc.length_);
60 
61         attributes_.emplace(ccc.valueHandle_, std::move(cccAttributeValue));
62         valueHandleMap_.emplace(ccc.valueHandle_, std::make_pair(service.handle_, ccc.handle_));
63 
64         for (auto &descriptor : ccc.descriptors_) {
65             descriptor.handle_ = currentHandle++;
66             // copy descriptor
67             Descriptor dbDescriptor(descriptor);
68             AttributeEntity descAttributeValue(descriptor.permissions_, descriptor.handle_, descriptor.uuid_);
69             descAttributeValue.SetValue(descriptor.value_.get(), descriptor.length_);
70 
71             attributes_.emplace(descriptor.handle_, std::move(descAttributeValue));
72             valueHandleMap_.emplace(descriptor.handle_, std::make_pair(service.handle_, ccc.handle_));
73             dbCharacteristic.descriptors_.emplace(dbDescriptor.handle_, std::move(dbDescriptor));
74         }
75 
76         dbCharacteristic.endHandle_ = currentHandle - 1;
77         dbService.characteristics_.emplace(dbCharacteristic.handle_, std::move(dbCharacteristic));
78     }
79 
80     services_.emplace(dbService.handle_, std::move(dbService));
81     return GattStatus::GATT_SUCCESS;
82 }
83 
DeleteService(uint16_t handle)84 int GattDatabase::DeleteService(uint16_t handle)
85 {
86     auto sIt = services_.find(handle);
87     if (sIt == services_.end()) {
88         return GattStatus::INVALID_PARAMETER;
89     }
90     if (IsReferenced(handle)) {
91         return GattStatus::REFERENCED_BY_OTHER_SERVICE;
92     }
93     // release handles
94     ReleaseHandle(sIt->second);
95     // delete attribute and handle map
96     for (auto &ccc : sIt->second.characteristics_) {
97         attributes_.erase(ccc.second.valueHandle_);
98         valueHandleMap_.erase(ccc.second.valueHandle_);
99         for (auto &descriptor : ccc.second.descriptors_) {
100             attributes_.erase(descriptor.second.handle_);
101             valueHandleMap_.erase(descriptor.second.handle_);
102         }
103     }
104     // delete service
105     services_.erase(sIt);
106     return GattStatus::GATT_SUCCESS;
107 }
108 
RemoveAllServices()109 void GattDatabase::RemoveAllServices()
110 {
111     availableHandles_.clear();
112     availableHandles_.emplace_front(MIN_ATTRIBUTE_HANDLE, MAX_ATTRIBUTE_HANDLE);
113     services_.clear();
114     attributes_.clear();
115     valueHandleMap_.clear();
116     restrictedGattBasedService_.clear();
117 }
118 
ReleaseHandle(GattDatabase::Service & service)119 void GattDatabase::ReleaseHandle(GattDatabase::Service &service)
120 {
121     if (availableHandles_.empty()) {
122         availableHandles_.emplace_front(service.handle_, service.endHandle_);
123         return;
124     }
125     auto item = availableHandles_.begin();
126     while (item != availableHandles_.end()) {
127         auto currentNode = item;
128         auto nextNode = ++item;
129 
130         //     service                  current
131         // [start handle, end handle][first,second]
132         if (currentNode->first > service.endHandle_) {
133             //              release service           current
134             // before   [start handle, end handle][c.first, c.second]
135             // after    [start handle,                      c.second]
136             if (currentNode->first == service.endHandle_ + 1) {
137                 availableHandles_.emplace(currentNode, service.handle_, currentNode->second);
138                 availableHandles_.erase(currentNode);
139                 //              release service           current
140                 // before   [start handle, end handle][c.first, c.second]
141                 // after    [start handle, end handle][c.first, c.second]
142             } else {
143                 availableHandles_.emplace(currentNode, service.handle_, service.endHandle_);
144             }
145 
146             break;
147         }
148         //   current           service
149         // [first,second][start handle, end handle]
150         if (nextNode == availableHandles_.end()) {
151             //              current           release service
152             // before   [c.first, c.second][start handle, end handle]
153             // after    [c.first,                         end handle]
154             if (service.handle_ == currentNode->second + 1) {
155                 availableHandles_.emplace(currentNode, currentNode->first, service.endHandle_);
156                 availableHandles_.erase(currentNode);
157                 //              current           release service
158                 // before   [c.first, c.second][start handle, end handle]
159                 // after    [c.first, c.second][start handle, end handle]
160             } else {
161                 availableHandles_.emplace(nextNode, service.handle_, service.endHandle_);
162             }
163 
164             break;
165         } else {
166             //   current            Next           service
167             // [first,second][first,second][start handle, end handle]
168             if (service.handle_ > nextNode->second) {
169                 continue;
170             }
171             //   current           service                Next
172             // [first,second][start handle, end handle][first,second]
173 
174             //              current           release service              Next
175             // before   [c.first, c.second][start handle, end handle][n.first, n.second]
176             // after    [c.first,                         end handle][n.first, n.second]
177             if (service.handle_ == currentNode->second + 1 && service.endHandle_ + 1 != nextNode->first) {
178                 availableHandles_.emplace(currentNode, currentNode->first, service.endHandle_);
179                 availableHandles_.erase(currentNode);
180                 //              current           release service           Next
181                 // before   [c.first, c.second][start handle, end handle][n.first, n.second]
182                 // after    [c.first, c.second][start handle,                      n.second]
183             } else if (service.handle_ != currentNode->second + 1 && service.endHandle_ + 1 == nextNode->first) {
184                 availableHandles_.emplace(nextNode, service.handle_, nextNode->second);
185                 availableHandles_.erase(nextNode);
186                 //              current           release service            Next
187                 // before   [c.first, c.second][start handle, end handle][n.first, n.second]
188                 // after    [c.first,                                              n.second]
189             } else if (service.handle_ == currentNode->second + 1 && service.endHandle_ + 1 == nextNode->first) {
190                 availableHandles_.emplace(nextNode, currentNode->first, nextNode->second);
191                 availableHandles_.erase(currentNode);
192                 availableHandles_.erase(nextNode);
193                 //              current           release service            Next
194                 // before   [c.first, c.second][start handle, end handle][n.first, n.second]
195                 // after    [c.first, c.second][start handle, end handle][n.first, n.second]
196             } else {
197                 availableHandles_.emplace(nextNode, service.handle_, service.endHandle_);
198             }
199 
200             break;
201         }
202     }
203 }
204 
IsReferenced(uint16_t handle) const205 bool GattDatabase::IsReferenced(uint16_t handle) const
206 {
207     return std::any_of(services_.begin(), services_.end(), [&handle](auto &svc) {
208         return std::any_of(svc.second.includeServices_.begin(),
209             svc.second.includeServices_.end(),
210             [&handle](auto &iSvc) { return handle == iSvc.startHandle_;
211         });
212     });
213 }
214 
GetServices() const215 const std::map<uint16_t, GattDatabase::Service> &GattDatabase::GetServices() const
216 {
217     return services_;
218 }
219 
GetIncludeServices(uint16_t serviceHandle)220 const std::vector<GattDatabase::IncludeService> *GattDatabase::GetIncludeServices(uint16_t serviceHandle)
221 {
222     auto service = services_.find(serviceHandle);
223     if (service != services_.end()) {
224         return &service->second.includeServices_;
225     }
226     return nullptr;
227 }
228 
GetIncludeService(uint16_t serviceHandle)229 const GattDatabase::IncludeService *GattDatabase::GetIncludeService(uint16_t serviceHandle)
230 {
231     for (auto &svc : services_) {
232         auto it = std::find_if(svc.second.includeServices_.begin(),
233             svc.second.includeServices_.end(),
234             [&serviceHandle](auto &iSvc) { return iSvc.handle_ == serviceHandle; });
235 
236         if (it != svc.second.includeServices_.end()) {
237             return it.base();
238         }
239     }
240     return nullptr;
241 }
242 
GetCharacteristics(uint16_t serviceHandle)243 const std::map<uint16_t, GattDatabase::Characteristic> *GattDatabase::GetCharacteristics(uint16_t serviceHandle)
244 {
245     auto service = services_.find(serviceHandle);
246     if (service != services_.end()) {
247         return &service->second.characteristics_;
248     }
249     return nullptr;
250 }
251 
GetService(uint16_t handle)252 const GattDatabase::Service *GattDatabase::GetService(uint16_t handle)
253 {
254     auto service = services_.find(handle);
255     if (service != services_.end()) {
256         return &service->second;
257     }
258     return nullptr;
259 }
260 
GetCharacteristic(uint16_t valueHandle)261 GattDatabase::Characteristic *GattDatabase::GetCharacteristic(uint16_t valueHandle)
262 {
263     auto it = valueHandleMap_.find(valueHandle);
264     if (it != valueHandleMap_.end() && it->second.second == valueHandle - 1) {
265         auto service = services_.find(it->second.first);
266         if (service != services_.end()) {
267             auto ccc = service->second.characteristics_.find(it->second.second);
268             if (ccc != service->second.characteristics_.end()) {
269                 return &ccc->second;
270             }
271         }
272     }
273     return nullptr;
274 }
275 
GetDescriptor(uint16_t valueHandle)276 const GattDatabase::Descriptor *GattDatabase::GetDescriptor(uint16_t valueHandle)
277 {
278     auto it = valueHandleMap_.find(valueHandle);
279     if (it == valueHandleMap_.end()) {
280         return nullptr;
281     }
282     auto service = services_.find(it->second.first);
283     if (service == services_.end()) {
284         return nullptr;
285     }
286     auto ccc = service->second.characteristics_.find(it->second.second);
287     if (ccc == service->second.characteristics_.end()) {
288         return nullptr;
289     }
290     auto descriptor = ccc->second.descriptors_.find(valueHandle);
291     if (descriptor == ccc->second.descriptors_.end()) {
292         return nullptr;
293     }
294     return &descriptor->second;
295 }
296 
GetDescriptors(uint16_t cccHandle)297 const std::map<uint16_t, GattDatabase::Descriptor> *GattDatabase::GetDescriptors(uint16_t cccHandle)
298 {
299     for (auto &service : services_) {
300         auto it = service.second.characteristics_.find(cccHandle);
301         if (it != service.second.characteristics_.end()) {
302             return &(it->second.descriptors_);
303         }
304     }
305     return nullptr;
306 }
307 
SetValueByHandle(const uint16_t handle,AttributeValue & value)308 int GattDatabase::SetValueByHandle(const uint16_t handle, AttributeValue &value)
309 {
310     auto it = attributes_.find(handle);
311     if (it == attributes_.end()) {
312         return GattStatus::HANDLE_NOT_FOUND;
313     }
314     it->second.value_ = std::move(value);
315     return GattStatus::GATT_SUCCESS;
316 }
317 
GetValueByHandle(const uint16_t handle)318 GattAttributeEntity GattDatabase::GetValueByHandle(const uint16_t handle)
319 {
320     auto it = attributes_.find(handle);
321     if (it == attributes_.end()) {
322         return std::nullopt;
323     }
324     return std::ref(it->second);
325 }
326 
CheckDescriptorsLegality(const bluetooth::Characteristic & characteristic) const327 int GattDatabase::CheckDescriptorsLegality(const bluetooth::Characteristic &characteristic) const
328 {
329     for (auto &desc : characteristic.descriptors_) {
330         if (desc.value_ == nullptr || desc.length_ == 0) {
331             return GattStatus::INVALID_CHARACTERISTIC_DESCRIPTOR_DATA;
332         }
333 
334         if (desc.permissions_ < 0 || desc.permissions_ > 0x10) {
335             return GattStatus::INVALID_CHARACTERISTIC_DESCRIPTOR;
336         }
337     }
338 
339     if ((characteristic.properties_ & CHARACTERISTIC_PROPERTIE_BROADCAST) &&
340         CountDescriptorByUuid(characteristic.descriptors_,
341             Uuid::ConvertFrom16Bits(UUID_SERVER_CHARACTERISTIC_CONFIGURATION)) != 1) {
342         return GattStatus::INVALID_CHARACTERISTIC_DESCRIPTOR;
343     }
344 
345     if (((characteristic.properties_ & CHARACTERISTIC_PROPERTIE_NOTIFY) ||
346         (characteristic.properties_ & CHARACTERISTIC_PROPERTIE_INDICATE)) &&
347         CountDescriptorByUuid(characteristic.descriptors_,
348             Uuid::ConvertFrom16Bits(UUID_CLIENT_CHARACTERISTIC_CONFIGURATION)) != 1) {
349         return GattStatus::INVALID_CHARACTERISTIC_DESCRIPTOR;
350     }
351 
352     if ((characteristic.properties_ & CHARACTERISTIC_PROPERTIE_EXTENDED_PROPERTIES) &&
353         CountDescriptorByUuid(characteristic.descriptors_,
354             Uuid::ConvertFrom16Bits(UUID_CHARACTERISTIC_EXTENDED_PROPERTIES)) != 1) {
355         return GattStatus::INVALID_CHARACTERISTIC_DESCRIPTOR;
356     }
357 
358     if (CountDescriptorByUuid(
359         characteristic.descriptors_, Uuid::ConvertFrom16Bits(UUID_CHARACTERISTIC_USER_DESCRIPTION)) > 1) {
360         return GattStatus::INVALID_CHARACTERISTIC_DESCRIPTOR;
361     }
362 
363     if ((CountDescriptorByUuid(characteristic.descriptors_, Uuid::ConvertFrom16Bits(UUID_CHARACTERISTIC_FROMAT)) > 1) &&
364         (CountDescriptorByUuid(characteristic.descriptors_,
365             Uuid::ConvertFrom16Bits(UUID_CHARACTERISTIC_AGGREGATE_FROMAT)) != 1)) {
366         return GattStatus::INVALID_CHARACTERISTIC_DESCRIPTOR;
367     }
368 
369     return GattStatus::GATT_SUCCESS;
370 }
371 
CheckCharacteristicsLegality(const bluetooth::Service & service) const372 int GattDatabase::CheckCharacteristicsLegality(const bluetooth::Service &service) const
373 {
374     for (auto &ccc : service.characteristics_) {
375         if (ccc.value_ == nullptr || ccc.length_ == 0) {
376             return GattStatus::INVALID_CHARACTERISTIC_DATA;
377         }
378 
379         if (ccc.properties_ > 0xFF || ccc.properties_ < 0 || ccc.permissions_ < 0 || ccc.permissions_ > 0x10) {
380             return GattStatus::INVALID_CHARACTERISTIC;
381         }
382 
383         if (((ccc.properties_ & CHARACTERISTIC_PROPERTIE_READ) &&
384             !(ccc.permissions_ & static_cast<int>(GattPermissionService::READABLE))) ||
385             ((ccc.properties_ & CHARACTERISTIC_PROPERTIE_WRITE) &&
386             !(ccc.permissions_ & static_cast<int>(GattPermissionService::WRITEABLE)))) {
387             return GattStatus::INVALID_CHARACTERISTIC;
388         }
389 
390         int result = CheckDescriptorsLegality(ccc);
391         if (GattStatus::GATT_SUCCESS != result) {
392             return result;
393         }
394     }
395 
396     return GattStatus::GATT_SUCCESS;
397 }
398 
CheckIncludeServicesLegality(bluetooth::Service & service) const399 int GattDatabase::CheckIncludeServicesLegality(bluetooth::Service &service) const
400 {
401     for (auto &includeService : service.includeServices_) {
402         auto sIt = services_.find(includeService.startHandle_);
403         if (sIt == services_.end()) {
404             return GattStatus::INCLUDE_SERVICE_NOT_FOUND;
405         } else {
406             includeService.endHandle_ = sIt->second.endHandle_;
407             includeService.uuid_ = sIt->second.uuid_;
408             includeService.isPrimary_ = sIt->second.isPrimary_;
409         }
410     }
411 
412     return GattStatus::GATT_SUCCESS;
413 }
414 
CheckLegalityOfServiceDefinition(bluetooth::Service & service)415 int GattDatabase::CheckLegalityOfServiceDefinition(bluetooth::Service &service)
416 {
417     if (!CheckRestrictedGattBasedService(service)) {
418         return GattStatus::REQUEST_NOT_SUPPORT;
419     }
420 
421     int result = CheckIncludeServicesLegality(service);
422     if (GattStatus::GATT_SUCCESS != result) {
423         return result;
424     }
425 
426     result = CheckCharacteristicsLegality(service);
427     if (GattStatus::GATT_SUCCESS != result) {
428         return result;
429     }
430 
431     return result;
432 }
433 
CheckRestrictedGattBasedService(const bluetooth::Service & service)434 bool GattDatabase::CheckRestrictedGattBasedService(const bluetooth::Service &service)
435 {
436     if (service.uuid_.ConvertTo16Bits() == 0x180A) { // DIS
437         if (restrictedGattBasedService_.count(0x180A) == 0) {
438             restrictedGattBasedService_.emplace(0x180A);
439         } else {
440             return false;
441         }
442     } else if (service.uuid_.ConvertTo16Bits() == 0x1800) { // GAS
443         if (restrictedGattBasedService_.count(0x1800) == 0) {
444             restrictedGattBasedService_.emplace(0x1800);
445         } else {
446             return false;
447         }
448     } else if (service.uuid_.ConvertTo16Bits() == 0x1801) { // GATTS
449         if (restrictedGattBasedService_.count(0x1801) == 0) {
450             restrictedGattBasedService_.emplace(0x1801);
451         } else {
452             return false;
453         }
454     }
455 
456     return true;
457 }
458 
CountDescriptorByUuid(const std::vector<bluetooth::Descriptor> & descriptors,const Uuid & uuid)459 int GattDatabase::CountDescriptorByUuid(const std::vector<bluetooth::Descriptor> &descriptors, const Uuid &uuid)
460 {
461     return std::count_if(descriptors.begin(), descriptors.end(), [&uuid](auto &item) { return uuid == item.uuid_; });
462 }
463 
CalculateAndAssignHandle(const bluetooth::Service & service)464 std::pair<uint16_t, uint16_t> GattDatabase::CalculateAndAssignHandle(const bluetooth::Service &service)
465 {
466     // calculate service
467     uint16_t count = 1;
468     std::pair<uint16_t, uint16_t> handlePair(0, 0);
469 
470     // calculate Service
471     count += service.includeServices_.size();
472 
473     // calculate Characteristics
474     count += service.characteristics_.size() * 0x2;
475     // calculate Descripors
476     for (auto &ccc : service.characteristics_) {
477         count += ccc.descriptors_.size();
478     }
479 
480     // assign handles
481     for (auto item = availableHandles_.begin(); item != availableHandles_.end(); item++) {
482         auto availableLength = item->second - item->first + 1;
483         if (availableLength >= count) {
484             handlePair = std::pair<uint16_t, uint16_t>(item->first, item->first + count - 1);
485             if (handlePair.second < item->second) {
486                 availableHandles_.insert(item, std::pair<uint16_t, uint16_t>(handlePair.second + 1, item->second));
487             }
488             availableHandles_.erase(item);
489             break;
490         }
491     }
492 
493     return handlePair;
494 }
495 }  // namespace bluetooth
496 }  // namespace OHOS
497