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