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 <unordered_map>
19 
20 #include "pw_bluetooth_sapphire/internal/host/l2cap/bredr_command_handler.h"
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/dynamic_channel_registry.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
23 #include "pw_bluetooth_sapphire/internal/host/l2cap/signaling_channel.h"
24 #include "pw_bluetooth_sapphire/internal/host/l2cap/types.h"
25 
26 namespace bt::l2cap::internal {
27 
28 // Implements factories for BR/EDR dynamic channels and dispatches incoming
29 // signaling channel requests to the corresponding channels by local ID.
30 //
31 // Must be run only on the L2CAP thread.
32 class BrEdrDynamicChannelRegistry final : public DynamicChannelRegistry {
33  public:
34   BrEdrDynamicChannelRegistry(SignalingChannelInterface* sig,
35                               DynamicChannelCallback close_cb,
36                               ServiceRequestCallback service_request_cb,
37                               bool random_channel_ids);
38   ~BrEdrDynamicChannelRegistry() override = default;
39 
extended_features()40   std::optional<ExtendedFeatures> extended_features() {
41     return extended_features_;
42   }
43 
44  private:
45   // DynamicChannelRegistry override
46   DynamicChannelPtr MakeOutbound(Psm psm,
47                                  ChannelId local_cid,
48                                  ChannelParameters params) override;
49   DynamicChannelPtr MakeInbound(Psm psm,
50                                 ChannelId local_cid,
51                                 ChannelId remote_cid,
52                                 ChannelParameters params) override;
53 
54   // Signaling channel request handlers
55   void OnRxConnReq(Psm psm,
56                    ChannelId remote_cid,
57                    BrEdrCommandHandler::ConnectionResponder* responder);
58   void OnRxConfigReq(ChannelId local_cid,
59                      uint16_t flags,
60                      ChannelConfiguration config,
61                      BrEdrCommandHandler::ConfigurationResponder* responder);
62   void OnRxDisconReq(ChannelId local_cid,
63                      ChannelId remote_cid,
64                      BrEdrCommandHandler::DisconnectionResponder* responder);
65   void OnRxInfoReq(InformationType type,
66                    BrEdrCommandHandler::InformationResponder* responder);
67 
68   // Signaling channel response handlers
69   void OnRxExtendedFeaturesInfoRsp(
70       const BrEdrCommandHandler::InformationResponse& rsp);
71 
72   // Send extended features information request.
73   // TODO(fxbug.dev/42174624): Send fixed channels information request.
74   void SendInformationRequests();
75 
76   // If an extended features information response has been received, returns the
77   // value of the ERTM bit in the peer's feature mask.
78   std::optional<bool> PeerSupportsERTM() const;
79 
80   using State = uint8_t;
81   enum StateBit : State {
82     // Extended Features Information Request (transmitted from local to remote)
83     kExtendedFeaturesSent = (1 << 0),
84 
85     // Extended Features Information Response (transmitted from remote to local)
86     kExtendedFeaturesReceived = (1 << 1),
87   };
88 
89   // Bit field assembled using the bit masks above.
90   State state_;
91 
92   SignalingChannelInterface* const sig_;
93 
94   std::optional<ExtendedFeatures> extended_features_;
95 };
96 
97 class BrEdrDynamicChannel;
98 using BrEdrDynamicChannelPtr = std::unique_ptr<BrEdrDynamicChannel>;
99 
100 // Creates, configures, and tears down dynamic channels using the BR/EDR
101 // signaling channel. The lifetime of this object matches that of the channel
102 // itself: created in order to start an outbound channel or in response to an
103 // inbound channel request, then destroyed immediately after the channel is
104 // closed. This is intended to be created and owned by
105 // BrEdrDynamicChannelRegistry.
106 //
107 // This implements the state machine described by v5.0 Vol 3 Part A Sec 6. The
108 // state of OPEN ("user data transfer state") matches the implementation of the
109 // |DynamicChannel::IsOpen()|.
110 //
111 // Channel Configuration design:
112 // Implementation-defined behavior:
113 // * Inbound and outbound configuration requests/responses are exchanged
114 // simultaneously
115 // * If the desired channel mode is ERTM, the configuration request is not sent
116 // until the extended
117 //   features mask is received from the peer.
118 //   * If the peer doesn't support ERTM, the local device will negotiate Basic
119 //   Mode instead of ERTM
120 // * after both configuration requests have been accepted, if they are
121 // inconsistent, the channel
122 //   is disconnected (this can happen if the peer doesn't follow the spec)
123 // Configuration Request Handling:
124 // * when the peer requests an MTU below the minumum, send an Unacceptable
125 // Parameters response
126 //     suggesting the minimum MTU.
127 // * allow peer to send a maximum of 2 configuration requests with undesired
128 // channel modes
129 //   before disconnecting
130 // * reject all channel modes other than Basic Mode and ERTM
131 // Negative Configuration Response Handling:
132 // A maximum of 2 negotiation attempts will be made before disconnecting,
133 // according to the following rules:
134 // * if the response does not contain the Retransmission & Flow Control option,
135 // disconnect
136 // * when the response specifies a different channel mode than the peer sent in
137 // a configuration
138 //   request, disconnect
139 // * when the response rejected Basic Mode, disconnect
140 // * otherwise, send a second configuration request with Basic Mode
141 //
142 // Must be run only on the L2CAP thread.
143 class BrEdrDynamicChannel final : public DynamicChannel {
144  public:
145   using ResponseHandlerAction = SignalingChannel::ResponseHandlerAction;
146 
147   static BrEdrDynamicChannelPtr MakeOutbound(
148       DynamicChannelRegistry* registry,
149       SignalingChannelInterface* signaling_channel,
150       Psm psm,
151       ChannelId local_cid,
152       ChannelParameters params,
153       std::optional<bool> peer_supports_ertm);
154 
155   static BrEdrDynamicChannelPtr MakeInbound(
156       DynamicChannelRegistry* registry,
157       SignalingChannelInterface* signaling_channel,
158       Psm psm,
159       ChannelId local_cid,
160       ChannelId remote_cid,
161       ChannelParameters params,
162       std::optional<bool> peer_supports_ertm);
163 
164   // DynamicChannel overrides
165   ~BrEdrDynamicChannel() override = default;
166 
167   void Open(fit::closure open_cb) override;
168 
169   // Mark this channel as closed and disconnected. Send a Disconnection Request
170   // to the peer if possible (peer had sent an ID for its endpoint). |done_cb|
171   // will be called when Disconnection Response is received or if channel is
172   // already not connected.
173   void Disconnect(DisconnectDoneCallback done_cb) override;
174 
175   bool IsConnected() const override;
176   bool IsOpen() const override;
177 
178   // Must not be called until channel is open.
179   ChannelInfo info() const override;
180 
181   // Inbound request handlers. Request must have a destination channel ID that
182   // matches this instance's |local_cid|.
183   void OnRxConfigReq(uint16_t flags,
184                      ChannelConfiguration config,
185                      BrEdrCommandHandler::ConfigurationResponder* responder);
186   void OnRxDisconReq(BrEdrCommandHandler::DisconnectionResponder* responder);
187 
188   // Called when the peer indicates whether it supports Enhanced Retransmission
189   // Mode. Kicks off the configuration process if the preferred channel mode is
190   // ERTM.
191   void SetEnhancedRetransmissionSupport(bool supported);
192 
193   // Reply with affirmative connection response and begin configuration.
194   void CompleteInboundConnection(
195       BrEdrCommandHandler::ConnectionResponder* responder);
196 
197   // Contains options configured by remote configuration requests (Core Spec
198   // v5.1, Vol 3, Part A, Sections 5 and 7.1.1).
remote_config()199   const ChannelConfiguration& remote_config() const { return remote_config_; }
200 
201   // Contains options configured by local configuration requests (Core Spec
202   // v5.1, Vol 3, Part A, Sections 5 and 7.1.2).
local_config()203   const ChannelConfiguration& local_config() const { return local_config_; }
204 
205  private:
206   // The channel configuration state is described in v5.0 Vol 3 Part A Sec 6 (in
207   // particular in Fig. 6.2) as having numerous substates in order to capture
208   // the different orders in which configuration packets may be transmitted. It
209   // is implemented here as a bitfield where bits are set as each packet is
210   // transmitted.
211   //
212   // The initial state for a channel prior to any signaling packets transmitted
213   // is 0.
214   using State = uint8_t;
215   enum StateBit : State {
216     // Connection Req (transmitted in either direction)
217     kConnRequested = (1 << 0),
218 
219     // Connection Rsp (transmitted in opposite direction of Connection Req)
220     kConnResponded = (1 << 1),
221 
222     // Configuration Req (transmitted from local to remote)
223     kLocalConfigSent = (1 << 2),
224 
225     // Configuration Rsp (successful; transmitted from remote to local)
226     kLocalConfigAccepted = (1 << 3),
227 
228     // Configuration Req (transmitted from remote to local)
229     kRemoteConfigReceived = (1 << 4),
230 
231     // Configuration Rsp (successful; transmitted from local to remote)
232     kRemoteConfigAccepted = (1 << 5),
233 
234     // Disconnection Req (transmitted in either direction)
235     kDisconnected = (1 << 6),
236   };
237 
238   // TODO(fxbug.dev/42182060): Add Extended Flow Specification steps (exchange &
239   // controller configuration)
240 
241   BrEdrDynamicChannel(DynamicChannelRegistry* registry,
242                       SignalingChannelInterface* signaling_channel,
243                       Psm psm,
244                       ChannelId local_cid,
245                       ChannelId remote_cid,
246                       ChannelParameters params,
247                       std::optional<bool> peer_supports_ertm);
248 
249   // Deliver the result of channel connection and configuration to the |Open|
250   // originator. Can be called multiple times but only the first invocation
251   // passes the result.
252   void PassOpenResult();
253 
254   // Error during channel connection or configuration (before it is open).
255   // Deliver the error open result to the |Open| originator. Disconnect the
256   // remote endpoint of the channel if possible. If the channel is already open,
257   // use |Disconnect| instead.
258   void PassOpenError();
259 
260   // Overwrites the local configuration's MTU and Retransmission & Flow Control
261   // options using ChannelParameters provided by the local service and the
262   // peer's support for Enhanced Retransmission Mode (set using
263   // SetEnhancedRetransmissionSupport).
264   void UpdateLocalConfigForErtm();
265 
266   // Returns the maximum outbound SDU size based on service preference provided
267   // in ChannelParameters, specification limits, and ERTM transmission
268   // constraints.
269   uint16_t CalculateLocalMtu() const;
270 
271   // Returns true if the local service prefers ERTM and the peer has indicated
272   // support for ERTM.
273   bool ShouldRequestEnhancedRetransmission() const;
274 
275   // Returns true if the preferred channel parameters require waiting for an
276   // extended features information response and the response has not yet been
277   // received. Must be false before sending local config.
278   bool IsWaitingForPeerErtmSupport();
279 
280   // Begin the local channel Configuration Request flow if it has not yet
281   // happened. The channel must not be waiting for the extended features info
282   // response.
283   void TrySendLocalConfig();
284 
285   // Send local configuration request.
286   void SendLocalConfig();
287 
288   // Returns true if both the remote and local configs have been accepted.
289   bool BothConfigsAccepted() const;
290 
291   // Returns true if negotiated channel modes are consistent. Must not be called
292   // until after both configs have been accepted (|BothConfigsAccepted()| is
293   // true).
294   [[nodiscard]] bool AcceptedChannelModesAreConsistent() const;
295 
296   // Checks options in a configuration request for unacceptable MTU and
297   // Retransmission and Flow Control options. Returns a configuration object
298   // where for each unacceptable option, there is a corresponding option with a
299   // value that would have been accepted if sent in the original request.
300   [[nodiscard]] ChannelConfiguration CheckForUnacceptableConfigReqOptions(
301       const ChannelConfiguration& config) const;
302 
303   // Checks parameters for Enhanced Retransmission Mode in the Retransmission &
304   // Flow Control and if there are any unacceptable values, returns an option
305   // containing values that would have been accepted. Otherwise, returns
306   // std::nullopt.
307   [[nodiscard]] std::optional<
308       ChannelConfiguration::RetransmissionAndFlowControlOption>
309   CheckForUnacceptableErtmOptions(const ChannelConfiguration& config) const;
310 
311   // Try to recover from a configuration response with the "Unacceptable
312   // Parameters" result. Returns true if the negative response could be
313   // recovered from, and false otherwise (in which case an error should be
314   // reported).
315   [[nodiscard]] bool TryRecoverFromUnacceptableParametersConfigRsp(
316       const ChannelConfiguration& config);
317 
318   // Response handlers for outbound requests
319   ResponseHandlerAction OnRxConnRsp(
320       const BrEdrCommandHandler::ConnectionResponse& rsp);
321   ResponseHandlerAction OnRxConfigRsp(
322       const BrEdrCommandHandler::ConfigurationResponse& rsp);
323 
324   SignalingChannelInterface* const signaling_channel_;
325 
326   // Preferred parameters from the local service.
327   const ChannelParameters parameters_;
328 
329   // Bit field assembled using the bit masks above. When zero, it represents a
330   // closed (i.e. not yet open) channel.
331   State state_;
332 
333   // This shall be reset to nullptr after invocation to enforce its single-use
334   // semantics. See |DynamicChannel::Open| for details.
335   fit::closure open_result_cb_;
336 
337   // Support for ERTM is indicated in the peer's extended features mask,
338   // received in the extended features information response. Since the response
339   // may not yet have been received when this channel is created, this value may
340   // be assigned in either the constructor or in the
341   // |SetEnhancedRetransmissionSupport| callback. This will be set to false if
342   // the peer rejects ERTM during negotiation and set to true if the peer
343   // requests ERTM before responding to the extended features information
344   // request.
345   std::optional<bool> peer_supports_ertm_;
346 
347   // Contains options configured by remote configuration requests (Core Spec
348   // v5.1, Vol 3, Part A, Sections 5 and 7.1.1).
349   ChannelConfiguration remote_config_;
350 
351   // Each peer configuration request may be split into multiple requests with
352   // the continuation flag (C) set to 1. This variable accumulates the options
353   // received in each request until C is 0. This is not simply done with
354   // |remote_config_| because the previous value of |remote_config_| may be
355   // accessed during this process, or the final request may be rejected. This
356   // variable is nullopt when no sequence of continuation requests is being
357   // processed.
358   std::optional<ChannelConfiguration> remote_config_accum_;
359 
360   // Contains options configured by local configuration requests (Core Spec
361   // v5.1, Vol 3, Part A, Sections 5 and 7.1.2).
362   ChannelConfiguration local_config_;
363 
364   WeakSelf<BrEdrDynamicChannel> weak_self_;
365 
366   // Counter for number of basic mode configuration requests
367   uint8_t num_basic_config_requests_ = 0;
368 };
369 
370 }  // namespace bt::l2cap::internal
371