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