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