Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9db38779 authored by Henri Chataing's avatar Henri Chataing
Browse files

RootCanal: Implement additional resolving list parameter validation

Additional checks for:
  - LeSetAddressResolutionEnable
  - LeAddDeviceToResolvingList
  - LeClearResolvingList

Test: gd cert test
Bug: 245578454
Ignore-AOSP-First: cherry-pick from AOSP
Merged-In: Ic89a428ca678376d5ce86e16a018d6edf8f3b3c2
Change-Id: Ic89a428ca678376d5ce86e16a018d6edf8f3b3c2
(cherry picked from commit da2a2900)
parent ac32e7a8
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -117,6 +117,39 @@ cc_library_static {
    srcs: ["model/devices/scripted_beacon_ble_payload.proto"],
}

cc_test_host {
    name: "rootcanal_hci_test",
    defaults: [
        "clang_file_coverage",
        "clang_coverage_bin",
        "rootcanal_defaults",
    ],
    srcs: [
        "test/controller/le/le_add_device_to_resolving_list_test.cc",
        "test/controller/le/le_clear_resolving_list_test.cc",
        "test/controller/le/le_remove_device_from_resolving_list_test.cc",
        "test/controller/le/le_set_address_resolution_enable_test.cc",
    ],
    header_libs: [
        "libbluetooth_headers",
    ],
    local_include_dirs: [
        "include",
        ".",
    ],
    include_dirs: [
        "packages/modules/Bluetooth/system",
        "packages/modules/Bluetooth/system/gd",
    ],
    shared_libs: [
        "liblog",
    ],
    static_libs: [
        "libbt-rootcanal",
        "libjsoncpp",
    ],
}

// test-vendor unit tests for host
cc_test_host {
    name: "rootcanal_test_host",
+15 −15
Original line number Diff line number Diff line
@@ -2041,7 +2041,7 @@ void DualModeController::LeSetAddressResolutionEnable(CommandView command) {
      gd_hci::LeSecurityCommandView::Create(
          gd_hci::SecurityCommandView::Create(command)));
  ASSERT(command_view.IsValid());
  auto status = link_layer_controller_.LeSetAddressResolutionEnable(
  ErrorCode status = link_layer_controller_.LeSetAddressResolutionEnable(
      command_view.GetAddressResolutionEnable() ==
      bluetooth::hci::Enable::ENABLED);
  send_event_(
@@ -2374,9 +2374,9 @@ void DualModeController::LeClearResolvingList(CommandView command) {
  auto command_view = gd_hci::LeClearResolvingListView::Create(
      gd_hci::LeSecurityCommandView::Create(command));
  ASSERT(command_view.IsValid());
  link_layer_controller_.LeResolvingListClear();
  ErrorCode status = link_layer_controller_.LeClearResolvingList();
  send_event_(bluetooth::hci::LeClearResolvingListCompleteBuilder::Create(
      kNumCommandPackets, ErrorCode::SUCCESS));
      kNumCommandPackets, status));
}

void DualModeController::LeReadResolvingListSize(CommandView command) {
@@ -2438,17 +2438,17 @@ void DualModeController::LeAddDeviceToResolvingList(CommandView command) {
  auto command_view = gd_hci::LeAddDeviceToResolvingListView::Create(
      gd_hci::LeSecurityCommandView::Create(command));
  ASSERT(command_view.IsValid());
  AddressType peer_address_type;
  AddressType peer_identity_address_type;
  switch (command_view.GetPeerIdentityAddressType()) {
    case bluetooth::hci::PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS:
      peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
      peer_identity_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
      break;
    case bluetooth::hci::PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS:
      peer_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
      peer_identity_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
      break;
  }
  auto status = link_layer_controller_.LeResolvingListAddDevice(
      command_view.GetPeerIdentityAddress(), peer_address_type,
  ErrorCode status = link_layer_controller_.LeAddDeviceToResolvingList(
      peer_identity_address_type, command_view.GetPeerIdentityAddress(),
      command_view.GetPeerIrk(), command_view.GetLocalIrk());
  send_event_(bluetooth::hci::LeAddDeviceToResolvingListCompleteBuilder::Create(
      kNumCommandPackets, status));
@@ -2459,20 +2459,20 @@ void DualModeController::LeRemoveDeviceFromResolvingList(CommandView command) {
      gd_hci::LeSecurityCommandView::Create(command));
  ASSERT(command_view.IsValid());

  AddressType peer_address_type;
  AddressType peer_identity_address_type;
  switch (command_view.GetPeerIdentityAddressType()) {
    case bluetooth::hci::PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS:
      peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
      peer_identity_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
      break;
    case bluetooth::hci::PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS:
      peer_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
      peer_identity_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
      break;
  }
  link_layer_controller_.LeResolvingListRemoveDevice(
      command_view.GetPeerIdentityAddress(), peer_address_type);
  ErrorCode status = link_layer_controller_.LeRemoveDeviceFromResolvingList(
      peer_identity_address_type, command_view.GetPeerIdentityAddress());
  send_event_(
      bluetooth::hci::LeRemoveDeviceFromResolvingListCompleteBuilder::Create(
          kNumCommandPackets, ErrorCode::SUCCESS));
          kNumCommandPackets, status));
}

void DualModeController::LeSetExtendedScanParameters(CommandView command) {
@@ -2571,7 +2571,7 @@ void DualModeController::LeSetPrivacyMode(CommandView command) {
      break;
  }
  if (link_layer_controller_.LeResolvingListContainsDevice(
          peer_identity_address, peer_identity_address_type)) {
          peer_identity_address_type, peer_identity_address)) {
    link_layer_controller_.LeSetPrivacyMode(
        peer_identity_address_type, peer_identity_address, privacy_mode);
  }
+151 −66
Original line number Diff line number Diff line
@@ -67,6 +67,35 @@ bool LinkLayerController::IsLeEventUnmasked(SubeventCode subevent) const {
         (le_event_mask_ & bit) != 0;
}

bool LinkLayerController::LeResolvingListContainsDevice(
    AddressType peer_identity_address_type, Address peer_identity_address) {
  for (auto const& entry : le_resolving_list_) {
    if (entry.peer_identity_address_type == peer_identity_address_type &&
        entry.peer_identity_address == peer_identity_address) {
      return true;
    }
  }

  return false;
}

bool LinkLayerController::LeResolvingListContainsDevice(
    bluetooth::hci::PeerAddressType peer_identity_address_type,
    Address peer_identity_address) {
  AddressType peer_address_type;
  switch (peer_identity_address_type) {
    case bluetooth::hci::PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS:
      peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
      break;
    case bluetooth::hci::PeerAddressType::RANDOM_DEVICE_OR_IDENTITY_ADDRESS:
      peer_address_type = AddressType::RANDOM_DEVICE_ADDRESS;
      break;
  }

  return LeResolvingListContainsDevice(peer_address_type,
                                       peer_identity_address);
}

// =============================================================================
//  General LE Coommands
// =============================================================================
@@ -130,6 +159,122 @@ ErrorCode LinkLayerController::LeSetHostFeature(uint8_t bit_number,
  return ErrorCode::SUCCESS;
}

// =============================================================================
//  LE Resolving List
// =============================================================================

// HCI command LE_Add_Device_To_Resolving_List (Vol 4, Part E § 7.8.38).
ErrorCode LinkLayerController::LeAddDeviceToResolvingList(
    AddressType peer_identity_address_type, Address peer_identity_address,
    std::array<uint8_t, kIrkSize> peer_irk,
    std::array<uint8_t, kIrkSize> local_irk) {
  // This command shall not be used when address resolution is enabled in the
  // Controller and:
  //  • Advertising (other than periodic advertising) is enabled,
  //  • Scanning is enabled, or
  //  • an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or
  //    HCI_LE_Periodic_Advertising_Create_Sync command is pending.
  if (ResolvingListBusy()) {
    LOG_INFO(
        "device is currently advertising, scanning, or establishing an"
        " LE connection");
    return ErrorCode::COMMAND_DISALLOWED;
  }

  // When a Controller cannot add a device to the list because there is no space
  // available, it shall return the error code Memory Capacity Exceeded (0x07).
  if (le_resolving_list_.size() >= properties_.le_resolving_list_size) {
    LOG_INFO("resolving list is full");
    return ErrorCode::MEMORY_CAPACITY_EXCEEDED;
  }

  // If there is an existing entry in the resolving list with the same
  // Peer_Identity_Address and Peer_Identity_Address_Type, or with the same
  // Peer_IRK, the Controller should return the error code Invalid HCI Command
  // Parameters (0x12).
  for (auto const& entry : le_resolving_list_) {
    if ((entry.peer_identity_address_type == peer_identity_address_type &&
         entry.peer_identity_address == peer_identity_address) ||
        entry.peer_irk == peer_irk) {
      LOG_INFO("device is already present in the resolving list");
      return ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
    }
  }

  le_resolving_list_.emplace_back(ResolvingListEntry{
      peer_identity_address_type, peer_identity_address, peer_irk, local_irk});
  return ErrorCode::SUCCESS;
}

// HCI command LE_Remove_Device_From_Resolving_List (Vol 4, Part E § 7.8.39).
ErrorCode LinkLayerController::LeRemoveDeviceFromResolvingList(
    AddressType peer_identity_address_type, Address peer_identity_address) {
  // This command shall not be used when address resolution is enabled in the
  // Controller and:
  //  • Advertising (other than periodic advertising) is enabled,
  //  • Scanning is enabled, or
  //  • an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or
  //    HCI_LE_Periodic_Advertising_Create_Sync command is pending.
  if (ResolvingListBusy()) {
    LOG_INFO(
        "device is currently advertising, scanning, or establishing an"
        " LE connection");
    return ErrorCode::COMMAND_DISALLOWED;
  }

  for (auto it = le_resolving_list_.begin(); it != le_resolving_list_.end();
       it++) {
    if (it->peer_identity_address_type == peer_identity_address_type &&
        it->peer_identity_address == peer_identity_address) {
      le_resolving_list_.erase(it);
      return ErrorCode::SUCCESS;
    }
  }

  // When a Controller cannot remove a device from the resolving list because
  // it is not found, it shall return the error code
  // Unknown Connection Identifier (0x02).
  LOG_INFO("peer address not found in the resolving list");
  return ErrorCode::UNKNOWN_CONNECTION;
}

// HCI command LE_Clear_Resolving_List (Vol 4, Part E § 7.8.40).
ErrorCode LinkLayerController::LeClearResolvingList() {
  // This command shall not be used when address resolution is enabled in the
  // Controller and:
  //  • Advertising (other than periodic advertising) is enabled,
  //  • Scanning is enabled, or
  //  • an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or
  //    HCI_LE_Periodic_Advertising_Create_Sync command is pending.
  if (ResolvingListBusy()) {
    LOG_INFO(
        "device is currently advertising, scanning,"
        " or establishing an LE connection");
    return ErrorCode::COMMAND_DISALLOWED;
  }

  le_resolving_list_.clear();
  return ErrorCode::SUCCESS;
}

// HCI command LE_Set_Address_Resolution_Enable (Vol 4, Part E § 7.8.44).
ErrorCode LinkLayerController::LeSetAddressResolutionEnable(bool enable) {
  // This command shall not be used when:
  //  • Advertising (other than periodic advertising) is enabled,
  //  • Scanning is enabled, or
  //  • an HCI_LE_Create_Connection, HCI_LE_Extended_Create_Connection, or
  //    HCI_LE_Periodic_Advertising_Create_Sync command is pending.
  if (ResolvingListBusy()) {
    LOG_INFO(
        "device is currently advertising, scanning,"
        " or establishing an LE connection");
    return ErrorCode::COMMAND_DISALLOWED;
  }

  le_resolving_list_enabled_ = enable;
  return ErrorCode::SUCCESS;
}

void LinkLayerController::SetSecureSimplePairingSupport(bool enable) {
  uint64_t bit = 0x1;
  secure_simple_pairing_host_support_ = enable;
@@ -1608,10 +1753,10 @@ void LinkLayerController::IncomingLeLegacyAdvertisingPdu(
    for (const auto& entry : le_resolving_list_) {
      if (rpa_matches_irk(advertising_address, entry.peer_irk)) {
        LOG_INFO("Matched against IRK for %s",
                 entry.address.ToString().c_str());
                 entry.peer_identity_address.ToString().c_str());
        resolved = true;
        resolved_address = entry.address;
        resolved_address_type = entry.address_type;
        resolved_address = entry.peer_identity_address;
        resolved_address_type = entry.peer_identity_address_type;
        rpa = generate_rpa(entry.local_irk);
      }
    }
@@ -3430,8 +3575,9 @@ ErrorCode LinkLayerController::SetLeExtendedAdvertisingParameters(
            own_address_type ==
                bluetooth::hci::OwnAddressType::RESOLVABLE_OR_RANDOM_ADDRESS) {
          for (const auto& entry : le_resolving_list_) {
            if (entry.address == peer_address.GetAddress() &&
                entry.address_type == peer_address.GetAddressType()) {
            if (entry.peer_identity_address == peer_address.GetAddress() &&
                entry.peer_identity_address_type ==
                    peer_address.GetAddressType()) {
              return generate_rpa(entry.local_irk);
            }
          }
@@ -3552,24 +3698,6 @@ ErrorCode LinkLayerController::LeFilterAcceptListClear() {
  return ErrorCode::SUCCESS;
}

ErrorCode LinkLayerController::LeSetAddressResolutionEnable(bool enable) {
  if (ResolvingListBusy()) {
    return ErrorCode::COMMAND_DISALLOWED;
  }

  le_resolving_list_enabled_ = enable;
  return ErrorCode::SUCCESS;
}

ErrorCode LinkLayerController::LeResolvingListClear() {
  if (ResolvingListBusy()) {
    return ErrorCode::COMMAND_DISALLOWED;
  }

  le_resolving_list_.clear();
  return ErrorCode::SUCCESS;
}

ErrorCode LinkLayerController::LeFilterAcceptListAddDevice(
    Address addr, AddressType addr_type) {
  if (FilterAcceptListBusy()) {
@@ -3587,20 +3715,6 @@ ErrorCode LinkLayerController::LeFilterAcceptListAddDevice(
  return ErrorCode::SUCCESS;
}

ErrorCode LinkLayerController::LeResolvingListAddDevice(
    Address addr, AddressType addr_type, std::array<uint8_t, kIrkSize> peerIrk,
    std::array<uint8_t, kIrkSize> localIrk) {
  if (ResolvingListBusy()) {
    return ErrorCode::COMMAND_DISALLOWED;
  }
  if (LeResolvingListFull()) {
    return ErrorCode::MEMORY_CAPACITY_EXCEEDED;
  }
  le_resolving_list_.emplace_back(
      ResolvingListEntry{addr, addr_type, peerIrk, localIrk});
  return ErrorCode::SUCCESS;
}

bool LinkLayerController::HasAclConnection() {
  return (connections_.GetAclHandles().size() > 0);
}
@@ -3961,20 +4075,6 @@ ErrorCode LinkLayerController::LeFilterAcceptListRemoveDevice(
  return ErrorCode::SUCCESS;
}

ErrorCode LinkLayerController::LeResolvingListRemoveDevice(
    Address addr, AddressType addr_type) {
  if (ResolvingListBusy()) {
    return ErrorCode::COMMAND_DISALLOWED;
  }
  for (size_t i = 0; i < le_resolving_list_.size(); i++) {
    auto curr = le_resolving_list_[i];
    if (curr.address == addr && curr.address_type == addr_type) {
      le_resolving_list_.erase(le_resolving_list_.begin() + i);
    }
  }
  return ErrorCode::SUCCESS;
}

bool LinkLayerController::LeFilterAcceptListContainsDevice(
    Address addr, AddressType addr_type) {
  for (size_t i = 0; i < le_connect_list_.size(); i++) {
@@ -3986,25 +4086,10 @@ bool LinkLayerController::LeFilterAcceptListContainsDevice(
  return false;
}

bool LinkLayerController::LeResolvingListContainsDevice(Address addr,
                                                        AddressType addr_type) {
  for (size_t i = 0; i < le_connect_list_.size(); i++) {
    auto curr = le_connect_list_[i];
    if (curr.address == addr && curr.address_type == addr_type) {
      return true;
    }
  }
  return false;
}

bool LinkLayerController::LeFilterAcceptListFull() {
  return le_connect_list_.size() >= properties_.le_filter_accept_list_size;
}

bool LinkLayerController::LeResolvingListFull() {
  return le_resolving_list_.size() >= properties_.le_resolving_list_size;
}

void LinkLayerController::Reset() {
  connections_ = AclConnectionHandler();
  le_connect_list_.clear();
+37 −16
Original line number Diff line number Diff line
@@ -48,12 +48,6 @@ class LinkLayerController {
 public:
  static constexpr size_t kIrkSize = 16;

  // HCI LE Set Random Address command (Vol 4, Part E § 7.8.4).
  ErrorCode LeSetRandomAddress(Address random_address);

  // HCI LE Set Host Feature command (Vol 4, Part E § 7.8.115).
  ErrorCode LeSetHostFeature(uint8_t bit_number, uint8_t bit_value);

  LinkLayerController(const Address& address,
                      const ControllerProperties& properties);

@@ -218,15 +212,13 @@ class LinkLayerController {
  ErrorCode LeFilterAcceptListRemoveDevice(Address addr, AddressType addr_type);
  bool LeFilterAcceptListContainsDevice(Address addr, AddressType addr_type);
  bool LeFilterAcceptListFull();

  bool ResolvingListBusy();
  ErrorCode LeSetAddressResolutionEnable(bool enable);
  ErrorCode LeResolvingListClear();
  ErrorCode LeResolvingListAddDevice(Address addr, AddressType addr_type,
                                     std::array<uint8_t, kIrkSize> peerIrk,
                                     std::array<uint8_t, kIrkSize> localIrk);
  ErrorCode LeResolvingListRemoveDevice(Address addr, AddressType addr_type);
  bool LeResolvingListContainsDevice(Address addr, AddressType addr_type);
  bool LeResolvingListFull();
  bool LeResolvingListContainsDevice(AddressType peer_identity_address_type,
                                     Address peer_identity_address);
  bool LeResolvingListContainsDevice(
      bluetooth::hci::PeerAddressType peer_identity_address_type,
      Address peer_identity_address);
  void LeSetPrivacyMode(AddressType address_type, Address addr, uint8_t mode);

  void LeReadIsoTxSync(uint16_t handle);
@@ -401,6 +393,32 @@ class LinkLayerController {

  void HandleIso(bluetooth::hci::IsoView iso);

  // LE Commands

  // HCI LE Set Random Address command (Vol 4, Part E § 7.8.4).
  ErrorCode LeSetRandomAddress(Address random_address);

  // HCI LE Set Host Feature command (Vol 4, Part E § 7.8.115).
  ErrorCode LeSetHostFeature(uint8_t bit_number, uint8_t bit_value);

  // LE Address Resolving

  // HCI command LE_Add_Device_To_Resolving_List (Vol 4, Part E § 7.8.38).
  ErrorCode LeAddDeviceToResolvingList(AddressType peer_identity_address_type,
                                       Address peer_address,
                                       std::array<uint8_t, kIrkSize> peer_irk,
                                       std::array<uint8_t, kIrkSize> local_irk);

  // HCI command LE_Remove_Device_From_Resolving_List (Vol 4, Part E § 7.8.39).
  ErrorCode LeRemoveDeviceFromResolvingList(
      AddressType peer_identity_address_type, Address peer_identity_address);

  // HCI command LE_Clear_Resolving_List (Vol 4, Part E § 7.8.40).
  ErrorCode LeClearResolvingList();

  // HCI command LE_Set_Address_Resolution_Enable (Vol 4, Part E § 7.8.44).
  ErrorCode LeSetAddressResolutionEnable(bool enable);

 protected:
  void SendLeLinkLayerPacketWithRssi(
      Address source, Address dest, uint8_t rssi,
@@ -761,12 +779,14 @@ class LinkLayerController {
    AddressType address_type;
  };
  std::vector<ConnectListEntry> le_connect_list_;

  struct ResolvingListEntry {
    Address address;
    AddressType address_type;
    AddressType peer_identity_address_type;
    Address peer_identity_address;
    std::array<uint8_t, kIrkSize> peer_irk;
    std::array<uint8_t, kIrkSize> local_irk;
  };

  std::vector<ResolvingListEntry> le_resolving_list_;
  bool le_resolving_list_enabled_{false};

@@ -803,6 +823,7 @@ class LinkLayerController {
#else
  SecurityManager security_manager_{10};
#endif /* ROOTCANAL_LMP */

  std::chrono::steady_clock::time_point last_inquiry_;
  model::packets::InquiryType inquiry_mode_{
      model::packets::InquiryType::STANDARD};
+128 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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 <gtest/gtest.h>

#include "model/controller/link_layer_controller.h"

namespace rootcanal {

using namespace bluetooth::hci;

class LeAddDeviceToResolvingListTest : public ::testing::Test {
 public:
  LeAddDeviceToResolvingListTest() {
    // Reduce the size of the resolving list to simplify testing.
    properties_.le_resolving_list_size = 2;
  }

  ~LeAddDeviceToResolvingListTest() override = default;

 protected:
  Address address_{0};
  ControllerProperties properties_{};
  LinkLayerController controller_{address_, properties_};
};

TEST_F(LeAddDeviceToResolvingListTest, Success) {
  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{1}, std::array<uint8_t, 16>{1}),
            ErrorCode::SUCCESS);

  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::RANDOM_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{2}, std::array<uint8_t, 16>{2}),
            ErrorCode::SUCCESS);
}

TEST_F(LeAddDeviceToResolvingListTest, ListFull) {
  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{1}, std::array<uint8_t, 16>{1}),
            ErrorCode::SUCCESS);

  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{2},
                std::array<uint8_t, 16>{2}, std::array<uint8_t, 16>{2}),
            ErrorCode::SUCCESS);

  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{3},
                std::array<uint8_t, 16>{3}, std::array<uint8_t, 16>{3}),
            ErrorCode::MEMORY_CAPACITY_EXCEEDED);
}

TEST_F(LeAddDeviceToResolvingListTest, ScanningActive) {
  ASSERT_EQ(controller_.LeSetAddressResolutionEnable(true), ErrorCode::SUCCESS);
  controller_.SetLeScanEnable(OpCode::LE_SET_SCAN_ENABLE);

  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{1}, std::array<uint8_t, 16>{1}),
            ErrorCode::COMMAND_DISALLOWED);
}

TEST_F(LeAddDeviceToResolvingListTest, LegacyAdvertisingActive) {
  ASSERT_EQ(controller_.LeSetAddressResolutionEnable(true), ErrorCode::SUCCESS);
  ASSERT_EQ(controller_.SetLeAdvertisingEnable(1), ErrorCode::SUCCESS);

  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{1}, std::array<uint8_t, 16>{1}),
            ErrorCode::COMMAND_DISALLOWED);
}

TEST_F(LeAddDeviceToResolvingListTest, ExtendedAdvertisingActive) {
  EnabledSet enabled_set;
  enabled_set.advertising_handle_ = 1;
  enabled_set.duration_ = 0;
  ASSERT_EQ(controller_.LeSetAddressResolutionEnable(true), ErrorCode::SUCCESS);
  ASSERT_EQ(controller_.SetLeExtendedAdvertisingEnable(Enable::ENABLED,
                                                       {enabled_set}),
            ErrorCode::SUCCESS);

  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{1}, std::array<uint8_t, 16>{1}),
            ErrorCode::COMMAND_DISALLOWED);
}

TEST_F(LeAddDeviceToResolvingListTest, PeerAddressDuplicate) {
  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{1}, std::array<uint8_t, 16>{1}),
            ErrorCode::SUCCESS);

  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{2}, std::array<uint8_t, 16>{2}),
            ErrorCode::INVALID_HCI_COMMAND_PARAMETERS);
}

TEST_F(LeAddDeviceToResolvingListTest, PeerIrkDuplicate) {
  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::PUBLIC_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{1}, std::array<uint8_t, 16>{1}),
            ErrorCode::SUCCESS);

  ASSERT_EQ(controller_.LeAddDeviceToResolvingList(
                AddressType::RANDOM_DEVICE_ADDRESS, Address{1},
                std::array<uint8_t, 16>{1}, std::array<uint8_t, 16>{1}),
            ErrorCode::INVALID_HCI_COMMAND_PARAMETERS);
}

}  // namespace rootcanal
Loading