blob: c6ff0876f8b14cad9b1017faf622de866a50a9b0 [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 "fragmenter.h"
#include "pdu.h"
#include "gtest/gtest.h"
#include "garnet/drivers/bluetooth/lib/common/test_helpers.h"
#include "garnet/drivers/bluetooth/lib/hci/hci.h"
namespace btlib {
namespace l2cap {
namespace {
constexpr hci::ConnectionHandle kTestHandle = 0x0001;
constexpr ChannelId kTestChannelId = 0x0001;
TEST(L2CAP_FragmenterTest, EmptyPayload) {
common::BufferView payload;
auto expected_fragment = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x00, 0x04, 0x00,
// Basic L2CAP header (0-length Information Payload)
0x00, 0x00, 0x01, 0x00);
// Make the fragment limit a lot larger than the test frame size.
Fragmenter fragmenter(kTestHandle, 1024);
PDU pdu = fragmenter.BuildBasicFrame(kTestChannelId, payload);
ASSERT_TRUE(pdu.is_valid());
EXPECT_EQ(1u, pdu.fragment_count());
auto fragments = pdu.ReleaseFragments();
EXPECT_TRUE(common::ContainersEqual(expected_fragment,
fragments.begin()->view().data()));
}
TEST(L2CAP_FragmenterTest, SingleFragment) {
auto payload = common::CreateStaticByteBuffer('T', 'e', 's', 't');
auto expected_fragment = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x00, 0x08, 0x00,
// Basic L2CAP header
0x04, 0x00, 0x01, 0x00, 'T', 'e', 's', 't');
// Make the fragment limit a lot larger than the test frame size.
Fragmenter fragmenter(kTestHandle, 1024);
PDU pdu = fragmenter.BuildBasicFrame(kTestChannelId, payload);
ASSERT_TRUE(pdu.is_valid());
EXPECT_EQ(1u, pdu.fragment_count());
auto fragments = pdu.ReleaseFragments();
EXPECT_TRUE(common::ContainersEqual(expected_fragment,
fragments.begin()->view().data()));
}
TEST(L2CAP_FragmenterTest, SingleFragmentExactFit) {
auto payload = common::CreateStaticByteBuffer('T', 'e', 's', 't');
auto expected_fragment = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x00, 0x08, 0x00,
// Basic L2CAP header
0x04, 0x00, 0x01, 0x00, 'T', 'e', 's', 't');
// Make the fragment limit large enough to fit exactly one B-frame containing
// |payload|.
Fragmenter fragmenter(kTestHandle, payload.size() + sizeof(BasicHeader));
PDU pdu = fragmenter.BuildBasicFrame(kTestChannelId, payload);
ASSERT_TRUE(pdu.is_valid());
EXPECT_EQ(1u, pdu.fragment_count());
auto fragments = pdu.ReleaseFragments();
EXPECT_TRUE(common::ContainersEqual(expected_fragment,
fragments.begin()->view().data()));
}
TEST(L2CAP_FragmenterTest, TwoFragmentsOffByOne) {
auto payload = common::CreateStaticByteBuffer('T', 'e', 's', 't', '!');
auto expected_fragment0 = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x00, 0x08, 0x00,
// Basic L2CAP header, contains the complete length but a partial payload
0x05, 0x00, 0x01, 0x00, 'T', 'e', 's', 't');
auto expected_fragment1 = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x10, 0x01, 0x00,
// Continuing payload
'!');
// Make the fragment limit large enough to fit exactly one B-frame containing
// 1 octet less than |payload|. The last octet should be placed in a second
// fragment.
Fragmenter fragmenter(kTestHandle, payload.size() + sizeof(BasicHeader) - 1);
PDU pdu = fragmenter.BuildBasicFrame(kTestChannelId, payload);
ASSERT_TRUE(pdu.is_valid());
EXPECT_EQ(2u, pdu.fragment_count());
auto fragments = pdu.ReleaseFragments();
EXPECT_TRUE(common::ContainersEqual(expected_fragment0,
fragments.begin()->view().data()));
EXPECT_TRUE(common::ContainersEqual(expected_fragment1,
(++fragments.begin())->view().data()));
}
TEST(L2CAP_FragmenterTest, TwoFragmentsExact) {
auto payload = common::CreateStaticByteBuffer('T', 'e', 's', 't');
ZX_DEBUG_ASSERT_MSG(payload.size() % 2 == 0,
"test payload size should be even");
auto expected_fragment0 = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x00, 0x04, 0x00,
// Basic L2CAP header, contains the complete length but a partial payload
0x04, 0x00, 0x01, 0x00);
auto expected_fragment1 = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x10, 0x04, 0x00,
// Continuing payload
'T', 'e', 's', 't');
// Make the fragment limit large enough to fit exactly half a B-frame
// containing |payload|. The frame should be evenly divided across two
// fragments.
Fragmenter fragmenter(kTestHandle,
(payload.size() + sizeof(BasicHeader)) / 2);
PDU pdu = fragmenter.BuildBasicFrame(kTestChannelId, payload);
ASSERT_TRUE(pdu.is_valid());
EXPECT_EQ(2u, pdu.fragment_count());
auto fragments = pdu.ReleaseFragments();
EXPECT_TRUE(common::ContainersEqual(expected_fragment0,
fragments.begin()->view().data()));
EXPECT_TRUE(common::ContainersEqual(expected_fragment1,
(++fragments.begin())->view().data()));
}
TEST(L2CAP_FragmenterTest, ManyFragmentsOffByOne) {
constexpr size_t kMaxFragmentPayloadSize = 5;
constexpr size_t kExpectedFragmentCount = 4;
constexpr size_t kFrameSize =
(kExpectedFragmentCount - 1) * kMaxFragmentPayloadSize + 1;
common::StaticByteBuffer<kFrameSize - sizeof(BasicHeader)> payload;
payload.Fill('X');
auto expected_fragment0 = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x00, 0x05, 0x00,
// Basic L2CAP header contains the complete length but partial payload
0x0C, 0x00, 0x01, 0x00, 'X');
auto expected_fragment1 = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x10, 0x05, 0x00,
// Continuing payload
'X', 'X', 'X', 'X', 'X');
auto expected_fragment2 = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x10, 0x05, 0x00,
// Continuing payload
'X', 'X', 'X', 'X', 'X');
auto expected_fragment3 = common::CreateStaticByteBuffer(
// ACL data header
0x01, 0x10, 0x01, 0x00,
// Continuing payload
'X');
Fragmenter fragmenter(kTestHandle, kMaxFragmentPayloadSize);
PDU pdu = fragmenter.BuildBasicFrame(kTestChannelId, payload);
ASSERT_TRUE(pdu.is_valid());
EXPECT_EQ(kExpectedFragmentCount, pdu.fragment_count());
auto fragments = pdu.ReleaseFragments();
auto iter = fragments.begin();
EXPECT_TRUE(
common::ContainersEqual(expected_fragment0, (iter++)->view().data()));
EXPECT_TRUE(
common::ContainersEqual(expected_fragment1, (iter++)->view().data()));
EXPECT_TRUE(
common::ContainersEqual(expected_fragment2, (iter++)->view().data()));
EXPECT_TRUE(common::ContainersEqual(expected_fragment3, iter->view().data()));
}
TEST(L2CAP_FragmenterTest, MaximalSizedPayload) {
common::DynamicByteBuffer payload(65535);
Fragmenter fragmenter(kTestHandle, 1024);
PDU pdu = fragmenter.BuildBasicFrame(kTestChannelId, payload);
ASSERT_TRUE(pdu.is_valid());
EXPECT_LT(64u, pdu.fragment_count());
}
} // namespace
} // namespace l2cap
} // namespace btlib