• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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