blob: f6cd7045edc4359ad9264df6da1c6758a662f8f0 [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.
#ifndef SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_RECOMBINER_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_RECOMBINER_H_
#include <endian.h>
#include <fbl/macros.h>
#include <cstdint>
#include "src/connectivity/bluetooth/core/bt-host/hci/acl_data_packet.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/l2cap.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/pdu.h"
namespace bt {
namespace l2cap {
// A Recombiner can be used to obtain complete L2CAP frames from received
// fragments. Incoming ACL data packets can be accumulated in a Recombiner.
//
// Each instance of Recombiner is intended to be used over a unique logical
// link. ACL data packets with different connection handles should not be added
// to the same Recombiner (the code will assert this in debug-mode).
//
// THREAD-SAFETY:
//
// This class is not thread-safe. External locking should be provided if an
// instance will be accessed on multiple threads.
class Recombiner final {
public:
Recombiner();
// Returns true if packet is complete. This means that all HCI data fragments
// for this packet have been received and Release() can be called to obtain
// the packet.
bool ready() const { return ready_; }
// Returns true if no PDU is currently being built, otherwise a partial or
// complete set of fragments have been accumulated.
bool empty() const { return !pdu_; }
// Appends the given ACL data fragment to this PDU. Returns true if the
// fragment was accepted. Otherwise returns false; this either means that the
// PDU was ready before the call or |fragment| did not pass validity checks
// and was rejected.
//
// Takes ownership of |fragment| only in the success case. The contents will
// not be moved in the case of failure.
bool AddFragment(hci::ACLDataPacketPtr&& fragment);
// Returns a complete PDU in |out_pdu| (overwriting its contents) if the
// accumulated ACL data fragments form a complete L2CAP frame. Otherwise,
// returns false.
bool Release(PDU* out_pdu);
// Drops the current packet. Once this method returns, Recombiner::empty()
// will return true.
void Drop();
private:
// If |fragment| is a valid first fragment, this initializes the internal
// variables and makes this recombiner "non-empty". This does not append the
// fragment to |pdu_|.
bool ProcessFirstFragment(const hci::ACLDataPacket& fragment);
bool ready_;
size_t frame_length_;
size_t cur_length_;
// The PDU currently being constructed, if any.
std::optional<PDU> pdu_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Recombiner);
};
} // namespace l2cap
} // namespace bt
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_RECOMBINER_H_