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 17 #include <optional> 18 19 #include "pw_bluetooth_sapphire/internal/host/common/bounded_inspect_list_node.h" 20 #include "pw_bluetooth_sapphire/internal/host/common/expiring_set.h" 21 #include "pw_bluetooth_sapphire/internal/host/common/metrics.h" 22 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_connection.h" 23 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_connection_request.h" 24 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h" 25 #include "pw_bluetooth_sapphire/internal/host/gap/peer.h" 26 #include "pw_bluetooth_sapphire/internal/host/gap/types.h" 27 #include "pw_bluetooth_sapphire/internal/host/hci-spec/constants.h" 28 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h" 29 #include "pw_bluetooth_sapphire/internal/host/hci/bredr_connection_request.h" 30 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h" 31 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_manager.h" 32 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h" 33 #include "pw_bluetooth_sapphire/internal/host/sdp/service_discoverer.h" 34 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h" 35 #include "pw_bluetooth_sapphire/internal/host/transport/control_packets.h" 36 #include "pw_bluetooth_sapphire/internal/host/transport/error.h" 37 #include "pw_bluetooth_sapphire/internal/host/transport/transport.h" 38 39 namespace bt { 40 41 namespace hci { 42 class SequentialCommandRunner; 43 } // namespace hci 44 45 namespace gap { 46 47 class PairingDelegate; 48 class PeerCache; 49 50 enum class DisconnectReason : uint8_t { 51 // A FIDL method explicitly requested this disconnect 52 kApiRequest, 53 // The interrogation procedure for this peer failed 54 kInterrogationFailed, 55 // The connection encountered an error during Pairing 56 kPairingFailed, 57 // An error was encountered on the ACL link 58 kAclLinkError, 59 // Peer Disconnected 60 kPeerDisconnection, 61 }; 62 63 // Manages all activity related to connections in the BR/EDR section of the 64 // controller, including whether the peer can be connected to, incoming 65 // connections, and initiating connections. 66 // 67 // There are two flows for destroying connections: explicit local 68 // disconnections, and peer disconnections. When the connection is disconnected 69 // explicitly with |Disconnect()|, the connection is immediately cleaned up and 70 // removed from the internal |connections_| map and owned by itself until the 71 // HCI Disconnection Complete event is received by the underlying 72 // hci::Connection object. When the peer disconnects, the |OnPeerDisconnect()| 73 // callback is called by the underlying hci::Connection object and the 74 // connection is cleaned up and removed from the internal |connections_| map. 75 class BrEdrConnectionManager final { 76 public: 77 BrEdrConnectionManager(hci::Transport::WeakPtr hci, 78 PeerCache* peer_cache, 79 DeviceAddress local_address, 80 l2cap::ChannelManager* l2cap, 81 bool use_interlaced_scan, 82 bool local_secure_connections_supported, 83 bool legacy_pairing_enabled, 84 pw::async::Dispatcher& dispatcher); 85 ~BrEdrConnectionManager(); 86 87 // Set whether this host is connectable 88 void SetConnectable(bool connectable, hci::ResultFunction<> status_cb); 89 90 // Returns the PairingDelegate currently assigned to this connection manager. pairing_delegate()91 const PairingDelegate::WeakPtr& pairing_delegate() const { 92 return pairing_delegate_; 93 } 94 95 // Assigns a new PairingDelegate to handle BR/EDR authentication challenges. 96 // Replacing an existing pairing delegate cancels all ongoing pairing 97 // procedures. If a delegate is not set then all pairing requests will be 98 // rejected. 99 void SetPairingDelegate(PairingDelegate::WeakPtr delegate); 100 101 // Retrieves the peer id that is connected to the connection |handle|. 102 // Returns kInvalidPeerId if no such peer exists. 103 PeerId GetPeerId(hci_spec::ConnectionHandle handle) const; 104 105 // Opens a new L2CAP channel to service |psm| on |peer_id| using the preferred 106 // parameters |params|. If the current connection doesn't meet 107 // |security_requirements|, attempt to upgrade the link key and report an 108 // error via |cb| if the upgrade fails. 109 // 110 // |cb| will be called with the channel created to the peer, or nullptr if the 111 // channel creation resulted in an error. 112 void OpenL2capChannel(PeerId peer_id, 113 l2cap::Psm psm, 114 BrEdrSecurityRequirements security_requirements, 115 l2cap::ChannelParameters params, 116 l2cap::ChannelCallback cb); 117 118 // See ScoConnectionManager for documentation. If a BR/EDR connection with 119 // the peer does not exist, returns nullopt. 120 using ScoRequestHandle = BrEdrConnection::ScoRequestHandle; 121 std::optional<ScoRequestHandle> OpenScoConnection( 122 PeerId peer_id, 123 bt::StaticPacket< 124 pw::bluetooth::emboss::SynchronousConnectionParametersWriter> 125 parameters, 126 sco::ScoConnectionManager::OpenConnectionCallback callback); 127 std::optional<ScoRequestHandle> AcceptScoConnection( 128 PeerId peer_id, 129 std::vector<bt::StaticPacket< 130 pw::bluetooth::emboss::SynchronousConnectionParametersWriter>> 131 parameters, 132 sco::ScoConnectionManager::AcceptConnectionCallback callback); 133 134 // Add a service search to be performed on new connected remote peers. 135 // This search will happen on every peer connection. 136 // |callback| will be called with the |attributes| that exist in the service 137 // entry on the peer's SDP server. If |attributes| is empty, all attributes on 138 // the server will be returned. Returns a SearchId which can be used to remove 139 // the search later. Identical searches will perform the same search for each 140 // search added. Results of added service searches will be added to each 141 // Peer's BrEdrData. 142 // TODO(fxbug.dev/42086791): Make identical searches just search once 143 using SearchCallback = sdp::ServiceDiscoverer::ResultCallback; 144 using SearchId = sdp::ServiceDiscoverer::SearchId; 145 SearchId AddServiceSearch(const UUID& uuid, 146 std::unordered_set<sdp::AttributeId> attributes, 147 SearchCallback callback); 148 149 // Remove a search previously added with AddServiceSearch() 150 // Returns true if a search was removed. 151 // This function is idempotent. 152 bool RemoveServiceSearch(SearchId id); 153 154 using ConnectResultCallback = 155 fit::function<void(hci::Result<>, BrEdrConnection*)>; 156 157 // Initiates an outgoing Create Connection Request to attempt to connect to 158 // the peer identified by |peer_id|. Returns false if the connection 159 // request was invalid, otherwise returns true and |callback| will be called 160 // with the result of the procedure, whether successful or not 161 // TODO(fxbug.dev/42087181) - implement a timeout 162 [[nodiscard]] bool Connect(PeerId peer_id, ConnectResultCallback callback); 163 164 // Initiate pairing to the peer with |peer_id| using the bondable preference. 165 // Pairing will only be initiated if the current link key does not meet the 166 // |security| requirements. |callback| will be called with the result of the 167 // procedure, successful or not. 168 void Pair(PeerId peer_id, 169 BrEdrSecurityRequirements security, 170 hci::ResultFunction<> callback); 171 172 // Disconnects any existing BR/EDR connection to |peer_id|. Returns true if 173 // the peer is disconnected, false if the peer can not be disconnected. 174 bool Disconnect(PeerId peer_id, DisconnectReason reason); 175 176 // Sets the BR/EDR security mode of the local device (Core Spec v5.4, Vol 3, 177 // Part C, 5.2.2). If set to SecureConnectionsOnly, any currently encrypted 178 // links not meeting the requirements of Security Mode 4 Level 4 will be 179 // disconnected. 180 void SetSecurityMode(BrEdrSecurityMode mode); 181 security_mode()182 BrEdrSecurityMode security_mode() { return *security_mode_; } 183 184 // If `reason` is DisconnectReason::kApiRequest, then incoming connections 185 // from `peer_id` are rejected for kLocalDisconnectCooldownDuration 186 static constexpr pw::chrono::SystemClock::duration 187 kLocalDisconnectCooldownDuration = std::chrono::seconds(30); 188 189 // Attach Inspect node as child of |parent| named |name|. 190 // Only connections established after a call to AttachInspect are tracked. 191 void AttachInspect(inspect::Node& parent, std::string name); 192 193 private: 194 using ConnectionMap = 195 std::unordered_map<hci_spec::ConnectionHandle, BrEdrConnection>; 196 197 // Callback for hci::Connection. Called when the peer disconnects. 198 void OnPeerDisconnect(const hci::Connection* connection); 199 200 // Called to cancel an outgoing connection request 201 void SendCreateConnectionCancelCommand(DeviceAddress addr); 202 203 // Attempt to complete the active connection request for the peer |peer_id| 204 // with status |status| 205 void CompleteRequest(PeerId peer_id, 206 DeviceAddress address, 207 hci::Result<> status, 208 hci_spec::ConnectionHandle handle); 209 210 // Is there a current incoming connection request in progress for the given 211 // address 212 bool ExistsIncomingRequest(PeerId id); 213 214 // Writes page timeout duration to the controller. 215 // |page_timeout| must be in the range [PageTimeout::MIN (0x0001), 216 // PageTimeout::MAX (0xFFFF)] |cb| will be called with the resulting return 217 // parameter status. 218 void WritePageTimeout(pw::chrono::SystemClock::duration page_timeout, 219 hci::ResultFunction<> cb); 220 221 // Reads the controller page scan settings. 222 void ReadPageScanSettings(); 223 224 // Writes page scan parameters to the controller. 225 // If |interlaced| is true, and the controller does not support interlaced 226 // page scan mode, standard mode is used. 227 void WritePageScanSettings(uint16_t interval, 228 uint16_t window, 229 bool interlaced, 230 hci::ResultFunction<> cb); 231 232 // Write PIN type used for legacy pairing to the controller. 233 void WritePinType(pw::bluetooth::emboss::PinType pin_type); 234 235 // Helper to register an event handler to run. 236 hci::CommandChannel::EventHandlerId AddEventHandler( 237 const hci_spec::EventCode& code, hci::CommandChannel::EventCallback cb); 238 239 // Find the outstanding connection request object for a connection request 240 // to/from |peer_id|. Returns nullopt if no request for |peer_id| exists. 241 std::optional<BrEdrConnectionRequest*> FindConnectionRequestById( 242 PeerId peer_id); 243 244 // Find the handle for a connection to |peer_id|. Returns nullopt if no BR/EDR 245 // |peer_id| is connected. 246 std::optional<std::pair<hci_spec::ConnectionHandle, BrEdrConnection*>> 247 FindConnectionById(PeerId peer_id); 248 249 // Find the handle for a connection to |bd_addr|. Returns nullopt if no BR/EDR 250 // |bd_addr| is connected. 251 std::optional<std::pair<hci_spec::ConnectionHandle, BrEdrConnection*>> 252 FindConnectionByAddress(const DeviceAddressBytes& bd_addr); 253 254 // Find a peer with |addr| or create one if not found. 255 Peer* FindOrInitPeer(DeviceAddress addr); 256 257 // Initialize ACL connection state from |connection_handle| obtained from the 258 // controller and begin interrogation. The connection will be initialized with 259 // the role |role|. 260 void InitializeConnection(DeviceAddress addr, 261 hci_spec::ConnectionHandle connection_handle, 262 pw::bluetooth::emboss::ConnectionRole role); 263 264 // Called once interrogation completes to make connection identified by 265 // |handle| available to upper layers and begin new connection procedures. 266 void CompleteConnectionSetup(Peer::WeakPtr peer, 267 hci_spec::ConnectionHandle handle); 268 269 // Callbacks for registered events 270 hci::CommandChannel::EventCallbackResult OnAuthenticationComplete( 271 const hci::EventPacket& event); 272 hci::CommandChannel::EventCallbackResult OnConnectionRequest( 273 const hci::EventPacket& event); 274 hci::CommandChannel::EventCallbackResult OnConnectionComplete( 275 const hci::EventPacket& event); 276 hci::CommandChannel::EventCallbackResult OnIoCapabilityRequest( 277 const hci::EventPacket& event); 278 hci::CommandChannel::EventCallbackResult OnIoCapabilityResponse( 279 const hci::EventPacket& event); 280 hci::CommandChannel::EventCallbackResult OnLinkKeyRequest( 281 const hci::EventPacket& event); 282 hci::CommandChannel::EventCallbackResult OnLinkKeyNotification( 283 const hci::EventPacket& event); 284 hci::CommandChannel::EventCallbackResult OnSimplePairingComplete( 285 const hci::EventPacket& event_packet); 286 hci::CommandChannel::EventCallbackResult OnUserConfirmationRequest( 287 const hci::EventPacket& event_packet); 288 hci::CommandChannel::EventCallbackResult OnUserPasskeyRequest( 289 const hci::EventPacket& event_packet); 290 hci::CommandChannel::EventCallbackResult OnUserPasskeyNotification( 291 const hci::EventPacket& event_packet); 292 hci::CommandChannel::EventCallbackResult OnRoleChange( 293 const hci::EventPacket& event); 294 hci::CommandChannel::EventCallbackResult OnPinCodeRequest( 295 const hci::EventPacket& event); 296 297 void HandleNonAclConnectionRequest(const DeviceAddress& addr, 298 pw::bluetooth::emboss::LinkType link_type); 299 300 // Called when we complete a pending request. Initiates a new connection 301 // attempt for the next peer in the pending list, if any. 302 void TryCreateNextConnection(); 303 304 // Called when a request times out waiting for a connection complete packet, 305 // *after* the command status was received. This is responsible for canceling 306 // the request and initiating the next one in the queue 307 void OnRequestTimeout(); 308 309 // Clean up |conn| after it has been deliberately disconnected or after its 310 // link closed. Unregisters the connection from the data domain and marks the 311 // peer's BR/EDR cache state as disconnected. Takes ownership of |conn| and 312 // destroys it. 313 void CleanUpConnection(hci_spec::ConnectionHandle handle, 314 BrEdrConnection conn, 315 DisconnectReason reason); 316 317 // Helpers for sending commands on the command channel for this controller. 318 // All callbacks will run on |dispatcher_|. 319 void SendAuthenticationRequested(hci_spec::ConnectionHandle handle, 320 hci::ResultFunction<> cb); 321 void SendIoCapabilityRequestReply( 322 DeviceAddressBytes bd_addr, 323 pw::bluetooth::emboss::IoCapability io_capability, 324 pw::bluetooth::emboss::OobDataPresent oob_data_present, 325 pw::bluetooth::emboss::AuthenticationRequirements auth_requirements, 326 hci::ResultFunction<> cb = nullptr); 327 void SendIoCapabilityRequestNegativeReply( 328 DeviceAddressBytes bd_addr, 329 pw::bluetooth::emboss::StatusCode reason, 330 hci::ResultFunction<> cb = nullptr); 331 void SendUserConfirmationRequestReply(DeviceAddressBytes bd_addr, 332 hci::ResultFunction<> cb = nullptr); 333 void SendUserConfirmationRequestNegativeReply( 334 DeviceAddressBytes bd_addr, hci::ResultFunction<> cb = nullptr); 335 void SendUserPasskeyRequestReply(DeviceAddressBytes bd_addr, 336 uint32_t numeric_value, 337 hci::ResultFunction<> cb = nullptr); 338 void SendUserPasskeyRequestNegativeReply(DeviceAddressBytes bd_addr, 339 hci::ResultFunction<> cb = nullptr); 340 void SendLinkKeyRequestNegativeReply(DeviceAddressBytes bd_addr, 341 hci::ResultFunction<> cb = nullptr); 342 void SendLinkKeyRequestReply(DeviceAddressBytes bd_addr, 343 hci_spec::LinkKey link_key, 344 hci::ResultFunction<> cb = nullptr); 345 void SendAcceptConnectionRequest(DeviceAddressBytes addr, 346 hci::ResultFunction<> cb = nullptr); 347 void SendRejectConnectionRequest(DeviceAddress addr, 348 pw::bluetooth::emboss::StatusCode reason, 349 hci::ResultFunction<> cb = nullptr); 350 void SendRejectSynchronousRequest(DeviceAddress addr, 351 pw::bluetooth::emboss::StatusCode reason, 352 hci::ResultFunction<> cb = nullptr); 353 void SendPinCodeRequestReply(DeviceAddressBytes bd_addr, 354 uint16_t pin_code, 355 hci::ResultFunction<> cb = nullptr); 356 void SendPinCodeRequestNegativeReply(DeviceAddressBytes bd_addr, 357 hci::ResultFunction<> cb = nullptr); 358 359 // Send the HCI command encoded in |command_packet|. If |cb| is not nullptr, 360 // the event returned will be decoded for its status, which is passed to |cb|. 361 template <typename T> 362 void SendCommandWithStatusCallback(T command_packet, 363 hci::ResultFunction<> cb); 364 365 // Record a disconnection in Inspect's list of disconnections. 366 void RecordDisconnectInspect(const BrEdrConnection& conn, 367 DisconnectReason reason); 368 369 hci::Transport::WeakPtr hci_; 370 std::unique_ptr<hci::SequentialCommandRunner> hci_cmd_runner_; 371 372 // The pairing delegate used for authentication challenges. If nullptr, all 373 // pairing requests will be rejected. 374 PairingDelegate::WeakPtr pairing_delegate_; 375 376 // Peer cache is used to look up parameters for connecting to peers and 377 // update the state of connected peers as well as introduce unknown peers. 378 // This object must outlive this instance. 379 PeerCache* cache_; 380 381 const DeviceAddress local_address_; 382 383 l2cap::ChannelManager* l2cap_; 384 385 // Discoverer for SDP services 386 sdp::ServiceDiscoverer discoverer_; 387 388 // Holds the connections that are active. 389 ConnectionMap connections_; 390 391 // Current security mode 392 StringInspectable<BrEdrSecurityMode> security_mode_{ 393 BrEdrSecurityMode::Mode4, 394 /*convert=*/[](auto mode) { return BrEdrSecurityModeToString(mode); }}; 395 396 // Holds a denylist with cooldowns for locally requested disconnects. 397 ExpiringSet<DeviceAddress> deny_incoming_; 398 399 // Handler IDs for registered events 400 std::vector<hci::CommandChannel::EventHandlerId> event_handler_ids_; 401 402 // The current page scan parameters of the controller. 403 // Set to 0 when non-connectable. 404 uint16_t page_scan_interval_; 405 uint16_t page_scan_window_; 406 pw::bluetooth::emboss::PageScanType page_scan_type_; 407 bool use_interlaced_scan_; 408 409 // True when local Host and Controller support BR/EDR Secure Connections 410 bool local_secure_connections_supported_; 411 412 // When True, BR/EDR pairing may attempt to use legacy pairing if the peer 413 // does not support SSP. 414 bool legacy_pairing_enabled_; 415 416 // Outstanding incoming and outgoing connection requests from remote peer with 417 // |PeerId|. 418 std::unordered_map<PeerId, BrEdrConnectionRequest> connection_requests_; 419 420 // Represents an outgoing HCI_Connection_Request that has not been fulfilled. 421 // There may only be one outstanding request at any given time. 422 // 423 // This request is fulfilled on either an HCI_Connection_Complete event from 424 // the peer this request was sent to or a failure during the connection 425 // process. This request might not complete if the connection closes or if the 426 // request times out. 427 std::unique_ptr<hci::BrEdrConnectionRequest> pending_request_; 428 429 struct InspectProperties { 430 BoundedInspectListNode last_disconnected_list = 431 BoundedInspectListNode(/*capacity=*/5); 432 inspect::Node connections_node_; 433 inspect::Node requests_node_; 434 struct DirectionalCounts { 435 inspect::Node node_; 436 UintMetricCounter connection_attempts_; 437 UintMetricCounter successful_connections_; 438 UintMetricCounter failed_connections_; 439 }; 440 441 // These stats only represent HCI connections. 442 // Connections may be closed if we fail to initialize, interrogate, or pair 443 DirectionalCounts outgoing_; 444 DirectionalCounts incoming_; 445 446 // Successfully initialized connections 447 UintMetricCounter interrogation_complete_count_; 448 449 UintMetricCounter disconnect_local_api_request_count_; 450 UintMetricCounter disconnect_interrogation_failed_count_; 451 UintMetricCounter disconnect_pairing_failed_count_; 452 UintMetricCounter disconnect_acl_link_error_count_; 453 UintMetricCounter disconnect_peer_disconnection_count_; 454 }; 455 InspectProperties inspect_properties_; 456 inspect::Node inspect_node_; 457 458 pw::async::Dispatcher& dispatcher_; 459 460 // Keep this as the last member to make sure that all weak pointers are 461 // invalidated before other members get destroyed. 462 WeakSelf<BrEdrConnectionManager> weak_self_; 463 464 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(BrEdrConnectionManager); 465 }; 466 467 } // namespace gap 468 } // namespace bt 469