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 <lib/fit/function.h> 17 18 #include <list> 19 20 #include "pw_bluetooth_sapphire/internal/host/common/smart_task.h" 21 #include "pw_bluetooth_sapphire/internal/host/l2cap/tx_engine.h" 22 23 namespace bt::l2cap::internal { 24 25 // Implements the sender-side functionality of L2CAP Enhanced Retransmission 26 // Mode. See Bluetooth Core Spec v5.0, Volume 3, Part A, Sec 2.4, "Modes of 27 // Operation". 28 // 29 // THREAD-SAFETY: This class may is _not_ thread-safe. In particular: 30 // * the class assumes that some other party ensures that QueueSdu() is not 31 // invoked concurrently with the destructor, and 32 // * the class assumes that all calls to QueueSdu occur on a single thread, 33 // for the entire lifetime of an object. 34 class EnhancedRetransmissionModeTxEngine final : public TxEngine { 35 public: 36 using ConnectionFailureCallback = fit::function<void()>; 37 38 // Create a transmit engine. 39 // 40 // The engine will invoke channel->SendFrame() when a PDU is ready for 41 // transmission; see tx_engine.h for further detail. 42 // 43 // The engine will invoke |connection_failure_callback| when a fatal error 44 // occurs on this connection. This callback _may_ occur synchronously. For 45 // example, a call to UpdateAckSeq() may synchronously invoke 46 // |connection_failure_callback|. 47 EnhancedRetransmissionModeTxEngine( 48 ChannelId channel_id, 49 uint16_t max_tx_sdu_size, 50 uint8_t max_transmissions, 51 uint8_t n_frames_in_tx_window, 52 TxChannel& channel, 53 ConnectionFailureCallback connection_failure_callback, 54 pw::async::Dispatcher& dispatcher); 55 ~EnhancedRetransmissionModeTxEngine() override = default; 56 57 void NotifySduQueued() override; 58 59 // Updates the Engine's knowledge of the last frame acknowledged by our peer. 60 // The value of |is_poll_response| should reflect the 'F' bit in header of the 61 // frame which led to this call. 62 // 63 // * This _may_ trigger retransmission of previously transmitted data. 64 // * This _may_ cause the (initial) transmission of queued data. 65 void UpdateAckSeq(uint8_t new_seq, bool is_poll_response); 66 67 // Updates the Engine's knowledge of the next frame we expect to receive from 68 // our peer. 69 void UpdateReqSeq(uint8_t new_seq); 70 71 // Informs the Engine that the peer is able to receive frames. 72 void ClearRemoteBusy(); 73 74 // Informs the Engine that the peer is unable to receive additional frames at 75 // this time. 76 void SetRemoteBusy(); 77 78 // Requests that the next UpdateAckSeq always retransmit the frame identified 79 // by its |new_seq| parameter, even if it's not a poll response. This path 80 // fulfills the requirements of receiving the SREJ function. 81 // 82 // Only one of Set{Single,Range}Retransmit can be called before each 83 // UpdateAckSeq. 84 // 85 // |is_poll_request| should be set if the request to retransmit has its P bit 86 // set and will cause the first retransmitted frame to have its 87 // |is_poll_response| bit (F bit) set per the Retransmit-Requested-I-frame 88 // action in Core Spec v5.0 Vol 3, Part A, Sec 8.6.5.6. 89 // 90 // If |is_poll_request| is false, UpdateAckSeq will be inhibited from dropping 91 // the unacked packets from ExpectedAckSeq to |new_seq| because this action is 92 // used to selectively retransmit missing frames that precede frames that the 93 // peer has already received. 94 // 95 // ClearRemoteBusy should be called if necessary because RemoteBusy is cleared 96 // as the first action to take when receiving an SREJ per Core Spec v5.0 Vol 97 // 3, Part A, Sec 8.6.5.9–11. 98 void SetSingleRetransmit(bool is_poll_request); 99 100 // Requests that the next UpdateAckSeq always retransmit starting at its 101 // |new_seq| parameter, even if it's not a poll response. This path fulfills 102 // the requirements of receiving the REJ function. 103 // 104 // Only one of Set{Single,Range}Retransmit can be called before each 105 // UpdateAckSeq. 106 // 107 // |is_poll_request| should be set if the request to retransmit has its P bit 108 // set and will cause the first retransmitted frame to have its 109 // |is_poll_response| bit (F bit) set per the Retransmit-I-frames action in 110 // Core Spec v5.0 Vol 3, Part A, Sec 8.6.5.6. 111 // 112 // ClearRemoteBusy should be called if necessary because RemoteBusy is cleared 113 // as the first action to take when receiving a REJ per Core Spec v5.0 Vol 3, 114 // Part A, Sec 8.6.5.9–11. 115 void SetRangeRetransmit(bool is_poll_request); 116 117 // Transmits data that has been queued, but which has never been previously 118 // sent to our peer. The transmissions are subject to remote-busy and transmit 119 // window constraints. 120 void MaybeSendQueuedData(); 121 122 private: 123 struct PendingPdu { PendingPduPendingPdu124 PendingPdu(DynamicByteBuffer buf_in) 125 : buf(std::move(buf_in)), tx_count(0) {} 126 DynamicByteBuffer buf; 127 uint8_t tx_count; 128 }; 129 130 // State of a request from a peer to retransmit a frame of unacked data (SREJ 131 // per Core Spec v5.0, Vol 3, Part A, Sec 8.6.1.4). 132 struct SingleRetransmitRequest { 133 // True if the request to retransmit has its P bit set. 134 bool is_poll_request; 135 }; 136 137 // State of a request from a peer to retransmit a range of unacked data (REJ 138 // per Core Spec v5.0, Vol 3, Part A, Sec 8.6.1.2). 139 struct RangeRetransmitRequest { 140 // True if the request to retransmit has its P bit set. 141 bool is_poll_request; 142 }; 143 144 // Actions to take with a new AckSeq from the peer. 145 enum class UpdateAckSeqAction { 146 kConsumeAckSeq, // Done with the received AckSeq. 147 kDiscardAcknowledged, // Discard frames prior to AckSeq then send pending 148 // frames. 149 }; 150 151 // Called from UpdateAckSeq to check if a SingleRetransmitRequest is pending. 152 // Retransmits if necessary and returns the action to take with |new_seq|. 153 // 154 // This call clears |single_request_| if set, so it is not idempotent. 155 UpdateAckSeqAction ProcessSingleRetransmitRequest(uint8_t new_seq, 156 bool is_poll_response); 157 158 // Starts the receiver ready poll timer. If already running, the existing 159 // timer is cancelled, and a new timer is started. 160 // Notes: 161 // * The specification refers to this as the "retransmission timer". However, 162 // the expiry of this timer doesn't immediately trigger 163 // retransmission. Rather, the timer expiration triggers us asking the 164 // receiver to acknowledge all previously received data. See 165 // "RetransTimer-Expires", in Core Spec v5.0, Volume 3, Part A, Table 8.4. 166 // * Replacing the existing timer is required per Core Spec v5.0, Volume 3, 167 // Part A, Section 8.6.5.6, "Start-RetransTimer". 168 void StartReceiverReadyPollTimer(); 169 170 // Starts the monitor timer. If already running, the existing timer is 171 // cancelled, and a new timer is started. 172 // 173 // Note that replacing the existing timer is required per Core Spec v5.0, 174 // Volume 3, Part A, Section 8.6.5.6, "Start-MonitorTimer". 175 void StartMonitorTimer(); 176 177 void SendReceiverReadyPoll(); 178 179 // Return and consume the next sequence number. 180 uint8_t GetNextTxSeq(); 181 182 // Returns the number of frames that have been transmitted but not yet 183 // acknowledged. 184 uint8_t NumUnackedFrames(); 185 186 void SendPdu(PendingPdu* pdu); 187 188 // Retransmits frames from |pending_pdus_|. Invokes 189 // |connection_failure_callback_| on error and returns false. Cancels 190 // |monitor_task_| if it's running. 191 // 192 // If |only_with_seq| is set, then only the unacked frame with that TxSeq will 193 // be retransmitted. 194 // 195 // If |set_is_poll_response| is true, then the first frame to be sent will 196 // have its |is_poll_response| field set. 197 // 198 // Notes: 199 // * The caller must ensure that |!remote_is_busy_|. 200 // * When return value is an error, |this| may be invalid. 201 [[nodiscard]] bool RetransmitUnackedData(std::optional<uint8_t> only_with_seq, 202 bool set_is_poll_response); 203 204 // Process a new SDU from the channel queue. 205 void ProcessSdu(ByteBufferPtr sdu); 206 207 pw::async::Dispatcher& pw_dispatcher_; 208 209 const uint8_t max_transmissions_; 210 const uint8_t n_frames_in_tx_window_; 211 212 // Invoked when the connection encounters a fatal error. 213 const ConnectionFailureCallback connection_failure_callback_; 214 215 // The sequence number we expect in the next acknowledgement from our peer. 216 // 217 // We assume that the Extended Window Size option is _not_ enabled. In such 218 // cases, the sequence number is a 6-bit counter that wraps on overflow. See 219 // Core Spec v5.0, Vol 3, Part A, Secs 5.7 and 8.3. 220 uint8_t expected_ack_seq_; 221 222 // The sequence number we will use for the next new outbound I-frame. 223 // 224 // We assume that the Extended Window Size option is _not_ enabled. In such 225 // cases, the sequence number is a 6-bit counter that wraps on overflow. See 226 // Core Spec v5.0, Vol 3, Part A, Secs 5.7 and 8.3. 227 uint8_t next_tx_seq_; 228 229 // The sequence number of the "newest" transmitted frame. 230 // 231 // This sequence number is updated when a new frame is transmitted. This 232 // excludes cases where a frame is queued but not transmitted (due to transmit 233 // window limitations), and cases where a frame is retransmitted. 234 // 235 // This value is useful for determining the number of frames than are 236 // in-flight to our peer (frames that have been transmitted but not 237 // acknowledged). 238 // 239 // We assume that the Extended Window Size option is _not_ enabled. In such 240 // cases, the sequence number is a 6-bit counter that wraps on overflow. See 241 // Core Spec v5.0, Vol 3, Part A, Secs 5.7 and 8.3. 242 uint8_t last_tx_seq_; // (AKA TxSeq) 243 244 // The sequence number we expect for the next packet sent _to_ us. 245 // 246 // We assume that the Extended Window Size option is _not_ enabled. In such 247 // cases, the sequence number is a 6-bit counter that wraps on overflow. See 248 // Core Spec v5.0, Vol 3, Part A, Secs 5.7 and 8.3. 249 uint8_t req_seqnum_; 250 251 // Filled by SetSingleRetransmit and cleared by UpdateAckSeq. 252 std::optional<SingleRetransmitRequest> single_request_; 253 254 // Filled by SetRangeRetransmit and cleared by UpdateAckSeq. 255 std::optional<RangeRetransmitRequest> range_request_; 256 257 // Set to AckSeq of the most recent frame retransmitted after sending a poll 258 // request but before receiving a poll response. Corresponds to the 259 // SrejActioned and SrejSaveReqSeq variables defined in Core Spec v5.0, Vol 3, 260 // Part A, Sec 8.6.5.3. 261 std::optional<uint8_t> retransmitted_single_during_poll_; 262 263 // True if we retransmitted a range of unacked data after sending a poll 264 // request but before receiving a poll response. Corresponds to the 265 // RejActioned variable defined in Core Spec v5.0 Vol 3, Part A, Sec 8.6.5.3. 266 bool retransmitted_range_during_poll_; 267 268 uint8_t n_receiver_ready_polls_sent_; 269 bool remote_is_busy_; 270 std::list<PendingPdu> pending_pdus_; 271 SmartTask receiver_ready_poll_task_{pw_dispatcher_}; 272 SmartTask monitor_task_{pw_dispatcher_}; 273 274 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(EnhancedRetransmissionModeTxEngine); 275 }; 276 277 } // namespace bt::l2cap::internal 278