• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 HIMSA II K/S - www.himsa.com.
3  * Represented by EHIMA - www.ehima.com
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 #pragma once
19 #include <base/logging.h>
20 #include <base/strings/string_number_conversions.h>
21 
22 #include <algorithm>
23 #include <map>
24 #include <vector>
25 
26 #include "bta_csis_api.h"
27 #include "bta_gatt_api.h"
28 #include "bta_groups.h"
29 #include "gap_api.h"
30 #include "gd/common/init_flags.h"
31 #include "gd/common/strings.h"
32 #include "stack/crypto_toolbox/crypto_toolbox.h"
33 
34 namespace bluetooth {
35 namespace csis {
36 
37 using bluetooth::csis::CsisLockCb;
38 
39 // CSIP additions
40 /* Generic UUID is used when CSIS is not included in any context */
41 static const bluetooth::Uuid kCsisServiceUuid = bluetooth::Uuid::From16Bit(0x1846);
42 static const bluetooth::Uuid kCsisSirkUuid = bluetooth::Uuid::From16Bit(0x2B84);
43 static const bluetooth::Uuid kCsisSizeUuid = bluetooth::Uuid::From16Bit(0x2B85);
44 static const bluetooth::Uuid kCsisLockUuid = bluetooth::Uuid::From16Bit(0x2B86);
45 static const bluetooth::Uuid kCsisRankUuid = bluetooth::Uuid::From16Bit(0x2B87);
46 
47 static constexpr uint8_t kCsisErrorCodeLockDenied = 0x80;
48 static constexpr uint8_t kCsisErrorCodeReleaseNotAllowed = 0x81;
49 static constexpr uint8_t kCsisErrorCodeInvalidValue = 0x82;
50 static constexpr uint8_t kCsisErrorCodeLockAccessSirkRejected = 0x83;
51 static constexpr uint8_t kCsisErrorCodeLockOobSirkOnly = 0x84;
52 static constexpr uint8_t kCsisErrorCodeLockAlreadyGranted = 0x85;
53 
54 static constexpr uint8_t kCsisSirkTypeEncrypted = 0x00;
55 static constexpr uint8_t kCsisSirkCharLen = 17;
56 
57 struct hdl_pair {
hdl_pairhdl_pair58   hdl_pair() {}
hdl_pairhdl_pair59   hdl_pair(uint16_t val_hdl, uint16_t ccc_hdl) : val_hdl(val_hdl), ccc_hdl(ccc_hdl) {}
60 
61   uint16_t val_hdl;
62   uint16_t ccc_hdl;
63 };
64 
65 /* CSIS Types */
66 static constexpr uint8_t kDefaultScanDurationS = 5;
67 static constexpr uint8_t kDefaultCsisSetSize = 1;
68 static constexpr uint8_t kUnknownRank = 0xff;
69 
70 /* Enums */
71 enum class CsisLockState : uint8_t {
72   CSIS_STATE_UNSET = 0x00,
73   CSIS_STATE_UNLOCKED,
74   CSIS_STATE_LOCKED
75 };
76 
77 enum class CsisDiscoveryState : uint8_t {
78   CSIS_DISCOVERY_IDLE = 0x00,
79   CSIS_DISCOVERY_ONGOING,
80   CSIS_DISCOVERY_COMPLETED,
81 };
82 
83 class GattServiceDevice {
84  public:
85   RawAddress addr;
86   /*
87    * This is true only during first connection to profile, until we store the
88    * device.
89    */
90   bool first_connection;
91 
92   /*
93    * We are making active attempt to connect to this device, 'direct connect'.
94    */
95   bool connecting_actively = false;
96 
97   uint16_t conn_id = GATT_INVALID_CONN_ID;
98   uint16_t service_handle = GAP_INVALID_HANDLE;
99   bool is_gatt_service_valid = false;
100 
GattServiceDevice(const RawAddress & addr,bool first_connection)101   GattServiceDevice(const RawAddress& addr, bool first_connection)
102       : addr(addr), first_connection(first_connection) {}
103 
GattServiceDevice()104   GattServiceDevice() : GattServiceDevice(RawAddress::kEmpty, false) {}
105 
IsConnected()106   bool IsConnected() const { return (conn_id != GATT_INVALID_CONN_ID); }
107 
108   class MatchAddress {
109    private:
110     RawAddress addr;
111 
112    public:
MatchAddress(const RawAddress & addr)113     MatchAddress(const RawAddress& addr) : addr(addr) {}
operator()114     bool operator()(const std::shared_ptr<GattServiceDevice>& other) const {
115       return (addr == other->addr);
116     }
117   };
118 
119   class MatchConnId {
120    private:
121     uint16_t conn_id;
122 
123    public:
MatchConnId(uint16_t conn_id)124     MatchConnId(uint16_t conn_id) : conn_id(conn_id) {}
operator()125     bool operator()(const std::shared_ptr<GattServiceDevice>& other) const {
126       return (conn_id == other->conn_id);
127     }
128   };
129 };
130 
131 /*
132  * CSIS instance represents single CSIS service on the remote device
133  * along with the handle in database and specific data to control CSIS like:
134  * rank, lock state.
135  *
136  * It also inclues UUID of the primary service which includes that CSIS
137  * instance. If this is 0x0000 it means CSIS is per device and not for specific
138  * service.
139  */
140 class CsisInstance {
141  public:
142   bluetooth::Uuid coordinated_service = bluetooth::groups::kGenericContextUuid;
143 
144   struct SvcData {
145     uint16_t start_handle;
146     uint16_t end_handle;
147     struct hdl_pair sirk_handle;
148     struct hdl_pair lock_handle;
149     uint16_t rank_handle;
150     struct hdl_pair size_handle;
151   } svc_data = {
152       GAP_INVALID_HANDLE,
153       GAP_INVALID_HANDLE,
154       {GAP_INVALID_HANDLE, GAP_INVALID_HANDLE},
155       {GAP_INVALID_HANDLE, GAP_INVALID_HANDLE},
156       GAP_INVALID_HANDLE,
157       {GAP_INVALID_HANDLE, GAP_INVALID_HANDLE},
158   };
159 
CsisInstance(uint16_t start_handle,uint16_t end_handle,const bluetooth::Uuid & uuid)160   CsisInstance(uint16_t start_handle, uint16_t end_handle, const bluetooth::Uuid& uuid)
161       : coordinated_service(uuid),
162         group_id_(bluetooth::groups::kGroupUnknown),
163         rank_(kUnknownRank),
164         lock_state_(CsisLockState::CSIS_STATE_UNSET) {
165     svc_data.start_handle = start_handle;
166     svc_data.end_handle = end_handle;
167   }
168 
SetLockState(CsisLockState state)169   void SetLockState(CsisLockState state) {
170     DLOG(INFO) << __func__ << " current lock state: " << (int)(lock_state_)
171                << " new lock state: " << (int)(state);
172     lock_state_ = state;
173   }
GetLockState(void)174   CsisLockState GetLockState(void) const { return lock_state_; }
GetRank(void)175   uint8_t GetRank(void) const { return rank_; }
SetRank(uint8_t rank)176   void SetRank(uint8_t rank) {
177     DLOG(INFO) << __func__ << " current rank state: " << loghex(rank_)
178                << " new rank state: " << loghex(rank);
179     rank_ = rank;
180   }
181 
SetGroupId(int group_id)182   void SetGroupId(int group_id) {
183     LOG(INFO) << __func__ << " set group id: " << group_id
184               << " instance handle: " << loghex(svc_data.start_handle);
185     group_id_ = group_id;
186   }
187 
GetGroupId(void)188   int GetGroupId(void) const { return group_id_; }
189 
HasSameUuid(const CsisInstance & csis_instance)190   bool HasSameUuid(const CsisInstance& csis_instance) const {
191     return (csis_instance.coordinated_service == coordinated_service);
192   }
193 
GetUuid(void)194   const bluetooth::Uuid& GetUuid(void) const { return coordinated_service; }
IsForUuid(const bluetooth::Uuid & uuid)195   bool IsForUuid(const bluetooth::Uuid& uuid) const { return coordinated_service == uuid; }
196 
197  private:
198   int group_id_;
199   uint8_t rank_;
200   CsisLockState lock_state_;
201 };
202 
203 /*
204  * Csis Device represents remote device and its all CSIS instances.
205  * It can happen that device can have more than one CSIS service instance
206  * if those instances are included in other services. In this way, coordinated
207  * set is within the context of the primary service which includes the instance.
208  *
209  * CsisDevice contains vector of the instances.
210  */
211 class CsisDevice : public GattServiceDevice {
212  public:
213   using GattServiceDevice::GattServiceDevice;
214 
ClearSvcData()215   void ClearSvcData() {
216     GattServiceDevice::service_handle = GAP_INVALID_HANDLE;
217     GattServiceDevice::is_gatt_service_valid = false;
218 
219     csis_instances_.clear();
220   }
221 
GetCsisInstanceByOwningHandle(uint16_t handle)222   std::shared_ptr<CsisInstance> GetCsisInstanceByOwningHandle(uint16_t handle) {
223     uint16_t hdl = 0;
224     for (const auto& [h, inst] : csis_instances_) {
225       if (handle >= inst->svc_data.start_handle && handle <= inst->svc_data.end_handle) {
226         hdl = h;
227         DLOG(INFO) << __func__ << " found " << loghex(hdl);
228         break;
229       }
230     }
231     return (hdl > 0) ? csis_instances_.at(hdl) : nullptr;
232   }
233 
GetCsisInstanceByGroupId(int group_id)234   std::shared_ptr<CsisInstance> GetCsisInstanceByGroupId(int group_id) {
235     uint16_t hdl = 0;
236     for (const auto& [handle, inst] : csis_instances_) {
237       if (inst->GetGroupId() == group_id) {
238         hdl = handle;
239         break;
240       }
241     }
242     return (hdl > 0) ? csis_instances_.at(hdl) : nullptr;
243   }
244 
SetCsisInstance(uint16_t handle,std::shared_ptr<CsisInstance> csis_instance)245   void SetCsisInstance(uint16_t handle, std::shared_ptr<CsisInstance> csis_instance) {
246     if (csis_instances_.count(handle)) {
247       DLOG(INFO) << __func__ << " instance is already here: " << csis_instance->GetUuid();
248       return;
249     }
250 
251     csis_instances_.insert({handle, csis_instance});
252     DLOG(INFO) << __func__ << " instance added: " << loghex(handle) << "device: " << addr;
253   }
254 
RemoveCsisInstance(int group_id)255   void RemoveCsisInstance(int group_id) {
256     for (auto it = csis_instances_.begin(); it != csis_instances_.end(); it++) {
257       if (it->second->GetGroupId() == group_id) {
258         csis_instances_.erase(it);
259         return;
260       }
261     }
262   }
263 
GetNumberOfCsisInstances(void)264   int GetNumberOfCsisInstances(void) { return csis_instances_.size(); }
265 
ForEachCsisInstance(std::function<void (const std::shared_ptr<CsisInstance> &)> cb)266   void ForEachCsisInstance(std::function<void(const std::shared_ptr<CsisInstance>&)> cb) {
267     for (auto const& kv_pair : csis_instances_) {
268       cb(kv_pair.second);
269     }
270   }
271 
272  private:
273   /* Instances per start handle  */
274   std::map<uint16_t, std::shared_ptr<CsisInstance>> csis_instances_;
275 };
276 
277 /*
278  * CSIS group gathers devices which belongs to specific group.
279  * It also contains methond to decode encrypted SIRK and also to
280  * resolve PRSI in order to find out if device belongs to given group
281  */
282 class CsisGroup {
283  public:
CsisGroup(int group_id,const bluetooth::Uuid & uuid)284   CsisGroup(int group_id, const bluetooth::Uuid& uuid)
285       : group_id_(group_id),
286         size_(kDefaultCsisSetSize),
287         uuid_(uuid),
288         member_discovery_state_(CsisDiscoveryState::CSIS_DISCOVERY_IDLE),
289         lock_state_(CsisLockState::CSIS_STATE_UNSET),
290         target_lock_state_(CsisLockState::CSIS_STATE_UNSET),
291         lock_transition_cnt_(0) {
292     devices_.clear();
293   }
294 
AddDevice(std::shared_ptr<CsisDevice> csis_device)295   void AddDevice(std::shared_ptr<CsisDevice> csis_device) {
296     auto it =
297         find_if(devices_.begin(), devices_.end(), CsisDevice::MatchAddress(csis_device->addr));
298     if (it != devices_.end()) return;
299 
300     devices_.push_back(std::move(csis_device));
301   }
302 
RemoveDevice(const RawAddress & bd_addr)303   void RemoveDevice(const RawAddress& bd_addr) {
304     auto it = find_if(devices_.begin(), devices_.end(), CsisDevice::MatchAddress(bd_addr));
305     if (it != devices_.end()) devices_.erase(it);
306   }
307 
GetCurrentSize(void)308   int GetCurrentSize(void) const { return devices_.size(); }
GetUuid()309   bluetooth::Uuid GetUuid() const { return uuid_; }
SetUuid(const bluetooth::Uuid & uuid)310   void SetUuid(const bluetooth::Uuid& uuid) { uuid_ = uuid; }
GetGroupId(void)311   int GetGroupId(void) const { return group_id_; }
GetDesiredSize(void)312   int GetDesiredSize(void) const { return size_; }
SetDesiredSize(int size)313   void SetDesiredSize(int size) { size_ = size; }
IsGroupComplete(void)314   bool IsGroupComplete(void) const { return size_ == (int)devices_.size(); }
IsEmpty(void)315   bool IsEmpty(void) const { return devices_.empty(); }
316 
IsDeviceInTheGroup(std::shared_ptr<CsisDevice> & csis_device)317   bool IsDeviceInTheGroup(std::shared_ptr<CsisDevice>& csis_device) {
318     auto it =
319         find_if(devices_.begin(), devices_.end(), CsisDevice::MatchAddress(csis_device->addr));
320     return (it != devices_.end());
321   }
IsRsiMatching(const RawAddress & rsi)322   bool IsRsiMatching(const RawAddress& rsi) const { return is_rsi_match_sirk(rsi, GetSirk()); }
IsSirkBelongsToGroup(Octet16 sirk)323   bool IsSirkBelongsToGroup(Octet16 sirk) const { return (sirk_available_ && sirk_ == sirk); }
GetSirk(void)324   Octet16 GetSirk(void) const { return sirk_; }
SetSirk(Octet16 & sirk)325   void SetSirk(Octet16& sirk) {
326     if (sirk_available_) {
327       DLOG(INFO) << __func__ << " Updating SIRK";
328     }
329     sirk_available_ = true;
330     sirk_ = sirk;
331   }
332 
GetNumOfConnectedDevices(void)333   int GetNumOfConnectedDevices(void) {
334     return std::count_if(devices_.begin(), devices_.end(),
335                          [](auto& d) { return d->IsConnected(); });
336   }
337 
GetDiscoveryState(void)338   CsisDiscoveryState GetDiscoveryState(void) const { return member_discovery_state_; }
SetDiscoveryState(CsisDiscoveryState state)339   void SetDiscoveryState(CsisDiscoveryState state) {
340     DLOG(INFO) << __func__ << " current discovery state: " << (int)(member_discovery_state_)
341                << " new discovery state: " << (int)(state);
342     member_discovery_state_ = state;
343   }
344 
SetCurrentLockState(CsisLockState state)345   void SetCurrentLockState(CsisLockState state) { lock_state_ = state; }
346 
347   void SetTargetLockState(CsisLockState state, CsisLockCb cb = base::DoNothing()) {
348     target_lock_state_ = state;
349     cb_ = std::move(cb);
350     switch (state) {
351       case CsisLockState::CSIS_STATE_LOCKED:
352         lock_transition_cnt_ = GetNumOfConnectedDevices();
353         break;
354       case CsisLockState::CSIS_STATE_UNLOCKED:
355       case CsisLockState::CSIS_STATE_UNSET:
356         lock_transition_cnt_ = 0;
357         break;
358     }
359   }
360 
GetLockCb(void)361   CsisLockCb GetLockCb(void) { return std::move(cb_); }
362 
GetCurrentLockState(void)363   CsisLockState GetCurrentLockState(void) const { return lock_state_; }
GetTargetLockState(void)364   CsisLockState GetTargetLockState(void) const { return target_lock_state_; }
365 
IsAvailableForCsisLockOperation(void)366   bool IsAvailableForCsisLockOperation(void) {
367     int id = group_id_;
368     int number_of_connected = 0;
369     auto iter = std::find_if(
370         devices_.begin(), devices_.end(), [id, &number_of_connected](auto& d) {
371           if (!d->IsConnected()) {
372             LOG_DEBUG("Device %s is not connected in group %d",
373                       d->addr.ToString().c_str(), id);
374             return false;
375           }
376           auto inst = d->GetCsisInstanceByGroupId(id);
377           if (!inst) {
378             LOG_DEBUG("Instance not available for group %d", id);
379             return false;
380           }
381           number_of_connected++;
382           LOG_DEBUG("Device %s,  lock state: %d", d->addr.ToString().c_str(),
383                     (int)inst->GetLockState());
384           return inst->GetLockState() == CsisLockState::CSIS_STATE_LOCKED;
385         });
386 
387     LOG_DEBUG("Locked set: %d, number of connected %d", iter != devices_.end(),
388               number_of_connected);
389     /* If there is no locked device, we are good to go */
390     if (iter != devices_.end()) {
391       LOG_WARN("Device %s is locked ", (*iter)->addr.ToString().c_str());
392       return false;
393     }
394 
395     return (number_of_connected > 0);
396   }
397 
SortByCsisRank(void)398   void SortByCsisRank(void) {
399     int id = group_id_;
400     std::sort(devices_.begin(), devices_.end(), [id](auto& dev1, auto& dev2) {
401       auto inst1 = dev1->GetCsisInstanceByGroupId(id);
402       auto inst2 = dev2->GetCsisInstanceByGroupId(id);
403       if (!inst1 || !inst2) {
404         /* One of the device is not connected */
405         DLOG(INFO) << __func__ << " one of the device is not connected: inst1: " << inst1
406                    << " inst2: " << inst2;
407         return dev1->IsConnected();
408       }
409       return (inst1->GetRank() < inst2->GetRank());
410     });
411   }
412 
GetFirstDevice(void)413   std::shared_ptr<CsisDevice> GetFirstDevice(void) { return (devices_.front()); }
GetLastDevice(void)414   std::shared_ptr<CsisDevice> GetLastDevice(void) { return (devices_.back()); }
GetNextDevice(std::shared_ptr<CsisDevice> & device)415   std::shared_ptr<CsisDevice> GetNextDevice(std::shared_ptr<CsisDevice>& device) {
416     auto iter =
417         std::find_if(devices_.begin(), devices_.end(), CsisDevice::MatchAddress(device->addr));
418 
419     /* If reference device not found */
420     if (iter == devices_.end()) return nullptr;
421 
422     iter++;
423     /* If reference device is last in group */
424     if (iter == devices_.end()) return nullptr;
425 
426     return (*iter);
427   }
GetPrevDevice(std::shared_ptr<CsisDevice> & device)428   std::shared_ptr<CsisDevice> GetPrevDevice(std::shared_ptr<CsisDevice>& device) {
429     auto iter =
430         std::find_if(devices_.rbegin(), devices_.rend(), CsisDevice::MatchAddress(device->addr));
431 
432     /* If reference device not found */
433     if (iter == devices_.rend()) return nullptr;
434 
435     iter++;
436 
437     if (iter == devices_.rend()) return nullptr;
438     return (*iter);
439   }
440 
GetLockTransitionCnt(void)441   int GetLockTransitionCnt(void) const { return lock_transition_cnt_; }
UpdateLockTransitionCnt(int i)442   int UpdateLockTransitionCnt(int i) {
443     lock_transition_cnt_ += i;
444     return lock_transition_cnt_;
445   }
446 
447   /* Return true if given Autoset Private Address |srpa| matches Set Identity
448    * Resolving Key |sirk| */
is_rsi_match_sirk(const RawAddress & rsi,const Octet16 & sirk)449   static bool is_rsi_match_sirk(const RawAddress& rsi, const Octet16& sirk) {
450     /* use the 3 MSB of bd address as prand */
451     uint8_t rand[3];
452     rand[0] = rsi.address[2];
453     rand[1] = rsi.address[1];
454     rand[2] = rsi.address[0];
455     DLOG(INFO) << "Prand " << base::HexEncode(rand, 3);
456 
457     DLOG(INFO) << "SIRK " << base::HexEncode(sirk.data(), 16);
458     /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
459     Octet16 x = crypto_toolbox::aes_128(sirk, &rand[0], 3);
460 
461     DLOG(INFO) << "X" << base::HexEncode(x.data(), 16);
462 
463     rand[0] = rsi.address[5];
464     rand[1] = rsi.address[4];
465     rand[2] = rsi.address[3];
466 
467     DLOG(INFO) << "Hash " << base::HexEncode(rand, 3);
468 
469     if (memcmp(x.data(), &rand[0], 3) == 0) {
470       // match
471       return true;
472     }
473     // not a match
474     return false;
475   }
476 
477  private:
478   int group_id_;
479   Octet16 sirk_ = {0};
480   bool sirk_available_ = false;
481   int size_;
482   bluetooth::Uuid uuid_;
483 
484   std::vector<std::shared_ptr<CsisDevice>> devices_;
485   CsisDiscoveryState member_discovery_state_;
486 
487   CsisLockState lock_state_;
488   CsisLockState target_lock_state_;
489   int lock_transition_cnt_;
490 
491   CsisLockCb cb_;
492 };
493 
494 }  // namespace csis
495 }  // namespace bluetooth
496