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 "pw_bluetooth_sapphire/internal/host/common/identifier.h"
17 #include "pw_bluetooth_sapphire/internal/host/common/inspectable.h"
18 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h"
19 #include "pw_bluetooth_sapphire/internal/host/gap/generic_access_client.h"
20 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_connection_handle.h"
21 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_connection_request.h"
22 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt.h"
23 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
24 #include "pw_bluetooth_sapphire/internal/host/hci/low_energy_connection.h"
25 #include "pw_bluetooth_sapphire/internal/host/iso/iso_stream_manager.h"
26 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_manager.h"
27 #include "pw_bluetooth_sapphire/internal/host/sm/delegate.h"
28 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
29 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h"
30 
31 namespace bt::sm {
32 class SecurityManager;
33 }
34 
35 namespace bt::gap {
36 
37 namespace internal {
38 
39 // LowEnergyConnector constructs LowEnergyConnection instances immediately upon
40 // successful completion of the link layer connection procedure (to hook up HCI
41 // event callbacks). However, LowEnergyConnections aren't exposed to the rest of
42 // the stack (including the LowEnergyConnectionManager) until fully
43 // interrogated, as completion of the link-layer connection process is
44 // insufficient to guarantee a working connection. Thus this class represents
45 // the state of an active *AND* (outside of LowEnergyConnector) known-functional
46 // connection.
47 //
48 // Instances are kept alive as long as there is at least one
49 // LowEnergyConnectionHandle that references them. Instances are expected to be
50 // destroyed immediately after a peer disconnect event is received (as indicated
51 // by peer_disconnect_cb).
52 class LowEnergyConnection final : public sm::Delegate {
53  public:
54   // |peer| is the peer that this connection is connected to.
55   // |link| is the underlying LE HCI connection that this connection corresponds
56   // to. |peer_disconnect_cb| will be called when the peer disconnects. It will
57   // not be called before this method returns. |error_cb| will be called when a
58   // fatal connection error occurs and the connection should be closed (e.g.
59   // when L2CAP reports an error). It will not be called before this method
60   // returns. |conn_mgr| is the LowEnergyConnectionManager that owns this
61   // connection. |l2cap|, |gatt|, and |hci| are pointers to the interfaces of
62   // the corresponding layers. Returns nullptr if connection initialization
63   // fails.
64   using PeerDisconnectCallback =
65       fit::callback<void(pw::bluetooth::emboss::StatusCode)>;
66   using ErrorCallback = fit::callback<void()>;
67   static std::unique_ptr<LowEnergyConnection> Create(
68       Peer::WeakPtr peer,
69       std::unique_ptr<hci::LowEnergyConnection> link,
70       LowEnergyConnectionOptions connection_options,
71       PeerDisconnectCallback peer_disconnect_cb,
72       ErrorCallback error_cb,
73       WeakSelf<LowEnergyConnectionManager>::WeakPtr conn_mgr,
74       l2cap::ChannelManager* l2cap,
75       gatt::GATT::WeakPtr gatt,
76       hci::Transport::WeakPtr hci,
77       pw::async::Dispatcher& dispatcher);
78 
79   // Notifies request callbacks and connection refs of the disconnection.
80   ~LowEnergyConnection() override;
81 
82   // Create a reference to this connection. When the last reference is dropped,
83   // this connection will be disconnected.
84   std::unique_ptr<LowEnergyConnectionHandle> AddRef();
85 
86   // Decrements the ref count. Must be called when a LowEnergyConnectionHandle
87   // is released/destroyed.
88   void DropRef(LowEnergyConnectionHandle* ref);
89 
90   // Used to respond to protocol/service requests for increased security.
91   void OnSecurityRequest(sm::SecurityLevel level, sm::ResultFunction<> cb);
92 
93   // Handles a pairing request (i.e. security upgrade) received from "higher
94   // levels", likely initiated from GAP. This will only be used by pairing
95   // requests that are initiated in the context of testing. May only be called
96   // on an already-established connection.
97   void UpgradeSecurity(sm::SecurityLevel level,
98                        sm::BondableMode bondable_mode,
99                        sm::ResultFunction<> cb);
100 
101   // Cancels any on-going pairing procedures and sets up SMP to use the provided
102   // new I/O capabilities for future pairing procedures.
103   void ResetSecurityManager(sm::IOCapability ioc);
104 
105   // Must be called when interrogation has completed. May update connection
106   // parameters if all initialization procedures have completed.
107   void OnInterrogationComplete();
108 
109   // Opens an L2CAP channel using the parameters |params|. Otherwise, calls |cb|
110   // with a nullptr.
111   void OpenL2capChannel(l2cap::Psm psm,
112                         l2cap::ChannelParameters params,
113                         l2cap::ChannelCallback cb);
114 
115   // Accept a future incoming request to establish an Isochronous stream on this
116   // LE connection. |id| specifies the CIG/CIS pair that identify the stream.
117   // |cb| will be called after the request is received to indicate success of
118   // establishing a stream, and the associated parameters.
119   iso::AcceptCisStatus AcceptCis(iso::CigCisIdentifier id,
120                                  iso::CisEstablishedCallback cb);
121 
122   // Attach connection as child node of |parent| with specified |name|.
123   void AttachInspect(inspect::Node& parent, std::string name);
124 
125   void set_security_mode(LESecurityMode mode);
126 
127   // Sets a callback that will be called when the peer disconnects.
set_peer_disconnect_callback(PeerDisconnectCallback cb)128   void set_peer_disconnect_callback(PeerDisconnectCallback cb) {
129     PW_CHECK(cb);
130     peer_disconnect_callback_ = std::move(cb);
131   }
132 
133   // |peer_conn_token| is a token generated by the connected Peer, and is used
134   // to synchronize connection state.
set_peer_conn_token(Peer::ConnectionToken peer_conn_token)135   void set_peer_conn_token(Peer::ConnectionToken peer_conn_token) {
136     PW_CHECK(interrogation_completed_);
137     PW_CHECK(!peer_conn_token_);
138     peer_conn_token_ = std::move(peer_conn_token);
139   }
140 
141   // Sets a callback that will be called when a fatal connection error occurs.
set_error_callback(ErrorCallback cb)142   void set_error_callback(ErrorCallback cb) {
143     PW_CHECK(cb);
144     error_callback_ = std::move(cb);
145   }
146 
ref_count()147   size_t ref_count() const { return refs_->size(); }
148 
peer_id()149   PeerId peer_id() const { return peer_->identifier(); }
handle()150   hci_spec::ConnectionHandle handle() const { return link_->handle(); }
link()151   hci::LowEnergyConnection* link() const { return link_.get(); }
152   sm::BondableMode bondable_mode() const;
153 
154   sm::SecurityProperties security() const;
155 
role()156   pw::bluetooth::emboss::ConnectionRole role() const { return link()->role(); }
157 
158   using WeakPtr = WeakSelf<LowEnergyConnection>::WeakPtr;
GetWeakPtr()159   LowEnergyConnection::WeakPtr GetWeakPtr() { return weak_self_.GetWeakPtr(); }
160 
161  private:
162   LowEnergyConnection(Peer::WeakPtr peer,
163                       std::unique_ptr<hci::LowEnergyConnection> link,
164                       LowEnergyConnectionOptions connection_options,
165                       PeerDisconnectCallback peer_disconnect_cb,
166                       ErrorCallback error_cb,
167                       WeakSelf<LowEnergyConnectionManager>::WeakPtr conn_mgr,
168                       std::unique_ptr<iso::IsoStreamManager> iso_mgr,
169                       l2cap::ChannelManager* l2cap,
170                       gatt::GATT::WeakPtr gatt,
171                       hci::Transport::WeakPtr hci,
172                       pw::async::Dispatcher& dispatcher);
173 
174   // Registers this connection with L2CAP and initializes the fixed channel
175   // protocols. Return true on success, false on failure.
176   [[nodiscard]] bool InitializeFixedChannels();
177 
178   // Register handlers for HCI events that correspond to this connection.
179   void RegisterEventHandlers();
180 
181   // Start kLEConnectionPauseCentral/Peripheral timeout that will update
182   // connection parameters. Should be called as soon as this GAP connection is
183   // established.
184   void StartConnectionPauseTimeout();
185 
186   // Start kLEConnectionPausePeripheral timeout that will send a connection
187   // parameter update request. Should be called as soon as connection is
188   // established.
189   void StartConnectionPausePeripheralTimeout();
190 
191   // Start kLEConnectionPauseCentral timeout that will update connection
192   // parameters. Should be called as soon as connection is established.
193   void StartConnectionPauseCentralTimeout();
194 
195   // Initializes SecurityManager and GATT.
196   // Called by the L2CAP layer once the link has been registered and the fixed
197   // channels have been opened. Returns false if GATT initialization fails.
198   [[nodiscard]] bool OnL2capFixedChannelsOpened(
199       l2cap::Channel::WeakPtr att,
200       l2cap::Channel::WeakPtr smp,
201       LowEnergyConnectionOptions connection_options);
202 
203   // Called when the preferred connection parameters have been received for a LE
204   // peripheral. This can happen in the form of:
205   //
206   //   1. <<Peripheral Connection Interval Range>> advertising data field
207   //   2. "Peripheral Preferred Connection Parameters" GATT characteristic
208   //      (under "GAP" service)
209   //   3. HCI LE Remote Connection Parameter Request Event
210   //   4. L2CAP Connection Parameter Update request
211   //
212   // TODO(fxbug.dev/42147867): Support #1 above.
213   // TODO(fxbug.dev/42147868): Support #3 above.
214   //
215   // This method caches |params| for later connection attempts and sends the
216   // parameters to the controller if the initializing procedures are complete
217   // (since we use more agressing initial parameters for pairing and service
218   // discovery, as recommended by the specification in v5.0, Vol 3, Part C,
219   // Section 9.3.12.1).
220   //
221   // |peer_id| uniquely identifies the peer. |handle| represents
222   // the logical link that |params| should be applied to.
223   void OnNewLEConnectionParams(
224       const hci_spec::LEPreferredConnectionParameters& params);
225 
226   // As an LE peripheral, request that the connection parameters |params| be
227   // used on the given connection |conn| with peer |peer_id|. This may send an
228   // HCI LE Connection Update command or an L2CAP Connection Parameter Update
229   // Request depending on what the local and remote controllers support.
230   //
231   // Interrogation must have completed before this may be called.
232   void RequestConnectionParameterUpdate(
233       const hci_spec::LEPreferredConnectionParameters& params);
234 
235   // Handler for connection parameter update command sent when an update is
236   // requested by RequestConnectionParameterUpdate.
237   //
238   // If the HCI LE Connection Update command fails with status
239   // kUnsupportedRemoteFeature, the update will be retried with an L2CAP
240   // Connection Parameter Update Request.
241   void HandleRequestConnectionParameterUpdateCommandStatus(
242       hci_spec::LEPreferredConnectionParameters params, hci::Result<> status);
243 
244   // As an LE peripheral, send an L2CAP Connection Parameter Update Request
245   // requesting |params| on the LE signaling channel of the given logical link
246   // |handle|.
247   //
248   // NOTE: This should only be used if the LE peripheral and/or LE central do
249   // not support the Connection Parameters Request Link Layer Control Procedure
250   // (Core Spec v5.2  Vol 3, Part A, Sec 4.20). If they do,
251   // UpdateConnectionParams(...) should be used instead.
252   void L2capRequestConnectionParameterUpdate(
253       const hci_spec::LEPreferredConnectionParameters& params);
254 
255   // Requests that the controller use the given connection |params| by sending
256   // an HCI LE Connection Update command. This may be issued on both the LE
257   // peripheral and the LE central.
258   //
259   // The link layer may modify the preferred parameters |params| before
260   // initiating the Connection Parameters Request Link Layer Control Procedure
261   // (Core Spec v5.2, Vol 6, Part B, Sec 5.1.7).
262   //
263   // If non-null, |status_cb| will be called when the HCI Command Status event
264   // is received.
265   //
266   // The HCI LE Connection Update Complete event will be generated after the
267   // parameters have been applied or if the update fails, and will indicate the
268   // (possibly modified) parameter values.
269   //
270   // NOTE: If the local host is an LE peripheral, then the local controller and
271   // the remote LE central must have indicated support for this procedure in the
272   // LE feature mask. Otherwise, L2capRequestConnectionParameterUpdate(...)
273   // should be used instead.
274   using StatusCallback = hci::ResultCallback<>;
275   void UpdateConnectionParams(
276       const hci_spec::LEPreferredConnectionParameters& params,
277       StatusCallback status_cb = nullptr);
278 
279   // This event may be generated without host interaction by the Link Layer, or
280   // as the result of a Connection Update Command sent by either device, which
281   // is why it is not simply handled by the command handler. (See Core Spec
282   // v5.2, Vol 6, Part B, Sec 5.1.7.1).
283   void OnLEConnectionUpdateComplete(const hci::EventPacket& event);
284 
285   // Updates or requests an update of the connection parameters, for central and
286   // peripheral roles respectively, if interrogation has completed.
287   // TODO(fxbug.dev/42159733): Wait to update connection parameters until all
288   // initialization procedures have completed.
289   void MaybeUpdateConnectionParameters();
290 
291   // Registers the peer with GATT and initiates service discovery. If
292   // |service_uuid| is specified, only discover the indicated service and the
293   // GAP service. Returns true on success, false on failure.
294   bool InitializeGatt(l2cap::Channel::WeakPtr att,
295                       std::optional<UUID> service_uuid);
296 
297   // Called when service discovery completes. |services| will only include
298   // services with the GAP UUID (there should only be one, but this is not
299   // guaranteed).
300   void OnGattServicesResult(att::Result<> status, gatt::ServiceList services);
301 
302   // Notifies all connection refs of disconnection.
303   void CloseRefs();
304 
305   // sm::Delegate overrides:
306   void OnNewPairingData(const sm::PairingData& pairing_data) override;
307   void OnPairingComplete(sm::Result<> status) override;
308   void OnAuthenticationFailure(hci::Result<> status) override;
309   void OnNewSecurityProperties(const sm::SecurityProperties& sec) override;
310   std::optional<sm::IdentityInfo> OnIdentityInformationRequest() override;
311   void ConfirmPairing(ConfirmCallback confirm) override;
312   void DisplayPasskey(uint32_t passkey,
313                       sm::Delegate::DisplayMethod method,
314                       ConfirmCallback confirm) override;
315   void RequestPasskey(PasskeyResponseCallback respond) override;
316 
317   pw::async::Dispatcher& dispatcher_;
318 
319   // Notifies Peer of connection destruction. This should be ordered first so
320   // that it is destroyed last.
321   std::optional<Peer::ConnectionToken> peer_conn_token_;
322 
323   Peer::WeakPtr peer_;
324   std::unique_ptr<hci::LowEnergyConnection> link_;
325   LowEnergyConnectionOptions connection_options_;
326   WeakSelf<LowEnergyConnectionManager>::WeakPtr conn_mgr_;
327 
328   // Manages all Isochronous streams for this connection. If this connection is
329   // operating as a Central, |iso_mgr_| is used to establish an outgoing
330   // connection to a peer. When operating as a Peripheral, |iso_mgr_| is used to
331   // allow incoming requests for specified CIG/CIS combinations.
332   std::unique_ptr<iso::IsoStreamManager> iso_mgr_;
333 
334   struct InspectProperties {
335     inspect::StringProperty peer_id;
336     inspect::StringProperty peer_address;
337   };
338   InspectProperties inspect_properties_;
339   inspect::Node inspect_node_;
340 
341   // Used to update the L2CAP layer to reflect the correct link security level.
342   l2cap::ChannelManager* l2cap_;
343 
344   // Reference to the GATT profile layer is used to initiate service discovery
345   // and register the link.
346   gatt::GATT::WeakPtr gatt_;
347 
348   // The ATT Bearer is owned by LowEnergyConnection but weak pointers are passed
349   // to the GATT layer. As such, this connection must be unregistered from the
350   // GATT layer before the Bearer is destroyed. Created during initialization,
351   // but if initialization fails this may be nullptr.
352   std::unique_ptr<att::Bearer> att_bearer_;
353 
354   // SMP pairing manager.
355   std::unique_ptr<sm::SecurityManager> sm_;
356 
357   hci::CommandChannel::WeakPtr cmd_;
358 
359   hci::Transport::WeakPtr hci_;
360 
361   // Called when the peer disconnects.
362   PeerDisconnectCallback peer_disconnect_callback_;
363 
364   // Called when a fatal connection error occurs and the connection should be
365   // closed (e.g. when L2CAP reports an error).
366   ErrorCallback error_callback_;
367 
368   // Event handler ID for the HCI LE Connection Update Complete event.
369   hci::CommandChannel::EventHandlerId conn_update_cmpl_handler_id_;
370 
371   // Called with the status of the next HCI LE Connection Update Complete event.
372   // The HCI LE Connection Update command does not have its own complete event
373   // handler because the HCI LE Connection Complete event can be generated for
374   // other reasons.
375   fit::callback<void(pw::bluetooth::emboss::StatusCode)>
376       le_conn_update_complete_command_callback_;
377 
378   // Called after kLEConnectionPausePeripheral.
379   std::optional<SmartTask> conn_pause_peripheral_timeout_;
380 
381   // Called after kLEConnectionPauseCentral.
382   std::optional<SmartTask> conn_pause_central_timeout_;
383 
384   // Set to true when a request to update the connection parameters has been
385   // sent.
386   bool connection_parameters_update_requested_ = false;
387 
388   bool interrogation_completed_ = false;
389 
390   // LowEnergyConnectionManager is responsible for making sure that these
391   // pointers are always valid.
392   using ConnectionHandleSet = std::unordered_set<LowEnergyConnectionHandle*>;
393   IntInspectable<ConnectionHandleSet> refs_;
394 
395   // Null until service discovery completes.
396   std::optional<GenericAccessClient> gap_service_client_;
397 
398   WeakSelf<LowEnergyConnection> weak_self_;
399   WeakSelf<sm::Delegate> weak_delegate_;
400 
401   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyConnection);
402 };
403 
404 }  // namespace internal
405 }  // namespace bt::gap
406