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 #include <memory> 20 #include <unordered_map> 21 #include <unordered_set> 22 #include <vector> 23 24 #include "lib/fit/result.h" 25 #include "pw_bluetooth_sapphire/internal/host/common/error.h" 26 #include "pw_bluetooth_sapphire/internal/host/common/macros.h" 27 #include "pw_bluetooth_sapphire/internal/host/common/metrics.h" 28 #include "pw_bluetooth_sapphire/internal/host/common/windowed_inspect_numeric_property.h" 29 #include "pw_bluetooth_sapphire/internal/host/gap/adapter_state.h" 30 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h" 31 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_connection_request.h" 32 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_connector.h" 33 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_discovery_manager.h" 34 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt.h" 35 #include "pw_bluetooth_sapphire/internal/host/hci/low_energy_connection.h" 36 #include "pw_bluetooth_sapphire/internal/host/hci/low_energy_connector.h" 37 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_manager.h" 38 #include "pw_bluetooth_sapphire/internal/host/sm/error.h" 39 #include "pw_bluetooth_sapphire/internal/host/sm/types.h" 40 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h" 41 #include "pw_bluetooth_sapphire/internal/host/transport/control_packets.h" 42 #include "pw_bluetooth_sapphire/internal/host/transport/error.h" 43 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h" 44 45 namespace bt { 46 47 namespace sm { 48 using SecurityManagerFactory = std::function<std::unique_ptr<SecurityManager>( 49 hci::LowEnergyConnection::WeakPtr, 50 l2cap::Channel::WeakPtr, 51 IOCapability, 52 Delegate::WeakPtr, 53 BondableMode, 54 gap::LESecurityMode, 55 pw::async::Dispatcher&)>; 56 } // namespace sm 57 58 namespace hci { 59 class LocalAddressDelegate; 60 } // namespace hci 61 62 namespace gap { 63 64 namespace internal { 65 class LowEnergyConnection; 66 } // namespace internal 67 68 // TODO(armansito): Document the usage pattern. 69 70 class LowEnergyConnectionManager; 71 class PairingDelegate; 72 class Peer; 73 class PeerCache; 74 75 enum class LowEnergyDisconnectReason : uint8_t { 76 // Explicit disconnect request 77 kApiRequest, 78 // An internal error was encountered 79 kError, 80 }; 81 82 // LowEnergyConnectionManager is responsible for connecting and initializing new 83 // connections, interrogating connections, intiating pairing, and disconnecting 84 // connections. 85 class LowEnergyConnectionManager final { 86 public: 87 // Duration after which connection failures are removed from Inspect. 88 static constexpr pw::chrono::SystemClock::duration 89 kInspectRecentConnectionFailuresExpiryDuration = std::chrono::minutes(10); 90 91 // |hci|: The HCI transport used to track link layer connection events from 92 // the controller. 93 // |addr_delegate|: Used to obtain local identity information during pairing 94 // procedures. 95 // |connector|: Adapter object for initiating link layer connections. This 96 // object abstracts the legacy and extended HCI command sets. 97 // |peer_cache|: The cache that stores peer peer data. The connection 98 // manager stores and retrieves pairing data and connection 99 // parameters to/from the cache. It also updates the 100 // connection and bonding state of a peer via the cache. 101 // |l2cap|: Used to interact with the L2CAP layer. 102 // |gatt|: Used to interact with the GATT profile layer. 103 // |adapter_state|: Provides information on controller capabilities. 104 LowEnergyConnectionManager( 105 hci::Transport::WeakPtr hci, 106 hci::LocalAddressDelegate* addr_delegate, 107 hci::LowEnergyConnector* connector, 108 PeerCache* peer_cache, 109 l2cap::ChannelManager* l2cap, 110 gatt::GATT::WeakPtr gatt, 111 LowEnergyDiscoveryManager::WeakPtr discovery_manager, 112 sm::SecurityManagerFactory sm_creator, 113 const AdapterState& adapter_state, 114 pw::async::Dispatcher& dispatcher); 115 ~LowEnergyConnectionManager(); 116 117 // Allows a caller to claim shared ownership over a connection to the 118 // requested remote LE peer identified by |peer_id|. 119 // * If |peer_id| is not recognized, |callback| is called with an error. 120 // 121 // * If the requested peer is already connected, |callback| is called with a 122 // LowEnergyConnectionHandle immediately. 123 // This is done for both local and remote initiated connections (i.e. the 124 // local adapter can either be in the LE central or peripheral roles). 125 // 126 // * If the requested peer is NOT connected, then this method initiates a 127 // connection to the requested peer using the 128 // internal::LowEnergyConnector. See that class's documentation for a more 129 // detailed overview of the Connection process. A 130 // LowEnergyConnectionHandle is asynchronously returned to the caller once 131 // the connection has been set up. 132 // 133 // The status of the procedure is reported in |callback| in the case of an 134 // error. 135 using ConnectionResult = 136 fit::result<HostError, std::unique_ptr<LowEnergyConnectionHandle>>; 137 using ConnectionResultCallback = fit::function<void(ConnectionResult)>; 138 void Connect(PeerId peer_id, 139 ConnectionResultCallback callback, 140 LowEnergyConnectionOptions connection_options); 141 local_address_delegate()142 hci::LocalAddressDelegate* local_address_delegate() const { 143 return local_address_delegate_; 144 } 145 146 // Disconnects any existing or pending LE connection to |peer_id|, 147 // invalidating all active LowEnergyConnectionHandles. Returns false if the 148 // peer can not be disconnected. 149 bool Disconnect(PeerId peer_id, 150 LowEnergyDisconnectReason reason = 151 LowEnergyDisconnectReason::kApiRequest); 152 153 // Initializes a new connection over the given |link| and asynchronously 154 // returns a connection reference. 155 // 156 // |link| must be the result of a remote initiated connection. 157 // 158 // |callback| will be called with a connection status and connection 159 // reference. The connection reference will be nullptr if the connection was 160 // rejected (as indicated by a failure status). 161 // 162 // TODO(armansito): Add an |own_address| parameter for the locally advertised 163 // address that was connected to. 164 // 165 // A link with the given handle should not have been previously registered. 166 void RegisterRemoteInitiatedLink( 167 std::unique_ptr<hci::LowEnergyConnection> link, 168 sm::BondableMode bondable_mode, 169 ConnectionResultCallback callback); 170 171 // Returns the PairingDelegate currently assigned to this connection manager. pairing_delegate()172 const PairingDelegate::WeakPtr& pairing_delegate() const { 173 return pairing_delegate_; 174 } 175 176 // Assigns a new PairingDelegate to handle LE authentication challenges. 177 // Replacing an existing pairing delegate cancels all ongoing pairing 178 // procedures. If a delegate is not set then all pairing requests will be 179 // rejected. 180 void SetPairingDelegate(const PairingDelegate::WeakPtr& delegate); 181 182 // Opens a new L2CAP channel to service |psm| on |peer_id| using the preferred 183 // parameters |params|. 184 // 185 // |cb| will be called with the channel created to the peer, or nullptr if the 186 // channel creation resulted in an error. 187 void OpenL2capChannel(PeerId peer_id, 188 l2cap::Psm psm, 189 l2cap::ChannelParameters params, 190 sm::SecurityLevel security_level, 191 l2cap::ChannelCallback cb); 192 193 // TODO(armansito): Add a PeerCache::Observer interface and move these 194 // callbacks there. 195 196 // Called when a link with the given handle gets disconnected. This event is 197 // guaranteed to be called before invalidating connection references. 198 // |callback| is run on the creation thread. 199 // 200 // NOTE: This is intended ONLY for unit tests. Clients should watch for 201 // disconnection events using LowEnergyConnectionHandle::set_closed_callback() 202 // instead. DO NOT use outside of tests. 203 using DisconnectCallback = fit::function<void(hci_spec::ConnectionHandle)>; 204 void SetDisconnectCallbackForTesting(DisconnectCallback callback); 205 206 // Sets the timeout interval to be used on future connect requests. The 207 // default value is kLECreateConnectionTimeout. set_request_timeout_for_testing(pw::chrono::SystemClock::duration value)208 void set_request_timeout_for_testing( 209 pw::chrono::SystemClock::duration value) { 210 request_timeout_ = value; 211 } 212 213 // Callback for hci::Connection, called when the peer disconnects. 214 // |reason| is used to control retry logic. 215 void OnPeerDisconnect(const hci::Connection* connection, 216 pw::bluetooth::emboss::StatusCode reason); 217 218 // Initiates the pairing process. Expected to only be called during 219 // higher-level testing. 220 // |peer_id|: the peer to pair to - if the peer is not connected, |cb| is 221 // called with an error. |pairing_level|: determines the security level of 222 // the pairing. **Note**: If the security 223 // level of the link is already >= |pairing level|, no 224 // pairing takes place. 225 // |bondable_mode|: sets the bonding mode of this connection. A device in 226 // bondable mode forms a 227 // bond to the peer upon pairing, assuming the peer is also 228 // in bondable mode. A device in non-bondable mode will not 229 // allow pairing that forms a bond. 230 // |cb|: callback called upon completion of this function, whether pairing 231 // takes place or not. 232 void Pair(PeerId peer_id, 233 sm::SecurityLevel pairing_level, 234 sm::BondableMode bondable_mode, 235 sm::ResultFunction<> cb); 236 237 // Sets the LE security mode of the local device (see v5.2 Vol. 3 Part C 238 // Section 10.2). If set to SecureConnectionsOnly, any currently encrypted 239 // links not meeting the requirements of Security Mode 1 Level 4 will be 240 // disconnected. 241 void SetSecurityMode(LESecurityMode mode); 242 243 // Attach manager inspect node as a child node of |parent|. 244 void AttachInspect(inspect::Node& parent, std::string name); 245 security_mode()246 LESecurityMode security_mode() const { return security_mode_; } sm_factory_func()247 sm::SecurityManagerFactory sm_factory_func() const { 248 return sm_factory_func_; 249 } 250 251 using WeakPtr = WeakSelf<LowEnergyConnectionManager>::WeakPtr; 252 253 private: 254 friend class internal::LowEnergyConnection; 255 256 // Mapping from peer identifiers to open LE connections. 257 using ConnectionMap = 258 std::unordered_map<PeerId, 259 std::unique_ptr<internal::LowEnergyConnection>>; 260 261 // Called by LowEnergyConnectionHandle::Release(). 262 void ReleaseReference(LowEnergyConnectionHandle* handle); 263 264 // Initiates a new connection attempt for the next peer in the pending list, 265 // if any. 266 void TryCreateNextConnection(); 267 268 // Called by internal::LowEnergyConnector to indicate the result of a local 269 // connect request. 270 void OnLocalInitiatedConnectResult( 271 hci::Result<std::unique_ptr<internal::LowEnergyConnection>> result); 272 273 // Called by internal::LowEnergyConnector to indicate the result of a remote 274 // connect request. 275 void OnRemoteInitiatedConnectResult( 276 PeerId peer_id, 277 hci::Result<std::unique_ptr<internal::LowEnergyConnection>> result); 278 279 // Either report an error to clients or initialize the connection and report 280 // success to clients. 281 void ProcessConnectResult( 282 hci::Result<std::unique_ptr<internal::LowEnergyConnection>> result, 283 internal::LowEnergyConnectionRequest request); 284 285 // Finish setting up connection, adding to |connections_| map, and notifying 286 // clients. 287 bool InitializeConnection( 288 std::unique_ptr<internal::LowEnergyConnection> connection, 289 internal::LowEnergyConnectionRequest request); 290 291 // Cleans up a connection state. This results in a HCI_Disconnect command if 292 // the connection has not already been disconnected, and notifies any 293 // referenced LowEnergyConnectionHandles of the disconnection. Marks the 294 // corresponding PeerCache entry as disconnected and cleans up all data 295 // bearers. 296 // 297 // |conn_state| will have been removed from the underlying map at the time of 298 // a call. Its ownership is passed to the method for disposal. 299 // 300 // This is also responsible for unregistering the link from managed subsystems 301 // (e.g. L2CAP). 302 void CleanUpConnection(std::unique_ptr<internal::LowEnergyConnection> conn); 303 304 // Updates |peer_cache_| with the given |link| and returns the corresponding 305 // Peer. 306 // 307 // Creates a new Peer if |link| matches a peer that did not 308 // previously exist in the cache. Otherwise this updates and returns an 309 // existing Peer. 310 // 311 // The returned peer is marked as non-temporary and its connection 312 // parameters are updated. 313 // 314 // Called by RegisterRemoteInitiatedLink() and RegisterLocalInitiatedLink(). 315 Peer* UpdatePeerWithLink(const hci::LowEnergyConnection& link); 316 317 // Called when the peer disconnects with a "Connection Failed to be 318 // Established" error. Cleans up the existing connection and adds the 319 // connection request back to the queue for a retry. 320 void CleanUpAndRetryConnection( 321 std::unique_ptr<internal::LowEnergyConnection> connection); 322 323 // Returns an iterator into |connections_| if a connection is found that 324 // matches the given logical link |handle|. Otherwise, returns an iterator 325 // that is equal to |connections_.end()|. 326 // 327 // The general rules of validity around std::unordered_map::iterator apply to 328 // the returned value. 329 ConnectionMap::iterator FindConnection(hci_spec::ConnectionHandle handle); 330 331 pw::async::Dispatcher& dispatcher_; 332 333 hci::Transport::WeakPtr hci_; 334 335 // The pairing delegate used for authentication challenges. If nullptr, all 336 // pairing requests will be rejected. 337 PairingDelegate::WeakPtr pairing_delegate_; 338 339 // The GAP LE security mode of the device (v5.2 Vol. 3 Part C 10.2). 340 LESecurityMode security_mode_; 341 342 // The function used to create each channel's SecurityManager implementation. 343 sm::SecurityManagerFactory sm_factory_func_; 344 345 // Time after which a connection attempt is considered to have timed out. This 346 // is configurable to allow unit tests to set a shorter value. 347 pw::chrono::SystemClock::duration request_timeout_; 348 349 // The peer cache is used to look up and persist remote peer data that is 350 // relevant during connection establishment (such as the address, preferred 351 // connection parameters, etc). Expected to outlive this instance. 352 PeerCache* peer_cache_; // weak 353 354 // The reference to L2CAP, used to interact with the L2CAP layer to 355 // manage LE logical links, fixed channels, and LE-specific L2CAP signaling 356 // events (e.g. connection parameter update). 357 l2cap::ChannelManager* l2cap_; 358 359 // The GATT layer reference, used to add and remove ATT data bearers and 360 // service discovery. 361 gatt::GATT::WeakPtr gatt_; 362 363 // Provides us with information on the capabilities of our controller 364 AdapterState adapter_state_; 365 366 // Local GATT service registry. 367 std::unique_ptr<gatt::LocalServiceManager> gatt_registry_; 368 369 LowEnergyDiscoveryManager::WeakPtr discovery_manager_; 370 371 // Callbacks used by unit tests to observe connection state events. 372 DisconnectCallback test_disconn_cb_; 373 374 // Outstanding connection requests based on remote peer ID. 375 std::unordered_map<PeerId, internal::LowEnergyConnectionRequest> 376 pending_requests_; 377 378 // Mapping from peer identifiers to currently open LE connections. 379 ConnectionMap connections_; 380 381 struct RequestAndConnector { 382 internal::LowEnergyConnectionRequest request; 383 std::unique_ptr<internal::LowEnergyConnector> connector; 384 }; 385 // The in-progress locally initiated connection request, if any. 386 std::optional<RequestAndConnector> current_request_; 387 388 // Active connectors for remote connection requests. 389 std::unordered_map<PeerId, RequestAndConnector> remote_connectors_; 390 391 // For passing to internal::LowEnergyConnector. |hci_connector_| must 392 // out-live this connection manager. 393 hci::LowEnergyConnector* hci_connector_; // weak 394 395 // Address manager is used to obtain local identity information during pairing 396 // procedures. Expected to outlive this instance. 397 hci::LocalAddressDelegate* local_address_delegate_; // weak 398 399 // True if the connection manager is performing a scan for a peer before 400 // connecting. 401 bool scanning_ = false; 402 403 struct InspectProperties { 404 // Count of connection failures in the past 10 minutes. InspectPropertiesInspectProperties405 explicit InspectProperties(pw::async::Dispatcher& pw_dispatcher) 406 : recent_connection_failures( 407 pw_dispatcher, kInspectRecentConnectionFailuresExpiryDuration) {} 408 WindowedInspectIntProperty recent_connection_failures; 409 410 UintMetricCounter outgoing_connection_success_count_; 411 UintMetricCounter outgoing_connection_failure_count_; 412 UintMetricCounter incoming_connection_success_count_; 413 UintMetricCounter incoming_connection_failure_count_; 414 415 UintMetricCounter disconnect_explicit_disconnect_count_; 416 UintMetricCounter disconnect_link_error_count_; 417 UintMetricCounter disconnect_zero_ref_count_; 418 UintMetricCounter disconnect_remote_disconnection_count_; 419 }; 420 InspectProperties inspect_properties_{dispatcher_}; 421 inspect::Node inspect_node_; 422 // Container node for pending request nodes. 423 inspect::Node inspect_pending_requests_node_; 424 // container node for connection nodes. 425 inspect::Node inspect_connections_node_; 426 427 // Keep this as the last member to make sure that all weak pointers are 428 // invalidated before other members get destroyed. 429 WeakSelf<LowEnergyConnectionManager> weak_self_; 430 431 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyConnectionManager); 432 }; 433 434 } // namespace gap 435 } // namespace bt 436