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