blob: 950a99f7508843ccbf7a31d96afc7db5892565cf [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 "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/bredr_signaling_channel.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/mock_channel_test.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
namespace bt::l2cap::internal {
namespace {
constexpr hci_spec::ConnectionHandle kTestHandle = 0x0001;
constexpr uint8_t kTestCmdId = 97;
constexpr pw::bluetooth::emboss::ConnectionRole kDeviceRole =
pw::bluetooth::emboss::ConnectionRole::CENTRAL;
class BrEdrSignalingChannelTest : public testing::MockChannelTest {
public:
BrEdrSignalingChannelTest() = default;
~BrEdrSignalingChannelTest() override = default;
BrEdrSignalingChannelTest(const BrEdrSignalingChannelTest&) = delete;
BrEdrSignalingChannelTest& operator=(const BrEdrSignalingChannelTest&) =
delete;
protected:
void SetUp() override {
ChannelOptions options(kSignalingChannelId);
options.conn_handle = kTestHandle;
fake_chan_ = CreateFakeChannel(options);
sig_ = std::make_unique<BrEdrSignalingChannel>(
fake_chan_->GetWeakPtr(), kDeviceRole, dispatcher());
}
void TearDown() override {
RunUntilIdle();
sig_ = nullptr;
}
BrEdrSignalingChannel* sig() const { return sig_.get(); }
private:
testing::FakeChannel::WeakPtr fake_chan_;
std::unique_ptr<BrEdrSignalingChannel> sig_;
};
TEST_F(BrEdrSignalingChannelTest, RespondsToEchoRequest) {
const StaticByteBuffer cmd(
// Command header (Echo Request, length 1)
0x08,
kTestCmdId,
0x01,
0x00,
// Payload
0x23);
const StaticByteBuffer response(
// Command header (Echo Response, length 1)
0x09,
kTestCmdId,
0x01,
0x00,
// Payload
0x23);
EXPECT_PACKET_OUT(response);
fake_chan()->Receive(cmd);
}
TEST_F(BrEdrSignalingChannelTest, IgnoreEmptyFrame) {
fake_chan()->Receive(BufferView());
}
TEST_F(BrEdrSignalingChannelTest, RejectMalformedAdditionalCommand) {
constexpr uint8_t kTestId0 = 14;
constexpr uint8_t kTestId1 = 15;
// Echo Request (see other test for command support), followed by an
// incomplete command packet
StaticByteBuffer cmd(
// Command header (length 3)
0x08,
kTestId0,
0x03,
0x00,
// Payload data
'L',
'O',
'L',
// Second command header
0x08,
kTestId1,
0x01,
0x00);
// Echo Response packet
StaticByteBuffer rsp0(
// Command header (length 3)
0x09,
kTestId0,
0x03,
0x00,
// Payload data
'L',
'O',
'L');
// Command Reject packet
StaticByteBuffer rsp1(
// Command header
0x01,
kTestId1,
0x02,
0x00,
// Reason (Command not understood)
0x00,
0x00);
EXPECT_PACKET_OUT(rsp0);
EXPECT_PACKET_OUT(rsp1);
fake_chan()->Receive(cmd);
}
TEST_F(BrEdrSignalingChannelTest, HandleMultipleCommands) {
constexpr uint8_t kTestId0 = 14;
constexpr uint8_t kTestId1 = 15;
constexpr uint8_t kTestId2 = 16;
StaticByteBuffer cmd(
// Command header (Echo Request)
0x08,
kTestId0,
0x04,
0x00,
// Payload data
'L',
'O',
'L',
'Z',
// Header with command to be rejected
0xFF,
kTestId1,
0x03,
0x00,
// Payload data
'L',
'O',
'L',
// Command header (Echo Request, no payload data)
0x08,
kTestId2,
0x00,
0x00,
// Additional command fragment to be dropped
0xFF,
0x00);
StaticByteBuffer echo_rsp0(
// Command header (Echo Response)
0x09,
kTestId0,
0x04,
0x00,
// Payload data
'L',
'O',
'L',
'Z');
StaticByteBuffer reject_rsp1(
// Command header (Command Rejected)
0x01,
kTestId1,
0x02,
0x00,
// Reason (Command not understood)
0x00,
0x00);
StaticByteBuffer echo_rsp2(
// Command header (Echo Response)
0x09,
kTestId2,
0x00,
0x00);
EXPECT_PACKET_OUT(echo_rsp0);
EXPECT_PACKET_OUT(reject_rsp1);
EXPECT_PACKET_OUT(echo_rsp2);
fake_chan()->Receive(cmd);
}
TEST_F(BrEdrSignalingChannelTest, SendAndReceiveEcho) {
const StaticByteBuffer expected_req(
// Echo request with 3-byte payload.
0x08,
0x01,
0x03,
0x00,
// Payload
'P',
'W',
'N');
const BufferView req_data = expected_req.view(4, 3);
const StaticByteBuffer expected_rsp(
// Echo response with 4-byte payload.
0x09,
0x01,
0x04,
0x00,
// Payload
'L',
'3',
'3',
'T');
const BufferView rsp_data = expected_rsp.view(4, 4);
EXPECT_PACKET_OUT(expected_req);
bool rx_success = false;
EXPECT_TRUE(
sig()->TestLink(req_data, [&rx_success, &rsp_data](const auto& data) {
rx_success = ContainersEqual(rsp_data, data);
}));
RunUntilIdle();
EXPECT_TRUE(AllExpectedPacketsSent());
// Remote sends back an echo response with a different payload than in local
// request (this is allowed).
fake_chan()->Receive(expected_rsp);
EXPECT_TRUE(rx_success);
}
} // namespace
} // namespace bt::l2cap::internal