1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_bluetooth_sapphire/internal/host/l2cap/enhanced_retransmission_mode_engines.h"
16 
17 #include <gmock/gmock.h>
18 #include <pw_async/fake_dispatcher_fixture.h>
19 
20 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_tx_channel.h"
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/fragmenter.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
23 #include "pw_unit_test/framework.h"
24 
25 namespace bt::l2cap::internal {
26 namespace {
27 
28 class EnhancedRetransmissionModeEnginesTest
29     : public pw::async::test::FakeDispatcherFixture {
30  protected:
TxProcessSdu(TxEngine & engine,ByteBufferPtr sdu)31   void TxProcessSdu(TxEngine& engine, ByteBufferPtr sdu) {
32     channel_.QueueSdu(std::move(sdu));
33     engine.NotifySduQueued();
34   }
35 
channel()36   FakeTxChannel& channel() { return channel_; }
37 
38  private:
39   FakeTxChannel channel_;
40 };
41 
42 constexpr size_t kMaxTransmissions = 2;
43 constexpr size_t kTxWindow = 63;
44 
45 constexpr hci_spec::ConnectionHandle kTestHandle = 0x0001;
46 constexpr ChannelId kTestChannelId = 0x0001;
47 constexpr uint8_t kExtendedControlFBitMask = 0b1000'0000;
48 constexpr uint8_t kExtendedControlPBitMask = 0b0001'0000;
49 constexpr uint8_t kExtendedControlRejFunctionMask = 0b0000'0100;
50 constexpr uint8_t kExtendedControlReceiverNotReadyFunctionMask = 0b0000'1000;
51 constexpr uint8_t kExtendedControlSrejFunctionMask = 0b0000'1100;
52 
NoOpFailureCallback()53 void NoOpFailureCallback() {}
54 
TEST_F(EnhancedRetransmissionModeEnginesTest,MakeLinkedERTMEngines)55 TEST_F(EnhancedRetransmissionModeEnginesTest, MakeLinkedERTMEngines) {
56   auto [rx_engine, tx_engine] =
57       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
58                                                   kDefaultMTU,
59                                                   kMaxTransmissions,
60                                                   kTxWindow,
61                                                   channel(),
62                                                   NoOpFailureCallback,
63                                                   dispatcher());
64   EXPECT_TRUE(rx_engine);
65   EXPECT_TRUE(tx_engine);
66 }
67 
68 // This test that TxEngine sends I-Frames whose acknowledgement sequence numbers
69 // match the receive sequence number in RxEngine. This also tests that peer
70 // acknowledgement restarts our outbound data that was paused by hitting
71 // TxWindow. This mirrors the L2CAP Test Specification L2CAP/ERM/BV-06-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,OutboundInformationFramesAcknowledgeReceivedInformationFrames)72 TEST_F(EnhancedRetransmissionModeEnginesTest,
73        OutboundInformationFramesAcknowledgeReceivedInformationFrames) {
74   int tx_count = 0;
75   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
76     ASSERT_TRUE(pdu);
77     // Unlike the Test Spec's sequence diagram, we respond to the peer's
78     // I-Frame with a Receiver Ready (which is always allowed), so our
79     // subsequent I-Frame is actually the third outbound.
80     if (tx_count == 0) {
81       ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
82       ASSERT_TRUE(
83           pdu->To<EnhancedControlField>().designates_information_frame());
84       const auto& header = pdu->To<SimpleInformationFrameHeader>();
85       EXPECT_EQ(0, header.tx_seq());
86       EXPECT_EQ(0, header.receive_seq_num());
87     } else if (tx_count == 2) {
88       ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
89       ASSERT_TRUE(
90           pdu->To<EnhancedControlField>().designates_information_frame());
91       const auto& header = pdu->To<SimpleInformationFrameHeader>();
92       EXPECT_EQ(1, header.tx_seq());
93 
94       // Acknowledges the I-Frame from the peer.
95       EXPECT_EQ(1, header.receive_seq_num());
96     }
97     tx_count++;
98   });
99   auto [rx_engine, tx_engine] =
100       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
101                                                   kDefaultMTU,
102                                                   kMaxTransmissions,
103                                                   /*n_frames_in_tx_window=*/1,
104                                                   channel(),
105                                                   NoOpFailureCallback,
106                                                   dispatcher());
107   ASSERT_TRUE(rx_engine);
108   ASSERT_TRUE(tx_engine);
109 
110   TxProcessSdu(*tx_engine,
111                std::make_unique<DynamicByteBuffer>(
112                    StaticByteBuffer{'p', 'i', 'n', 'g'}));
113   EXPECT_EQ(1, tx_count);
114 
115   // Receive an I-frame containing an acknowledgment including the frame that we
116   // transmitted. See Core Spec, v5, Vol 3, Part A, Section 3.3.2, I-Frame
117   // Enhanced Control Field.
118   StaticByteBuffer info_frame(0, 1, 'p', 'o', 'n', 'g');
119   EXPECT_TRUE(rx_engine->ProcessPdu(
120       Fragmenter(kTestHandle)
121           .BuildFrame(kTestChannelId,
122                       info_frame,
123                       FrameCheckSequenceOption::kIncludeFcs)));
124   EXPECT_EQ(2, tx_count);
125 
126   TxProcessSdu(*tx_engine,
127                std::make_unique<DynamicByteBuffer>(
128                    StaticByteBuffer{'b', 'y', 'e', 'e'}));
129   EXPECT_EQ(3, tx_count);
130 }
131 
132 // This test simulates a peer's non-response to our S-Frame poll request which
133 // causes us to raise a channel error after the monitor timer expires. This
134 // mirrors L2CAP Test Specification v5.0.2 L2CAP/ERM/BV-11-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,SignalFailureAfterMonitorTimerExpiry)135 TEST_F(EnhancedRetransmissionModeEnginesTest,
136        SignalFailureAfterMonitorTimerExpiry) {
137   int tx_count = 0;
138   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
139     ASSERT_TRUE(pdu);
140     // Unlike the Test Spec's sequence diagram, we respond to the peer's I-Frame
141     // with a Receiver Ready (which is always allowed), so our subsequent
142     // I-Frame is actually the third outbound.
143     if (tx_count == 0) {
144       ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
145       ASSERT_TRUE(
146           pdu->To<EnhancedControlField>().designates_information_frame());
147       const auto& header = pdu->To<SimpleInformationFrameHeader>();
148       EXPECT_EQ(0, header.tx_seq());
149       EXPECT_EQ(0, header.receive_seq_num());
150     } else if (tx_count == 1) {
151       ASSERT_EQ(sizeof(SimpleSupervisoryFrame), pdu->size());
152       ASSERT_TRUE(
153           pdu->To<EnhancedControlField>().designates_supervisory_frame());
154       ASSERT_TRUE(pdu->To<SimpleSupervisoryFrame>().is_poll_request());
155     }
156     tx_count++;
157   });
158   bool failure_cb_called = false;
159   auto failure_cb = [&failure_cb_called] { failure_cb_called = true; };
160   auto [rx_engine, tx_engine] =
161       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
162                                                   kDefaultMTU,
163                                                   /*max_transmissions=*/1,
164                                                   kTxWindow,
165                                                   channel(),
166                                                   failure_cb,
167                                                   dispatcher());
168   ASSERT_TRUE(rx_engine);
169   ASSERT_TRUE(tx_engine);
170 
171   TxProcessSdu(*tx_engine,
172                std::make_unique<DynamicByteBuffer>(
173                    StaticByteBuffer{'p', 'i', 'n', 'g'}));
174   EXPECT_EQ(1, tx_count);
175 
176   // Send a poll request after timer expiry waiting for peer acknowledgment.
177   RETURN_IF_FATAL(RunFor(kErtmReceiverReadyPollTimerDuration));
178   EXPECT_EQ(2, tx_count);
179 
180   // Monitor Timer expires without a response from the peer, signaling a channel
181   // failure.
182   EXPECT_FALSE(failure_cb_called);
183   RETURN_IF_FATAL(RunFor(kErtmMonitorTimerDuration));
184   EXPECT_TRUE(failure_cb_called);
185 }
186 
187 // This test simulates non-acknowledgment of an I-Frame that the local host
188 // sends which causes us to meet the MaxTransmit that the peer specified,
189 // raising a local error for the channel. This mirrors L2CAP Test Specification
190 // v5.0.2 L2CAP/ERM/BV-12-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,SignalFailureAfterMaxTransmitExhausted)191 TEST_F(EnhancedRetransmissionModeEnginesTest,
192        SignalFailureAfterMaxTransmitExhausted) {
193   int tx_count = 0;
194   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
195     ASSERT_TRUE(pdu);
196     // Unlike the Test Spec's sequence diagram, we respond to the peer's I-Frame
197     // with a Receiver Ready (which is always allowed), so our subsequent
198     // I-Frame is actually the third outbound.
199     if (tx_count == 0) {
200       ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
201       ASSERT_TRUE(
202           pdu->To<EnhancedControlField>().designates_information_frame());
203       const auto& header = pdu->To<SimpleInformationFrameHeader>();
204       EXPECT_EQ(0, header.tx_seq());
205       EXPECT_EQ(0, header.receive_seq_num());
206     } else if (tx_count == 1) {
207       ASSERT_EQ(sizeof(SimpleSupervisoryFrame), pdu->size());
208       ASSERT_TRUE(
209           pdu->To<EnhancedControlField>().designates_supervisory_frame());
210       ASSERT_TRUE(pdu->To<SimpleSupervisoryFrame>().is_poll_request());
211     }
212     tx_count++;
213   });
214   bool failure_cb_called = false;
215   auto failure_cb = [&failure_cb_called] { failure_cb_called = true; };
216   auto [rx_engine, tx_engine] =
217       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
218                                                   kDefaultMTU,
219                                                   /*max_transmissions=*/1,
220                                                   kTxWindow,
221                                                   channel(),
222                                                   failure_cb,
223                                                   dispatcher());
224   ASSERT_TRUE(rx_engine);
225   ASSERT_TRUE(tx_engine);
226 
227   TxProcessSdu(*tx_engine,
228                std::make_unique<DynamicByteBuffer>(
229                    StaticByteBuffer{'p', 'i', 'n', 'g'}));
230   EXPECT_EQ(1, tx_count);
231 
232   // Send a poll request after timer expiry waiting for peer acknowledgment.
233   RETURN_IF_FATAL(RunFor(kErtmReceiverReadyPollTimerDuration));
234   EXPECT_EQ(2, tx_count);
235 
236   // Peer response doesn't acknowledge the I-Frame's TxSeq and we already used
237   // up MaxTransmit, signaling a channel failure.
238   EXPECT_FALSE(failure_cb_called);
239 
240   // Receive an S-frame containing an acknowledgment not including the frame
241   // that we transmitted. F is set. See Core Spec, v5, Vol 3, Part A,
242   // Section 3.3.2, S-Frame Enhanced Control Field.
243   StaticByteBuffer receiver_ready(0b1 | kExtendedControlFBitMask, 0);
244   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
245                             .BuildFrame(kTestChannelId,
246                                         receiver_ready,
247                                         FrameCheckSequenceOption::kIncludeFcs));
248   EXPECT_TRUE(failure_cb_called);
249 }
250 
251 // This tests the integration of receiving Reject frames with triggering
252 // retransmission of requested unacknowledged I-Frames. This mirrors the L2CAP
253 // Test Specification v5.0.2 L2CAP/ERM/BV-13-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,RetransmitAfterReceivingRejectSFrame)254 TEST_F(EnhancedRetransmissionModeEnginesTest,
255        RetransmitAfterReceivingRejectSFrame) {
256   int tx_count = 0;
257   int iframe_0_tx_count = 0;
258   int iframe_1_tx_count = 0;
259   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
260     tx_count++;
261     ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
262     ASSERT_TRUE(pdu->To<EnhancedControlField>().designates_information_frame());
263     const auto& header = pdu->To<SimpleInformationFrameHeader>();
264     if (header.tx_seq() == 0) {
265       iframe_0_tx_count++;
266     } else if (header.tx_seq() == 1) {
267       iframe_1_tx_count++;
268     }
269   });
270   auto [rx_engine, tx_engine] =
271       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
272                                                   kDefaultMTU,
273                                                   kMaxTransmissions,
274                                                   kTxWindow,
275                                                   channel(),
276                                                   NoOpFailureCallback,
277                                                   dispatcher());
278   ASSERT_TRUE(rx_engine);
279   ASSERT_TRUE(tx_engine);
280 
281   TxProcessSdu(*tx_engine,
282                std::make_unique<DynamicByteBuffer>(StaticByteBuffer('a')));
283   EXPECT_EQ(1, tx_count);
284   EXPECT_EQ(1, iframe_0_tx_count);
285   EXPECT_EQ(0, iframe_1_tx_count);
286 
287   TxProcessSdu(*tx_engine,
288                std::make_unique<DynamicByteBuffer>(StaticByteBuffer('b')));
289   EXPECT_EQ(2, tx_count);
290   EXPECT_EQ(1, iframe_0_tx_count);
291   EXPECT_EQ(1, iframe_1_tx_count);
292 
293   // Receive an S-frame containing a retransmission request starting at seq = 0.
294   // See Core Spec v5.0, Vol 3, Part A, Section 3.3.2 S-Frame Enhanced Control
295   // Field.
296   StaticByteBuffer reject(0b1 | kExtendedControlRejFunctionMask, 0);
297   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
298                             .BuildFrame(kTestChannelId,
299                                         reject,
300                                         FrameCheckSequenceOption::kIncludeFcs));
301 
302   // Check that this caused a retransmission of the two I-Frames.
303   EXPECT_EQ(4, tx_count);
304   EXPECT_EQ(2, iframe_0_tx_count);
305   EXPECT_EQ(2, iframe_1_tx_count);
306 }
307 
308 // This tests the integration of receiving Selective Reject frames that are poll
309 // requests, triggering retransmission as well as acknowledgment that frees up
310 // transmit window. This mirrors the L2CAP Test Specification v5.0.2
311 // L2CAP/ERM/BV-14-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,RetransmitAfterReceivingSelectiveRejectPollRequestSFrame)312 TEST_F(EnhancedRetransmissionModeEnginesTest,
313        RetransmitAfterReceivingSelectiveRejectPollRequestSFrame) {
314   int tx_count = 0;
315   std::array<int, 4> iframe_tx_counts{};
316   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
317     tx_count++;
318     ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
319     ASSERT_TRUE(pdu->To<EnhancedControlField>().designates_information_frame());
320     const auto& header = pdu->To<SimpleInformationFrameHeader>();
321     ASSERT_GT(iframe_tx_counts.size(), header.tx_seq());
322     iframe_tx_counts[header.tx_seq()]++;
323   });
324   auto [rx_engine, tx_engine] =
325       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
326                                                   kDefaultMTU,
327                                                   kMaxTransmissions,
328                                                   /*n_frames_in_tx_window=*/3,
329                                                   channel(),
330                                                   NoOpFailureCallback,
331                                                   dispatcher());
332   ASSERT_TRUE(rx_engine);
333   ASSERT_TRUE(tx_engine);
334 
335   for (int i = 0; i < 4; i++) {
336     TxProcessSdu(
337         *tx_engine,
338         std::make_unique<DynamicByteBuffer>(StaticByteBuffer('a' + i)));
339   }
340 
341   // TxWindow caps transmissions.
342   EXPECT_EQ(3, tx_count);
343   EXPECT_THAT(iframe_tx_counts, testing::ElementsAre(1, 1, 1, 0));
344 
345   // Receive an S-frame containing a poll request retransmission request for seq
346   // = 1. See Core Spec v5.0, Vol 3, Part A, Section 3.3.2 S-Frame Enhanced
347   // Control Field.
348   StaticByteBuffer selective_reject(
349       0b1 | kExtendedControlSrejFunctionMask | kExtendedControlPBitMask, 1);
350   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
351                             .BuildFrame(kTestChannelId,
352                                         selective_reject,
353                                         FrameCheckSequenceOption::kIncludeFcs));
354 
355   // Check that this caused a retransmission of I-Frames 1 and 3 because the
356   // poll request acknowledged I-Frame 0, freeing up space in the transmit
357   // window.
358   EXPECT_EQ(5, tx_count);
359   EXPECT_THAT(iframe_tx_counts, testing::ElementsAre(1, 2, 1, 1));
360 }
361 
362 // This tests the integration of receiving Selective Reject frames that are not
363 // poll requests, triggering retransmission only. This mirrors the L2CAP Test
364 // Specification v5.0.2 L2CAP/ERM/BV-15-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,RetransmitAfterReceivingSelectiveRejectSFrame)365 TEST_F(EnhancedRetransmissionModeEnginesTest,
366        RetransmitAfterReceivingSelectiveRejectSFrame) {
367   int tx_count = 0;
368   std::array<int, 4> iframe_tx_counts{};
369   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
370     tx_count++;
371     ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
372     ASSERT_TRUE(pdu->To<EnhancedControlField>().designates_information_frame());
373     const auto& header = pdu->To<SimpleInformationFrameHeader>();
374     ASSERT_GT(iframe_tx_counts.size(), header.tx_seq());
375     iframe_tx_counts[header.tx_seq()]++;
376   });
377   auto [rx_engine, tx_engine] =
378       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
379                                                   kDefaultMTU,
380                                                   kMaxTransmissions,
381                                                   /*n_frames_in_tx_window=*/3,
382                                                   channel(),
383                                                   NoOpFailureCallback,
384                                                   dispatcher());
385   ASSERT_TRUE(rx_engine);
386   ASSERT_TRUE(tx_engine);
387 
388   for (int i = 0; i < 4; i++) {
389     TxProcessSdu(
390         *tx_engine,
391         std::make_unique<DynamicByteBuffer>(StaticByteBuffer('a' + i)));
392   }
393 
394   // TxWindow caps transmissions.
395   EXPECT_EQ(3, tx_count);
396   EXPECT_THAT(iframe_tx_counts, testing::ElementsAre(1, 1, 1, 0));
397 
398   // Receive an S-frame containing a retransmission request for seq = 1. See
399   // Core Spec v5.0, Vol 3, Part A, Section 3.3.2 S-Frame Enhanced Control
400   // Field.
401   StaticByteBuffer selective_reject(0b1 | kExtendedControlSrejFunctionMask, 1);
402   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
403                             .BuildFrame(kTestChannelId,
404                                         selective_reject,
405                                         FrameCheckSequenceOption::kIncludeFcs));
406 
407   // Check that this caused a retransmission of I-Frame 1 only.
408   EXPECT_EQ(4, tx_count);
409   EXPECT_THAT(iframe_tx_counts, testing::ElementsAre(1, 2, 1, 0));
410 
411   // Receive an S-frame containing an acknowledgment up to seq = 3.
412   StaticByteBuffer ack_3(0b1, 3);
413   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
414                             .BuildFrame(kTestChannelId,
415                                         ack_3,
416                                         FrameCheckSequenceOption::kIncludeFcs));
417 
418   // Initial transmission of I-Frame 3 after the acknowledgment freed up
419   // transmit window capacity.
420   EXPECT_EQ(5, tx_count);
421   EXPECT_THAT(iframe_tx_counts, testing::ElementsAre(1, 2, 1, 1));
422 
423   // Receive an S-frame containing an acknowledgment up to seq = 3.
424   StaticByteBuffer ack_4(0b1, 4);
425   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
426                             .BuildFrame(kTestChannelId,
427                                         ack_4,
428                                         FrameCheckSequenceOption::kIncludeFcs));
429 
430   EXPECT_EQ(5, tx_count);
431 }
432 
433 // This tests the integration of receiving an acknowledgment sequence with
434 // triggering retransmission of unacknowledged I-Frames. This mirrors the L2CAP
435 // Test Specification L2CAP/ERM/BV-18-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,RetransmitAfterPollResponseDoesNotAcknowledgeSentFrames)436 TEST_F(EnhancedRetransmissionModeEnginesTest,
437        RetransmitAfterPollResponseDoesNotAcknowledgeSentFrames) {
438   DynamicByteBuffer info_frame;
439   int tx_count = 0;
440   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
441     // The first packet is the I-Frame containing the data that we sent.
442     // The second packet is the S-Frame polling for the peer after the
443     // Retransmission Timer expires. It is not checked to keep the tests less
444     // fragile, as the first two packets are already covered by
445     // EnhancedRetransmissionModeTxEngineTest.
446     if (tx_count == 0) {
447       info_frame = DynamicByteBuffer(*pdu);
448     } else if (tx_count == 2) {
449       EXPECT_TRUE(ContainersEqual(info_frame, *pdu));
450     }
451     tx_count++;
452   });
453   auto [rx_engine, tx_engine] =
454       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
455                                                   kDefaultMTU,
456                                                   kMaxTransmissions,
457                                                   kTxWindow,
458                                                   channel(),
459                                                   NoOpFailureCallback,
460                                                   dispatcher());
461   ASSERT_TRUE(rx_engine);
462   ASSERT_TRUE(tx_engine);
463 
464   TxProcessSdu(*tx_engine,
465                std::make_unique<DynamicByteBuffer>(StaticByteBuffer{'a'}));
466   EXPECT_EQ(1, tx_count);
467 
468   RunFor(kErtmReceiverReadyPollTimerDuration);
469   EXPECT_EQ(2, tx_count);
470 
471   // Receive an S-frame containing an acknowledgment not including the frame
472   // that we transmitted. F is set. See Core Spec, v5, Vol 3, Part A,
473   // Section 3.3.2, S-Frame Enhanced Control Field.
474   StaticByteBuffer receiver_ready(0b1 | kExtendedControlFBitMask, 0);
475   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
476                             .BuildFrame(kTestChannelId,
477                                         receiver_ready,
478                                         FrameCheckSequenceOption::kIncludeFcs));
479 
480   // Check that this caused a retransmission of the initial I-Frame.
481   EXPECT_EQ(3, tx_count);
482 }
483 
484 // This test simulates the peer declaring that it is busy by sending the
485 // ReceiverNotReady S-Frame, which prevents us from retransmitting an
486 // unacknowledged outbound I-Frame. This mirrors L2CAP Test Specification v5.0.2
487 // L2CAP/ERM/BV-20-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,DoNotRetransmitAfterReceivingReceiverNotReadyPollResponse)488 TEST_F(EnhancedRetransmissionModeEnginesTest,
489        DoNotRetransmitAfterReceivingReceiverNotReadyPollResponse) {
490   int tx_count = 0;
491   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
492     ASSERT_TRUE(pdu);
493     // Unlike the Test Spec's sequence diagram, we respond to the peer's I-Frame
494     // with a Receiver Ready (which is always allowed), so our subsequent
495     // I-Frame is actually the third outbound.
496     if (tx_count == 0) {
497       ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
498       ASSERT_TRUE(
499           pdu->To<EnhancedControlField>().designates_information_frame());
500       const auto& header = pdu->To<SimpleInformationFrameHeader>();
501       EXPECT_EQ(0, header.tx_seq());
502       EXPECT_EQ(0, header.receive_seq_num());
503     } else if (tx_count == 1) {
504       ASSERT_EQ(sizeof(SimpleSupervisoryFrame), pdu->size());
505       ASSERT_TRUE(
506           pdu->To<EnhancedControlField>().designates_supervisory_frame());
507       ASSERT_TRUE(pdu->To<SimpleSupervisoryFrame>().is_poll_request());
508     }
509     tx_count++;
510   });
511   auto [rx_engine, tx_engine] =
512       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
513                                                   kDefaultMTU,
514                                                   kMaxTransmissions,
515                                                   kTxWindow,
516                                                   channel(),
517                                                   NoOpFailureCallback,
518                                                   dispatcher());
519   ASSERT_TRUE(rx_engine);
520   ASSERT_TRUE(tx_engine);
521 
522   TxProcessSdu(*tx_engine,
523                std::make_unique<DynamicByteBuffer>(
524                    StaticByteBuffer{'p', 'i', 'n', 'g'}));
525   EXPECT_EQ(1, tx_count);
526 
527   // Send a poll request after timer expiry waiting for peer acknowledgment.
528   RETURN_IF_FATAL(RunFor(kErtmReceiverReadyPollTimerDuration));
529   EXPECT_EQ(2, tx_count);
530 
531   // Receive an Receiver Not Ready containing an acknowledgment not including
532   // the frame that we transmitted. F is set. See Core Spec, v5, Vol 3, Part A,
533   // Section 3.3.2, S-Frame Enhanced Control Field.
534   StaticByteBuffer receiver_not_ready(
535       0b1 | kExtendedControlReceiverNotReadyFunctionMask |
536           kExtendedControlFBitMask,
537       0);
538   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
539                             .BuildFrame(kTestChannelId,
540                                         receiver_not_ready,
541                                         FrameCheckSequenceOption::kIncludeFcs));
542 
543   // RNR sets our RemoteBusy flag, so we should not transmit anything.
544   EXPECT_EQ(2, tx_count);
545 }
546 // This tests that explicitly a requested selective retransmission and another
547 // for the same I-Frame that is a poll response causes only one retransmission.
548 // This mirrors the L2CAP Test Specification v5.0.2 L2CAP/ERM/BI-03-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,RetransmitOnlyOnceAfterReceivingDuplicateSelectiveRejectSFramesForSameIFrameDuringReceiverReadyPoll)549 TEST_F(
550     EnhancedRetransmissionModeEnginesTest,
551     RetransmitOnlyOnceAfterReceivingDuplicateSelectiveRejectSFramesForSameIFrameDuringReceiverReadyPoll) {
552   int tx_count = 0;
553   int iframe_0_tx_count = 0;
554   int iframe_1_tx_count = 0;
555   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
556     tx_count++;
557 
558     // After outbound I-Frames, expect an outbound poll request S-Frame.
559     if (tx_count == 3) {
560       ASSERT_EQ(sizeof(SimpleSupervisoryFrame), pdu->size());
561       ASSERT_TRUE(
562           pdu->To<EnhancedControlField>().designates_supervisory_frame());
563       ASSERT_TRUE(pdu->To<SimpleSupervisoryFrame>().is_poll_request());
564       return;
565     }
566 
567     ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
568     ASSERT_TRUE(pdu->To<EnhancedControlField>().designates_information_frame());
569     const auto& header = pdu->To<SimpleInformationFrameHeader>();
570     if (header.tx_seq() == 0) {
571       iframe_0_tx_count++;
572     } else if (header.tx_seq() == 1) {
573       iframe_1_tx_count++;
574     }
575   });
576   auto [rx_engine, tx_engine] =
577       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
578                                                   kDefaultMTU,
579                                                   kMaxTransmissions,
580                                                   kTxWindow,
581                                                   channel(),
582                                                   NoOpFailureCallback,
583                                                   dispatcher());
584   ASSERT_TRUE(rx_engine);
585   ASSERT_TRUE(tx_engine);
586 
587   TxProcessSdu(*tx_engine,
588                std::make_unique<DynamicByteBuffer>(StaticByteBuffer('a')));
589   TxProcessSdu(*tx_engine,
590                std::make_unique<DynamicByteBuffer>(StaticByteBuffer('b')));
591   EXPECT_EQ(2, tx_count);
592   EXPECT_EQ(1, iframe_0_tx_count);
593   EXPECT_EQ(1, iframe_1_tx_count);
594 
595   RunFor(kErtmReceiverReadyPollTimerDuration);
596   EXPECT_EQ(3, tx_count);
597 
598   // Receive an S-frame containing a retransmission request for I-Frame 0. See
599   // Core Spec v5.0, Vol 3, Part A, Section 3.3.2 S-Frame Enhanced Control
600   // Field.
601   StaticByteBuffer selective_reject(0b1 | kExtendedControlSrejFunctionMask, 0);
602   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
603                             .BuildFrame(kTestChannelId,
604                                         selective_reject,
605                                         FrameCheckSequenceOption::kIncludeFcs));
606 
607   // Receive an S-frame containing a retransmission request for I-Frame 0 and a
608   // poll response.
609   StaticByteBuffer selective_reject_f(
610       0b1 | kExtendedControlSrejFunctionMask | kExtendedControlFBitMask, 0);
611   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
612                             .BuildFrame(kTestChannelId,
613                                         selective_reject_f,
614                                         FrameCheckSequenceOption::kIncludeFcs));
615 
616   // Check that these two SREJs caused a retransmission of I-Frame 0 only once.
617   EXPECT_EQ(4, tx_count);
618   EXPECT_EQ(2, iframe_0_tx_count);
619   EXPECT_EQ(1, iframe_1_tx_count);
620 
621   // Acknowledge all of the outbound I-Frames per the specification's sequence
622   // diagram.
623   StaticByteBuffer receiver_ready_2(0b1, 2);
624   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
625                             .BuildFrame(kTestChannelId,
626                                         receiver_ready_2,
627                                         FrameCheckSequenceOption::kIncludeFcs));
628   EXPECT_EQ(4, tx_count);
629 }
630 
631 // This tests that explicitly requested retransmission and receiving a poll
632 // response that doesn't acknowledge all I-Frames results in only a single set
633 // of retransmissions. This mirrors the L2CAP Test Specification v5.0.2
634 // L2CAP/ERM/BI-04-C.
TEST_F(EnhancedRetransmissionModeEnginesTest,RetransmitAfterReceivingRejectSFrameAndReceiverReadyPollResponseNotAcknowledgingSentFrames)635 TEST_F(
636     EnhancedRetransmissionModeEnginesTest,
637     RetransmitAfterReceivingRejectSFrameAndReceiverReadyPollResponseNotAcknowledgingSentFrames) {
638   int tx_count = 0;
639   int iframe_0_tx_count = 0;
640   int iframe_1_tx_count = 0;
641   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
642     tx_count++;
643 
644     // After outbound I-Frames, expect an outbound poll request S-Frame.
645     if (tx_count == 3) {
646       ASSERT_EQ(sizeof(SimpleSupervisoryFrame), pdu->size());
647       ASSERT_TRUE(
648           pdu->To<EnhancedControlField>().designates_supervisory_frame());
649       ASSERT_TRUE(pdu->To<SimpleSupervisoryFrame>().is_poll_request());
650       return;
651     }
652 
653     ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
654     ASSERT_TRUE(pdu->To<EnhancedControlField>().designates_information_frame());
655     const auto& header = pdu->To<SimpleInformationFrameHeader>();
656     if (header.tx_seq() == 0) {
657       iframe_0_tx_count++;
658     } else if (header.tx_seq() == 1) {
659       iframe_1_tx_count++;
660     }
661   });
662   auto [rx_engine, tx_engine] =
663       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
664                                                   kDefaultMTU,
665                                                   kMaxTransmissions,
666                                                   kTxWindow,
667                                                   channel(),
668                                                   NoOpFailureCallback,
669                                                   dispatcher());
670   ASSERT_TRUE(rx_engine);
671   ASSERT_TRUE(tx_engine);
672 
673   TxProcessSdu(*tx_engine,
674                std::make_unique<DynamicByteBuffer>(StaticByteBuffer('a')));
675   TxProcessSdu(*tx_engine,
676                std::make_unique<DynamicByteBuffer>(StaticByteBuffer('b')));
677   EXPECT_EQ(2, tx_count);
678   EXPECT_EQ(1, iframe_0_tx_count);
679   EXPECT_EQ(1, iframe_1_tx_count);
680 
681   RunFor(kErtmReceiverReadyPollTimerDuration);
682   EXPECT_EQ(3, tx_count);
683 
684   // Receive an S-frame containing a retransmission request starting at seq = 0.
685   // See Core Spec v5.0, Vol 3, Part A, Section 3.3.2 S-Frame Enhanced Control
686   // Field.
687   StaticByteBuffer reject(0b1 | kExtendedControlRejFunctionMask, 0);
688   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
689                             .BuildFrame(kTestChannelId,
690                                         reject,
691                                         FrameCheckSequenceOption::kIncludeFcs));
692 
693   // Receive an S-frame containing an acknowledgment not including the frames
694   // that we transmitted. F is set. See Core Spec v5.0, Vol 3, Part A,
695   // Section 3.3.2 S-Frame Enhanced Control Field.
696   StaticByteBuffer receiver_ready_0(0b1 | kExtendedControlFBitMask, 0);
697   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
698                             .BuildFrame(kTestChannelId,
699                                         receiver_ready_0,
700                                         FrameCheckSequenceOption::kIncludeFcs));
701 
702   // Check that this caused a retransmission of the two I-Frames only once each.
703   EXPECT_EQ(5, tx_count);
704   EXPECT_EQ(2, iframe_0_tx_count);
705   EXPECT_EQ(2, iframe_1_tx_count);
706 
707   // Acknowledge all of the outbound I-Frames per the specification's sequence
708   // diagram.
709   StaticByteBuffer receiver_ready_2(0b1, 2);
710   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
711                             .BuildFrame(kTestChannelId,
712                                         receiver_ready_2,
713                                         FrameCheckSequenceOption::kIncludeFcs));
714   EXPECT_EQ(5, tx_count);
715 }
716 
717 // This tests that explicitly requested retransmission and receiving a I-Frame
718 // that doesn't acknowledge all I-Frames results in only a single set of
719 // retransmissions. This mirrors the L2CAP Test Specification v5.0.2
720 // L2CAP/ERM/BI-05-C in which we—the IUT—perform the ALT1 path in the sequence
721 // diagram Figure 4.96.
TEST_F(EnhancedRetransmissionModeEnginesTest,RetransmitAfterReceivingRejectSFrameAndIFramePollResponseNotAcknowledgingSentFrames)722 TEST_F(
723     EnhancedRetransmissionModeEnginesTest,
724     RetransmitAfterReceivingRejectSFrameAndIFramePollResponseNotAcknowledgingSentFrames) {
725   int tx_count = 0;
726   int iframe_0_tx_count = 0;
727   int iframe_1_tx_count = 0;
728   channel().HandleSendFrame([&](ByteBufferPtr pdu) {
729     tx_count++;
730     SCOPED_TRACE(tx_count);
731 
732     if (tx_count == 3) {
733       // After outbound I-Frames (not retransmitted), expect an outbound poll
734       // request S-Frame.
735       ASSERT_EQ(sizeof(SimpleSupervisoryFrame), pdu->size());
736       ASSERT_TRUE(
737           pdu->To<EnhancedControlField>().designates_supervisory_frame());
738       EXPECT_TRUE(pdu->To<SimpleSupervisoryFrame>().is_poll_request());
739       return;
740     } else if (tx_count == 6) {
741       // After retransmitted I-Frames, expect an outbound ReceiverReady that
742       // acknowledges the peer's I-Frame.
743       ASSERT_EQ(sizeof(SimpleSupervisoryFrame), pdu->size());
744       ASSERT_TRUE(
745           pdu->To<EnhancedControlField>().designates_supervisory_frame());
746       EXPECT_FALSE(pdu->To<SimpleSupervisoryFrame>().is_poll_request());
747       EXPECT_EQ(1, pdu->To<SimpleSupervisoryFrame>().receive_seq_num());
748       return;
749     }
750 
751     ASSERT_LE(sizeof(SimpleInformationFrameHeader), pdu->size());
752     ASSERT_TRUE(pdu->To<EnhancedControlField>().designates_information_frame());
753     const auto& header = pdu->To<SimpleInformationFrameHeader>();
754     EXPECT_EQ(0, header.receive_seq_num());
755     if (header.tx_seq() == 0) {
756       iframe_0_tx_count++;
757     } else if (header.tx_seq() == 1) {
758       iframe_1_tx_count++;
759     }
760   });
761   auto [rx_engine, tx_engine] =
762       MakeLinkedEnhancedRetransmissionModeEngines(kTestChannelId,
763                                                   kDefaultMTU,
764                                                   kMaxTransmissions,
765                                                   kTxWindow,
766                                                   channel(),
767                                                   NoOpFailureCallback,
768                                                   dispatcher());
769   ASSERT_TRUE(rx_engine);
770   ASSERT_TRUE(tx_engine);
771 
772   TxProcessSdu(*tx_engine,
773                std::make_unique<DynamicByteBuffer>(StaticByteBuffer('a')));
774   TxProcessSdu(*tx_engine,
775                std::make_unique<DynamicByteBuffer>(StaticByteBuffer('b')));
776   EXPECT_EQ(2, tx_count);
777   EXPECT_EQ(1, iframe_0_tx_count);
778   EXPECT_EQ(1, iframe_1_tx_count);
779 
780   RunFor(kErtmReceiverReadyPollTimerDuration);
781   EXPECT_EQ(3, tx_count);
782 
783   // Receive an S-frame containing a retransmission request starting at seq = 0.
784   // See Core Spec v5.0, Vol 3, Part A, Section 3.3.2 S-Frame Enhanced Control
785   // Field.
786   StaticByteBuffer reject(0b1 | kExtendedControlRejFunctionMask, 0);
787   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
788                             .BuildFrame(kTestChannelId,
789                                         reject,
790                                         FrameCheckSequenceOption::kIncludeFcs));
791 
792   // Receive an I-frame containing an acknowledgment not including the frames
793   // that we transmitted. F is set. See Core Spec v5.0, Vol 3, Part A,
794   // Section 3.3.2 I-Frame Enhanced Control Field.
795   StaticByteBuffer inbound_iframe(kExtendedControlFBitMask, 0, 'A');
796   auto inbound_pdu = rx_engine->ProcessPdu(
797       Fragmenter(kTestHandle)
798           .BuildFrame(kTestChannelId,
799                       inbound_iframe,
800                       FrameCheckSequenceOption::kIncludeFcs));
801   EXPECT_TRUE(inbound_pdu);
802 
803   // Check that this caused a retransmission of the two I-Frames only once each,
804   // plus our acknowledgment of the peer I-Frame.
805   EXPECT_EQ(6, tx_count);
806   EXPECT_EQ(2, iframe_0_tx_count);
807   EXPECT_EQ(2, iframe_1_tx_count);
808 
809   // Acknowledge all of the outbound I-Frames per the specification's sequence
810   // diagram.
811   StaticByteBuffer receiver_ready(0b1, 2);
812   rx_engine->ProcessPdu(Fragmenter(kTestHandle)
813                             .BuildFrame(kTestChannelId,
814                                         receiver_ready,
815                                         FrameCheckSequenceOption::kIncludeFcs));
816   EXPECT_EQ(6, tx_count);
817 }
818 
819 }  // namespace
820 }  // namespace bt::l2cap::internal
821