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