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