| // 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_FRAGMENTER_H_ |
| #define SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_FRAGMENTER_H_ |
| |
| #include <fbl/macros.h> |
| |
| #include "src/connectivity/bluetooth/core/bt-host/common/byte_buffer.h" |
| #include "src/connectivity/bluetooth/core/bt-host/hci-spec/protocol.h" |
| #include "src/connectivity/bluetooth/core/bt-host/l2cap/pdu.h" |
| |
| namespace bt::l2cap { |
| |
| enum class FrameCheckSequenceOption { |
| kNoFcs, // FCS is not appended to the L2CAP frame |
| kIncludeFcs // FCS is appended to the L2CAP frame |
| }; |
| |
| // Represents an unfragmented view of a complete L2CAP frame, used to construct PDUs. Unlike PDU, |
| // this does not own its underlying data and is read-only. To avoid extraneous copies, the only way |
| // to access the view is to perform a copy from a slice of the view. |
| class OutboundFrame final { |
| public: |
| OutboundFrame(ChannelId channel_id, const ByteBuffer& data, FrameCheckSequenceOption fcs_option); |
| |
| // Returns the total size of the frame including the L2CAP Basic Header and Information payload. |
| [[nodiscard]] size_t size() const; |
| |
| // Fills |fragment_payload| with frame data starting at |offset| into the frame, up to the |
| // fragment's capacity or the end of this frame, whichever comes first. |
| void WriteToFragment(MutableBufferView fragment_payload, size_t offset); |
| |
| private: |
| using BasicHeaderBuffer = StaticByteBuffer<sizeof(BasicHeader)>; |
| using FrameCheckSequenceBuffer = StaticByteBuffer<sizeof(FrameCheckSequence)>; |
| |
| bool include_fcs() const { return fcs_option_ == FrameCheckSequenceOption::kIncludeFcs; } |
| |
| // Build wire representation of Basic L2CAP header for this frame. |
| BasicHeaderBuffer MakeBasicHeader() const; |
| |
| // Build wire representation of Frame Check Sequence for this frame. |
| // Used to initialize |fcs_|. All other fields must have already been initialized. |
| FrameCheckSequenceBuffer MakeFcs() const; |
| |
| const ChannelId channel_id_; |
| const BufferView data_; |
| const FrameCheckSequenceOption fcs_option_; |
| const std::optional<FrameCheckSequenceBuffer> fcs_; |
| |
| DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(OutboundFrame); |
| }; |
| |
| // A Fragmenter is used to construct L2CAP PDUs composed of fragments that can |
| // be sent over the HCI ACL data channel. This is intended for building PDUs |
| // that will be sent in the host-to-controller direction only. |
| // |
| // Each instance of Fragmenter is intended to operate on a single logical link. |
| // |
| // THREAD-SAFETY: |
| // |
| // This class is not thread-safe. External locking should be provided if an |
| // instance will be accessed on multiple threads. |
| class Fragmenter final { |
| public: |
| // |max_acl_payload_size| is the maximum number of bytes that should be |
| // allowed in a ACL data packet, exluding the header. |connection_handle| |
| // represents the logical link that this Fragmenter operates on. |
| // |
| // NOTE: |max_acl_payload_size| is required by the spec to be at least 27 (see |
| // Core Spec v5.0, Vol 2, Part E, Section 5.4.2). We do not enforce this here |
| // as unit tests are allowed to pass a smaller number. |
| Fragmenter(hci::ConnectionHandle connection_handle, |
| uint16_t max_acl_payload_size = hci::kMaxACLPayloadSize); |
| |
| void set_max_acl_payload_size(size_t value) { max_acl_payload_size_ = value; } |
| |
| // Constructs and returns a PDU to be sent over the L2CAP channel |channel_id|. |data| will be |
| // treated as the Information payload of a B-frame, i.e. the PDU will contain: |
| // |
| // <Basic L2CAP header><data>[FCS] |
| // |
| // All L2CAP frames have a Basic L2CAP header and optionally an FCS footer and can be constructed |
| // using this method. |
| // |
| // If |flushable| is true, then this will build an automatically flushable L2CAP PDU. |
| // Automatically flushable packets are sent over ACL-U logical links based on the setting of an |
| // automatic flush timer. Only non-automatically flushable PDUs can be sent over LE-U links (see |
| // Core Spec v5.0, Vol 2, Part E, Section 5.4.2). |
| [[nodiscard]] PDU BuildFrame(ChannelId channel_id, const ByteBuffer& data, |
| FrameCheckSequenceOption fcs_option, bool flushable = false) const; |
| |
| private: |
| hci::ConnectionHandle connection_handle_; |
| size_t max_acl_payload_size_; |
| |
| DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Fragmenter); |
| }; |
| |
| } // namespace bt::l2cap |
| |
| #endif // SRC_CONNECTIVITY_BLUETOOTH_CORE_BT_HOST_L2CAP_FRAGMENTER_H_ |