blob: 3aba9d2db1ac51fb74f6d0e010ead6a240a53998 [file] [log] [blame]
// Copyright 2017 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 "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/acl_data_channel.h"
#include <unordered_map>
#include <gmock/gmock.h>
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/assert.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/constants.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci-spec/defaults.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/hci/connection.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/inspect.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/inspect_util.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/acl_data_packet.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/data_buffer_info.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/fake_acl_connection.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/link_type.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/transport/transport.h"
#pragma clang diagnostic ignored "-Wshadow"
namespace bt::hci {
namespace {
constexpr hci_spec::ConnectionHandle kConnectionHandle0 = 0x0000;
constexpr hci_spec::ConnectionHandle kConnectionHandle1 = 0x0001;
constexpr size_t kMaxMtu = 10;
constexpr size_t kBufferMaxNumPackets = 2;
std::array<std::pair<DataBufferInfo, DataBufferInfo>, 2> bredr_both_buffers = {{
{DataBufferInfo(kMaxMtu, kBufferMaxNumPackets),
DataBufferInfo()}, // OnlyBREDRBufferAvailable
{DataBufferInfo(kMaxMtu, kBufferMaxNumPackets),
DataBufferInfo(kMaxMtu, kBufferMaxNumPackets)} // BothBuffersAvailable
}};
std::array<std::pair<DataBufferInfo, DataBufferInfo>, 3> all_buffer_options = {{
{DataBufferInfo(kMaxMtu, kBufferMaxNumPackets),
DataBufferInfo()}, // OnlyBREDRBufferAvailable
{DataBufferInfo(),
DataBufferInfo(kMaxMtu, kBufferMaxNumPackets)}, // OnlyLEBufferAvailable
{DataBufferInfo(kMaxMtu, kBufferMaxNumPackets),
DataBufferInfo(kMaxMtu, kBufferMaxNumPackets)} // BothBuffersAvailable
}};
using pw::bluetooth::AclPriority;
using TestingBase =
testing::FakeDispatcherControllerTest<bt::testing::MockController>;
class AclDataChannelTest : public TestingBase {
public:
AclDataChannelTest() = default;
protected:
// TestBase overrides:
void SetUp() override { TestingBase::SetUp(); }
// Fill up controller buffer then queue one additional packet
void FillControllerBufferThenQueuePacket(FakeAclConnection& connection) {
for (size_t i = 0; i <= kBufferMaxNumPackets; i++) {
// Last packet should remain queued
if (i < kBufferMaxNumPackets) {
const StaticByteBuffer kPacket(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(i));
EXPECT_ACL_PACKET_OUT(test_device(), kPacket);
}
// Create packet to send
ACLDataPacketPtr packet = ACLDataPacket::New(
kConnectionHandle0,
hci_spec::ACLPacketBoundaryFlag::kFirstNonFlushable,
hci_spec::ACLBroadcastFlag::kPointToPoint,
/*payload_size=*/1);
packet->mutable_view()->mutable_payload_data()[0] =
static_cast<uint8_t>(i);
connection.QueuePacket(std::move(packet));
RunUntilIdle();
}
}
private:
BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AclDataChannelTest);
};
class AclDataChannelMtuTest : public AclDataChannelTest {
public:
DataBufferInfo BREDRBufferInfo() { return DataBufferInfo(1024, 50); }
DataBufferInfo LEBufferInfo() { return DataBufferInfo(64, 16); }
};
class AclDataChannelOnlyBREDRBufferAvailable : public AclDataChannelTest {
public:
void SetUp() override {
AclDataChannelTest::SetUp();
InitializeACLDataChannel(DataBufferInfo(kMaxMtu, kBufferMaxNumPackets),
DataBufferInfo());
}
};
class AclDataChannelOnlyLEBufferAvailable : public AclDataChannelTest {
public:
void SetUp() override {
AclDataChannelTest::SetUp();
InitializeACLDataChannel(DataBufferInfo(),
DataBufferInfo(kMaxMtu, kBufferMaxNumPackets));
}
};
// Value-parameterized test class for when: 1) only BR/EDR buffer available 2)
// when both BR/EDR and LE buffers available
class AclDataChannelBREDRAndBothBuffers
: public AclDataChannelTest,
public ::testing::WithParamInterface<
std::pair<DataBufferInfo, DataBufferInfo>> {};
// Value-parameterized test class for when: 1) only BR/EDR buffer available 2)
// only LE buffer available 3) when both BR/EDR and LE buffers available
class AclDataChannelAllBufferCombinations
: public AclDataChannelTest,
public ::testing::WithParamInterface<
std::pair<DataBufferInfo, DataBufferInfo>> {};
/*
* Tests Begin
*/
#ifndef NINSPECT
TEST_F(AclDataChannelTest, InspectHierarchyContainsOutboundQueueState) {
InitializeACLDataChannel(DataBufferInfo(kMaxMtu, kBufferMaxNumPackets),
DataBufferInfo(kMaxMtu, kBufferMaxNumPackets));
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kLE);
FakeAclConnection connection_1(
acl_data_channel(), kConnectionHandle1, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
acl_data_channel()->RegisterConnection(connection_1.GetWeakPtr());
// Fill up both BR/EDR and LE controller buffers then queue one additional
// packet in the queue of each type
for (size_t i = 0; i <= kBufferMaxNumPackets; i++) {
for (FakeAclConnection* connection : {&connection_0, &connection_1}) {
if (i < kBufferMaxNumPackets) {
const StaticByteBuffer kPacket(LowerBits(connection->handle()),
UpperBits(connection->handle()),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(i));
EXPECT_ACL_PACKET_OUT(test_device(), kPacket);
}
// Create packet to send
ACLDataPacketPtr packet = ACLDataPacket::New(
connection->handle(),
hci_spec::ACLPacketBoundaryFlag::kFirstNonFlushable,
hci_spec::ACLBroadcastFlag::kPointToPoint,
/*payload_size=*/1);
packet->mutable_view()->mutable_payload_data()[0] =
static_cast<uint8_t>(i);
connection->QueuePacket(std::move(packet));
RunUntilIdle();
}
}
inspect::Inspector inspector;
const std::string kNodeName = "adc_node_name";
acl_data_channel()->AttachInspect(inspector.GetRoot(), kNodeName);
using namespace ::inspect::testing;
auto bredr_matcher =
NodeMatches(AllOf(NameMatches("bredr"),
PropertyList(ElementsAre(UintIs(
"num_sent_packets", kBufferMaxNumPackets)))));
auto le_matcher =
NodeMatches(AllOf(NameMatches("le"),
PropertyList(UnorderedElementsAre(
UintIs("num_sent_packets", kBufferMaxNumPackets),
BoolIs("independent_from_bredr", true)))));
}
#endif // NINSPECT
class AclPriorityTest
: public AclDataChannelTest,
public ::testing::WithParamInterface<std::pair<AclPriority, bool>> {};
TEST_P(AclPriorityTest, RequestAclPriority) {
const auto kPriority = GetParam().first;
const bool kExpectSuccess = GetParam().second;
InitializeACLDataChannel(DataBufferInfo(1024, 50), DataBufferInfo());
// Arbitrary command payload larger than hci_spec::CommandHeader.
const auto op_code = hci_spec::VendorOpCode(0x01);
const StaticByteBuffer kEncodedCommand(LowerBits(op_code),
UpperBits(op_code), // op code
0x04, // parameter size
0x00,
0x01,
0x02,
0x03); // test parameter
std::optional<hci_spec::ConnectionHandle> connection;
std::optional<AclPriority> priority;
test_device()->set_encode_vendor_command_cb(
[&](pw::bluetooth::VendorCommandParameters cb_params,
fit::callback<void(pw::Result<pw::span<const std::byte>>)> cb) {
ASSERT_TRUE(std::holds_alternative<
pw::bluetooth::SetAclPriorityCommandParameters>(cb_params));
pw::bluetooth::SetAclPriorityCommandParameters params =
std::get<pw::bluetooth::SetAclPriorityCommandParameters>(cb_params);
connection = params.connection_handle;
priority = params.priority;
cb(pw::span(reinterpret_cast<const std::byte*>(kEncodedCommand.data()),
kEncodedCommand.size()));
});
auto cmd_complete = bt::testing::CommandCompletePacket(
op_code,
kExpectSuccess ? pw::bluetooth::emboss::StatusCode::SUCCESS
: pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
EXPECT_CMD_PACKET_OUT(test_device(), kEncodedCommand, &cmd_complete);
size_t request_cb_count = 0;
acl_data_channel()->RequestAclPriority(
kPriority, kConnectionHandle1, [&](auto result) {
request_cb_count++;
EXPECT_EQ(kExpectSuccess, result.is_ok());
});
RunUntilIdle();
EXPECT_EQ(request_cb_count, 1u);
ASSERT_TRUE(connection);
EXPECT_EQ(connection.value(), kConnectionHandle1);
ASSERT_TRUE(priority);
EXPECT_EQ(priority.value(), kPriority);
}
const std::array<std::pair<AclPriority, bool>, 4> kPriorityParams = {
{{AclPriority::kSource, /*expect_success=*/false},
{AclPriority::kSource, true},
{AclPriority::kSink, true},
{AclPriority::kNormal, true}}};
INSTANTIATE_TEST_SUITE_P(ACLDataChannelTest,
AclPriorityTest,
::testing::ValuesIn(kPriorityParams));
TEST_F(AclDataChannelTest, RequestAclPriorityEncodeFails) {
InitializeACLDataChannel(DataBufferInfo(1024, 50), DataBufferInfo());
test_device()->set_encode_vendor_command_cb(
[](auto, auto cb) { cb(pw::Status::Internal()); });
size_t request_cb_count = 0;
acl_data_channel()->RequestAclPriority(
hci::AclPriority::kSink, kConnectionHandle1, [&](auto result) {
request_cb_count++;
EXPECT_TRUE(result.is_error());
});
RunUntilIdle();
EXPECT_EQ(request_cb_count, 1u);
}
TEST_F(AclDataChannelTest, RequestAclPriorityEncodeReturnsTooSmallBuffer) {
InitializeACLDataChannel(DataBufferInfo(1024, 50), DataBufferInfo());
test_device()->set_encode_vendor_command_cb(
[](auto, fit::callback<void(pw::Result<pw::span<const std::byte>>)> cb) {
const std::byte buffer[] = {std::byte{0x00}};
cb(buffer);
});
size_t request_cb_count = 0;
acl_data_channel()->RequestAclPriority(
hci::AclPriority::kSink, kConnectionHandle1, [&](auto result) {
request_cb_count++;
EXPECT_TRUE(result.is_error());
});
RunUntilIdle();
EXPECT_EQ(request_cb_count, 1u);
}
TEST_F(AclDataChannelMtuTest, VerifyBREDRBufferMtus) {
InitializeACLDataChannel(BREDRBufferInfo(), DataBufferInfo());
EXPECT_EQ(BREDRBufferInfo(), acl_data_channel()->GetBufferInfo());
EXPECT_EQ(BREDRBufferInfo(), acl_data_channel()->GetLeBufferInfo());
}
TEST_F(AclDataChannelMtuTest, VerifyLEBufferMtus) {
InitializeACLDataChannel(DataBufferInfo(), LEBufferInfo());
EXPECT_EQ(DataBufferInfo(), acl_data_channel()->GetBufferInfo());
EXPECT_EQ(LEBufferInfo(), acl_data_channel()->GetLeBufferInfo());
}
TEST_F(AclDataChannelMtuTest, VerifyBREDRAndLEBufferMtus) {
InitializeACLDataChannel(BREDRBufferInfo(), LEBufferInfo());
EXPECT_EQ(BREDRBufferInfo(), acl_data_channel()->GetBufferInfo());
EXPECT_EQ(LEBufferInfo(), acl_data_channel()->GetLeBufferInfo());
}
TEST_F(AclDataChannelOnlyBREDRBufferAvailable,
NumberOfCompletedPacketsExceedsPendingPackets) {
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
FillControllerBufferThenQueuePacket(connection_0);
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// Send out last packet
EXPECT_ACL_PACKET_OUT(test_device(),
StaticByteBuffer(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(kBufferMaxNumPackets)));
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle0,
kBufferMaxNumPackets + 1));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 0u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
}
TEST_F(AclDataChannelOnlyBREDRBufferAvailable,
UnregisterLinkDropsFutureSentPackets) {
constexpr size_t kMaxNumPackets = 1;
InitializeACLDataChannel(DataBufferInfo(kMaxMtu, kMaxNumPackets),
DataBufferInfo());
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
const StaticByteBuffer kPacket(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(1));
EXPECT_ACL_PACKET_OUT(test_device(), kPacket);
// Create packet to send
ACLDataPacketPtr packet =
ACLDataPacket::New(kConnectionHandle0,
hci_spec::ACLPacketBoundaryFlag::kFirstNonFlushable,
hci_spec::ACLBroadcastFlag::kPointToPoint,
/*payload_size=*/1);
packet->mutable_view()->mutable_payload_data()[0] = static_cast<uint8_t>(1);
connection_0.QueuePacket(std::move(packet));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 0u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
acl_data_channel()->UnregisterConnection(kConnectionHandle0);
// Attempt to send packet on an unregistered link
connection_0.QueuePacket(std::move(packet));
RunUntilIdle();
// Second packet should not have been sent
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
}
TEST_F(AclDataChannelOnlyLEBufferAvailable,
UnregisterLinkDropsFutureSentPackets) {
constexpr size_t kMaxNumPackets = 1;
InitializeACLDataChannel(DataBufferInfo(kMaxMtu, kMaxNumPackets),
DataBufferInfo());
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
const StaticByteBuffer kPacket(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(1));
EXPECT_ACL_PACKET_OUT(test_device(), kPacket);
// Create packet to send
ACLDataPacketPtr packet =
ACLDataPacket::New(kConnectionHandle0,
hci_spec::ACLPacketBoundaryFlag::kFirstNonFlushable,
hci_spec::ACLBroadcastFlag::kPointToPoint,
/*payload_size=*/1);
packet->mutable_view()->mutable_payload_data()[0] = static_cast<uint8_t>(1);
connection_0.QueuePacket(std::move(packet));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 0u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
acl_data_channel()->UnregisterConnection(kConnectionHandle0);
// Attempt to send packet on an unregistered link
connection_0.QueuePacket(std::move(packet));
RunUntilIdle();
// Second packet should not have been sent
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
}
TEST_F(AclDataChannelOnlyBREDRBufferAvailable,
IgnoreNumberOfCompletedPacketsEventForUnknownConnectionHandle) {
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
FillControllerBufferThenQueuePacket(connection_0);
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// |kConnectionHandle1| is not registered so this event is ignored (no packets
// should be sent)
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle1, 1));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
}
TEST_F(AclDataChannelOnlyLEBufferAvailable,
IgnoreNumberOfCompletedPacketsEventForUnknownConnectionHandle) {
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kLE);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
FillControllerBufferThenQueuePacket(connection_0);
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// |kConnectionHandle1| is not registered so this event is ignored (no packets
// should be sent)
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle1, 1));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
}
TEST_P(AclDataChannelBREDRAndBothBuffers,
SendMoreBREDRPacketsThanMaximumBufferSpace) {
InitializeACLDataChannel(GetParam().first, GetParam().second);
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
FillControllerBufferThenQueuePacket(connection_0);
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// Send out last packet
EXPECT_ACL_PACKET_OUT(test_device(),
StaticByteBuffer(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(kBufferMaxNumPackets)));
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle0, 1));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 0u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
}
TEST_F(AclDataChannelOnlyLEBufferAvailable,
SendMoreBREDRPacketsThanMaximumBufferSpace) {
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
// Create packet to send
ACLDataPacketPtr packet =
ACLDataPacket::New(kConnectionHandle0,
hci_spec::ACLPacketBoundaryFlag::kFirstNonFlushable,
hci_spec::ACLBroadcastFlag::kPointToPoint,
/*payload_size=*/1);
packet->mutable_view()->mutable_payload_data()[0] = static_cast<uint8_t>(1);
connection_0.QueuePacket(std::move(packet));
RunUntilIdle();
// No packet should be sent since the controller's BR/EDR buffer has no
// availabity
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
}
TEST_P(AclDataChannelAllBufferCombinations,
SendMoreLEPacketsThanMaximumBufferSpace) {
InitializeACLDataChannel(GetParam().first, GetParam().second);
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kLE);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
FillControllerBufferThenQueuePacket(connection_0);
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// Send out last packet
EXPECT_ACL_PACKET_OUT(test_device(),
StaticByteBuffer(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(kBufferMaxNumPackets)));
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle0, 1));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 0u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
}
/*
* Multiple Connections
*/
TEST_P(AclDataChannelBREDRAndBothBuffers,
RegisterTwoBREDRConnectionsAndUnregisterFirstConnection) {
InitializeACLDataChannel(GetParam().first, GetParam().second);
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kACL);
FakeAclConnection connection_1(
acl_data_channel(), kConnectionHandle1, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
acl_data_channel()->RegisterConnection(connection_1.GetWeakPtr());
StaticByteBuffer kPacket0(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
0x00);
StaticByteBuffer kPacket1(
// ACL data header (handle: 1, length 1)
LowerBits(kConnectionHandle1),
UpperBits(kConnectionHandle1),
// payload length
0x01,
0x00,
// payload
0x01);
EXPECT_ACL_PACKET_OUT(test_device(), kPacket0);
// Create packet to send
ACLDataPacketPtr out_packet_0 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_0->mutable_view()->mutable_data().Write(kPacket0);
out_packet_0->InitializeFromBuffer();
connection_0.QueuePacket(std::move(out_packet_0));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// Sending a NumberOfCompletedPackets event is necessary because since
// |kBufferMaxNumPackets| is 2, the controller buffer is full and we won't be
// able to send any more packets until at least 1 is ACKed by the controller
// to free up the buffer space
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle0, 1));
RunUntilIdle();
EXPECT_ACL_PACKET_OUT(test_device(), kPacket1);
// Create packet to send
ACLDataPacketPtr out_packet_1 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_1->mutable_view()->mutable_data().Write(kPacket1);
out_packet_1->InitializeFromBuffer();
connection_1.QueuePacket(std::move(out_packet_1));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle1, 1));
RunUntilIdle();
acl_data_channel()->UnregisterConnection(kConnectionHandle0);
RunUntilIdle();
EXPECT_ACL_PACKET_OUT(test_device(), kPacket1);
// Create packet to send
out_packet_1 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_1->mutable_view()->mutable_data().Write(kPacket1);
out_packet_1->InitializeFromBuffer();
connection_1.QueuePacket(std::move(out_packet_1));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
acl_data_channel()->UnregisterConnection(kConnectionHandle1);
}
TEST_P(
AclDataChannelBREDRAndBothBuffers,
RegisterTwoBREDRConnectionsAndClearControllerPacketCountOfFirstConnection) {
InitializeACLDataChannel(GetParam().first, GetParam().second);
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kACL);
FakeAclConnection connection_1(
acl_data_channel(), kConnectionHandle1, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
acl_data_channel()->RegisterConnection(connection_1.GetWeakPtr());
StaticByteBuffer kPacket0(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
0x00);
StaticByteBuffer kPacket1(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
0x01);
StaticByteBuffer kPacket2(
// ACL data header (handle: 1, length 1)
LowerBits(kConnectionHandle1),
UpperBits(kConnectionHandle1),
// payload length
0x01,
0x00,
// payload
0x02);
EXPECT_ACL_PACKET_OUT(test_device(), kPacket0);
ACLDataPacketPtr out_packet_0 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_0->mutable_view()->mutable_data().Write(kPacket0);
out_packet_0->InitializeFromBuffer();
connection_0.QueuePacket(std::move(out_packet_0));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// The second packet should fill up the controller buffer
// (kBufferMaxNumPackets)
ASSERT_EQ(kBufferMaxNumPackets, 2u);
EXPECT_ACL_PACKET_OUT(test_device(), kPacket1);
ACLDataPacketPtr out_packet_1 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_1->mutable_view()->mutable_data().Write(kPacket1);
out_packet_1->InitializeFromBuffer();
connection_0.QueuePacket(std::move(out_packet_1));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
ACLDataPacketPtr out_packet_2 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_2->mutable_view()->mutable_data().Write(kPacket2);
out_packet_2->InitializeFromBuffer();
connection_1.QueuePacket(std::move(out_packet_2));
RunUntilIdle();
// |out_packet_2| should not be sent because the controller buffer is full
EXPECT_EQ(connection_1.queued_packets().size(), 1u);
// |UnregisterConnection| should not free up any buffer space, so next packet
// should not be sent
acl_data_channel()->UnregisterConnection(kConnectionHandle0);
RunUntilIdle();
// Clearing the pending packet count for |connection_0| should result in
// |out_packet_2| being sent
EXPECT_ACL_PACKET_OUT(test_device(), kPacket2);
acl_data_channel()->ClearControllerPacketCount(kConnectionHandle0);
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// There are no active connections now
acl_data_channel()->UnregisterConnection(kConnectionHandle1);
acl_data_channel()->ClearControllerPacketCount(kConnectionHandle1);
RunUntilIdle();
}
TEST_P(AclDataChannelAllBufferCombinations,
RegisterTwoLEConnectionsAndUnregisterFirstConnection) {
InitializeACLDataChannel(GetParam().first, GetParam().second);
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kLE);
FakeAclConnection connection_1(
acl_data_channel(), kConnectionHandle1, bt::LinkType::kLE);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
acl_data_channel()->RegisterConnection(connection_1.GetWeakPtr());
StaticByteBuffer kPacket0(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
0x00);
StaticByteBuffer kPacket1(
// ACL data header (handle: 1, length 1)
LowerBits(kConnectionHandle1),
UpperBits(kConnectionHandle1),
// payload length
0x01,
0x00,
// payload
0x01);
EXPECT_ACL_PACKET_OUT(test_device(), kPacket0);
// Create packet to send
ACLDataPacketPtr out_packet_0 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_0->mutable_view()->mutable_data().Write(kPacket0);
out_packet_0->InitializeFromBuffer();
connection_0.QueuePacket(std::move(out_packet_0));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// Sending a NumberOfCompletedPackets event is necessary because since
// |kBufferMaxNumPackets| is 2, the controller buffer is full and we won't be
// able to send any more packets until at least 1 is ACKed by the controller
// to free up the buffer space
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle0, 1));
RunUntilIdle();
EXPECT_ACL_PACKET_OUT(test_device(), kPacket1);
// Create packet to send
ACLDataPacketPtr out_packet_1 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_1->mutable_view()->mutable_data().Write(kPacket1);
out_packet_1->InitializeFromBuffer();
connection_1.QueuePacket(std::move(out_packet_1));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle1, 1));
RunUntilIdle();
acl_data_channel()->UnregisterConnection(kConnectionHandle0);
RunUntilIdle();
EXPECT_ACL_PACKET_OUT(test_device(), kPacket1);
// Create packet to send
out_packet_1 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_1->mutable_view()->mutable_data().Write(kPacket1);
out_packet_1->InitializeFromBuffer();
connection_1.QueuePacket(std::move(out_packet_1));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
acl_data_channel()->UnregisterConnection(kConnectionHandle1);
}
TEST_P(AclDataChannelAllBufferCombinations,
RegisterTwoLEConnectionsAndClearControllerPacketCountOfFirstConnection) {
InitializeACLDataChannel(GetParam().first, GetParam().second);
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kLE);
FakeAclConnection connection_1(
acl_data_channel(), kConnectionHandle1, bt::LinkType::kLE);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
acl_data_channel()->RegisterConnection(connection_1.GetWeakPtr());
StaticByteBuffer kPacket0(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
0x00);
StaticByteBuffer kPacket1(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
0x01);
StaticByteBuffer kPacket2(
// ACL data header (handle: 1, length 1)
LowerBits(kConnectionHandle1),
UpperBits(kConnectionHandle1),
// payload length
0x01,
0x00,
// payload
0x02);
EXPECT_ACL_PACKET_OUT(test_device(), kPacket0);
ACLDataPacketPtr out_packet_0 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_0->mutable_view()->mutable_data().Write(kPacket0);
out_packet_0->InitializeFromBuffer();
connection_0.QueuePacket(std::move(out_packet_0));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// The second packet should fill up the controller buffer
// (kBufferMaxNumPackets)
ASSERT_EQ(kBufferMaxNumPackets, 2u);
EXPECT_ACL_PACKET_OUT(test_device(), kPacket1);
ACLDataPacketPtr out_packet_1 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_1->mutable_view()->mutable_data().Write(kPacket1);
out_packet_1->InitializeFromBuffer();
connection_0.QueuePacket(std::move(out_packet_1));
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
ACLDataPacketPtr out_packet_2 = ACLDataPacket::New(/*payload_size=*/1);
out_packet_2->mutable_view()->mutable_data().Write(kPacket2);
out_packet_2->InitializeFromBuffer();
connection_1.QueuePacket(std::move(out_packet_2));
RunUntilIdle();
// |out_packet_2| should not be sent because the controller buffer is full
EXPECT_EQ(connection_1.queued_packets().size(), 1u);
// |UnregisterConnection| should not free up any buffer space, so next packet
// should not be sent
acl_data_channel()->UnregisterConnection(kConnectionHandle0);
RunUntilIdle();
// Clearing the pending packet count for |connection_0| should result in
// |out_packet_2| being sent
EXPECT_ACL_PACKET_OUT(test_device(), kPacket2);
acl_data_channel()->ClearControllerPacketCount(kConnectionHandle0);
RunUntilIdle();
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// There are no active connections now
acl_data_channel()->UnregisterConnection(kConnectionHandle1);
acl_data_channel()->ClearControllerPacketCount(kConnectionHandle1);
RunUntilIdle();
}
TEST_F(AclDataChannelTest,
SendMoreBREDRAndLEPacketsThanMaximumBREDRBufferSpace) {
constexpr size_t kBufferMaxNumPackets = 5;
// Only BR/EDR buffer available
InitializeACLDataChannel(DataBufferInfo(kMaxMtu, kBufferMaxNumPackets),
DataBufferInfo());
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kLE);
FakeAclConnection connection_1(
acl_data_channel(), kConnectionHandle1, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
acl_data_channel()->RegisterConnection(connection_1.GetWeakPtr());
// Queue 12 packets in total, distributed between the two connections
// Although the LE MTU is zero, we still expect all packets to be sent using
// the BR/EDR buffer First 5 packets should be sent immediately, and the next
// 6 should be queued
for (size_t i = 0; i < 12; ++i) {
FakeAclConnection* connection = (i % 2) ? &connection_1 : &connection_0;
const StaticByteBuffer kPacket(
// ACL data header (handle: 0, length 1)
LowerBits(connection->handle()),
UpperBits(connection->handle()),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(i));
EXPECT_ACL_PACKET_OUT(test_device(), kPacket);
// Create packet to send
ACLDataPacketPtr packet =
ACLDataPacket::New(connection->handle(),
hci_spec::ACLPacketBoundaryFlag::kFirstNonFlushable,
hci_spec::ACLBroadcastFlag::kPointToPoint,
/*payload_size=*/1);
packet->mutable_view()->mutable_payload_data()[0] = static_cast<uint8_t>(i);
connection->QueuePacket(std::move(packet));
RunUntilIdle();
}
// Since |kBufferMaxNumPackets| is 5, the controller should have received 3
// packets on |connection_0| and 2 on |connection_1|
EXPECT_EQ(connection_0.queued_packets().size(), 3u);
EXPECT_EQ(connection_1.queued_packets().size(), 4u);
EXPECT_FALSE(test_device()->AllExpectedDataPacketsSent());
// Notify the processed packets with a Number Of Completed Packet HCI event
// This should cause 5 more packets to be sent
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle0, 3));
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle1, 2));
RunUntilIdle();
// Since we're alternating between |connection_0| and |connection_1|, the
// controller should have received 2 more packets on |connection_0| and 3 more
// packets on |connection_1|
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_EQ(connection_1.queued_packets().size(), 1u);
EXPECT_FALSE(test_device()->AllExpectedDataPacketsSent());
// Notify the processed packets with a Number Of Completed Packet HCI event
// This should cause the remaining 2 packets to be sent
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle0, 2));
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle1, 3));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 0u);
EXPECT_EQ(connection_1.queued_packets().size(), 0u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
}
TEST_F(AclDataChannelTest, SendMoreBREDRAndLEPacketsThanMaximumLEBufferSpace) {
constexpr size_t kBufferMaxNumPackets = 3;
// Only LE buffer available
InitializeACLDataChannel(DataBufferInfo(),
DataBufferInfo(kMaxMtu, kBufferMaxNumPackets));
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kLE);
FakeAclConnection connection_1(
acl_data_channel(), kConnectionHandle1, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
acl_data_channel()->RegisterConnection(connection_1.GetWeakPtr());
// Queue 12 packets in total, distributed between the two connections
// Since the BR/EDR MTU is zero, we expect to only see LE packets transmitted
for (size_t i = 0; i < 12; ++i) {
FakeAclConnection* connection = (i % 2) ? &connection_0 : &connection_1;
if (i % 2) {
const StaticByteBuffer kPacket(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(i));
EXPECT_ACL_PACKET_OUT(test_device(), kPacket);
}
// Create packet to send
ACLDataPacketPtr packet =
ACLDataPacket::New(connection->handle(),
hci_spec::ACLPacketBoundaryFlag::kFirstNonFlushable,
hci_spec::ACLBroadcastFlag::kPointToPoint,
/*payload_size=*/1);
packet->mutable_view()->mutable_payload_data()[0] = static_cast<uint8_t>(i);
connection->QueuePacket(std::move(packet));
RunUntilIdle();
}
// Since |kBufferMaxNumPackets| is 3 and no BR/EDR packets should have been
// sent, the controller should have received 3 packets on |connection_0| and
// none on |connection_1|
EXPECT_EQ(connection_0.queued_packets().size(), 3u);
EXPECT_EQ(connection_1.queued_packets().size(), 6u);
EXPECT_FALSE(test_device()->AllExpectedDataPacketsSent());
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle0, 3));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 0u);
EXPECT_EQ(connection_1.queued_packets().size(), 6u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
}
TEST_F(AclDataChannelTest,
SendMoreBREDRAndLEPacketsThanMaximumSharedBufferSpace) {
InitializeACLDataChannel(DataBufferInfo(kMaxMtu, kBufferMaxNumPackets),
DataBufferInfo(kMaxMtu, kBufferMaxNumPackets));
FakeAclConnection connection_0(
acl_data_channel(), kConnectionHandle0, bt::LinkType::kLE);
FakeAclConnection connection_1(
acl_data_channel(), kConnectionHandle1, bt::LinkType::kACL);
acl_data_channel()->RegisterConnection(connection_0.GetWeakPtr());
acl_data_channel()->RegisterConnection(connection_1.GetWeakPtr());
// Fill up BR/EDR controller buffer then queue one additional packet
for (size_t i = 0; i <= kBufferMaxNumPackets; ++i) {
// Last packet should remain queued
if (i < kBufferMaxNumPackets) {
const StaticByteBuffer kPacket(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(i));
EXPECT_ACL_PACKET_OUT(test_device(), kPacket);
}
// Create packet to send
ACLDataPacketPtr packet =
ACLDataPacket::New(kConnectionHandle0,
hci_spec::ACLPacketBoundaryFlag::kFirstNonFlushable,
hci_spec::ACLBroadcastFlag::kPointToPoint,
/*payload_size=*/1);
packet->mutable_view()->mutable_payload_data()[0] = static_cast<uint8_t>(i);
connection_0.QueuePacket(std::move(packet));
RunUntilIdle();
}
EXPECT_EQ(connection_0.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// Fill up LE controller buffer then queue one additional packet
for (size_t i = 0; i <= kBufferMaxNumPackets; ++i) {
// Last packet should remain queued
if (i < kBufferMaxNumPackets) {
const StaticByteBuffer kPacket(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(i));
EXPECT_ACL_PACKET_OUT(test_device(), kPacket);
}
// Create packet to send
ACLDataPacketPtr packet =
ACLDataPacket::New(kConnectionHandle0,
hci_spec::ACLPacketBoundaryFlag::kFirstNonFlushable,
hci_spec::ACLBroadcastFlag::kPointToPoint,
/*payload_size=*/1);
packet->mutable_view()->mutable_payload_data()[0] = static_cast<uint8_t>(i);
connection_1.QueuePacket(std::move(packet));
RunUntilIdle();
}
EXPECT_EQ(connection_1.queued_packets().size(), 1u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
// Send out last packet on BR/EDR link
EXPECT_ACL_PACKET_OUT(test_device(),
StaticByteBuffer(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(kBufferMaxNumPackets)));
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle0, 1));
RunUntilIdle();
// Send out last packet on LE link
EXPECT_ACL_PACKET_OUT(test_device(),
StaticByteBuffer(
// ACL data header (handle: 0, length 1)
LowerBits(kConnectionHandle0),
UpperBits(kConnectionHandle0),
// payload length
0x01,
0x00,
// payload
static_cast<uint8_t>(kBufferMaxNumPackets)));
test_device()->SendCommandChannelPacket(
bt::testing::NumberOfCompletedPacketsPacket(kConnectionHandle1, 1));
RunUntilIdle();
EXPECT_EQ(connection_0.queued_packets().size(), 0u);
EXPECT_EQ(connection_1.queued_packets().size(), 0u);
EXPECT_TRUE(test_device()->AllExpectedDataPacketsSent());
}
INSTANTIATE_TEST_SUITE_P(AclDataChannelTest,
AclDataChannelBREDRAndBothBuffers,
::testing::ValuesIn(bredr_both_buffers));
INSTANTIATE_TEST_SUITE_P(AclDataChannelTest,
AclDataChannelAllBufferCombinations,
::testing::ValuesIn(all_buffer_options));
} // namespace
} // namespace bt::hci