blob: 48d401106ead8123d68f1c9292ff340b5f3c8e48 [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_PDU_H_
#define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_PDU_H_
#include <endian.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/macros.h>
#include <zircon/assert.h>
#include "src/connectivity/bluetooth/core/bt-host/hci/acl_data_packet.h"
#include "src/connectivity/bluetooth/core/bt-host/l2cap/l2cap.h"
namespace bt {
namespace l2cap {
// Represents a L2CAP PDU. Each PDU contains a complete L2CAP frame that can be
// transmitted over a L2CAP channel. PDUs are the building blocks for SDUs
// (higher-layer service data units).
//
// A PDU is composed of one or more fragments, each contained in a HCI ACL data
// packet. A PDU cannot be populated directly and must be obtained from a
// Recombiner or Fragmenter.
//
// A PDU instance is light-weight (it consists of a single unique_ptr via
// LinkedList and a size_t field) and can be passed around by value.
// As the PDU uniquely owns its chain of fragments, a PDU is move-only.
//
// THREAD-SAFETY:
//
// This class is not thread-safe. External locking should be provided if an
// instance will be accessed on multiple threads.
class PDU final {
public:
using FragmentList = LinkedList<hci::ACLDataPacket>;
PDU();
~PDU() = default;
// Allow move operations.
PDU(PDU&& other);
PDU& operator=(PDU&& other);
// An unpopulated PDU is considered invalid, which is the default-constructed
// state.
bool is_valid() const {
ZX_DEBUG_ASSERT(fragments_.is_empty() && !fragment_count_ ||
!fragments_.is_empty() && fragment_count_);
return !fragments_.is_empty();
}
// The number of ACL data fragments that are currently a part of this PDU.
size_t fragment_count() const { return fragment_count_; }
// Returns the number of bytes that are currently contained in this PDU,
// excluding the Basic L2CAP header.
uint16_t length() const { return le16toh(basic_header().length); }
// The L2CAP channel that this packet belongs to.
ChannelId channel_id() const { return le16toh(basic_header().channel_id); }
// The connection handle that identifies the logical link this PDU is intended
// for.
hci::ConnectionHandle connection_handle() const {
ZX_DEBUG_ASSERT(is_valid());
return fragments_.begin()->connection_handle();
}
// This method will attempt to read |size| bytes of the basic-frame
// information payload (i.e. contents of this PDU excludng the basic L2CAP
// header) starting at offset |pos| and copy the contents into |out_buffer|.
//
// The amount read may be smaller then the amount requested if the PDU does
// not have enough data. |out_buffer| should be sufficiently large.
//
// Returns the number of bytes copied into |out_buffer|.
//
// NOTE: Use this method wisely as it can be costly. In particular, large
// values of |pos| will incur a cost (O(pos)) as the underlying fragments need
// to be traversed to find the initial fragment.
size_t Copy(MutableByteBuffer* out_buffer, size_t pos = 0,
size_t size = std::numeric_limits<std::size_t>::max()) const;
// Release ownership of the current fragments, moving them to the caller. Once
// this is called, the PDU will become invalid.
FragmentList ReleaseFragments();
private:
friend class Reader;
friend class Fragmenter;
friend class Recombiner;
// Methods accessed by friends.
const BasicHeader& basic_header() const;
// Takes ownership of |fragment| and adds it to |fragments_|. This method
// assumes that validity checks on |fragment| have already been performed.
void AppendFragment(hci::ACLDataPacketPtr fragment);
// The number of fragments currently stored in this PDU.
size_t fragment_count_;
// ACL data fragments that currently form this PDU. In a complete PDU, it is
// expected that the sum of the payload sizes of all elements in |fragments_|
// is equal to the length of the frame (i.e. length() + sizeof(BasicHeader)).
FragmentList fragments_;
DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(PDU);
};
} // namespace l2cap
} // namespace bt
#endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_PDU_H_