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 "pw_bluetooth_sapphire/internal/host/common/identifier.h" 17 #include "pw_bluetooth_sapphire/internal/host/common/inspectable.h" 18 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h" 19 #include "pw_bluetooth_sapphire/internal/host/gap/generic_access_client.h" 20 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_connection_handle.h" 21 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_connection_request.h" 22 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt.h" 23 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h" 24 #include "pw_bluetooth_sapphire/internal/host/hci/low_energy_connection.h" 25 #include "pw_bluetooth_sapphire/internal/host/iso/iso_stream_manager.h" 26 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_manager.h" 27 #include "pw_bluetooth_sapphire/internal/host/sm/delegate.h" 28 #include "pw_bluetooth_sapphire/internal/host/sm/types.h" 29 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h" 30 31 namespace bt::sm { 32 class SecurityManager; 33 } 34 35 namespace bt::gap { 36 37 namespace internal { 38 39 // LowEnergyConnector constructs LowEnergyConnection instances immediately upon 40 // successful completion of the link layer connection procedure (to hook up HCI 41 // event callbacks). However, LowEnergyConnections aren't exposed to the rest of 42 // the stack (including the LowEnergyConnectionManager) until fully 43 // interrogated, as completion of the link-layer connection process is 44 // insufficient to guarantee a working connection. Thus this class represents 45 // the state of an active *AND* (outside of LowEnergyConnector) known-functional 46 // connection. 47 // 48 // Instances are kept alive as long as there is at least one 49 // LowEnergyConnectionHandle that references them. Instances are expected to be 50 // destroyed immediately after a peer disconnect event is received (as indicated 51 // by peer_disconnect_cb). 52 class LowEnergyConnection final : public sm::Delegate { 53 public: 54 // |peer| is the peer that this connection is connected to. 55 // |link| is the underlying LE HCI connection that this connection corresponds 56 // to. |peer_disconnect_cb| will be called when the peer disconnects. It will 57 // not be called before this method returns. |error_cb| will be called when a 58 // fatal connection error occurs and the connection should be closed (e.g. 59 // when L2CAP reports an error). It will not be called before this method 60 // returns. |conn_mgr| is the LowEnergyConnectionManager that owns this 61 // connection. |l2cap|, |gatt|, and |hci| are pointers to the interfaces of 62 // the corresponding layers. Returns nullptr if connection initialization 63 // fails. 64 using PeerDisconnectCallback = 65 fit::callback<void(pw::bluetooth::emboss::StatusCode)>; 66 using ErrorCallback = fit::callback<void()>; 67 static std::unique_ptr<LowEnergyConnection> Create( 68 Peer::WeakPtr peer, 69 std::unique_ptr<hci::LowEnergyConnection> link, 70 LowEnergyConnectionOptions connection_options, 71 PeerDisconnectCallback peer_disconnect_cb, 72 ErrorCallback error_cb, 73 WeakSelf<LowEnergyConnectionManager>::WeakPtr conn_mgr, 74 l2cap::ChannelManager* l2cap, 75 gatt::GATT::WeakPtr gatt, 76 hci::Transport::WeakPtr hci, 77 pw::async::Dispatcher& dispatcher); 78 79 // Notifies request callbacks and connection refs of the disconnection. 80 ~LowEnergyConnection() override; 81 82 // Create a reference to this connection. When the last reference is dropped, 83 // this connection will be disconnected. 84 std::unique_ptr<LowEnergyConnectionHandle> AddRef(); 85 86 // Decrements the ref count. Must be called when a LowEnergyConnectionHandle 87 // is released/destroyed. 88 void DropRef(LowEnergyConnectionHandle* ref); 89 90 // Used to respond to protocol/service requests for increased security. 91 void OnSecurityRequest(sm::SecurityLevel level, sm::ResultFunction<> cb); 92 93 // Handles a pairing request (i.e. security upgrade) received from "higher 94 // levels", likely initiated from GAP. This will only be used by pairing 95 // requests that are initiated in the context of testing. May only be called 96 // on an already-established connection. 97 void UpgradeSecurity(sm::SecurityLevel level, 98 sm::BondableMode bondable_mode, 99 sm::ResultFunction<> cb); 100 101 // Cancels any on-going pairing procedures and sets up SMP to use the provided 102 // new I/O capabilities for future pairing procedures. 103 void ResetSecurityManager(sm::IOCapability ioc); 104 105 // Must be called when interrogation has completed. May update connection 106 // parameters if all initialization procedures have completed. 107 void OnInterrogationComplete(); 108 109 // Opens an L2CAP channel using the parameters |params|. Otherwise, calls |cb| 110 // with a nullptr. 111 void OpenL2capChannel(l2cap::Psm psm, 112 l2cap::ChannelParameters params, 113 l2cap::ChannelCallback cb); 114 115 // Accept a future incoming request to establish an Isochronous stream on this 116 // LE connection. |id| specifies the CIG/CIS pair that identify the stream. 117 // |cb| will be called after the request is received to indicate success of 118 // establishing a stream, and the associated parameters. 119 iso::AcceptCisStatus AcceptCis(iso::CigCisIdentifier id, 120 iso::CisEstablishedCallback cb); 121 122 // Attach connection as child node of |parent| with specified |name|. 123 void AttachInspect(inspect::Node& parent, std::string name); 124 125 void set_security_mode(LESecurityMode mode); 126 127 // Sets a callback that will be called when the peer disconnects. set_peer_disconnect_callback(PeerDisconnectCallback cb)128 void set_peer_disconnect_callback(PeerDisconnectCallback cb) { 129 PW_CHECK(cb); 130 peer_disconnect_callback_ = std::move(cb); 131 } 132 133 // |peer_conn_token| is a token generated by the connected Peer, and is used 134 // to synchronize connection state. set_peer_conn_token(Peer::ConnectionToken peer_conn_token)135 void set_peer_conn_token(Peer::ConnectionToken peer_conn_token) { 136 PW_CHECK(interrogation_completed_); 137 PW_CHECK(!peer_conn_token_); 138 peer_conn_token_ = std::move(peer_conn_token); 139 } 140 141 // Sets a callback that will be called when a fatal connection error occurs. set_error_callback(ErrorCallback cb)142 void set_error_callback(ErrorCallback cb) { 143 PW_CHECK(cb); 144 error_callback_ = std::move(cb); 145 } 146 ref_count()147 size_t ref_count() const { return refs_->size(); } 148 peer_id()149 PeerId peer_id() const { return peer_->identifier(); } handle()150 hci_spec::ConnectionHandle handle() const { return link_->handle(); } link()151 hci::LowEnergyConnection* link() const { return link_.get(); } 152 sm::BondableMode bondable_mode() const; 153 154 sm::SecurityProperties security() const; 155 role()156 pw::bluetooth::emboss::ConnectionRole role() const { return link()->role(); } 157 158 using WeakPtr = WeakSelf<LowEnergyConnection>::WeakPtr; GetWeakPtr()159 LowEnergyConnection::WeakPtr GetWeakPtr() { return weak_self_.GetWeakPtr(); } 160 161 private: 162 LowEnergyConnection(Peer::WeakPtr peer, 163 std::unique_ptr<hci::LowEnergyConnection> link, 164 LowEnergyConnectionOptions connection_options, 165 PeerDisconnectCallback peer_disconnect_cb, 166 ErrorCallback error_cb, 167 WeakSelf<LowEnergyConnectionManager>::WeakPtr conn_mgr, 168 std::unique_ptr<iso::IsoStreamManager> iso_mgr, 169 l2cap::ChannelManager* l2cap, 170 gatt::GATT::WeakPtr gatt, 171 hci::Transport::WeakPtr hci, 172 pw::async::Dispatcher& dispatcher); 173 174 // Registers this connection with L2CAP and initializes the fixed channel 175 // protocols. Return true on success, false on failure. 176 [[nodiscard]] bool InitializeFixedChannels(); 177 178 // Register handlers for HCI events that correspond to this connection. 179 void RegisterEventHandlers(); 180 181 // Start kLEConnectionPauseCentral/Peripheral timeout that will update 182 // connection parameters. Should be called as soon as this GAP connection is 183 // established. 184 void StartConnectionPauseTimeout(); 185 186 // Start kLEConnectionPausePeripheral timeout that will send a connection 187 // parameter update request. Should be called as soon as connection is 188 // established. 189 void StartConnectionPausePeripheralTimeout(); 190 191 // Start kLEConnectionPauseCentral timeout that will update connection 192 // parameters. Should be called as soon as connection is established. 193 void StartConnectionPauseCentralTimeout(); 194 195 // Initializes SecurityManager and GATT. 196 // Called by the L2CAP layer once the link has been registered and the fixed 197 // channels have been opened. Returns false if GATT initialization fails. 198 [[nodiscard]] bool OnL2capFixedChannelsOpened( 199 l2cap::Channel::WeakPtr att, 200 l2cap::Channel::WeakPtr smp, 201 LowEnergyConnectionOptions connection_options); 202 203 // Called when the preferred connection parameters have been received for a LE 204 // peripheral. This can happen in the form of: 205 // 206 // 1. <<Peripheral Connection Interval Range>> advertising data field 207 // 2. "Peripheral Preferred Connection Parameters" GATT characteristic 208 // (under "GAP" service) 209 // 3. HCI LE Remote Connection Parameter Request Event 210 // 4. L2CAP Connection Parameter Update request 211 // 212 // TODO(fxbug.dev/42147867): Support #1 above. 213 // TODO(fxbug.dev/42147868): Support #3 above. 214 // 215 // This method caches |params| for later connection attempts and sends the 216 // parameters to the controller if the initializing procedures are complete 217 // (since we use more agressing initial parameters for pairing and service 218 // discovery, as recommended by the specification in v5.0, Vol 3, Part C, 219 // Section 9.3.12.1). 220 // 221 // |peer_id| uniquely identifies the peer. |handle| represents 222 // the logical link that |params| should be applied to. 223 void OnNewLEConnectionParams( 224 const hci_spec::LEPreferredConnectionParameters& params); 225 226 // As an LE peripheral, request that the connection parameters |params| be 227 // used on the given connection |conn| with peer |peer_id|. This may send an 228 // HCI LE Connection Update command or an L2CAP Connection Parameter Update 229 // Request depending on what the local and remote controllers support. 230 // 231 // Interrogation must have completed before this may be called. 232 void RequestConnectionParameterUpdate( 233 const hci_spec::LEPreferredConnectionParameters& params); 234 235 // Handler for connection parameter update command sent when an update is 236 // requested by RequestConnectionParameterUpdate. 237 // 238 // If the HCI LE Connection Update command fails with status 239 // kUnsupportedRemoteFeature, the update will be retried with an L2CAP 240 // Connection Parameter Update Request. 241 void HandleRequestConnectionParameterUpdateCommandStatus( 242 hci_spec::LEPreferredConnectionParameters params, hci::Result<> status); 243 244 // As an LE peripheral, send an L2CAP Connection Parameter Update Request 245 // requesting |params| on the LE signaling channel of the given logical link 246 // |handle|. 247 // 248 // NOTE: This should only be used if the LE peripheral and/or LE central do 249 // not support the Connection Parameters Request Link Layer Control Procedure 250 // (Core Spec v5.2 Vol 3, Part A, Sec 4.20). If they do, 251 // UpdateConnectionParams(...) should be used instead. 252 void L2capRequestConnectionParameterUpdate( 253 const hci_spec::LEPreferredConnectionParameters& params); 254 255 // Requests that the controller use the given connection |params| by sending 256 // an HCI LE Connection Update command. This may be issued on both the LE 257 // peripheral and the LE central. 258 // 259 // The link layer may modify the preferred parameters |params| before 260 // initiating the Connection Parameters Request Link Layer Control Procedure 261 // (Core Spec v5.2, Vol 6, Part B, Sec 5.1.7). 262 // 263 // If non-null, |status_cb| will be called when the HCI Command Status event 264 // is received. 265 // 266 // The HCI LE Connection Update Complete event will be generated after the 267 // parameters have been applied or if the update fails, and will indicate the 268 // (possibly modified) parameter values. 269 // 270 // NOTE: If the local host is an LE peripheral, then the local controller and 271 // the remote LE central must have indicated support for this procedure in the 272 // LE feature mask. Otherwise, L2capRequestConnectionParameterUpdate(...) 273 // should be used instead. 274 using StatusCallback = hci::ResultCallback<>; 275 void UpdateConnectionParams( 276 const hci_spec::LEPreferredConnectionParameters& params, 277 StatusCallback status_cb = nullptr); 278 279 // This event may be generated without host interaction by the Link Layer, or 280 // as the result of a Connection Update Command sent by either device, which 281 // is why it is not simply handled by the command handler. (See Core Spec 282 // v5.2, Vol 6, Part B, Sec 5.1.7.1). 283 void OnLEConnectionUpdateComplete(const hci::EventPacket& event); 284 285 // Updates or requests an update of the connection parameters, for central and 286 // peripheral roles respectively, if interrogation has completed. 287 // TODO(fxbug.dev/42159733): Wait to update connection parameters until all 288 // initialization procedures have completed. 289 void MaybeUpdateConnectionParameters(); 290 291 // Registers the peer with GATT and initiates service discovery. If 292 // |service_uuid| is specified, only discover the indicated service and the 293 // GAP service. Returns true on success, false on failure. 294 bool InitializeGatt(l2cap::Channel::WeakPtr att, 295 std::optional<UUID> service_uuid); 296 297 // Called when service discovery completes. |services| will only include 298 // services with the GAP UUID (there should only be one, but this is not 299 // guaranteed). 300 void OnGattServicesResult(att::Result<> status, gatt::ServiceList services); 301 302 // Notifies all connection refs of disconnection. 303 void CloseRefs(); 304 305 // sm::Delegate overrides: 306 void OnNewPairingData(const sm::PairingData& pairing_data) override; 307 void OnPairingComplete(sm::Result<> status) override; 308 void OnAuthenticationFailure(hci::Result<> status) override; 309 void OnNewSecurityProperties(const sm::SecurityProperties& sec) override; 310 std::optional<sm::IdentityInfo> OnIdentityInformationRequest() override; 311 void ConfirmPairing(ConfirmCallback confirm) override; 312 void DisplayPasskey(uint32_t passkey, 313 sm::Delegate::DisplayMethod method, 314 ConfirmCallback confirm) override; 315 void RequestPasskey(PasskeyResponseCallback respond) override; 316 317 pw::async::Dispatcher& dispatcher_; 318 319 // Notifies Peer of connection destruction. This should be ordered first so 320 // that it is destroyed last. 321 std::optional<Peer::ConnectionToken> peer_conn_token_; 322 323 Peer::WeakPtr peer_; 324 std::unique_ptr<hci::LowEnergyConnection> link_; 325 LowEnergyConnectionOptions connection_options_; 326 WeakSelf<LowEnergyConnectionManager>::WeakPtr conn_mgr_; 327 328 // Manages all Isochronous streams for this connection. If this connection is 329 // operating as a Central, |iso_mgr_| is used to establish an outgoing 330 // connection to a peer. When operating as a Peripheral, |iso_mgr_| is used to 331 // allow incoming requests for specified CIG/CIS combinations. 332 std::unique_ptr<iso::IsoStreamManager> iso_mgr_; 333 334 struct InspectProperties { 335 inspect::StringProperty peer_id; 336 inspect::StringProperty peer_address; 337 }; 338 InspectProperties inspect_properties_; 339 inspect::Node inspect_node_; 340 341 // Used to update the L2CAP layer to reflect the correct link security level. 342 l2cap::ChannelManager* l2cap_; 343 344 // Reference to the GATT profile layer is used to initiate service discovery 345 // and register the link. 346 gatt::GATT::WeakPtr gatt_; 347 348 // The ATT Bearer is owned by LowEnergyConnection but weak pointers are passed 349 // to the GATT layer. As such, this connection must be unregistered from the 350 // GATT layer before the Bearer is destroyed. Created during initialization, 351 // but if initialization fails this may be nullptr. 352 std::unique_ptr<att::Bearer> att_bearer_; 353 354 // SMP pairing manager. 355 std::unique_ptr<sm::SecurityManager> sm_; 356 357 hci::CommandChannel::WeakPtr cmd_; 358 359 hci::Transport::WeakPtr hci_; 360 361 // Called when the peer disconnects. 362 PeerDisconnectCallback peer_disconnect_callback_; 363 364 // Called when a fatal connection error occurs and the connection should be 365 // closed (e.g. when L2CAP reports an error). 366 ErrorCallback error_callback_; 367 368 // Event handler ID for the HCI LE Connection Update Complete event. 369 hci::CommandChannel::EventHandlerId conn_update_cmpl_handler_id_; 370 371 // Called with the status of the next HCI LE Connection Update Complete event. 372 // The HCI LE Connection Update command does not have its own complete event 373 // handler because the HCI LE Connection Complete event can be generated for 374 // other reasons. 375 fit::callback<void(pw::bluetooth::emboss::StatusCode)> 376 le_conn_update_complete_command_callback_; 377 378 // Called after kLEConnectionPausePeripheral. 379 std::optional<SmartTask> conn_pause_peripheral_timeout_; 380 381 // Called after kLEConnectionPauseCentral. 382 std::optional<SmartTask> conn_pause_central_timeout_; 383 384 // Set to true when a request to update the connection parameters has been 385 // sent. 386 bool connection_parameters_update_requested_ = false; 387 388 bool interrogation_completed_ = false; 389 390 // LowEnergyConnectionManager is responsible for making sure that these 391 // pointers are always valid. 392 using ConnectionHandleSet = std::unordered_set<LowEnergyConnectionHandle*>; 393 IntInspectable<ConnectionHandleSet> refs_; 394 395 // Null until service discovery completes. 396 std::optional<GenericAccessClient> gap_service_client_; 397 398 WeakSelf<LowEnergyConnection> weak_self_; 399 WeakSelf<sm::Delegate> weak_delegate_; 400 401 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyConnection); 402 }; 403 404 } // namespace internal 405 } // namespace bt::gap 406