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 
17 #include <pw_bytes/endian.h>
18 
19 #include <list>
20 
21 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
23 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
24 #include "pw_bluetooth_sapphire/internal/host/transport/acl_data_packet.h"
25 
26 namespace bt::l2cap {
27 
28 // Represents a L2CAP PDU. Each PDU contains a complete L2CAP frame that can be
29 // transmitted over a L2CAP channel. PDUs are the building blocks for SDUs
30 // (higher-layer service data units).
31 //
32 // A PDU is composed of one or more fragments, each contained in a HCI ACL data
33 // packet. A PDU cannot be populated directly and must be obtained from a
34 // Recombiner or Fragmenter.
35 //
36 // A PDU instance is light-weight and can be passed around by value.
37 // As the PDU uniquely owns its chain of fragments, a PDU is move-only.
38 class PDU final {
39  public:
40   using FragmentList = std::list<hci::ACLDataPacketPtr>;
41 
42   PDU() = default;
43   ~PDU() = default;
44 
45   // Allow move operations.
46   PDU(PDU&& other);
47   PDU& operator=(PDU&& other);
48 
49   // An unpopulated PDU is considered invalid, which is the default-constructed
50   // state.
is_valid()51   bool is_valid() const { return !fragments_.empty(); }
52 
53   // The number of ACL data fragments that are currently a part of this PDU.
fragment_count()54   size_t fragment_count() const { return fragments_.size(); }
55 
56   // Returns the number of bytes that are currently contained in this PDU,
57   // excluding the Basic L2CAP header.
length()58   uint16_t length() const {
59     return pw::bytes::ConvertOrderFrom(cpp20::endian::little,
60                                        basic_header().length);
61   }
62 
63   // The L2CAP channel that this packet belongs to.
channel_id()64   ChannelId channel_id() const {
65     return pw::bytes::ConvertOrderFrom(cpp20::endian::little,
66                                        basic_header().channel_id);
67   }
68 
69   // The connection handle that identifies the logical link this PDU is intended
70   // for.
connection_handle()71   hci_spec::ConnectionHandle connection_handle() const {
72     PW_DCHECK(is_valid());
73     return (*fragments_.begin())->connection_handle();
74   }
75 
76   // This method will attempt to read |size| bytes of the basic-frame
77   // information payload (i.e. contents of this PDU excludng the basic L2CAP
78   // header) starting at offset |pos| and copy the contents into |out_buffer|.
79   //
80   // The amount read may be smaller then the amount requested if the PDU does
81   // not have enough data. |out_buffer| should be sufficiently large.
82   //
83   // Returns the number of bytes copied into |out_buffer|.
84   //
85   // NOTE: Use this method wisely as it can be costly. In particular, large
86   // values of |pos| will incur a cost (O(pos)) as the underlying fragments need
87   // to be traversed to find the initial fragment.
88   size_t Copy(MutableByteBuffer* out_buffer,
89               size_t pos = 0,
90               size_t size = std::numeric_limits<std::size_t>::max()) const;
91 
92   // Release ownership of the current fragments, moving them to the caller. Once
93   // this is called, the PDU will become invalid.
94   FragmentList ReleaseFragments();
95 
set_trace_id(trace_flow_id_t id)96   void set_trace_id(trace_flow_id_t id) { trace_id_ = id; }
trace_id()97   trace_flow_id_t trace_id() { return trace_id_; }
98 
99  private:
100   friend class Reader;
101   friend class Fragmenter;
102   friend class Recombiner;
103 
104   // Methods accessed by friends.
105   const BasicHeader& basic_header() const;
106 
107   // Takes ownership of |fragment| and adds it to |fragments_|. This method
108   // assumes that validity checks on |fragment| have already been performed.
109   void AppendFragment(hci::ACLDataPacketPtr fragment);
110 
111   // ACL data fragments that currently form this PDU. In a complete PDU, it is
112   // expected that the sum of the payload sizes of all elements in |fragments_|
113   // is equal to the length of the frame (i.e. length() + sizeof(BasicHeader)).
114   FragmentList fragments_;
115 
116   trace_flow_id_t trace_id_;
117 
118   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(PDU);
119 };
120 
121 }  // namespace bt::l2cap
122