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