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 #include "pw_bluetooth_sapphire/internal/host/transport/acl_data_packet.h"
16
17 #include <endian.h>
18
19 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
20 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
21 #include "pw_bluetooth_sapphire/internal/host/transport/slab_allocators.h"
22
23 namespace bt::hci {
24 namespace {
25
26 // Type containing both a fixed packet storage buffer and a ACLDataPacket
27 // interface to the buffer. Limit to 3 template instantiations: small, medium,
28 // and large.
29 using SmallACLDataPacket =
30 allocators::internal::FixedSizePacket<hci_spec::ACLDataHeader,
31 allocators::kSmallACLDataPacketSize>;
32 using MediumACLDataPacket =
33 allocators::internal::FixedSizePacket<hci_spec::ACLDataHeader,
34 allocators::kMediumACLDataPacketSize>;
35 using LargeACLDataPacket =
36 allocators::internal::FixedSizePacket<hci_spec::ACLDataHeader,
37 allocators::kLargeACLDataPacketSize>;
38
NewACLDataPacket(size_t payload_size)39 ACLDataPacketPtr NewACLDataPacket(size_t payload_size) {
40 BT_ASSERT_MSG(payload_size <= allocators::kLargeACLDataPayloadSize,
41 "payload size %zu too large (allowed = %zu)",
42 payload_size,
43 allocators::kLargeACLDataPayloadSize);
44
45 if (payload_size <= allocators::kSmallACLDataPayloadSize) {
46 return std::make_unique<SmallACLDataPacket>(payload_size);
47 }
48
49 if (payload_size <= allocators::kMediumACLDataPayloadSize) {
50 return std::make_unique<MediumACLDataPacket>(payload_size);
51 }
52
53 return std::make_unique<LargeACLDataPacket>(payload_size);
54 }
55
56 } // namespace
57
58 // static
New(uint16_t payload_size)59 ACLDataPacketPtr ACLDataPacket::New(uint16_t payload_size) {
60 return NewACLDataPacket(payload_size);
61 }
62
63 // static
New(hci_spec::ConnectionHandle connection_handle,hci_spec::ACLPacketBoundaryFlag packet_boundary_flag,hci_spec::ACLBroadcastFlag broadcast_flag,uint16_t payload_size)64 ACLDataPacketPtr ACLDataPacket::New(
65 hci_spec::ConnectionHandle connection_handle,
66 hci_spec::ACLPacketBoundaryFlag packet_boundary_flag,
67 hci_spec::ACLBroadcastFlag broadcast_flag,
68 uint16_t payload_size) {
69 auto packet = NewACLDataPacket(payload_size);
70 if (!packet)
71 return nullptr;
72
73 packet->WriteHeader(connection_handle, packet_boundary_flag, broadcast_flag);
74 return packet;
75 }
76
connection_handle() const77 hci_spec::ConnectionHandle ACLDataPacket::connection_handle() const {
78 // Return the lower 12-bits of the first two octets.
79 return le16toh(ACLDataPacket::view().header().handle_and_flags) & 0x0FFF;
80 }
81
packet_boundary_flag() const82 hci_spec::ACLPacketBoundaryFlag ACLDataPacket::packet_boundary_flag() const {
83 // Return bits 4-5 in the higher octet of |handle_and_flags| or
84 // "0b00xx000000000000".
85 return static_cast<hci_spec::ACLPacketBoundaryFlag>(
86 (le16toh(ACLDataPacket::view().header().handle_and_flags) >> 12) &
87 0x0003);
88 }
89
broadcast_flag() const90 hci_spec::ACLBroadcastFlag ACLDataPacket::broadcast_flag() const {
91 // Return bits 6-7 in the higher octet of |handle_and_flags| or
92 // "0bxx00000000000000".
93 return static_cast<hci_spec::ACLBroadcastFlag>(
94 le16toh(view().header().handle_and_flags) >> 14);
95 }
96
InitializeFromBuffer()97 void ACLDataPacket::InitializeFromBuffer() {
98 mutable_view()->Resize(le16toh(view().header().data_total_length));
99 }
100
WriteHeader(hci_spec::ConnectionHandle connection_handle,hci_spec::ACLPacketBoundaryFlag packet_boundary_flag,hci_spec::ACLBroadcastFlag broadcast_flag)101 void ACLDataPacket::WriteHeader(
102 hci_spec::ConnectionHandle connection_handle,
103 hci_spec::ACLPacketBoundaryFlag packet_boundary_flag,
104 hci_spec::ACLBroadcastFlag broadcast_flag) {
105 // Must fit inside 12-bits.
106 BT_DEBUG_ASSERT(connection_handle <= 0x0FFF);
107
108 // Must fit inside 2-bits.
109 BT_DEBUG_ASSERT(static_cast<uint8_t>(packet_boundary_flag) <= 0x03);
110 BT_DEBUG_ASSERT(static_cast<uint8_t>(broadcast_flag) <= 0x03);
111
112 // Bitwise OR causes int promotion, so the result must be explicitly casted.
113 uint16_t handle_and_flags = static_cast<uint16_t>(
114 connection_handle | (static_cast<uint16_t>(packet_boundary_flag) << 12) |
115 (static_cast<uint16_t>(broadcast_flag) << 14));
116 mutable_view()->mutable_header()->handle_and_flags =
117 htole16(handle_and_flags);
118 mutable_view()->mutable_header()->data_total_length =
119 htole16(view().payload_size());
120 }
121
122 } // namespace bt::hci
123