/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "hci/le_address_manager.h" #include "common/init_flags.h" #include "os/log.h" #include "os/rand.h" namespace bluetooth { namespace hci { static constexpr uint8_t BLE_ADDR_MASK = 0xc0u; LeAddressManager::LeAddressManager( common::Callback)> enqueue_command, os::Handler* handler, Address public_address, uint8_t connect_list_size, uint8_t resolving_list_size) : enqueue_command_(enqueue_command), handler_(handler), public_address_(public_address), connect_list_size_(connect_list_size), resolving_list_size_(resolving_list_size){}; LeAddressManager::~LeAddressManager() { if (address_rotation_alarm_ != nullptr) { address_rotation_alarm_->Cancel(); address_rotation_alarm_.reset(); } } // Aborts if called more than once void LeAddressManager::SetPrivacyPolicyForInitiatorAddress( AddressPolicy address_policy, AddressWithType fixed_address, crypto_toolbox::Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { ASSERT(address_policy_ == AddressPolicy::POLICY_NOT_SET); ASSERT(address_policy != AddressPolicy::POLICY_NOT_SET); ASSERT_LOG(registered_clients_.empty(), "Policy must be set before clients are registered."); address_policy_ = address_policy; switch (address_policy_) { case AddressPolicy::USE_PUBLIC_ADDRESS: le_address_ = fixed_address; handler_->BindOnceOn(this, &LeAddressManager::resume_registered_clients).Invoke(); break; case AddressPolicy::USE_STATIC_ADDRESS: { auto addr = fixed_address.GetAddress(); auto address = addr.address; // The two most significant bits of the static address shall be equal to 1 ASSERT_LOG((address[5] & BLE_ADDR_MASK) == BLE_ADDR_MASK, "The two most significant bits shall be equal to 1"); // Bits of the random part of the address shall not be all 1 or all 0 if ((address[0] == 0x00 && address[1] == 0x00 && address[2] == 0x00 && address[3] == 0x00 && address[4] == 0x00 && address[5] == BLE_ADDR_MASK) || (address[0] == 0xFF && address[1] == 0xFF && address[2] == 0xFF && address[3] == 0xFF && address[4] == 0xFF && address[5] == 0xFF)) { LOG_ALWAYS_FATAL("Bits of the random part of the address shall not be all 1 or all 0"); } le_address_ = fixed_address; auto packet = hci::LeSetRandomAddressBuilder::Create(le_address_.GetAddress()); handler_->Post(common::BindOnce(enqueue_command_, std::move(packet))); } break; case AddressPolicy::USE_NON_RESOLVABLE_ADDRESS: case AddressPolicy::USE_RESOLVABLE_ADDRESS: le_address_ = fixed_address; rotation_irk_ = rotation_irk; minimum_rotation_time_ = minimum_rotation_time; maximum_rotation_time_ = maximum_rotation_time; address_rotation_alarm_ = std::make_unique(handler_); set_random_address(); break; case AddressPolicy::POLICY_NOT_SET: LOG_ALWAYS_FATAL("invalid parameters"); } } // TODO(jpawlowski): remove once we have config file abstraction in cert tests void LeAddressManager::SetPrivacyPolicyForInitiatorAddressForTest( AddressPolicy address_policy, AddressWithType fixed_address, crypto_toolbox::Octet16 rotation_irk, std::chrono::milliseconds minimum_rotation_time, std::chrono::milliseconds maximum_rotation_time) { ASSERT(address_policy != AddressPolicy::POLICY_NOT_SET); ASSERT_LOG(registered_clients_.empty(), "Policy must be set before clients are registered."); address_policy_ = address_policy; switch (address_policy_) { case AddressPolicy::USE_PUBLIC_ADDRESS: le_address_ = fixed_address; break; case AddressPolicy::USE_STATIC_ADDRESS: { auto addr = fixed_address.GetAddress(); auto address = addr.address; // The two most significant bits of the static address shall be equal to 1 ASSERT_LOG((address[5] & BLE_ADDR_MASK) == BLE_ADDR_MASK, "The two most significant bits shall be equal to 1"); // Bits of the random part of the address shall not be all 1 or all 0 if ((address[0] == 0x00 && address[1] == 0x00 && address[2] == 0x00 && address[3] == 0x00 && address[4] == 0x00 && address[5] == BLE_ADDR_MASK) || (address[0] == 0xFF && address[1] == 0xFF && address[2] == 0xFF && address[3] == 0xFF && address[4] == 0xFF && address[5] == 0xFF)) { LOG_ALWAYS_FATAL("Bits of the random part of the address shall not be all 1 or all 0"); } le_address_ = fixed_address; auto packet = hci::LeSetRandomAddressBuilder::Create(le_address_.GetAddress()); handler_->Call(enqueue_command_, std::move(packet)); } break; case AddressPolicy::USE_NON_RESOLVABLE_ADDRESS: case AddressPolicy::USE_RESOLVABLE_ADDRESS: rotation_irk_ = rotation_irk; minimum_rotation_time_ = minimum_rotation_time; maximum_rotation_time_ = maximum_rotation_time; address_rotation_alarm_ = std::make_unique(handler_); break; case AddressPolicy::POLICY_NOT_SET: LOG_ALWAYS_FATAL("invalid parameters"); } } LeAddressManager::AddressPolicy LeAddressManager::GetAddressPolicy() { return address_policy_; } LeAddressManager::AddressPolicy LeAddressManager::Register(LeAddressManagerCallback* callback) { handler_->BindOnceOn(this, &LeAddressManager::register_client, callback).Invoke(); return address_policy_; } void LeAddressManager::register_client(LeAddressManagerCallback* callback) { registered_clients_.insert(std::pair(callback, ClientState::RESUMED)); if (address_policy_ == AddressPolicy::POLICY_NOT_SET) { LOG_INFO("address policy isn't set yet, pause clients and return"); pause_registered_clients(); return; } else if ( address_policy_ == AddressPolicy::USE_RESOLVABLE_ADDRESS || address_policy_ == AddressPolicy::USE_NON_RESOLVABLE_ADDRESS) { if (bluetooth::common::init_flags::gd_acl_is_enabled() || bluetooth::common::init_flags::gd_l2cap_is_enabled()) { if (registered_clients_.size() == 1) { schedule_rotate_random_address(); } } else { prepare_to_rotate(); } } } void LeAddressManager::Unregister(LeAddressManagerCallback* callback) { handler_->BindOnceOn(this, &LeAddressManager::unregister_client, callback).Invoke(); } void LeAddressManager::unregister_client(LeAddressManagerCallback* callback) { registered_clients_.erase(callback); if (registered_clients_.empty() && address_rotation_alarm_ != nullptr) { address_rotation_alarm_->Cancel(); } } void LeAddressManager::AckPause(LeAddressManagerCallback* callback) { handler_->BindOnceOn(this, &LeAddressManager::ack_pause, callback).Invoke(); } void LeAddressManager::AckResume(LeAddressManagerCallback* callback) { handler_->BindOnceOn(this, &LeAddressManager::ack_resume, callback).Invoke(); } AddressWithType LeAddressManager::GetCurrentAddress() { ASSERT(address_policy_ != AddressPolicy::POLICY_NOT_SET); return le_address_; } AddressWithType LeAddressManager::GetAnotherAddress() { ASSERT( address_policy_ == AddressPolicy::USE_NON_RESOLVABLE_ADDRESS || address_policy_ == AddressPolicy::USE_RESOLVABLE_ADDRESS); hci::Address address = generate_rpa(); auto random_address = AddressWithType(address, AddressType::RANDOM_DEVICE_ADDRESS); return random_address; } void LeAddressManager::pause_registered_clients() { for (auto& client : registered_clients_) { if (client.second != ClientState::PAUSED && client.second != ClientState::WAITING_FOR_PAUSE) { client.second = ClientState::WAITING_FOR_PAUSE; client.first->OnPause(); } } } void LeAddressManager::push_command(Command command) { pause_registered_clients(); cached_commands_.push(std::move(command)); } void LeAddressManager::ack_pause(LeAddressManagerCallback* callback) { ASSERT(registered_clients_.find(callback) != registered_clients_.end()); registered_clients_.find(callback)->second = ClientState::PAUSED; for (auto client : registered_clients_) { if (client.second != ClientState::PAUSED) { // make sure all client paused return; } } if (address_policy_ != AddressPolicy::POLICY_NOT_SET) { handle_next_command(); } } void LeAddressManager::resume_registered_clients() { // Do not resume clients if cached command is not empty if (!cached_commands_.empty()) { handle_next_command(); return; } for (auto& client : registered_clients_) { client.second = ClientState::WAITING_FOR_RESUME; client.first->OnResume(); } } void LeAddressManager::ack_resume(LeAddressManagerCallback* callback) { ASSERT(registered_clients_.find(callback) != registered_clients_.end()); registered_clients_.find(callback)->second = ClientState::RESUMED; } void LeAddressManager::prepare_to_rotate() { Command command = {CommandType::ROTATE_RANDOM_ADDRESS, nullptr}; cached_commands_.push(std::move(command)); pause_registered_clients(); } void LeAddressManager::schedule_rotate_random_address() { address_rotation_alarm_->Schedule( common::BindOnce(&LeAddressManager::prepare_to_rotate, common::Unretained(this)), GetNextPrivateAddressIntervalMs()); } void LeAddressManager::set_random_address() { if (address_policy_ != AddressPolicy::USE_RESOLVABLE_ADDRESS && address_policy_ != AddressPolicy::USE_NON_RESOLVABLE_ADDRESS) { LOG_ALWAYS_FATAL("Invalid address policy!"); return; } hci::Address address; if (address_policy_ == AddressPolicy::USE_RESOLVABLE_ADDRESS) { address = generate_rpa(); } else { address = generate_nrpa(); } auto packet = hci::LeSetRandomAddressBuilder::Create(address); enqueue_command_.Run(std::move(packet)); cached_address_ = AddressWithType(address, AddressType::RANDOM_DEVICE_ADDRESS); } void LeAddressManager::rotate_random_address() { if (address_policy_ != AddressPolicy::USE_RESOLVABLE_ADDRESS && address_policy_ != AddressPolicy::USE_NON_RESOLVABLE_ADDRESS) { LOG_ALWAYS_FATAL("Invalid address policy!"); return; } schedule_rotate_random_address(); set_random_address(); } /* This function generates Resolvable Private Address (RPA) from Identity * Resolving Key |irk| and |prand|*/ hci::Address LeAddressManager::generate_rpa() { // most significant bit, bit7, bit6 is 01 to be resolvable random // Bits of the random part of prand shall not be all 1 or all 0 std::array prand = os::GenerateRandom<3>(); constexpr uint8_t BLE_RESOLVE_ADDR_MSB = 0x40; prand[2] &= ~BLE_ADDR_MASK; if ((prand[0] == 0x00 && prand[1] == 0x00 && prand[2] == 0x00) || (prand[0] == 0xFF && prand[1] == 0xFF && prand[2] == 0x3F)) { prand[0] = (uint8_t)(os::GenerateRandom() % 0xFE + 1); } prand[2] |= BLE_RESOLVE_ADDR_MSB; hci::Address address; address.address[3] = prand[0]; address.address[4] = prand[1]; address.address[5] = prand[2]; /* encrypt with IRK */ crypto_toolbox::Octet16 p = crypto_toolbox::aes_128(rotation_irk_, prand.data(), 3); /* set hash to be LSB of rpAddress */ address.address[0] = p[0]; address.address[1] = p[1]; address.address[2] = p[2]; return address; } // This function generates NON-Resolvable Private Address (NRPA) hci::Address LeAddressManager::generate_nrpa() { // The two most significant bits of the address shall be equal to 0 // Bits of the random part of the address shall not be all 1 or all 0 std::array random = os::GenerateRandom<6>(); random[5] &= ~BLE_ADDR_MASK; if ((random[0] == 0x00 && random[1] == 0x00 && random[2] == 0x00 && random[3] == 0x00 && random[4] == 0x00 && random[5] == 0x00) || (random[0] == 0xFF && random[1] == 0xFF && random[2] == 0xFF && random[3] == 0xFF && random[4] == 0xFF && random[5] == 0x3F)) { random[0] = (uint8_t)(os::GenerateRandom() % 0xFE + 1); } hci::Address address; address.FromOctets(random.data()); // the address shall not be equal to the public address while (address == public_address_) { address.address[0] = (uint8_t)(os::GenerateRandom() % 0xFE + 1); } return address; } std::chrono::milliseconds LeAddressManager::GetNextPrivateAddressIntervalMs() { auto interval_random_part_max_ms = maximum_rotation_time_ - minimum_rotation_time_; auto random_ms = std::chrono::milliseconds(os::GenerateRandom()) % (interval_random_part_max_ms); return minimum_rotation_time_ + random_ms; } uint8_t LeAddressManager::GetConnectListSize() { return connect_list_size_; } uint8_t LeAddressManager::GetResolvingListSize() { return resolving_list_size_; } void LeAddressManager::handle_next_command() { for (auto client : registered_clients_) { if (client.second != ClientState::PAUSED) { // make sure all client paused, if not, this function will be trigger again by ack_pause LOG_INFO("waiting for ack_pause, return"); return; } } ASSERT(!cached_commands_.empty()); auto command = std::move(cached_commands_.front()); cached_commands_.pop(); if (command.command_type == CommandType::ROTATE_RANDOM_ADDRESS) { rotate_random_address(); } else { enqueue_command_.Run(std::move(command.command_packet)); } } void LeAddressManager::AddDeviceToConnectList( ConnectListAddressType connect_list_address_type, bluetooth::hci::Address address) { auto packet_builder = hci::LeAddDeviceToConnectListBuilder::Create(connect_list_address_type, address); Command command = {CommandType::ADD_DEVICE_TO_CONNECT_LIST, std::move(packet_builder)}; handler_->BindOnceOn(this, &LeAddressManager::push_command, std::move(command)).Invoke(); } void LeAddressManager::AddDeviceToResolvingList( PeerAddressType peer_identity_address_type, Address peer_identity_address, const std::array& peer_irk, const std::array& local_irk) { auto packet_builder = hci::LeAddDeviceToResolvingListBuilder::Create( peer_identity_address_type, peer_identity_address, peer_irk, local_irk); Command command = {CommandType::ADD_DEVICE_TO_RESOLVING_LIST, std::move(packet_builder)}; handler_->BindOnceOn(this, &LeAddressManager::push_command, std::move(command)).Invoke(); } void LeAddressManager::RemoveDeviceFromConnectList( ConnectListAddressType connect_list_address_type, bluetooth::hci::Address address) { auto packet_builder = hci::LeRemoveDeviceFromConnectListBuilder::Create(connect_list_address_type, address); Command command = {CommandType::REMOVE_DEVICE_FROM_CONNECT_LIST, std::move(packet_builder)}; handler_->BindOnceOn(this, &LeAddressManager::push_command, std::move(command)).Invoke(); } void LeAddressManager::RemoveDeviceFromResolvingList( PeerAddressType peer_identity_address_type, Address peer_identity_address) { auto packet_builder = hci::LeRemoveDeviceFromResolvingListBuilder::Create(peer_identity_address_type, peer_identity_address); Command command = {CommandType::REMOVE_DEVICE_FROM_RESOLVING_LIST, std::move(packet_builder)}; handler_->BindOnceOn(this, &LeAddressManager::push_command, std::move(command)).Invoke(); } void LeAddressManager::ClearConnectList() { auto packet_builder = hci::LeClearConnectListBuilder::Create(); Command command = {CommandType::CLEAR_CONNECT_LIST, std::move(packet_builder)}; handler_->BindOnceOn(this, &LeAddressManager::push_command, std::move(command)).Invoke(); } void LeAddressManager::ClearResolvingList() { auto packet_builder = hci::LeClearResolvingListBuilder::Create(); Command command = {CommandType::CLEAR_RESOLVING_LIST, std::move(packet_builder)}; handler_->BindOnceOn(this, &LeAddressManager::push_command, std::move(command)).Invoke(); } void LeAddressManager::OnCommandComplete(bluetooth::hci::CommandCompleteView view) { if (!view.IsValid()) { LOG_ERROR("Received command complete with invalid packet"); return; } std::string op_code = OpCodeText(view.GetCommandOpCode()); LOG_INFO("Received command complete with op_code %s", op_code.c_str()); // The command was sent before any client registered, we can make sure all the clients paused when command complete. if (view.GetCommandOpCode() == OpCode::LE_SET_RANDOM_ADDRESS) { if (address_policy_ == AddressPolicy::USE_STATIC_ADDRESS) { LOG_INFO("Received LE_SET_RANDOM_ADDRESS complete and Address policy is USE_STATIC_ADDRESS, return"); return; } auto complete_view = LeSetRandomAddressCompleteView::Create(view); if (!complete_view.IsValid()) { LOG_ERROR("Received LE_SET_RANDOM_ADDRESS complete with invalid packet"); } else if (complete_view.IsValid() && complete_view.GetStatus() != ErrorCode::SUCCESS) { LOG_ERROR( "Received LE_SET_RANDOM_ADDRESS complete with status %s", ErrorCodeText(complete_view.GetStatus()).c_str()); } else { LOG_INFO("update random address : %s", cached_address_.GetAddress().ToString().c_str()); le_address_ = cached_address_; } } if (cached_commands_.empty()) { handler_->BindOnceOn(this, &LeAddressManager::resume_registered_clients).Invoke(); } else { handler_->BindOnceOn(this, &LeAddressManager::handle_next_command).Invoke(); } } } // namespace hci } // namespace bluetooth