blob: 3480b408e046c0f0ee684ca46aeca1e020c73246 [file] [log] [blame]
// Copyright 2020 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 <algorithm>
#include <limits>
#include <fuzzer/FuzzedDataProvider.h>
#include <pw_async/fake_dispatcher.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/l2cap/enhanced_retransmission_mode_engines.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/fake_tx_channel.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/fragmenter.h"
#include "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
constexpr static bt::hci_spec::ConnectionHandle kTestHandle = 0x0001;
constexpr bt::l2cap::ChannelId kTestChannelId = 0x0001;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider provider(data, size);
pw::async::test::FakeDispatcher dispatcher;
uint8_t tx_window =
std::max(provider.ConsumeIntegral<uint8_t>(), static_cast<uint8_t>(1u));
uint8_t max_transmissions = provider.ConsumeIntegral<uint8_t>();
uint16_t max_tx_sdu_size =
std::max(provider.ConsumeIntegral<uint16_t>(), bt::l2cap::kMinACLMTU);
bool failure = false;
auto failure_cb = [&failure] { failure = true; };
bt::l2cap::internal::FakeTxChannel channel;
auto [rx_engine, tx_engine] =
bt::l2cap::internal::MakeLinkedEnhancedRetransmissionModeEngines(
kTestChannelId,
max_tx_sdu_size,
max_transmissions,
tx_window,
channel,
failure_cb,
dispatcher);
// In the real stack, the engines are shut down on failure, so we do the same
// here.
while (provider.remaining_bytes() > 0 && !failure) {
bool tx = provider.ConsumeBool();
if (tx) {
auto n_bytes = provider.ConsumeIntegral<uint16_t>();
auto bytes = provider.ConsumeBytes<uint8_t>(n_bytes);
channel.QueueSdu(
std::make_unique<bt::DynamicByteBuffer>(bt::BufferView(bytes)));
tx_engine->NotifySduQueued();
} else {
bt::l2cap::Fragmenter fragmenter(kTestHandle);
auto n_bytes = provider.ConsumeIntegral<uint16_t>();
auto bytes = provider.ConsumeBytes<uint8_t>(n_bytes);
bool append_fcs = provider.ConsumeBool();
if (append_fcs) {
const size_t bounded_size =
std::min(bytes.size(),
std::numeric_limits<uint16_t>::max() -
sizeof(bt::l2cap::FrameCheckSequence));
bytes.resize(bounded_size);
}
auto fcs_option = append_fcs
? bt::l2cap::FrameCheckSequenceOption::kIncludeFcs
: bt::l2cap::FrameCheckSequenceOption::kNoFcs;
auto pdu = fragmenter.BuildFrame(
kTestChannelId, bt::BufferView(bytes), fcs_option);
rx_engine->ProcessPdu(std::move(pdu));
}
// Run for 0-255 seconds, which is enough to trigger poll timer and monitor
// timer.
auto run_duration =
std::chrono::seconds(provider.ConsumeIntegral<uint8_t>());
dispatcher.RunFor(run_duration);
}
return 0;
}