xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/l2cap/pdu_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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/l2cap/pdu.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
18 #include "pw_bluetooth_sapphire/internal/host/l2cap/fragmenter.h"
19 #include "pw_bluetooth_sapphire/internal/host/l2cap/recombiner.h"
20 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
21 #include "pw_bluetooth_sapphire/internal/host/transport/packet.h"
22 #include "pw_unit_test/framework.h"
23 
24 namespace bt::l2cap {
25 namespace {
26 
27 template <typename... T>
PacketFromBytes(T...data)28 hci::ACLDataPacketPtr PacketFromBytes(T... data) {
29   StaticByteBuffer bytes(std::forward<T>(data)...);
30   PW_DCHECK(bytes.size() >= sizeof(hci_spec::ACLDataHeader));
31 
32   auto packet = hci::ACLDataPacket::New(
33       static_cast<uint16_t>(bytes.size() - sizeof(hci_spec::ACLDataHeader)));
34   packet->mutable_view()->mutable_data().Write(bytes);
35   packet->InitializeFromBuffer();
36 
37   return packet;
38 }
39 
TEST(PduTest,CanCopyEmptyBody)40 TEST(PduTest, CanCopyEmptyBody) {
41   Recombiner recombiner(0x0001);
42 
43   // clang-format off
44 
45   auto packet = PacketFromBytes(
46     // ACL data header
47     0x01, 0x00, 0x04, 0x00,
48 
49     // Basic l2cap header
50     0x00, 0x00, 0xFF, 0xFF
51   );
52 
53   // clang-format on
54 
55   auto result = recombiner.ConsumeFragment(std::move(packet));
56   ASSERT_TRUE(result.pdu);
57 
58   PDU pdu = std::move(*result.pdu);
59   ASSERT_TRUE(pdu.is_valid());
60   ASSERT_EQ(1u, pdu.fragment_count());
61   ASSERT_EQ(0u, pdu.length());
62 
63   DynamicByteBuffer buf(0);
64   EXPECT_EQ(0u, pdu.Copy(&buf));
65 }
66 
TEST(PduTest,Move)67 TEST(PduTest, Move) {
68   Recombiner recombiner(0x0001);
69 
70   // clang-format off
71 
72   auto packet = PacketFromBytes(
73     // ACL data header
74     0x01, 0x00, 0x08, 0x00,
75 
76     // Basic l2cap header
77     0x04, 0x00, 0xFF, 0xFF, 'T', 'e', 's', 't'
78   );
79 
80   // clang-format on
81 
82   auto result = recombiner.ConsumeFragment(std::move(packet));
83   ASSERT_TRUE(result.pdu);
84 
85   PDU pdu = std::move(*result.pdu);
86   EXPECT_TRUE(pdu.is_valid());
87   EXPECT_EQ(1u, pdu.fragment_count());
88 
89   StaticByteBuffer<4> pdu_data;
90 
91   // Read the entire PDU.
92   EXPECT_EQ(4u, pdu.Copy(&pdu_data));
93   EXPECT_EQ("Test", pdu_data.AsString());
94 
95   PDU move_cted(std::move(pdu));
96   EXPECT_FALSE(pdu.is_valid());
97   EXPECT_EQ(0u, pdu.fragment_count());
98   EXPECT_TRUE(move_cted.is_valid());
99   EXPECT_EQ(1u, move_cted.fragment_count());
100 
101   pdu_data.SetToZeros();
102   EXPECT_EQ(4u, move_cted.Copy(&pdu_data));
103   EXPECT_EQ("Test", pdu_data.AsString());
104 
105   PDU move_assigned = std::move(move_cted);
106   EXPECT_FALSE(move_cted.is_valid());
107   EXPECT_EQ(0u, move_cted.fragment_count());
108   EXPECT_TRUE(move_assigned.is_valid());
109   EXPECT_EQ(1u, move_assigned.fragment_count());
110 
111   pdu_data.SetToZeros();
112   EXPECT_EQ(4u, move_assigned.Copy(&pdu_data));
113   EXPECT_EQ("Test", pdu_data.AsString());
114 }
115 
TEST(PduTest,ReleaseFragments)116 TEST(PduTest, ReleaseFragments) {
117   Recombiner recombiner(0x0001);
118 
119   // clang-format off
120 
121   auto packet = PacketFromBytes(
122     // ACL data header
123     0x01, 0x00, 0x08, 0x00,
124 
125     // Basic l2cap header
126     0x04, 0x00, 0xFF, 0xFF, 'T', 'e', 's', 't'
127   );
128 
129   // clang-format on
130 
131   auto result = recombiner.ConsumeFragment(std::move(packet));
132   ASSERT_TRUE(result.pdu);
133 
134   PDU pdu = std::move(*result.pdu);
135   EXPECT_TRUE(pdu.is_valid());
136   EXPECT_EQ(1u, pdu.fragment_count());
137 
138   auto fragments = pdu.ReleaseFragments();
139 
140   EXPECT_FALSE(pdu.is_valid());
141   ASSERT_FALSE(fragments.empty());
142   EXPECT_EQ(0u, pdu.fragment_count());
143 
144   // Directly count the elements in |fragments| to make sure the count is
145   // correct.
146   size_t count = 0;
147   for ([[maybe_unused]] const auto& f : fragments)
148     count++;
149   EXPECT_EQ(1u, count);
150 
151   // Check that the fragment we got out is identical to the one we fed in.
152   EXPECT_TRUE(ContainersEqual(StaticByteBuffer(
153                                   // ACL data header
154                                   0x01,
155                                   0x00,
156                                   0x08,
157                                   0x00,
158 
159                                   // Basic l2cap header
160                                   0x04,
161                                   0x00,
162                                   0xFF,
163                                   0xFF,
164                                   'T',
165                                   'e',
166                                   's',
167                                   't'),
168                               (*fragments.begin())->view().data()));
169 }
170 
TEST(PduTest,ReadSingleFragment)171 TEST(PduTest, ReadSingleFragment) {
172   Recombiner recombiner(0x0001);
173 
174   // clang-format off
175 
176   auto packet = PacketFromBytes(
177     // ACL data header
178     0x01, 0x00, 0x08, 0x00,
179 
180     // Basic l2cap header
181     0x04, 0x00, 0xFF, 0xFF, 'T', 'e', 's', 't'
182   );
183 
184   // clang-format on
185 
186   auto result = recombiner.ConsumeFragment(std::move(packet));
187   ASSERT_TRUE(result.pdu);
188 
189   PDU pdu = std::move(*result.pdu);
190   EXPECT_TRUE(pdu.is_valid());
191 
192   StaticByteBuffer<4> pdu_data;
193 
194   // Read the entire PDU.
195   EXPECT_EQ(4u, pdu.Copy(&pdu_data));
196   EXPECT_EQ("Test", pdu_data.AsString());
197 
198   // Read 1 byte at offset 1.
199   pdu_data.Fill('X');
200   EXPECT_EQ(1u, pdu.Copy(&pdu_data, 1, 1));
201   EXPECT_EQ("eXXX", pdu_data.AsString());
202 
203   // Read bytes starting at offset 2.
204   pdu_data.Fill('X');
205   EXPECT_EQ(2u, pdu.Copy(&pdu_data, 2));
206   EXPECT_EQ("stXX", pdu_data.AsString());
207 
208   // Read bytes starting at offset 3.
209   pdu_data.Fill('X');
210   EXPECT_EQ(1u, pdu.Copy(&pdu_data, 3));
211   EXPECT_EQ("tXXX", pdu_data.AsString());
212 }
213 
TEST(PduTest,ReadMultipleFragments)214 TEST(PduTest, ReadMultipleFragments) {
215   Recombiner recombiner(0x0001);
216 
217   // clang-format off
218 
219   // Partial initial fragment
220   auto packet0 = PacketFromBytes(
221     // ACL data header (PBF: initial fragment)
222     0x01, 0x00, 0x0A, 0x00,
223 
224     // Basic l2cap header
225     0x0F, 0x00, 0xFF, 0xFF, 'T', 'h', 'i', 's', ' ', 'i'
226   );
227 
228   // Continuation fragment
229   auto packet1 = PacketFromBytes(
230     // ACL data header (PBF: continuing fragment)
231     0x01, 0x10, 0x06, 0x00,
232 
233     // L2CAP PDU fragment
234     's', ' ', 'a', ' ', 't', 'e'
235   );
236 
237   // Continuation fragment
238   auto packet2 = PacketFromBytes(
239     // ACL data header (PBF: continuing fragment)
240     0x01, 0x10, 0x02, 0x00,
241 
242     // L2CAP PDU fragment
243     's', 't'
244   );
245 
246   // Continuation fragment
247   auto packet3 = PacketFromBytes(
248     // ACL data header (PBF: continuing fragment)
249     0x01, 0x10, 0x01, 0x00,
250 
251     // L2CAP PDU fragment
252     '!'
253   );
254 
255   EXPECT_FALSE(recombiner.ConsumeFragment(std::move(packet0)).frames_dropped);
256   EXPECT_FALSE(recombiner.ConsumeFragment(std::move(packet1)).frames_dropped);
257   EXPECT_FALSE(recombiner.ConsumeFragment(std::move(packet2)).frames_dropped);
258   auto result = recombiner.ConsumeFragment(std::move(packet3));
259   EXPECT_FALSE(result.frames_dropped);
260   ASSERT_TRUE(result.pdu);
261 
262   PDU pdu = std::move(*result.pdu);
263   EXPECT_TRUE(pdu.is_valid());
264   EXPECT_EQ(4u, pdu.fragment_count());
265 
266   StaticByteBuffer<15> pdu_data;
267 
268   // Read the entire PDU.
269   EXPECT_EQ(15u, pdu.Copy(&pdu_data));
270   EXPECT_EQ("This is a test!", pdu_data.AsString());
271 
272   // Read 1 byte at offset 1.
273   pdu_data.Fill('X');
274   EXPECT_EQ(1u, pdu.Copy(&pdu_data, 1, 1));
275   EXPECT_EQ("hXXXXXXXXXXXXXX", pdu_data.AsString());
276 
277   // Read bytes starting at offset 2.
278   pdu_data.Fill('X');
279   EXPECT_EQ(13u, pdu.Copy(&pdu_data, 2));
280   EXPECT_EQ("is is a test!XX", pdu_data.AsString());
281 
282   // Read bytes starting at the last octet of the first fragment.
283   pdu_data.Fill('X');
284   EXPECT_EQ(10u, pdu.Copy(&pdu_data, 5));
285   EXPECT_EQ("is a test!XXXXX", pdu_data.AsString());
286 
287   // Read bytes starting at the first octet of the second fragment.
288   pdu_data.Fill('X');
289   EXPECT_EQ(9u, pdu.Copy(&pdu_data, 6));
290   EXPECT_EQ("s a test!XXXXXX", pdu_data.AsString());
291 
292   // Read the very last octet from the last fragment.
293   pdu_data.Fill('X');
294   EXPECT_EQ(1u, pdu.Copy(&pdu_data, 14));
295   EXPECT_EQ("!XXXXXXXXXXXXXX", pdu_data.AsString());
296 
297   // Partial read across multiple fragments
298   pdu_data.Fill('X');
299   EXPECT_EQ(8u, pdu.Copy(&pdu_data, 5, 8));
300   EXPECT_EQ("is a tesXXXXXXX", pdu_data.AsString());
301 }
302 
303 }  // namespace
304 }  // namespace bt
305