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 #pragma once
16 #include <variant>
17 
18 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
19 #include "pw_bluetooth_sapphire/internal/host/l2cap/frame_headers.h"
20 #include "pw_bluetooth_sapphire/internal/host/l2cap/rx_engine.h"
21 
22 namespace bt::l2cap::internal {
23 
24 // Implements the receiver state and logic for an L2CAP channel operating in
25 // Enhanced Retransmission Mode.
26 //
27 // THREAD-SAFETY: This class is not thread-safe.
28 class EnhancedRetransmissionModeRxEngine final : public RxEngine {
29  public:
30   using SendFrameCallback = fit::function<void(ByteBufferPtr pdu)>;
31   using ConnectionFailureCallback = fit::function<void()>;
32 
33   EnhancedRetransmissionModeRxEngine(
34       SendFrameCallback send_frame_callback,
35       ConnectionFailureCallback connection_failure_callback);
36   ~EnhancedRetransmissionModeRxEngine() override = default;
37 
38   ByteBufferPtr ProcessPdu(PDU) override;
39 
40   // Set a callback to be invoked when any frame is received that indicates the
41   // peer's acknowledgment for the sequence of packets that it received from the
42   // local host. The values are not checked against the local sender's TxWindow.
43   // |is_poll_response| reflects the 'F' bit in the header of the received
44   // frame.
45   using ReceiveSeqNumCallback =
46       fit::function<void(uint8_t receive_seq_num, bool is_poll_response)>;
set_receive_seq_num_callback(ReceiveSeqNumCallback receive_seq_num_callback)47   void set_receive_seq_num_callback(
48       ReceiveSeqNumCallback receive_seq_num_callback) {
49     receive_seq_num_callback_ = std::move(receive_seq_num_callback);
50   }
51 
52   // Set a callback to be invoked that reports our acknowledgment of inbound
53   // frames from the peer. |ack_seq_num| is the TxSeq of the next I-frame we
54   // expect from the peer.
55   using AckSeqNumCallback = fit::function<void(uint8_t ack_seq_num)>;
set_ack_seq_num_callback(AckSeqNumCallback ack_seq_num_callback)56   void set_ack_seq_num_callback(AckSeqNumCallback ack_seq_num_callback) {
57     ack_seq_num_callback_ = std::move(ack_seq_num_callback);
58   }
59 
60   // Set callbacks to be invoked when the RemoteBusy state variable (Core Spec
61   // v5.0, Vol 3, Part A, Section 8.6.5.3) changes to indicate whether the peer
62   // can receive additional I-Frames.
63   using RemoteBusyChangedCallback = fit::closure;
set_remote_busy_set_callback(RemoteBusyChangedCallback remote_busy_set_callback)64   void set_remote_busy_set_callback(
65       RemoteBusyChangedCallback remote_busy_set_callback) {
66     remote_busy_set_callback_ = std::move(remote_busy_set_callback);
67   }
68 
set_remote_busy_cleared_callback(RemoteBusyChangedCallback remote_busy_cleared_callback)69   void set_remote_busy_cleared_callback(
70       RemoteBusyChangedCallback remote_busy_cleared_callback) {
71     remote_busy_cleared_callback_ = std::move(remote_busy_cleared_callback);
72   }
73 
74   // Set a callback to be invoked when a Reject function (Core Spec v5.0, Vol 3,
75   // Part A, Sec 8.6.1.2) is received. This invocation precedes the
76   // ReceiveSeqNumCallback invocation, which delivers the SeqNum that the
77   // TxEngine is expected to retransmit first.
78   //
79   // |is_poll_request| reflects the 'P' bit in the header of the received frame.
80   using RangeRetransmitSetCallback = fit::function<void(bool is_poll_request)>;
set_range_retransmit_set_callback(RangeRetransmitSetCallback range_retransmit_set_callback)81   void set_range_retransmit_set_callback(
82       RangeRetransmitSetCallback range_retransmit_set_callback) {
83     range_retransmit_set_callback_ = std::move(range_retransmit_set_callback);
84   }
85 
86   // Set a callback to be invoked when a Selective Reject function (Core Spec
87   // v5.0, Vol 3, Part A, Sec 8.6.1.4) is received. This invocation precedes the
88   // ReceiveSeqNumCallback invocation, which delivers the SeqNum of the I-Frame
89   // that the TxEngine is expected to retransmit.
90   //
91   // |is_poll_request| reflects the 'P' bit in the header of the received frame.
92   using SingleRetransmitSetCallback = fit::function<void(bool is_poll_request)>;
set_single_retransmit_set_callback(SingleRetransmitSetCallback single_retransmit_set_callback)93   void set_single_retransmit_set_callback(
94       SingleRetransmitSetCallback single_retransmit_set_callback) {
95     single_retransmit_set_callback_ = std::move(single_retransmit_set_callback);
96   }
97 
98  private:
99   ByteBufferPtr ProcessFrame(const SimpleInformationFrameHeader, PDU);
100   ByteBufferPtr ProcessFrame(const SimpleStartOfSduFrameHeader, PDU);
101   ByteBufferPtr ProcessFrame(const SimpleSupervisoryFrame, PDU);
102   ByteBufferPtr ProcessFrame(std::monostate, PDU);
103   void AdvanceSeqNum();
104 
105   // We assume that the Extended Window Size option is _not_ enabled. In such
106   // cases, the sequence number is a 6-bit counter that wraps on overflow. See
107   // Core Spec Ver 5, Vol 3, Part A, Secs 5.7 and 8.3.
108   uint8_t next_seqnum_;  // (AKA Expected-TxSeq)
109 
110   // Represents the RemoteBusy state variable (Core Spec v5.0, Vol 3, Part A,
111   // Section 8.6.5.3) for whether the peer has sent a Receiver Not Ready.
112   bool remote_is_busy_;
113 
114   SendFrameCallback send_frame_callback_;
115 
116   // Invoked when the connection encounters a fatal error.
117   const ConnectionFailureCallback connection_failure_callback_;
118 
119   // TODO(fxbug.dev/42129869): Refactor these delegates into a single interface
120   // for TxEngine to implement.
121   ReceiveSeqNumCallback receive_seq_num_callback_;
122   AckSeqNumCallback ack_seq_num_callback_;
123   RemoteBusyChangedCallback remote_busy_set_callback_;
124   RemoteBusyChangedCallback remote_busy_cleared_callback_;
125   RangeRetransmitSetCallback range_retransmit_set_callback_;
126   SingleRetransmitSetCallback single_retransmit_set_callback_;
127 
128   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(EnhancedRetransmissionModeRxEngine);
129 };
130 
131 }  // namespace bt::l2cap::internal
132