xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/testing/fake_dynamic_channel_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/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