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