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