1 // Copyright 2024 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 <fuchsia/bluetooth/host/cpp/fidl.h>
18 #include <lib/zx/channel.h>
19 
20 #include <memory>
21 #include <unordered_map>
22 #include <unordered_set>
23 
24 #include "fuchsia/bluetooth/cpp/fidl.h"
25 #include "fuchsia/bluetooth/sys/cpp/fidl.h"
26 #include "lib/fidl/cpp/interface_request.h"
27 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/server_base.h"
28 #include "pw_bluetooth_sapphire/fuchsia/lib/fidl/hanging_getter.h"
29 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h"
30 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
31 #include "pw_bluetooth_sapphire/internal/host/gap/adapter.h"
32 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_connection_manager.h"
33 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_discovery_manager.h"
34 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_discovery_manager.h"
35 #include "pw_bluetooth_sapphire/internal/host/gap/pairing_delegate.h"
36 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
37 
38 namespace bthost {
39 
40 // Implements the Host FIDL interface. Owns all FIDL connections that have been
41 // opened through it.
42 class HostServer : public AdapterServerBase<fuchsia::bluetooth::host::Host>,
43                    public bt::gap::PairingDelegate {
44  public:
45   HostServer(zx::channel channel,
46              const bt::gap::Adapter::WeakPtr& adapter,
47              bt::gatt::GATT::WeakPtr gatt);
48   ~HostServer() override;
49 
50   // ::fuchsia::bluetooth::host::Host overrides:
51   void RequestProtocol(
52       ::fuchsia::bluetooth::host::ProtocolRequest request) override;
53   void WatchState(WatchStateCallback callback) override;
54   void SetLocalData(::fuchsia::bluetooth::sys::HostData host_data) override;
55   void SetPeerWatcher(
56       ::fidl::InterfaceRequest<::fuchsia::bluetooth::host::PeerWatcher>
57           peer_watcher) override;
58   void SetLocalName(::std::string local_name,
59                     SetLocalNameCallback callback) override;
60   void SetDeviceClass(fuchsia::bluetooth::DeviceClass device_class,
61                       SetDeviceClassCallback callback) override;
62 
63   void StartDiscovery(
64       ::fuchsia::bluetooth::host::HostStartDiscoveryRequest request) override;
65   void SetConnectable(bool connectable,
66                       SetConnectableCallback callback) override;
67   void SetDiscoverable(bool discoverable,
68                        SetDiscoverableCallback callback) override;
69   void EnableBackgroundScan(bool enabled) override;
70   void EnablePrivacy(bool enabled) override;
71   void SetBrEdrSecurityMode(
72       ::fuchsia::bluetooth::sys::BrEdrSecurityMode mode) override;
73   void SetLeSecurityMode(
74       ::fuchsia::bluetooth::sys::LeSecurityMode mode) override;
75   void SetPairingDelegate(
76       ::fuchsia::bluetooth::sys::InputCapability input,
77       ::fuchsia::bluetooth::sys::OutputCapability output,
78       ::fidl::InterfaceHandle<::fuchsia::bluetooth::sys::PairingDelegate>
79           delegate) override;
80   void Connect(::fuchsia::bluetooth::PeerId id,
81                ConnectCallback callback) override;
82   void Disconnect(::fuchsia::bluetooth::PeerId id,
83                   DisconnectCallback callback) override;
84   void Pair(::fuchsia::bluetooth::PeerId id,
85             ::fuchsia::bluetooth::sys::PairingOptions options,
86             PairCallback callback) override;
87   void Forget(::fuchsia::bluetooth::PeerId id,
88               ForgetCallback callback) override;
89   void Shutdown() override;
90   void SetBondingDelegate(
91       ::fidl::InterfaceRequest<::fuchsia::bluetooth::host::BondingDelegate>
92           request) override;
93   void handle_unknown_method(uint64_t ordinal,
94                              bool method_has_response) override;
95 
96  private:
97   class DiscoverySessionServer
98       : public ServerBase<::fuchsia::bluetooth::host::DiscoverySession> {
99    public:
100     explicit DiscoverySessionServer(
101         fidl::InterfaceRequest<::fuchsia::bluetooth::host::DiscoverySession>
102             request,
103         HostServer* host);
104 
Close(zx_status_t epitaph)105     void Close(zx_status_t epitaph) { binding()->Close(epitaph); }
106 
107     // ::fuchsia::bluetooth::host::Discovery overrides:
108     void Stop() override;
109 
110    private:
111     void handle_unknown_method(uint64_t ordinal,
112                                bool method_has_response) override;
113 
114     HostServer* host_;
115   };
116 
117   class PeerWatcherServer
118       : public ServerBase<::fuchsia::bluetooth::host::PeerWatcher> {
119    public:
120     PeerWatcherServer(::fidl::InterfaceRequest<
121                           ::fuchsia::bluetooth::host::PeerWatcher> request,
122                       bt::gap::PeerCache* peer_cache,
123                       HostServer* host);
124     ~PeerWatcherServer() override;
125 
126     // Called by |adapter()->peer_cache()| when a peer is updated.
127     void OnPeerUpdated(const bt::gap::Peer& peer);
128 
129     // Called by |adapter()->peer_cache()| when a peer is removed.
130     void OnPeerRemoved(bt::PeerId identifier);
131 
132     void MaybeCallCallback();
133 
134    private:
135     using Updated = std::vector<fuchsia::bluetooth::sys::Peer>;
136     using Removed = std::vector<fuchsia::bluetooth::PeerId>;
137 
138     // PeerWatcher overrides:
139     void GetNext(::fuchsia::bluetooth::host::PeerWatcher::GetNextCallback
140                      callback) override;
141     void handle_unknown_method(uint64_t ordinal,
142                                bool method_has_response) override;
143 
144     std::unordered_set<bt::PeerId> updated_;
145     std::unordered_set<bt::PeerId> removed_;
146 
147     bt::gap::PeerCache* peer_cache_;
148     // Id of the PeerCache::add_peer_updated_callback callback. Used to remove
149     // the callback when this server is closed.
150     bt::gap::PeerCache::CallbackId peer_updated_callback_id_;
151 
152     ::fuchsia::bluetooth::host::PeerWatcher::GetNextCallback callback_ =
153         nullptr;
154 
155     HostServer* host_;
156 
157     // Keep this as the last member to make sure that all weak pointers are
158     // invalidated before other members get destroyed.
159     WeakSelf<PeerWatcherServer> weak_self_;
160   };
161 
162   class BondingDelegateServer
163       : public ServerBase<::fuchsia::bluetooth::host::BondingDelegate> {
164    public:
165     explicit BondingDelegateServer(
166         ::fidl::InterfaceRequest<::fuchsia::bluetooth::host::BondingDelegate>
167             request,
168         HostServer* host);
169 
170     void OnNewBondingData(const bt::gap::Peer& peer);
171 
172    private:
173     // BondingDelegate overrides:
174     void RestoreBonds(
175         ::std::vector<::fuchsia::bluetooth::sys::BondingData> bonds,
176         RestoreBondsCallback callback) override;
177     void WatchBonds(WatchBondsCallback callback) override;
178     void handle_unknown_method(uint64_t ordinal,
179                                bool method_has_response) override;
180 
181     void MaybeNotifyWatchBonds();
182 
183     HostServer* host_;
184     // Queued bond updates that will be sent on the next call to WatchBonds.
185     std::queue<::fuchsia::bluetooth::sys::BondingData> updated_;
186     fit::callback<void(
187         ::fuchsia::bluetooth::host::BondingDelegate_WatchBonds_Result)>
188         watch_bonds_cb_;
189   };
190 
191   // bt::gap::PairingDelegate overrides:
192   bt::sm::IOCapability io_capability() const override;
193   void CompletePairing(bt::PeerId id, bt::sm::Result<> status) override;
194   void ConfirmPairing(bt::PeerId id, ConfirmCallback confirm) override;
195   void DisplayPasskey(bt::PeerId id,
196                       uint32_t passkey,
197                       DisplayMethod method,
198                       ConfirmCallback confirm) override;
199   void RequestPasskey(bt::PeerId id, PasskeyResponseCallback respond) override;
200 
201   // Common code used for showing a user intent (except passkey request).
202   void DisplayPairingRequest(bt::PeerId id,
203                              std::optional<uint32_t> passkey,
204                              fuchsia::bluetooth::sys::PairingMethod method,
205                              ConfirmCallback confirm);
206 
207   // Called by |adapter()->peer_cache()| when a peer is bonded.
208   void OnPeerBonded(const bt::gap::Peer& peer);
209 
210   void ConnectLowEnergy(bt::PeerId id, ConnectCallback callback);
211   void ConnectBrEdr(bt::PeerId peer_id, ConnectCallback callback);
212 
213   void PairLowEnergy(bt::PeerId id,
214                      ::fuchsia::bluetooth::sys::PairingOptions options,
215                      PairCallback callback);
216   void PairBrEdr(bt::PeerId id, PairCallback callback);
217   // Called when a connection is established to a peer, either when initiated
218   // by a user via a client of Host.fidl, or automatically by the GAP adapter
219   void RegisterLowEnergyConnection(
220       std::unique_ptr<bt::gap::LowEnergyConnectionHandle> conn_ref,
221       bool auto_connect);
222 
223   // Called when |server| receives a channel connection error.
224   void OnConnectionError(Server* server);
225 
226   // Helper to start LE Discovery (called by StartDiscovery)
227   void StartLEDiscovery();
228 
229   void StopDiscovery(zx_status_t epitaph, bool notify_info_change = true);
230 
231   void OnDiscoverySessionServerClose(DiscoverySessionServer* server);
232 
233   // Resets the I/O capability of this server to no I/O and tells the GAP layer
234   // to reject incoming pairing requests.
235   void ResetPairingDelegate();
236 
237   // Resolves any HostInfo watcher with the current adapter state.
238   void NotifyInfoChange();
239 
240   void RestoreBonds(
241       ::std::vector<::fuchsia::bluetooth::sys::BondingData> bonds,
242       ::fuchsia::bluetooth::host::BondingDelegate::RestoreBondsCallback
243           callback);
244 
245   // Helper for binding a fidl::InterfaceRequest to a FIDL server of type
246   // ServerType.
247   template <typename ServerType, typename... Args>
BindServer(Args...args)248   void BindServer(Args... args) {
249     auto server = std::make_unique<ServerType>(std::move(args)...);
250     Server* s = server.get();
251     server->set_error_handler(
252         [this, s](zx_status_t status) { this->OnConnectionError(s); });
253     servers_[server.get()] = std::move(server);
254   }
255 
256   fuchsia::bluetooth::sys::PairingDelegatePtr pairing_delegate_;
257 
258   // We hold a weak pointer to GATT for dispatching GATT FIDL requests.
259   bt::gatt::GATT::WeakPtr gatt_;
260 
261   std::unordered_map<DiscoverySessionServer*,
262                      std::unique_ptr<DiscoverySessionServer>>
263       discovery_session_servers_;
264   std::unique_ptr<bt::gap::LowEnergyDiscoverySession> le_discovery_session_;
265   std::unique_ptr<bt::gap::BrEdrDiscoverySession> bredr_discovery_session_;
266 
267   bool requesting_background_scan_;
268   std::unique_ptr<bt::gap::LowEnergyDiscoverySession> le_background_scan_;
269 
270   bool requesting_discoverable_;
271   std::unique_ptr<bt::gap::BrEdrDiscoverableSession>
272       bredr_discoverable_session_;
273 
274   bt::sm::IOCapability io_capability_;
275 
276   // All active FIDL interface servers.
277   // NOTE: Each key is a raw pointer that is owned by the corresponding value.
278   // This allows us to create a set of managed objects that can be looked up via
279   // raw pointer.
280   std::unordered_map<Server*, std::unique_ptr<Server>> servers_;
281 
282   // All LE connections that were either initiated by this HostServer or
283   // auto-connected by the system.
284   // TODO(armansito): Consider storing auto-connected references separately from
285   // directly connected references.
286   std::unordered_map<bt::PeerId,
287                      std::unique_ptr<bt::gap::LowEnergyConnectionHandle>>
288       le_connections_;
289 
290   // Used to drive the WatchState() method.
291   bt_lib_fidl::HangingGetter<fuchsia::bluetooth::sys::HostInfo> info_getter_;
292 
293   std::optional<PeerWatcherServer> peer_watcher_server_;
294 
295   std::optional<BondingDelegateServer> bonding_delegate_server_;
296 
297   // Keep this as the last member to make sure that all weak pointers are
298   // invalidated before other members get destroyed.
299   WeakSelf<HostServer> weak_self_;
300 
301   WeakSelf<PairingDelegate> weak_pairing_;
302 
303   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(HostServer);
304 };
305 
306 }  // namespace bthost
307