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/testing/fake_dynamic_channel.h"
16
17 #include <pw_bytes/endian.h>
18
19 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
20 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/test_packets.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/fake_l2cap.h"
24 #include "pw_bluetooth_sapphire/internal/host/testing/fake_signaling_server.h"
25 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
26
27 namespace bt::testing {
28 namespace {
29
30 hci_spec::ConnectionHandle kConnectionHandle = 0x01;
31 l2cap::CommandId kCommandId = 0x02;
32 l2cap::Psm kPsm = l2cap::kSDP;
33
TEST(FakeDynamicChannelTest,ConnectOpenDisconnectChannel)34 TEST(FakeDynamicChannelTest, ConnectOpenDisconnectChannel) {
35 std::unique_ptr<ByteBuffer> received_packet;
36 auto send_cb = [&received_packet](
37 auto /*kConnectionHandle*/, auto /*cid*/, auto& buffer) {
38 received_packet = std::make_unique<DynamicByteBuffer>(buffer);
39 };
40 auto fake_l2cap = FakeL2cap(send_cb);
41 auto server = std::make_unique<FakeSignalingServer>();
42 server->RegisterWithL2cap(&fake_l2cap);
43 auto channel_cb = [](auto /*fake_dynamic_channel*/) {};
44 fake_l2cap.RegisterService(kPsm, channel_cb);
45 l2cap::ChannelId src_id = l2cap::kFirstDynamicChannelId;
46 l2cap::ChannelParameters params;
47
48 // Assemble and send the ConnectionRequest to connect, but not open, the
49 // channel.
50 auto connection_acl_packet = l2cap::testing::AclConnectionReq(
51 kCommandId, kConnectionHandle, src_id, kPsm);
52 const auto& connection_header =
53 connection_acl_packet.To<hci_spec::ACLDataHeader>();
54 auto connection_header_len = sizeof(connection_header);
55 uint16_t connection_payload_len = pw::bytes::ConvertOrderFrom(
56 cpp20::endian::little, connection_header.data_total_length);
57 auto connection_packet = DynamicByteBuffer(connection_payload_len);
58 connection_acl_packet.Copy(
59 &connection_packet, connection_header_len, connection_payload_len);
60 fake_l2cap.HandlePdu(kConnectionHandle, connection_packet);
61
62 // Anticipate that we then receive a ConfigurationRequest. HandlePdu will
63 // first send a ConnectionResponse, but the most recent packet should be a
64 // ConfigurationRequest. The channel should also be connected, but not open,
65 // at this time.
66 // Manually create the expected ConfigurationRequest with no payload.
67 StaticByteBuffer expected_request(
68 // Configuration request command code, CommandId associated with the test
69 l2cap::kConfigurationRequest,
70 kCommandId,
71 // Payload length (4 total bytes)
72 0x04,
73 0x00,
74 // Source ID (2 bytes)
75 LowerBits(src_id),
76 UpperBits(src_id),
77 // No continuation flags (2 bytes)
78 0x00,
79 0x00);
80 EXPECT_TRUE(ContainersEqual(expected_request, *received_packet));
81 EXPECT_FALSE(
82 fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
83 ->configuration_request_received());
84 EXPECT_FALSE(
85 fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
86 ->configuration_response_received());
87 EXPECT_FALSE(
88 fake_l2cap.FindDynamicChannelByRemoteId(kConnectionHandle, src_id)
89 ->opened());
90
91 // Send a ConfigurationResponse to the received ConfigurationRequest.
92 auto configuration_response_acl_packet = l2cap::testing::AclConfigRsp(
93 kCommandId, kConnectionHandle, src_id, params);
94 const auto& configuration_response_header =
95 configuration_response_acl_packet.To<hci_spec::ACLDataHeader>();
96 auto configuration_response_header_len =
97 sizeof(configuration_response_header);
98 uint16_t configuration_response_payload_len = pw::bytes::ConvertOrderFrom(
99 cpp20::endian::little, configuration_response_header.data_total_length);
100 auto configuration_response_packet =
101 DynamicByteBuffer(configuration_response_payload_len);
102 configuration_response_acl_packet.Copy(&configuration_response_packet,
103 configuration_response_header_len,
104 configuration_response_payload_len);
105 fake_l2cap.HandlePdu(kConnectionHandle, configuration_response_packet);
106 EXPECT_FALSE(
107 fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
108 ->configuration_request_received());
109 EXPECT_TRUE(fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
110 ->configuration_response_received());
111 EXPECT_FALSE(
112 fake_l2cap.FindDynamicChannelByRemoteId(kConnectionHandle, src_id)
113 ->opened());
114
115 // Assemble and send the ConfigurationRequest to open up the channel.
116 // In this isolated test, we can assume that the src_id and dest_id are
117 // identical.
118 auto configuration_request_acl_packet = l2cap::testing::AclConfigReq(
119 kCommandId, kConnectionHandle, src_id, params);
120 const auto& configuration_request_header =
121 configuration_request_acl_packet.To<hci_spec::ACLDataHeader>();
122 auto configuration_request_header_len = sizeof(configuration_request_header);
123 uint16_t configuration_request_payload_len = pw::bytes::ConvertOrderFrom(
124 cpp20::endian::little, configuration_request_header.data_total_length);
125 auto configuration_request_packet =
126 DynamicByteBuffer(configuration_request_payload_len);
127 configuration_request_acl_packet.Copy(&configuration_request_packet,
128 configuration_request_header_len,
129 configuration_request_payload_len);
130 fake_l2cap.HandlePdu(kConnectionHandle, configuration_request_packet);
131
132 // Anticipate that we then receive a ConfigurationResponse after we send a
133 // Manually create the expected ConfigurationRequest with no payload.
134 StaticByteBuffer expected_response(
135 // Configuration request command code, CommandId associated with the test
136 l2cap::kConfigurationResponse,
137 kCommandId,
138 // Payload length (6 total bytes)
139 0x06,
140 0x00,
141 // Source ID (2 bytes)
142 LowerBits(src_id),
143 UpperBits(src_id),
144 // No continuation flags (2 bytes)
145 0x00,
146 0x00,
147 // Result (Success)
148 LowerBits(0x0000),
149 UpperBits(0x0000));
150 EXPECT_TRUE(ContainersEqual(expected_response, *received_packet));
151 EXPECT_TRUE(fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
152 ->configuration_request_received());
153 EXPECT_TRUE(fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
154 ->configuration_response_received());
155 EXPECT_TRUE(
156 fake_l2cap.FindDynamicChannelByRemoteId(kConnectionHandle, src_id)
157 ->opened());
158
159 // Assemble and send the DisconnectionRequest to open up the channel.
160 // In this isolated test, we can assume that the src_id and dest_id are
161 // identical.
162 auto disconnection_acl_packet = l2cap::testing::AclDisconnectionReq(
163 kCommandId, kConnectionHandle, src_id, src_id);
164 const auto& disconnection_header =
165 disconnection_acl_packet.To<hci_spec::ACLDataHeader>();
166 auto disconnection_header_len = sizeof(disconnection_header);
167 uint16_t disconnection_payload_len = pw::bytes::ConvertOrderFrom(
168 cpp20::endian::little, disconnection_header.data_total_length);
169 auto disconnection_packet = DynamicByteBuffer(disconnection_payload_len);
170 disconnection_acl_packet.Copy(&disconnection_packet,
171 disconnection_header_len,
172 disconnection_payload_len);
173 fake_l2cap.HandlePdu(kConnectionHandle, disconnection_packet);
174
175 // Anticipate that we receive a DisconnectionResponse after we send the
176 // request and that the channel has been deleted.
177 StaticByteBuffer disconnection_response(
178 // Configuration request command code, CommandId associated with the test
179 l2cap::kDisconnectionResponse,
180 kCommandId,
181 // Payload length (4 total bytes)
182 0x04,
183 0x00,
184 // Source ID (2 bytes)
185 LowerBits(src_id),
186 UpperBits(src_id),
187 // Dest ID (2 bytes)
188 LowerBits(src_id),
189 UpperBits(src_id));
190 EXPECT_TRUE(ContainersEqual(disconnection_response, *received_packet));
191 EXPECT_FALSE(fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
192 .is_alive());
193 }
194
TEST(FakeDynamicChannelTest,FailToRegisterChannelWithoutRegisteredService)195 TEST(FakeDynamicChannelTest, FailToRegisterChannelWithoutRegisteredService) {
196 // Create a custom FakeL2cap with no registered services.
197 std::unique_ptr<ByteBuffer> received_packet;
198 auto send_cb = [&received_packet](
199 auto /*kConnectionHandle*/, auto /*cid*/, auto& buffer) {
200 received_packet = std::make_unique<DynamicByteBuffer>(buffer);
201 };
202 auto fake_l2cap_without_service = FakeL2cap(send_cb);
203 auto server = std::make_unique<FakeSignalingServer>();
204 server->RegisterWithL2cap(&fake_l2cap_without_service);
205 l2cap::ChannelId src_id = l2cap::kFirstDynamicChannelId;
206
207 // Assemble and send the ConnectionRequest to connect, but not open, the
208 // channel.
209 auto connection_acl_packet = l2cap::testing::AclConnectionReq(
210 kCommandId, kConnectionHandle, src_id, kPsm);
211 const auto& connection_header =
212 connection_acl_packet.To<hci_spec::ACLDataHeader>();
213 auto connection_header_len = sizeof(connection_header);
214 uint16_t connection_payload_len = pw::bytes::ConvertOrderFrom(
215 cpp20::endian::little, connection_header.data_total_length);
216 auto connection_packet = DynamicByteBuffer(connection_payload_len);
217 connection_acl_packet.Copy(
218 &connection_packet, connection_header_len, connection_payload_len);
219 fake_l2cap_without_service.HandlePdu(kConnectionHandle, connection_packet);
220
221 // Anticipate that we will receive a rejection as the packet is not supported.
222 // As this is an isolated test case, assume that src_id and dst_id are the
223 // same.
224 auto expected_acl_response = l2cap::testing::AclConnectionRsp(
225 kCommandId,
226 kConnectionHandle,
227 src_id,
228 l2cap::kInvalidChannelId,
229 l2cap::ConnectionResult::kPsmNotSupported);
230 auto expected_response = expected_acl_response.view(
231 sizeof(hci_spec::ACLDataHeader) + sizeof(l2cap::CommandHeader));
232 EXPECT_TRUE(ContainersEqual(expected_response, *received_packet));
233 EXPECT_FALSE(fake_l2cap_without_service
234 .FindDynamicChannelByLocalId(kConnectionHandle, src_id)
235 .is_alive());
236 }
237
TEST(FakeDynamicChannelTest,FailToRegisterChannelWithInvalidCid)238 TEST(FakeDynamicChannelTest, FailToRegisterChannelWithInvalidCid) {
239 // Configure FakeSignalingServer to copy any received signaling packets.
240 std::unique_ptr<ByteBuffer> received_packet;
241 auto send_cb = [&received_packet](
242 auto /*kConnectionHandle*/, auto /*cid*/, auto& buffer) {
243 received_packet = std::make_unique<DynamicByteBuffer>(buffer);
244 };
245 auto fake_l2cap = FakeL2cap(send_cb);
246 auto server = std::make_unique<FakeSignalingServer>();
247 server->RegisterWithL2cap(&fake_l2cap);
248 auto channel_cb = [](auto /*fake_dynamic_channel*/) {};
249 fake_l2cap.RegisterService(kPsm, channel_cb);
250 l2cap::ChannelId src_id = l2cap::kInvalidChannelId;
251
252 // Assemble and send the ConnectionRequest to connect, but not open, the
253 // channel.
254 auto connection_acl_packet = l2cap::testing::AclConnectionReq(
255 kCommandId, kConnectionHandle, src_id, kPsm);
256 const auto& connection_header =
257 connection_acl_packet.To<hci_spec::ACLDataHeader>();
258 auto connection_header_len = sizeof(connection_header);
259 uint16_t connection_payload_len = pw::bytes::ConvertOrderFrom(
260 cpp20::endian::little, connection_header.data_total_length);
261 auto connection_packet = DynamicByteBuffer(connection_payload_len);
262 connection_acl_packet.Copy(
263 &connection_packet, connection_header_len, connection_payload_len);
264 fake_l2cap.HandlePdu(kConnectionHandle, connection_packet);
265
266 // Anticipate that we will receive a rejection as the ID is not supported.
267 auto expected_acl_response = l2cap::testing::AclConnectionRsp(
268 kCommandId,
269 kConnectionHandle,
270 src_id,
271 l2cap::kInvalidChannelId,
272 l2cap::ConnectionResult::kInvalidSourceCID);
273 auto expected_response = expected_acl_response.view(
274 sizeof(hci_spec::ACLDataHeader) + sizeof(l2cap::CommandHeader));
275 EXPECT_TRUE(ContainersEqual(expected_response, *received_packet));
276 EXPECT_FALSE(fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
277 .is_alive());
278 }
279
TEST(FakeDynamicChannelTest,FailToRegisterDuplicateRemoteId)280 TEST(FakeDynamicChannelTest, FailToRegisterDuplicateRemoteId) {
281 std::unique_ptr<ByteBuffer> received_packet;
282 auto send_cb = [&received_packet](
283 auto /*kConnectionHandle*/, auto /*cid*/, auto& buffer) {
284 received_packet = std::make_unique<DynamicByteBuffer>(buffer);
285 };
286 auto fake_l2cap = FakeL2cap(send_cb);
287 auto server = std::make_unique<FakeSignalingServer>();
288 server->RegisterWithL2cap(&fake_l2cap);
289 auto channel_cb = [](auto /*fake_dynamic_channel*/) {};
290 fake_l2cap.RegisterService(kPsm, channel_cb);
291 l2cap::ChannelId src_id = l2cap::kFirstDynamicChannelId;
292 l2cap::ChannelParameters params;
293
294 // Assemble and send the ConnectionRequest to connect, but not open, the
295 // channel.
296 auto connection_acl_packet = l2cap::testing::AclConnectionReq(
297 kCommandId, kConnectionHandle, src_id, kPsm);
298 const auto& connection_header =
299 connection_acl_packet.To<hci_spec::ACLDataHeader>();
300 auto connection_header_len = sizeof(connection_header);
301 uint16_t connection_payload_len = pw::bytes::ConvertOrderFrom(
302 cpp20::endian::little, connection_header.data_total_length);
303 auto connection_packet = DynamicByteBuffer(connection_payload_len);
304 connection_acl_packet.Copy(
305 &connection_packet, connection_header_len, connection_payload_len);
306 fake_l2cap.HandlePdu(kConnectionHandle, connection_packet);
307
308 // Anticipate that we then receive a ConfigurationRequest. HandlePdu will
309 // first send a ConnectionResponse, but the most recent packet should be a
310 // ConfigurationRequest. The channel should also be connected, but not open,
311 // at this time.
312 // Manually create the expected ConfigurationRequest with no payload.
313 StaticByteBuffer expected_request(
314 // Configuration request command code, CommandId associated with the test
315 l2cap::kConfigurationRequest,
316 kCommandId,
317 // Payload length (4 total bytes)
318 0x04,
319 0x00,
320 // Source ID (2 bytes)
321 LowerBits(src_id),
322 UpperBits(src_id),
323 // No continuation flags (2 bytes)
324 0x00,
325 0x00);
326 EXPECT_TRUE(ContainersEqual(expected_request, *received_packet));
327 EXPECT_FALSE(
328 fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
329 ->configuration_request_received());
330 EXPECT_FALSE(
331 fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
332 ->configuration_response_received());
333 EXPECT_FALSE(
334 fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
335 ->opened());
336
337 // Send a ConfigurationResponse to the received ConfigurationRequest.
338 auto configuration_response_acl_packet = l2cap::testing::AclConfigRsp(
339 kCommandId, kConnectionHandle, src_id, params);
340 const auto& configuration_response_header =
341 configuration_response_acl_packet.To<hci_spec::ACLDataHeader>();
342 auto configuration_response_header_len =
343 sizeof(configuration_response_header);
344 uint16_t configuration_response_payload_len = pw::bytes::ConvertOrderFrom(
345 cpp20::endian::little, configuration_response_header.data_total_length);
346 auto configuration_response_packet =
347 DynamicByteBuffer(configuration_response_payload_len);
348 configuration_response_acl_packet.Copy(&configuration_response_packet,
349 configuration_response_header_len,
350 configuration_response_payload_len);
351 fake_l2cap.HandlePdu(kConnectionHandle, configuration_response_packet);
352 EXPECT_FALSE(
353 fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
354 ->configuration_request_received());
355 EXPECT_TRUE(fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
356 ->configuration_response_received());
357 EXPECT_FALSE(
358 fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
359 ->opened());
360
361 // Assemble and send the ConfigurationRequest to open up the channel.
362 // In this isolated test, we can assume that the src_id and dest_id are
363 // identical.
364 auto configuration_request_acl_packet = l2cap::testing::AclConfigReq(
365 kCommandId, kConnectionHandle, src_id, params);
366 const auto& configuration_request_header =
367 configuration_request_acl_packet.To<hci_spec::ACLDataHeader>();
368 auto configuration_request_header_len = sizeof(configuration_request_header);
369 uint16_t configuration_request_payload_len = pw::bytes::ConvertOrderFrom(
370 cpp20::endian::little, configuration_request_header.data_total_length);
371 auto configuration_request_packet =
372 DynamicByteBuffer(configuration_request_payload_len);
373 configuration_request_acl_packet.Copy(&configuration_request_packet,
374 configuration_request_header_len,
375 configuration_request_payload_len);
376 fake_l2cap.HandlePdu(kConnectionHandle, configuration_request_packet);
377
378 // Anticipate that we then receive a ConfigurationResponse after we send a
379 // Manually create the expected ConfigurationRequest with no payload.
380 StaticByteBuffer expected_response(
381 // Configuration request command code, CommandId associated with the test
382 l2cap::kConfigurationResponse,
383 kCommandId,
384 // Payload length (6 total bytes)
385 0x06,
386 0x00,
387 // Source ID (2 bytes)
388 LowerBits(src_id),
389 UpperBits(src_id),
390 // No continuation flags (2 bytes)
391 0x00,
392 0x00,
393 // Result (Success)
394 LowerBits(0x0000),
395 UpperBits(0x0000));
396 EXPECT_TRUE(ContainersEqual(expected_response, *received_packet));
397 EXPECT_TRUE(fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
398 ->configuration_request_received());
399 EXPECT_TRUE(fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
400 ->configuration_response_received());
401 EXPECT_TRUE(fake_l2cap.FindDynamicChannelByLocalId(kConnectionHandle, src_id)
402 ->opened());
403
404 // Try to open up the same channel again.
405 auto second_connection_acl_packet = l2cap::testing::AclConnectionReq(
406 kCommandId, kConnectionHandle, src_id, kPsm);
407 const auto& second_connection_header =
408 second_connection_acl_packet.To<hci_spec::ACLDataHeader>();
409 auto second_connection_header_len = sizeof(second_connection_header);
410 uint16_t second_connection_payload_len = pw::bytes::ConvertOrderFrom(
411 cpp20::endian::little, second_connection_header.data_total_length);
412 auto second_connection_packet =
413 DynamicByteBuffer(second_connection_payload_len);
414 second_connection_acl_packet.Copy(&second_connection_packet,
415 second_connection_header_len,
416 second_connection_payload_len);
417 fake_l2cap.HandlePdu(kConnectionHandle, second_connection_packet);
418
419 // Anticipate that we will receive a rejection as the remote ID has already
420 // been registered.
421 auto second_expected_acl_response = l2cap::testing::AclConnectionRsp(
422 kCommandId,
423 kConnectionHandle,
424 src_id,
425 l2cap::kInvalidChannelId,
426 l2cap::ConnectionResult::kSourceCIDAlreadyAllocated);
427 auto second_expected_response = second_expected_acl_response.view(
428 sizeof(hci_spec::ACLDataHeader) + sizeof(l2cap::CommandHeader));
429 EXPECT_TRUE(ContainersEqual(second_expected_response, *received_packet));
430 }
431
TEST(FakeDynamicChannelTest,FailWhenOutOfIds)432 TEST(FakeDynamicChannelTest, FailWhenOutOfIds) {
433 auto unexpected_cb = [](auto /*handle*/, auto& /*pdu*/) {};
434 std::unique_ptr<ByteBuffer> received_packet;
435 auto send_cb = [&received_packet](
436 auto /*kConnectionHandle*/, auto /*cid*/, auto& buffer) {
437 received_packet = std::make_unique<DynamicByteBuffer>(buffer);
438 };
439 auto fewer_ids_fake_l2cap_ =
440 FakeL2cap(send_cb, unexpected_cb, l2cap::kFirstDynamicChannelId);
441 auto server = std::make_unique<FakeSignalingServer>();
442 server->RegisterWithL2cap(&fewer_ids_fake_l2cap_);
443 auto channel_cb = [](auto /*fake_dynamic_channel*/) {};
444 fewer_ids_fake_l2cap_.RegisterService(kPsm, channel_cb);
445 l2cap::ChannelId src_id = l2cap::kFirstDynamicChannelId;
446
447 // Assemble and send the ConnectionRequest to connect, but not open, the
448 // channel.
449 auto connection_acl_packet = l2cap::testing::AclConnectionReq(
450 kCommandId, kConnectionHandle, src_id, kPsm);
451 const auto& connection_header =
452 connection_acl_packet.To<hci_spec::ACLDataHeader>();
453 auto connection_header_len = sizeof(connection_header);
454 uint16_t connection_payload_len = pw::bytes::ConvertOrderFrom(
455 cpp20::endian::little, connection_header.data_total_length);
456 auto connection_packet = DynamicByteBuffer(connection_payload_len);
457 connection_acl_packet.Copy(
458 &connection_packet, connection_header_len, connection_payload_len);
459 fewer_ids_fake_l2cap_.HandlePdu(kConnectionHandle, connection_packet);
460 EXPECT_FALSE(fewer_ids_fake_l2cap_
461 .FindDynamicChannelByLocalId(kConnectionHandle, src_id)
462 ->opened());
463
464 // The FakeL2cap instance should now be out of ChannelIds to assign.
465 l2cap::ChannelId second_src_id = l2cap::kFirstDynamicChannelId + 1;
466 auto second_connection_acl_packet = l2cap::testing::AclConnectionReq(
467 kCommandId, kConnectionHandle, second_src_id, kPsm);
468 const auto& second_connection_header =
469 second_connection_acl_packet.To<hci_spec::ACLDataHeader>();
470 auto second_connection_header_len = sizeof(second_connection_header);
471 uint16_t second_connection_payload_len = pw::bytes::ConvertOrderFrom(
472 cpp20::endian::little, second_connection_header.data_total_length);
473 auto second_connection_packet =
474 DynamicByteBuffer(second_connection_payload_len);
475 second_connection_acl_packet.Copy(&second_connection_packet,
476 second_connection_header_len,
477 second_connection_payload_len);
478 fewer_ids_fake_l2cap_.HandlePdu(kConnectionHandle, second_connection_packet);
479
480 // Anticipate that we will receive a rejection as there are no Ids left.
481 auto expected_acl_response =
482 l2cap::testing::AclConnectionRsp(kCommandId,
483 kConnectionHandle,
484 second_src_id,
485 l2cap::kInvalidChannelId,
486 l2cap::ConnectionResult::kNoResources);
487 auto expected_response = expected_acl_response.view(
488 sizeof(hci_spec::ACLDataHeader) + sizeof(l2cap::CommandHeader));
489 EXPECT_TRUE(ContainersEqual(expected_response, *received_packet));
490 EXPECT_FALSE(
491 fewer_ids_fake_l2cap_
492 .FindDynamicChannelByLocalId(kConnectionHandle, second_src_id)
493 .is_alive());
494 }
495
496 } // namespace
497 } // namespace bt::testing
498