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 <memory> 19 #include <string> 20 21 #include "pw_bluetooth_sapphire/internal/host/common/assert.h" 22 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h" 23 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h" 24 #include "pw_bluetooth_sapphire/internal/host/common/inspect.h" 25 #include "pw_bluetooth_sapphire/internal/host/common/macros.h" 26 #include "pw_bluetooth_sapphire/internal/host/gap/adapter_state.h" 27 #include "pw_bluetooth_sapphire/internal/host/gap/bonding_data.h" 28 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_connection_manager.h" 29 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_discovery_manager.h" 30 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_advertising_manager.h" 31 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_connection_manager.h" 32 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_discovery_manager.h" 33 #include "pw_bluetooth_sapphire/internal/host/gap/peer_cache.h" 34 #include "pw_bluetooth_sapphire/internal/host/gap/types.h" 35 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt.h" 36 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_manager.h" 37 #include "pw_bluetooth_sapphire/internal/host/sdp/server.h" 38 #include "pw_bluetooth_sapphire/internal/host/sdp/service_discoverer.h" 39 40 namespace bt { 41 42 namespace hci { 43 class LowEnergyAdvertiser; 44 class LowEnergyConnector; 45 class LowEnergyScanner; 46 class SequentialCommandRunner; 47 class Transport; 48 } // namespace hci 49 50 namespace gap { 51 52 class BrEdrConnectionManager; 53 class BrEdrDiscoveryManager; 54 class PairingDelegate; 55 class LowEnergyAddressManager; 56 57 // TODO(fxbug.dev/42082764): Consider removing this identifier from the bt-host 58 // layer. 59 class AdapterId : public Identifier<uint64_t> { 60 public: AdapterId(uint64_t value)61 constexpr explicit AdapterId(uint64_t value) : Identifier<uint64_t>(value) {} 62 AdapterId() = default; 63 }; 64 65 // Represents the host-subsystem state for a Bluetooth controller. 66 // 67 // This class is not guaranteed to be thread-safe and it is intended to be 68 // created, deleted, and accessed on the same event loop. No internal locking is 69 // provided. 70 // 71 // NOTE: We currently only support primary controllers. AMP controllers are not 72 // supported. 73 class Adapter { 74 public: 75 static constexpr const char* kMetricsInspectNodeName = "metrics"; 76 77 // Optionally, a FakeL2cap may be passed for testing purposes as |l2cap|. If 78 // nullptr is passed, then the Adapter will create and initialize its own 79 // L2cap. 80 static std::unique_ptr<Adapter> Create( 81 pw::async::Dispatcher& pw_dispatcher, 82 hci::Transport::WeakPtr hci, 83 gatt::GATT::WeakPtr gatt, 84 std::unique_ptr<l2cap::ChannelManager> l2cap = nullptr); 85 virtual ~Adapter() = default; 86 87 // Returns a uniquely identifier for this adapter on the current system. 88 virtual AdapterId identifier() const = 0; 89 90 // Initializes the host-subsystem state for the HCI device this was created 91 // for. This performs the initial HCI transport set up. Returns false if an 92 // immediate error occurs. Otherwise this returns true and asynchronously 93 // notifies the caller on the initialization status via |callback|. 94 // 95 // After successful initialization, |transport_closed_callback| will be 96 // invoked when the underlying HCI transport closed for any reason (e.g. the 97 // device disappeared or the transport channels were closed for an unknown 98 // reason). The implementation is responsible for cleaning up this adapter by 99 // calling ShutDown(). 100 using InitializeCallback = fit::callback<void(bool success)>; 101 virtual bool Initialize(InitializeCallback callback, 102 fit::closure transport_error_callback) = 0; 103 104 // Shuts down this Adapter. Invokes |callback| when shut down has completed. 105 // TODO(armansito): This needs to do several things to potentially preserve 106 // the state of various sub-protocols. For now we keep the interface pretty 107 // simple. 108 virtual void ShutDown() = 0; 109 110 // Returns true if the Initialize() sequence has started but not completed yet 111 // (i.e. the InitializeCallback that was passed to Initialize() has not yet 112 // been called). 113 virtual bool IsInitializing() const = 0; 114 115 // Returns true if this Adapter has been fully initialized. 116 virtual bool IsInitialized() const = 0; 117 118 // Returns the global adapter setting parameters. 119 virtual const AdapterState& state() const = 0; 120 121 // Interface to the LE features of the adapter. 122 class LowEnergy { 123 public: 124 virtual ~LowEnergy() = default; 125 126 // Allows a caller to claim shared ownership over a connection to the 127 // requested remote LE peer identified by |peer_id|. 128 // 129 // * If the requested peer is already connected, |callback| is called with 130 // a 131 // LowEnergyConnectionHandle. 132 // 133 // * If the requested peer is NOT connected, then this method initiates a 134 // connection to the requested peer. A LowEnergyConnectionHandle is 135 // asynchronously returned to the caller once the connection has been 136 // set up. 137 // 138 // The status of the procedure is reported in |callback| in the case of 139 // an error. 140 using ConnectionResult = gap::LowEnergyConnectionManager::ConnectionResult; 141 using ConnectionResultCallback = 142 gap::LowEnergyConnectionManager::ConnectionResultCallback; 143 virtual void Connect(PeerId peer_id, 144 ConnectionResultCallback callback, 145 LowEnergyConnectionOptions connection_options) = 0; 146 147 // Disconnects any existing LE connection to |peer_id|, invalidating all 148 // active LowEnergyConnectionHandles. Returns false if the peer can not be 149 // disconnected. 150 virtual bool Disconnect(PeerId peer_id) = 0; 151 152 // Initiates the pairing process. Expected to only be called during 153 // higher-level testing. 154 // |peer_id|: the peer to pair to - if the peer is not connected, |cb| is 155 // called with an error. |pairing_level|: determines the security level of 156 // the pairing. **Note**: If the 157 // security level of the link is already >= |pairing 158 // level|, no pairing takes place. 159 // |bondable_mode|: sets the bonding mode of this connection. A device in 160 // bondable mode forms 161 // a bond to the peer upon pairing, assuming the peer is 162 // also in bondable mode. 163 // |cb|: callback called upon completion of this function, whether pairing 164 // takes place or not. 165 virtual void Pair(PeerId peer_id, 166 sm::SecurityLevel pairing_level, 167 sm::BondableMode bondable_mode, 168 sm::ResultFunction<> cb) = 0; 169 170 // Sets the LE security mode of the local device (see v5.2 Vol. 3 Part C 171 // Section 10.2). If set to SecureConnectionsOnly, any currently encrypted 172 // links not meeting the requirements of Security Mode 1 Level 4 will be 173 // disconnected. 174 virtual void SetLESecurityMode(LESecurityMode mode) = 0; 175 176 // Returns the current LE security mode. 177 virtual LESecurityMode security_mode() const = 0; 178 179 // Asynchronously attempts to start advertising a set of |data| with 180 // additional scan response data |scan_rsp|. 181 // 182 // If |connectable| is provided, the advertisement will be connectable. 183 // The |connectable.connection_cb| will be called with the returned 184 // advertisement ID and a connection result when a peer attempts to connect 185 // to the advertisement, at which point the advertisement will have been 186 // stopped. |connectable.bondable_mode| indicates the bondable mode to 187 // initialize connections with. 188 // 189 // Returns false if the parameters represent an invalid advertisement: 190 // * if |anonymous| is true but |callback| is set 191 // 192 // |status_callback| may be called synchronously within this function. 193 // |status_callback| provides one of: 194 // - an |advertisement_id|, which can be used to stop advertising 195 // or disambiguate calls to |callback|, and a success |status|. 196 // - kInvalidAdvertisementId and an error indication in |status|: 197 // * HostError::kInvalidParameters if the advertising parameters 198 // are invalid (e.g. |data| is too large). 199 // * HostError::kNotSupported if another set cannot be advertised 200 // or if the requested parameters are not supported by the hardware. 201 // * HostError::kProtocolError with a HCI error reported from 202 // the controller, otherwise. 203 using ConnectionCallback = 204 fit::function<void(AdvertisementId, ConnectionResult)>; 205 using AdvertisingStatusCallback = 206 LowEnergyAdvertisingManager::AdvertisingStatusCallback; 207 struct ConnectableAdvertisingParameters { 208 ConnectionCallback connection_cb; 209 sm::BondableMode bondable_mode; 210 }; 211 virtual void StartAdvertising( 212 AdvertisingData data, 213 AdvertisingData scan_rsp, 214 AdvertisingInterval interval, 215 bool anonymous, 216 bool include_tx_power_level, 217 std::optional<ConnectableAdvertisingParameters> connectable, 218 AdvertisingStatusCallback status_callback) = 0; 219 220 // Stop advertising the advertisement with the id |advertisement_id| 221 // Returns true if an advertisement was stopped, and false otherwise. 222 virtual void StopAdvertising(AdvertisementId advertisement_id) = 0; 223 224 // Starts a new discovery session and reports the result via |callback|. If 225 // a session has been successfully started the caller will receive a new 226 // LowEnergyDiscoverySession instance via |callback| which it uniquely owns. 227 // |active| indicates whether active or passive discovery should occur. 228 // On failure a nullptr will be returned via |callback|. 229 using SessionCallback = LowEnergyDiscoveryManager::SessionCallback; 230 virtual void StartDiscovery(bool active, SessionCallback callback) = 0; 231 232 // Enable or disable the privacy feature. When enabled, the controller will 233 // be configured to use a new random address if it is currently allowed to 234 // do so. 235 virtual void EnablePrivacy(bool enabled) = 0; 236 // Returns true if the privacy feature is currently enabled. 237 virtual bool PrivacyEnabled() const = 0; 238 // Returns the current LE address. 239 virtual const DeviceAddress& CurrentAddress() const = 0; 240 // Register a callback to be notified any time the LE address changes. 241 virtual void register_address_changed_callback(fit::closure callback) = 0; 242 243 // Assigns the IRK to generate a RPA for the next address refresh when 244 // privacy is enabled. 245 virtual void set_irk(const std::optional<UInt128>& irk) = 0; 246 247 // Returns the currently assigned Identity Resolving Key, if any. 248 virtual std::optional<UInt128> irk() const = 0; 249 250 // Sets the timeout interval to be used on future connect requests. The 251 // default value is kLECreateConnectionTimeout. 252 virtual void set_request_timeout_for_testing( 253 pw::chrono::SystemClock::duration value) = 0; 254 255 // Sets a new scan period to any future and ongoing discovery procedures. 256 virtual void set_scan_period_for_testing( 257 pw::chrono::SystemClock::duration period) = 0; 258 }; 259 260 virtual LowEnergy* le() const = 0; 261 262 // Interface to the classic features of the adapter. 263 class BrEdr { 264 public: 265 virtual ~BrEdr() = default; 266 267 // Initiates an outgoing Create Connection Request to attempt to connect to 268 // the peer identified by |peer_id|. Returns false if the connection 269 // request was invalid, otherwise returns true and |callback| will be called 270 // with the result of the procedure, whether successful or not 271 using ConnectResultCallback = BrEdrConnectionManager::ConnectResultCallback; 272 [[nodiscard]] virtual bool Connect(PeerId peer_id, 273 ConnectResultCallback callback) = 0; 274 275 // Disconnects any existing BR/EDR connection to |peer_id|. Returns true if 276 // the peer is disconnected, false if the peer can not be disconnected. 277 virtual bool Disconnect(PeerId peer_id, DisconnectReason reason) = 0; 278 279 // Opens a new L2CAP channel to service |psm| on |peer_id| using the 280 // preferred parameters |params|. If the current connection doesn't meet 281 // |security_requirements|, attempt to upgrade the link key and report an 282 // error via |cb| if the upgrade fails. 283 // 284 // |cb| will be called with the channel created to the peer, or nullptr if 285 // the channel creation resulted in an error. 286 virtual void OpenL2capChannel( 287 PeerId peer_id, 288 l2cap::Psm psm, 289 BrEdrSecurityRequirements security_requirements, 290 l2cap::ChannelParameters params, 291 l2cap::ChannelCallback cb) = 0; 292 293 // Retrieves the peer id that is connected to the connection |handle|. 294 // Returns kInvalidPeerId if no such peer exists. 295 virtual PeerId GetPeerId(hci_spec::ConnectionHandle handle) const = 0; 296 297 // Add a service search to be performed on new connected remote peers. 298 // This search will happen on every peer connection. 299 // |callback| will be called with the |attributes| that exist in the service 300 // entry on the peer's SDP server. If |attributes| is empty, all attributes 301 // on the server will be returned. Returns a SearchId which can be used to 302 // remove the search later. Identical searches will perform the same search 303 // for each search added. Results of added service searches will be added to 304 // each Peer's BrEdrData. 305 using SearchCallback = sdp::ServiceDiscoverer::ResultCallback; 306 using SearchId = sdp::ServiceDiscoverer::SearchId; 307 virtual SearchId AddServiceSearch( 308 const UUID& uuid, 309 std::unordered_set<sdp::AttributeId> attributes, 310 SearchCallback callback) = 0; 311 312 // Remove a search previously added with AddServiceSearch() 313 // Returns true if a search was removed. 314 virtual bool RemoveServiceSearch(SearchId id) = 0; 315 316 // Initiate pairing to the peer with |peer_id| using the bondable 317 // preference. Pairing will only be initiated if the current link key does 318 // not meet the |security| requirements. |callback| will be called with the 319 // result of the procedure, successful or not. 320 virtual void Pair(PeerId peer_id, 321 BrEdrSecurityRequirements security, 322 hci::ResultFunction<> callback) = 0; 323 324 // Sets the BR/EDR security mode of the local device (Core Spec v5.4, Vol 3, 325 // Part C, 5.2.2). If set to SecureConnectionsOnly, any currently encrypted 326 // links not meeting the requirements of Security Mode 4 Level 4 will be 327 // disconnected. 328 virtual void SetBrEdrSecurityMode(BrEdrSecurityMode mode) = 0; 329 330 // Returns the current BR/EDR security mode. 331 virtual BrEdrSecurityMode security_mode() const = 0; 332 333 // Set whether this host is connectable. 334 virtual void SetConnectable(bool connectable, 335 hci::ResultFunction<> status_cb) = 0; 336 337 // Starts discovery and reports the status via |callback|. If discovery has 338 // been successfully started, the callback will receive a session object 339 // that it owns. If no sessions are owned, peer discovery is stopped. 340 using DiscoveryCallback = BrEdrDiscoveryManager::DiscoveryCallback; 341 virtual void RequestDiscovery(DiscoveryCallback callback) = 0; 342 343 // Requests this device be discoverable. We are discoverable as long as 344 // anyone holds a discoverable session. 345 using DiscoverableCallback = BrEdrDiscoveryManager::DiscoverableCallback; 346 virtual void RequestDiscoverable(DiscoverableCallback callback) = 0; 347 348 // Given incomplete ServiceRecords, register services that will be made 349 // available over SDP. Takes ownership of |records|. Channels created for 350 // this service will be configured using the preferred parameters in 351 // |chan_params|. 352 // 353 // A non-zero RegistrationHandle will be returned if the service was 354 // successfully registered. 355 // 356 // If any record in |records| fails registration checks, none of the 357 // services will be registered. 358 // 359 // |conn_cb| will be called for any connections made to any of the services 360 // in |records| with a connected channel and the descriptor list for the 361 // endpoint which was connected. 362 using ServiceConnectCallback = sdp::Server::ConnectCallback; 363 using RegistrationHandle = sdp::Server::RegistrationHandle; 364 virtual RegistrationHandle RegisterService( 365 std::vector<sdp::ServiceRecord> records, 366 l2cap::ChannelParameters chan_params, 367 ServiceConnectCallback conn_cb) = 0; 368 369 // Unregister services previously registered with RegisterService. 370 // Idempotent. Returns |true| if any records were removed. 371 virtual bool UnregisterService(RegistrationHandle handle) = 0; 372 373 // Initiate and outbound connection. A request will be queued if a 374 // connection is already in progress. On error, |callback| will be called 375 // with an error result. The error will be |kCanceled| if a connection was 376 // never attempted, or |kFailed| if establishing a connection failed. 377 // Returns a handle that will cancel the request when dropped (if connection 378 // establishment has not started). If a BR/EDR connection with the peer does 379 // not exist, returns nullopt. 380 using ScoRequestHandle = BrEdrConnection::ScoRequestHandle; 381 virtual std::optional<ScoRequestHandle> OpenScoConnection( 382 PeerId peer_id, 383 const bt::StaticPacket< 384 pw::bluetooth::emboss::SynchronousConnectionParametersWriter>& 385 parameters, 386 sco::ScoConnectionManager::OpenConnectionCallback callback) = 0; 387 388 // Accept inbound connection requests using the parameters given in order. 389 // The parameters will be tried in order until either a connection is 390 // successful, all parameters have been rejected, or the procedure is 391 // canceled. On success, |callback| will be called with the connection 392 // object and the index of the parameters used to establish the connection. 393 // On error, |callback| will be called with an error result. If another 394 // Open/Accept request is made before a connection request is received, this 395 // request will be canceled (with error |kCanceled|). Returns a handle that 396 // will cancel the request when destroyed (if connection establishment has 397 // not started). If a BR/EDR connection with the peer does not exist, 398 // returns nullopt. 399 virtual std::optional<ScoRequestHandle> AcceptScoConnection( 400 PeerId peer_id, 401 std::vector<bt::StaticPacket< 402 pw::bluetooth::emboss::SynchronousConnectionParametersWriter>> 403 parameters, 404 sco::ScoConnectionManager::AcceptConnectionCallback callback) = 0; 405 }; 406 407 // Returns nullptr if the controller does not support classic. 408 virtual BrEdr* bredr() const = 0; 409 410 // Returns this Adapter's peer cache. 411 virtual PeerCache* peer_cache() = 0; 412 413 // Add a previously bonded device to the peer cache and set it up for 414 // auto-connect procedures. 415 virtual bool AddBondedPeer(BondingData bonding_data) = 0; 416 417 // Assigns a pairing delegate to this adapter. This PairingDelegate and its 418 // I/O capabilities will be used for all future pairing procedures. Setting a 419 // new PairingDelegate cancels all ongoing pairing procedures. 420 virtual void SetPairingDelegate(PairingDelegate::WeakPtr delegate) = 0; 421 422 // Returns true if this adapter is currently in discoverable mode on the LE or 423 // BR/EDR transports. 424 virtual bool IsDiscoverable() const = 0; 425 426 // Returns true if any discovery process (LE or BR/EDR) is running on this 427 // adapter. 428 virtual bool IsDiscovering() const = 0; 429 430 // Sets the Local Name of this adapter, for both BR/EDR discoverability and 431 // public LE services. 432 virtual void SetLocalName(std::string name, 433 hci::ResultFunction<> callback) = 0; 434 435 virtual std::string local_name() const = 0; 436 437 // Sets the Device Class of this adapter. 438 virtual void SetDeviceClass(DeviceClass dev_class, 439 hci::ResultFunction<> callback) = 0; 440 441 // Assign a callback to be notified when a connection is automatically 442 // established to a bonded LE peer in the directed connectable mode (Vol 3, 443 // Part C, 9.3.3). 444 using AutoConnectCallback = 445 fit::function<void(std::unique_ptr<bt::gap::LowEnergyConnectionHandle>)>; 446 virtual void set_auto_connect_callback(AutoConnectCallback callback) = 0; 447 448 // Attach Adapter's inspect node as a child node under |parent| with the given 449 // |name|. 450 virtual void AttachInspect(inspect::Node& parent, std::string name) = 0; 451 452 // Returns a weak pointer to this adapter. 453 using WeakPtr = WeakSelf<Adapter>::WeakPtr; 454 virtual Adapter::WeakPtr AsWeakPtr() = 0; 455 }; 456 457 } // namespace gap 458 } // namespace bt 459