1 // Copyright 2023 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 15 #pragma once 16 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h" 17 #include "pw_bluetooth_sapphire/internal/host/common/macros.h" 18 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h" 19 #include "pw_bluetooth_sapphire/internal/host/l2cap/pdu.h" 20 21 namespace bt::l2cap { 22 23 enum class FrameCheckSequenceOption { 24 kNoFcs, // FCS is not appended to the L2CAP frame 25 kIncludeFcs // FCS is appended to the L2CAP frame 26 }; 27 28 // Represents an unfragmented view of a complete L2CAP frame, used to construct 29 // PDUs. Unlike PDU, this does not own its underlying data and is read-only. To 30 // avoid extraneous copies, the only way to access the view is to perform a copy 31 // from a slice of the view. 32 class OutboundFrame final { 33 public: 34 OutboundFrame(ChannelId channel_id, 35 const ByteBuffer& data, 36 FrameCheckSequenceOption fcs_option); 37 38 // Returns the total size of the frame including the L2CAP Basic Header and 39 // Information payload. 40 [[nodiscard]] size_t size() const; 41 42 // Fills |fragment_payload| with frame data starting at |offset| into the 43 // frame, up to the fragment's capacity or the end of this frame, whichever 44 // comes first. 45 void WriteToFragment(MutableBufferView fragment_payload, size_t offset); 46 47 private: 48 using BasicHeaderBuffer = StaticByteBuffer<sizeof(BasicHeader)>; 49 using FrameCheckSequenceBuffer = StaticByteBuffer<sizeof(FrameCheckSequence)>; 50 include_fcs()51 bool include_fcs() const { 52 return fcs_option_ == FrameCheckSequenceOption::kIncludeFcs; 53 } 54 55 // Build wire representation of Basic L2CAP header for this frame. 56 BasicHeaderBuffer MakeBasicHeader() const; 57 58 // Build wire representation of Frame Check Sequence for this frame. 59 // Used to initialize |fcs_|. All other fields must have already been 60 // initialized. 61 FrameCheckSequenceBuffer MakeFcs() const; 62 63 const ChannelId channel_id_; 64 const BufferView data_; 65 const FrameCheckSequenceOption fcs_option_; 66 const std::optional<FrameCheckSequenceBuffer> fcs_; 67 68 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(OutboundFrame); 69 }; 70 71 // A Fragmenter is used to construct L2CAP PDUs composed of fragments that can 72 // be sent over the HCI ACL data channel. This is intended for building PDUs 73 // that will be sent in the host-to-controller direction only. 74 // 75 // Each instance of Fragmenter is intended to operate on a single logical link. 76 // 77 // THREAD-SAFETY: 78 // 79 // This class is not thread-safe. External locking should be provided if an 80 // instance will be accessed on multiple threads. 81 class Fragmenter final { 82 public: 83 // |max_acl_payload_size| is the maximum number of bytes that should be 84 // allowed in a ACL data packet, exluding the header. |connection_handle| 85 // represents the logical link that this Fragmenter operates on. 86 // 87 // NOTE: |max_acl_payload_size| is required by the spec to be at least 27 (see 88 // Core Spec v5.0, Vol 2, Part E, Section 5.4.2). We do not enforce this here 89 // as unit tests are allowed to pass a smaller number. 90 Fragmenter(hci_spec::ConnectionHandle connection_handle, 91 uint16_t max_acl_payload_size = hci_spec::kMaxACLPayloadSize); 92 set_max_acl_payload_size(size_t value)93 void set_max_acl_payload_size(size_t value) { max_acl_payload_size_ = value; } 94 95 // Constructs and returns a PDU to be sent over the L2CAP channel 96 // |channel_id|. |data| will be treated as the Information payload of a 97 // B-frame, i.e. the PDU will contain: 98 // 99 // <Basic L2CAP header><data>[FCS] 100 // 101 // All L2CAP frames have a Basic L2CAP header and optionally an FCS footer and 102 // can be constructed using this method. 103 // 104 // If |flushable| is true, then this will build an automatically flushable 105 // L2CAP PDU. Automatically flushable packets are sent over ACL-U logical 106 // links based on the setting of an automatic flush timer. Only 107 // non-automatically flushable PDUs can be sent over LE-U links (see Core Spec 108 // v5.0, Vol 2, Part E, Section 5.4.2). 109 [[nodiscard]] PDU BuildFrame(ChannelId channel_id, 110 const ByteBuffer& data, 111 FrameCheckSequenceOption fcs_option, 112 bool flushable = false) const; 113 114 private: 115 hci_spec::ConnectionHandle connection_handle_; 116 size_t max_acl_payload_size_; 117 118 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Fragmenter); 119 }; 120 121 } // namespace bt::l2cap 122