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