blob: 5b5ee83385a48b545c9764c9a16e0f9c7ef9322a [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "low_energy_address_manager.h"
#include <fbl/function.h>
#include "gap.h"
#include "src/connectivity/bluetooth/core/bt-host/sm/util.h"
#include "src/connectivity/bluetooth/core/bt-host/testing/fake_controller_test.h"
#include "src/connectivity/bluetooth/core/bt-host/testing/test_controller.h"
namespace bt {
namespace gap {
namespace {
using testing::CommandTransaction;
using testing::TestController;
using TestingBase = testing::FakeControllerTest<TestController>;
const DeviceAddress kPublic(DeviceAddress::Type::kLEPublic,
"AA:BB:CC:DD:EE:FF");
class GAP_LowEnergyAddressManagerTest : public TestingBase {
public:
GAP_LowEnergyAddressManagerTest() = default;
~GAP_LowEnergyAddressManagerTest() override = default;
protected:
void SetUp() override {
TestingBase::SetUp();
addr_mgr_ = std::make_unique<LowEnergyAddressManager>(
kPublic, [this] { return IsRandomAddressChangeAllowed(); },
transport());
ASSERT_EQ(kPublic, addr_mgr()->identity_address());
ASSERT_FALSE(addr_mgr()->irk());
StartTestDevice();
}
void TearDown() override {
addr_mgr_ = nullptr;
TestingBase::TearDown();
}
DeviceAddress EnsureLocalAddress() {
bool called = false;
DeviceAddress result;
addr_mgr()->EnsureLocalAddress([&](const auto& addr) {
result = addr;
called = true;
});
RunLoopUntilIdle();
EXPECT_TRUE(called);
return result;
}
// Called by |addr_mgr_|.
bool IsRandomAddressChangeAllowed() const {
return random_address_change_allowed_;
}
LowEnergyAddressManager* addr_mgr() const { return addr_mgr_.get(); };
void set_random_address_change_allowed(bool value) {
random_address_change_allowed_ = value;
}
private:
std::unique_ptr<LowEnergyAddressManager> addr_mgr_;
bool random_address_change_allowed_ = true;
DISALLOW_COPY_ASSIGN_AND_MOVE(GAP_LowEnergyAddressManagerTest);
};
TEST_F(GAP_LowEnergyAddressManagerTest, DefaultState) {
EXPECT_EQ(kPublic, EnsureLocalAddress());
}
TEST_F(GAP_LowEnergyAddressManagerTest, EnablePrivacy) {
// Respond with success.
const auto kResponse =
CreateStaticByteBuffer(0x0E, 4, // Command Complete, 4 bytes,
1, // 1 allowed packet
0x05, 0x20, // opcode: HCI_LE_Set_Random_Address
0x00 // status: success
);
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kResponse}));
const UInt128 kIrk{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}};
int hci_cmd_count = 0;
DeviceAddress addr;
test_device()->SetTransactionCallback(
[&](const auto& rx) {
hci_cmd_count++;
const auto addr_bytes = rx.view(sizeof(hci::CommandHeader));
ASSERT_EQ(6u, addr_bytes.size());
addr = DeviceAddress(DeviceAddress::Type::kLERandom,
DeviceAddressBytes(addr_bytes));
},
dispatcher());
addr_mgr()->set_irk(kIrk);
ASSERT_TRUE(addr_mgr()->irk());
EXPECT_EQ(kIrk, *addr_mgr()->irk());
addr_mgr()->EnablePrivacy(true);
// Privacy is now considered enabled. Further requests to enable should not
// trigger additional HCI commands.
addr_mgr()->EnablePrivacy(true);
RunLoopUntilIdle();
// We should have received a HCI command with a RPA resolvable using |kIrk|.
EXPECT_EQ(1, hci_cmd_count);
EXPECT_TRUE(addr.IsResolvablePrivate());
EXPECT_TRUE(sm::util::IrkCanResolveRpa(kIrk, addr));
// The new random address should be returned.
EXPECT_EQ(addr, EnsureLocalAddress());
// Assign a new IRK. The new address should be used when it gets refreshed.
// Re-enable privacy with a new IRK. The latest IRK should be used.
const UInt128 kIrk2{{15, 14, 14, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}};
addr_mgr()->set_irk(kIrk2);
ASSERT_TRUE(addr_mgr()->irk());
EXPECT_EQ(kIrk2, *addr_mgr()->irk());
// Returns the same address.
EXPECT_EQ(addr, EnsureLocalAddress());
EXPECT_FALSE(sm::util::IrkCanResolveRpa(kIrk2, addr));
// Re-enable privacy to trigger a refresh.
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kResponse}));
addr_mgr()->EnablePrivacy(false);
addr_mgr()->EnablePrivacy(true);
RunLoopUntilIdle();
EXPECT_EQ(addr, EnsureLocalAddress());
EXPECT_TRUE(addr.IsResolvablePrivate());
EXPECT_TRUE(sm::util::IrkCanResolveRpa(kIrk2, addr));
}
TEST_F(GAP_LowEnergyAddressManagerTest, EnablePrivacyNoIrk) {
// Respond with success.
const auto kResponse =
CreateStaticByteBuffer(0x0E, 4, // Command Complete, 4 bytes,
1, // 1 allowed packet
0x05, 0x20, // opcode: HCI_LE_Set_Random_Address
0x00 // status: success
);
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kResponse}));
int hci_cmd_count = 0;
DeviceAddress addr;
test_device()->SetTransactionCallback(
[&](const auto& rx) {
hci_cmd_count++;
const auto addr_bytes = rx.view(sizeof(hci::CommandHeader));
ASSERT_EQ(6u, addr_bytes.size());
addr = DeviceAddress(DeviceAddress::Type::kLERandom,
DeviceAddressBytes(addr_bytes));
},
dispatcher());
addr_mgr()->EnablePrivacy(true);
// Privacy is now considered enabled. Further requests to enable should not
// trigger additional HCI commands.
addr_mgr()->EnablePrivacy(true);
RunLoopUntilIdle();
// We should have received a HCI command with a NRPA.
EXPECT_EQ(1, hci_cmd_count);
EXPECT_TRUE(addr.IsNonResolvablePrivate());
// The new random address should be returned.
EXPECT_EQ(addr, EnsureLocalAddress());
}
TEST_F(GAP_LowEnergyAddressManagerTest, EnablePrivacyHciError) {
// Respond with error.
const auto kErrorResponse =
CreateStaticByteBuffer(0x0E, 4, // Command Complete, 4 bytes,
1, // 1 allowed packet
0x05, 0x20, // opcode: HCI_LE_Set_Random_Address
0x0C // status: Command Disallowed
);
// The second time respond with success.
const auto kSuccessResponse =
CreateStaticByteBuffer(0x0E, 4, // Command Complete, 4 bytes,
1, // 1 allowed packet
0x05, 0x20, // opcode: HCI_LE_Set_Random_Address
0x00 // status: success
);
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kErrorResponse}));
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kSuccessResponse}));
addr_mgr()->EnablePrivacy(true);
// Request the new address and run the event loop. The old address should be
// returned due to the failure.
EXPECT_EQ(kPublic, EnsureLocalAddress());
// Requesting the address a second time while address update is disallowed
// should return the old address without sending HCI commands.
int hci_count = 0;
test_device()->SetTransactionCallback([&] { hci_count++; }, dispatcher());
set_random_address_change_allowed(false);
EXPECT_EQ(kPublic, EnsureLocalAddress());
EXPECT_EQ(0, hci_count);
// Requesting the address a third time while address update is allowed should
// configure and return the new address.
set_random_address_change_allowed(true);
EXPECT_TRUE(EnsureLocalAddress().IsNonResolvablePrivate());
EXPECT_EQ(1, hci_count);
}
TEST_F(GAP_LowEnergyAddressManagerTest,
EnablePrivacyWhileAddressChangeIsDisallowed) {
const auto kSuccessResponse =
CreateStaticByteBuffer(0x0E, 4, // Command Complete, 4 bytes,
1, // 1 allowed packet
0x05, 0x20, // opcode: HCI_LE_Set_Random_Address
0x00 // status: success
);
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kSuccessResponse}));
int hci_count = 0;
test_device()->SetTransactionCallback([&] { hci_count++; }, dispatcher());
set_random_address_change_allowed(false);
// No HCI commands should be sent while disallowed.
addr_mgr()->EnablePrivacy(true);
RunLoopUntilIdle();
EXPECT_EQ(0, hci_count);
EXPECT_EQ(kPublic, EnsureLocalAddress());
EXPECT_EQ(0, hci_count);
// Requesting the address while address change is allowed should configure and
// return the new address.
set_random_address_change_allowed(true);
EXPECT_TRUE(EnsureLocalAddress().IsNonResolvablePrivate());
EXPECT_EQ(1, hci_count);
}
TEST_F(GAP_LowEnergyAddressManagerTest, AddressExpiration) {
const auto kSuccessResponse =
CreateStaticByteBuffer(0x0E, 4, // Command Complete, 4 bytes,
1, // 1 allowed packet
0x05, 0x20, // opcode: HCI_LE_Set_Random_Address
0x00 // status: success
);
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kSuccessResponse}));
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kSuccessResponse}));
addr_mgr()->EnablePrivacy(true);
auto addr1 = EnsureLocalAddress();
EXPECT_TRUE(addr1.IsNonResolvablePrivate());
// Requesting the address again should keep returning the same address without
// sending any HCI commands.
int hci_count = 0;
test_device()->SetTransactionCallback([&] { hci_count++; }, dispatcher());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(0, hci_count);
// A new address should be generated and configured after the random address
// interval.
RunLoopFor(kPrivateAddressTimeout);
EXPECT_EQ(1, hci_count);
// Requesting the address again should return the new address.
auto addr2 = EnsureLocalAddress();
EXPECT_TRUE(addr2.IsNonResolvablePrivate());
EXPECT_NE(addr1, addr2);
EXPECT_EQ(1, hci_count);
}
TEST_F(GAP_LowEnergyAddressManagerTest,
AddressExpirationWhileAddressChangeIsDisallowed) {
const auto kSuccessResponse =
CreateStaticByteBuffer(0x0E, 4, // Command Complete, 4 bytes,
1, // 1 allowed packet
0x05, 0x20, // opcode: HCI_LE_Set_Random_Address
0x00 // status: success
);
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kSuccessResponse}));
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kSuccessResponse}));
addr_mgr()->EnablePrivacy(true);
auto addr1 = EnsureLocalAddress();
EXPECT_TRUE(addr1.IsNonResolvablePrivate());
// Requesting the address again should keep returning the same address without
// sending any HCI commands.
int hci_count = 0;
test_device()->SetTransactionCallback([&] { hci_count++; }, dispatcher());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(0, hci_count);
// After the interval ends, the address should be marked as expired but should
// not send an HCI command while the command is disallowed.
set_random_address_change_allowed(false);
RunLoopFor(kPrivateAddressTimeout);
EXPECT_EQ(addr1, EnsureLocalAddress());
EXPECT_EQ(0, hci_count);
// Requesting the address again while the command is allowed should configure
// and return the new address.
set_random_address_change_allowed(true);
auto addr2 = EnsureLocalAddress();
EXPECT_TRUE(addr2.IsNonResolvablePrivate());
EXPECT_NE(addr1, addr2);
EXPECT_EQ(1, hci_count);
}
TEST_F(GAP_LowEnergyAddressManagerTest, DisablePrivacy) {
// Enable privacy.
const auto kSuccessResponse =
CreateStaticByteBuffer(0x0E, 4, // Command Complete, 4 bytes,
1, // 1 allowed packet
0x05, 0x20, // opcode: HCI_LE_Set_Random_Address
0x00 // status: success
);
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kSuccessResponse}));
addr_mgr()->EnablePrivacy(true);
EXPECT_TRUE(EnsureLocalAddress().IsNonResolvablePrivate());
// Disable privacy.
addr_mgr()->EnablePrivacy(false);
// The public address should be returned for the local address.
EXPECT_EQ(DeviceAddress::Type::kLEPublic, EnsureLocalAddress().type());
// No HCI commands should get sent after private address interval expires.
int hci_count = 0;
test_device()->SetTransactionCallback([&] { hci_count++; }, dispatcher());
RunLoopFor(kPrivateAddressTimeout);
EXPECT_EQ(0, hci_count);
EXPECT_EQ(DeviceAddress::Type::kLEPublic, EnsureLocalAddress().type());
}
TEST_F(GAP_LowEnergyAddressManagerTest, DisablePrivacyDuringAddressChange) {
const auto kSuccessResponse =
CreateStaticByteBuffer(0x0E, 4, // Command Complete, 4 bytes,
1, // 1 allowed packet
0x05, 0x20, // opcode: HCI_LE_Set_Random_Address
0x00 // status: success
);
test_device()->QueueCommandTransaction(
CommandTransaction(hci::kLESetRandomAddress, {&kSuccessResponse}));
int hci_count = 0;
test_device()->SetTransactionCallback([&] { hci_count++; }, dispatcher());
// Enable and disable in quick succession. HCI command should be sent but the
// local address shouldn't take effect.
addr_mgr()->EnablePrivacy(true);
addr_mgr()->EnablePrivacy(false);
EXPECT_EQ(DeviceAddress::Type::kLEPublic, EnsureLocalAddress().type());
EXPECT_EQ(1, hci_count);
// No HCI commands should get sent after private address interval expires.
RunLoopFor(kPrivateAddressTimeout);
EXPECT_EQ(1, hci_count);
EXPECT_EQ(DeviceAddress::Type::kLEPublic, EnsureLocalAddress().type());
}
} // namespace
} // namespace gap
} // namespace bt