• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/host_server.h"
16 
17 #include <cpp-string/string_printf.h>
18 #include <lib/fpromise/result.h>
19 #include <pw_assert/check.h>
20 #include <zircon/errors.h>
21 
22 #include <utility>
23 #include <variant>
24 
25 #include "fuchsia/bluetooth/host/cpp/fidl.h"
26 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/gatt2_server_server.h"
27 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/gatt_server_server.h"
28 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/helpers.h"
29 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/low_energy_central_server.h"
30 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/low_energy_peripheral_server.h"
31 #include "pw_bluetooth_sapphire/fuchsia/host/fidl/profile_server.h"
32 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h"
33 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
34 #include "pw_bluetooth_sapphire/internal/host/gap/adapter.h"
35 #include "pw_bluetooth_sapphire/internal/host/gap/bonding_data.h"
36 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_connection_manager.h"
37 #include "pw_bluetooth_sapphire/internal/host/gap/bredr_discovery_manager.h"
38 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h"
39 #include "pw_bluetooth_sapphire/internal/host/gap/low_energy_discovery_manager.h"
40 #include "pw_bluetooth_sapphire/internal/host/sm/types.h"
41 #include "pw_bluetooth_sapphire/internal/host/sm/util.h"
42 
43 namespace bthost {
44 
45 namespace fbt = fuchsia::bluetooth;
46 namespace fsys = fuchsia::bluetooth::sys;
47 namespace fhost = fuchsia::bluetooth::host;
48 
49 using bt::PeerId;
50 using bt::gap::BrEdrSecurityModeToString;
51 using bt::gap::LeSecurityModeToString;
52 using bt::sm::IOCapability;
53 using fidl_helpers::BrEdrSecurityModeFromFidl;
54 using fidl_helpers::HostErrorToFidl;
55 using fidl_helpers::LeSecurityModeFromFidl;
56 using fidl_helpers::NewFidlError;
57 using fidl_helpers::PeerIdFromString;
58 using fidl_helpers::ResultToFidl;
59 using fidl_helpers::SecurityLevelFromFidl;
60 
HostServer(zx::channel channel,const bt::gap::Adapter::WeakPtr & adapter,bt::gatt::GATT::WeakPtr gatt)61 HostServer::HostServer(zx::channel channel,
62                        const bt::gap::Adapter::WeakPtr& adapter,
63                        bt::gatt::GATT::WeakPtr gatt)
64     : AdapterServerBase(adapter, this, std::move(channel)),
65       pairing_delegate_(nullptr),
66       gatt_(std::move(gatt)),
67       requesting_background_scan_(false),
68       requesting_discoverable_(false),
69       io_capability_(IOCapability::kNoInputNoOutput),
70       weak_self_(this),
71       weak_pairing_(this) {
72   PW_CHECK(gatt_.is_alive());
73 
74   auto self = weak_self_.GetWeakPtr();
75   adapter->peer_cache()->set_peer_bonded_callback([self](const auto& peer) {
76     if (self.is_alive()) {
77       self->OnPeerBonded(peer);
78     }
79   });
80   adapter->set_auto_connect_callback([self](auto conn_ref) {
81     if (self.is_alive()) {
82       self->RegisterLowEnergyConnection(std::move(conn_ref),
83                                         /*auto_connect=*/true);
84     }
85   });
86 
87   // Watch for changes in LE address.
88   adapter->le()->register_address_changed_callback([self]() {
89     if (self.is_alive()) {
90       self->NotifyInfoChange();
91     }
92   });
93 
94   // Initialize the HostInfo getter with the initial state.
95   NotifyInfoChange();
96 }
97 
~HostServer()98 HostServer::~HostServer() { Shutdown(); }
99 
RequestProtocol(fhost::ProtocolRequest request)100 void HostServer::RequestProtocol(fhost::ProtocolRequest request) {
101   switch (request.Which()) {
102     case fhost::ProtocolRequest::Tag::kCentral:
103       BindServer<LowEnergyCentralServer>(
104           adapter()->AsWeakPtr(), std::move(request.central()), gatt_);
105       break;
106     case fhost::ProtocolRequest::Tag::kPeripheral:
107       BindServer<LowEnergyPeripheralServer>(
108           adapter()->AsWeakPtr(), gatt_, std::move(request.peripheral()));
109       break;
110     case fhost::ProtocolRequest::Tag::kGattServer:
111       BindServer<GattServerServer>(gatt_->GetWeakPtr(),
112                                    std::move(request.gatt_server()));
113       break;
114     case fhost::ProtocolRequest::Tag::kGatt2Server:
115       BindServer<Gatt2ServerServer>(gatt_->GetWeakPtr(),
116                                     std::move(request.gatt2_server()));
117       break;
118     case fhost::ProtocolRequest::Tag::kProfile:
119       BindServer<ProfileServer>(adapter()->AsWeakPtr(),
120                                 std::move(request.profile()));
121       break;
122     case fhost::ProtocolRequest::Tag::kPrivilegedPeripheral:
123       BindServer<LowEnergyPrivilegedPeripheralServer>(
124           adapter()->AsWeakPtr(),
125           gatt_,
126           std::move(request.privileged_peripheral()));
127       break;
128     default:
129       bt_log(WARN, "fidl", "received unknown protocol request");
130       // The unknown protocol will be closed when `request` is destroyed.
131       break;
132   }
133 }
134 
WatchState(WatchStateCallback callback)135 void HostServer::WatchState(WatchStateCallback callback) {
136   info_getter_.Watch([cb = std::move(callback)](fsys::HostInfo info) {
137     cb(fhost::Host_WatchState_Result::WithResponse(
138         fhost::Host_WatchState_Response(std::move(info))));
139   });
140 }
141 
SetLocalData(fsys::HostData host_data)142 void HostServer::SetLocalData(fsys::HostData host_data) {
143   if (host_data.has_irk()) {
144     bt_log(DEBUG, "fidl", "assign IRK");
145     if (adapter()->le()) {
146       adapter()->le()->set_irk(host_data.irk().value);
147     }
148   }
149 }
150 
SetPeerWatcher(::fidl::InterfaceRequest<::fuchsia::bluetooth::host::PeerWatcher> peer_watcher)151 void HostServer::SetPeerWatcher(
152     ::fidl::InterfaceRequest<::fuchsia::bluetooth::host::PeerWatcher>
153         peer_watcher) {
154   if (peer_watcher_server_.has_value()) {
155     peer_watcher.Close(ZX_ERR_ALREADY_BOUND);
156     return;
157   }
158   peer_watcher_server_.emplace(
159       std::move(peer_watcher), adapter()->peer_cache(), this);
160 }
161 
SetLocalName(::std::string local_name,SetLocalNameCallback callback)162 void HostServer::SetLocalName(::std::string local_name,
163                               SetLocalNameCallback callback) {
164   PW_DCHECK(!local_name.empty());
165   adapter()->SetLocalName(std::move(local_name),
166                           [self = weak_self_.GetWeakPtr(),
167                            callback = std::move(callback)](auto status) {
168                             // Send adapter state update on success and if the
169                             // connection is still open.
170                             if (status.is_ok() && self.is_alive()) {
171                               self->NotifyInfoChange();
172                             }
173                             callback(ResultToFidl(status));
174                           });
175 }
176 
177 // TODO(fxbug.dev/42110379): Add a unit test for this method.
SetDeviceClass(fbt::DeviceClass device_class,SetDeviceClassCallback callback)178 void HostServer::SetDeviceClass(fbt::DeviceClass device_class,
179                                 SetDeviceClassCallback callback) {
180   // Device Class values must only contain data in the lower 3 bytes.
181   if (device_class.value >= 1 << 24) {
182     callback(fpromise::error(fsys::Error::INVALID_ARGUMENTS));
183     return;
184   }
185   bt::DeviceClass dev_class(device_class.value);
186   adapter()->SetDeviceClass(dev_class,
187                             [callback = std::move(callback)](auto status) {
188                               callback(ResultToFidl(status));
189                             });
190 }
191 
StartLEDiscovery()192 void HostServer::StartLEDiscovery() {
193   if (!adapter()->le()) {
194     StopDiscovery(ZX_ERR_INTERNAL);
195     return;
196   }
197 
198   // Set up a general-discovery filter for connectable devices.
199   // NOTE(armansito): This currently has no effect since peer updates
200   // are driven by PeerCache events. |session|'s "result callback" is
201   // unused.
202   bt::hci::DiscoveryFilter filter;
203   filter.set_connectable(true);
204   filter.SetGeneralDiscoveryFlags();
205 
206   adapter()->le()->StartDiscovery(
207       /*active=*/true,
208       {filter},
209       [self = weak_self_.GetWeakPtr()](auto session) {
210         // End the new session if this AdapterServer got destroyed in the
211         // meantime (e.g. because the client disconnected).
212         if (!self.is_alive() || self->discovery_session_servers_.empty()) {
213           return;
214         }
215 
216         if (!session) {
217           bt_log(ERROR, "fidl", "failed to start active LE discovery session");
218           self->StopDiscovery(ZX_ERR_INTERNAL);
219           return;
220         }
221 
222         self->le_discovery_session_ = std::move(session);
223 
224         // Send the adapter state update.
225         self->NotifyInfoChange();
226       });
227 }
228 
StartDiscovery(::fuchsia::bluetooth::host::HostStartDiscoveryRequest request)229 void HostServer::StartDiscovery(
230     ::fuchsia::bluetooth::host::HostStartDiscoveryRequest request) {
231   bt_log(DEBUG, "fidl", "%s", __FUNCTION__);
232   PW_DCHECK(adapter().is_alive());
233 
234   if (!request.has_token()) {
235     bt_log(WARN, "fidl", "missing Discovery token");
236     return;
237   }
238   fidl::InterfaceRequest<fhost::DiscoverySession> token =
239       std::move(*request.mutable_token());
240 
241   std::unique_ptr<DiscoverySessionServer> server =
242       std::make_unique<DiscoverySessionServer>(std::move(token), this);
243   DiscoverySessionServer* server_ptr = server.get();
244   discovery_session_servers_.emplace(server_ptr, std::move(server));
245 
246   // If there were existing sessions, then discovery is already
247   // starting/started.
248   if (discovery_session_servers_.size() != 1) {
249     return;
250   }
251 
252   if (!adapter()->bredr()) {
253     StartLEDiscovery();
254     return;
255   }
256   // TODO(jamuraa): start these in parallel instead of sequence
257   adapter()->bredr()->RequestDiscovery([self = weak_self_.GetWeakPtr(),
258                                         func = __FUNCTION__](
259                                            bt::hci::Result<> result,
260                                            auto session) mutable {
261     if (!self.is_alive() || self->discovery_session_servers_.empty()) {
262       return;
263     }
264 
265     if (result.is_error() || !session) {
266       bt_log(
267           ERROR, "fidl", "%s: failed to start BR/EDR discovery session", func);
268       self->StopDiscovery(ZX_ERR_INTERNAL);
269       return;
270     }
271 
272     self->bredr_discovery_session_ = std::move(session);
273     self->StartLEDiscovery();
274   });
275 }
276 
StopDiscovery(zx_status_t epitaph,bool notify_info_change)277 void HostServer::StopDiscovery(zx_status_t epitaph, bool notify_info_change) {
278   bool discovering = le_discovery_session_ || bredr_discovery_session_;
279   bredr_discovery_session_ = nullptr;
280   le_discovery_session_ = nullptr;
281   for (auto& [server, _] : discovery_session_servers_) {
282     server->Close(epitaph);
283   }
284   discovery_session_servers_.clear();
285 
286   if (discovering && notify_info_change) {
287     NotifyInfoChange();
288   }
289 }
290 
OnDiscoverySessionServerClose(DiscoverySessionServer * server)291 void HostServer::OnDiscoverySessionServerClose(DiscoverySessionServer* server) {
292   server->Close(ZX_ERR_CANCELED);
293   discovery_session_servers_.erase(server);
294   if (discovery_session_servers_.empty()) {
295     StopDiscovery(ZX_ERR_CANCELED);
296   }
297 }
298 
SetConnectable(bool connectable,SetConnectableCallback callback)299 void HostServer::SetConnectable(bool connectable,
300                                 SetConnectableCallback callback) {
301   bt_log(INFO, "fidl", "%s: %s", __FUNCTION__, connectable ? "true" : "false");
302 
303   auto classic = adapter()->bredr();
304   if (!classic) {
305     callback(fpromise::error(fsys::Error::NOT_SUPPORTED));
306     return;
307   }
308   classic->SetConnectable(connectable,
309                           [callback = std::move(callback)](const auto& result) {
310                             callback(ResultToFidl(result));
311                           });
312 }
313 
RestoreBonds(::std::vector<fsys::BondingData> bonds,fhost::BondingDelegate::RestoreBondsCallback callback)314 void HostServer::RestoreBonds(
315     ::std::vector<fsys::BondingData> bonds,
316     fhost::BondingDelegate::RestoreBondsCallback callback) {
317   bt_log(INFO, "fidl", "%s", __FUNCTION__);
318 
319   if (bonds.empty()) {
320     // Nothing to do. Reply with an empty list.
321     callback(fhost::BondingDelegate_RestoreBonds_Result::WithResponse(
322         fhost::BondingDelegate_RestoreBonds_Response()));
323     return;
324   }
325 
326   std::vector<fsys::BondingData> errors;
327   for (auto& bond : bonds) {
328     if (!bond.has_identifier() || !bond.has_address() ||
329         !(bond.has_le_bond() || bond.has_bredr_bond())) {
330       bt_log(ERROR,
331              "fidl",
332              "%s: BondingData mandatory fields missing!",
333              __FUNCTION__);
334       errors.push_back(std::move(bond));
335       continue;
336     }
337 
338     auto address = fidl_helpers::AddressFromFidlBondingData(bond);
339     if (!address) {
340       bt_log(ERROR,
341              "fidl",
342              "%s: BondingData address missing or invalid!",
343              __FUNCTION__);
344       errors.push_back(std::move(bond));
345       continue;
346     }
347 
348     bt::gap::BondingData bd;
349     bd.identifier = bt::PeerId{bond.identifier().value};
350     bd.address = *address;
351     if (bond.has_name()) {
352       bd.name = {bond.name()};
353     }
354 
355     if (bond.has_le_bond()) {
356       bd.le_pairing_data =
357           fidl_helpers::LePairingDataFromFidl(*address, bond.le_bond());
358     }
359     if (bond.has_bredr_bond()) {
360       bd.bredr_link_key = fidl_helpers::BredrKeyFromFidl(bond.bredr_bond());
361       bd.bredr_services =
362           fidl_helpers::BredrServicesFromFidl(bond.bredr_bond());
363     }
364 
365     // TODO(fxbug.dev/42137736): Convert bond.bredr.services to
366     // BondingData::bredr_services
367     if (!adapter()->AddBondedPeer(bd)) {
368       bt_log(ERROR,
369              "fidl",
370              "%s: failed to restore bonding data entry",
371              __FUNCTION__);
372       errors.push_back(std::move(bond));
373     }
374   }
375 
376   callback(fhost::BondingDelegate_RestoreBonds_Result::WithResponse(
377       fhost::BondingDelegate_RestoreBonds_Response(std::move(errors))));
378 }
379 
OnPeerBonded(const bt::gap::Peer & peer)380 void HostServer::OnPeerBonded(const bt::gap::Peer& peer) {
381   bt_log(DEBUG, "fidl", "%s", __FUNCTION__);
382   if (bonding_delegate_server_) {
383     bonding_delegate_server_->OnNewBondingData(peer);
384   }
385 }
386 
RegisterLowEnergyConnection(std::unique_ptr<bt::gap::LowEnergyConnectionHandle> conn_ref,bool auto_connect)387 void HostServer::RegisterLowEnergyConnection(
388     std::unique_ptr<bt::gap::LowEnergyConnectionHandle> conn_ref,
389     bool auto_connect) {
390   PW_DCHECK(conn_ref);
391 
392   bt::PeerId id = conn_ref->peer_identifier();
393   auto iter = le_connections_.find(id);
394   if (iter != le_connections_.end()) {
395     bt_log(
396         WARN,
397         "fidl",
398         "%s: peer already connected; connection reference dropped (peer: %s)",
399         __FUNCTION__,
400         bt_str(id));
401     return;
402   }
403 
404   bt_log(DEBUG,
405          "fidl",
406          "LE peer connected (%s): %s ",
407          (auto_connect ? "auto" : "direct"),
408          bt_str(id));
409   conn_ref->set_closed_callback([self = weak_self_.GetWeakPtr(), id] {
410     if (self.is_alive())
411       self->le_connections_.erase(id);
412   });
413   le_connections_[id] = std::move(conn_ref);
414 }
415 
SetDiscoverable(bool discoverable,SetDiscoverableCallback callback)416 void HostServer::SetDiscoverable(bool discoverable,
417                                  SetDiscoverableCallback callback) {
418   bt_log(INFO, "fidl", "%s(%s)", __FUNCTION__, discoverable ? "true" : "false");
419   // TODO(fxbug.dev/42177512): advertise LE here
420   if (!discoverable) {
421     bredr_discoverable_session_ = nullptr;
422     NotifyInfoChange();
423     callback(fpromise::ok());
424     return;
425   }
426   if (discoverable && requesting_discoverable_) {
427     bt_log(DEBUG, "fidl", "%s already in progress", __FUNCTION__);
428     callback(fpromise::error(fsys::Error::IN_PROGRESS));
429     return;
430   }
431   requesting_discoverable_ = true;
432   if (!adapter()->bredr()) {
433     callback(fpromise::error(fsys::Error::FAILED));
434     return;
435   }
436   adapter()->bredr()->RequestDiscoverable([self = weak_self_.GetWeakPtr(),
437                                            callback = std::move(callback),
438                                            func = __FUNCTION__](
439                                               bt::hci::Result<> result,
440                                               auto session) {
441     if (!self.is_alive()) {
442       callback(fpromise::error(fsys::Error::FAILED));
443       return;
444     }
445 
446     if (!self->requesting_discoverable_) {
447       callback(fpromise::error(fsys::Error::CANCELED));
448       return;
449     }
450 
451     if (result.is_error() || !session) {
452       bt_log(ERROR, "fidl", "%s: failed (result: %s)", func, bt_str(result));
453       fpromise::result<void, fsys::Error> fidl_result = ResultToFidl(result);
454       if (result.is_ok()) {
455         PW_CHECK(session == nullptr);
456         fidl_result = fpromise::error(fsys::Error::FAILED);
457       }
458       self->requesting_discoverable_ = false;
459       callback(std::move(fidl_result));
460       return;
461     }
462 
463     self->bredr_discoverable_session_ = std::move(session);
464     self->requesting_discoverable_ = false;
465     self->NotifyInfoChange();
466     callback(fpromise::ok());
467   });
468 }
469 
EnableBackgroundScan(bool enabled)470 void HostServer::EnableBackgroundScan(bool enabled) {
471   bt_log(INFO, "fidl", "%s background scan", (enabled ? "enable" : "disable"));
472   if (!adapter()->le()) {
473     bt_log(ERROR, "fidl", "%s: adapter does not support LE", __FUNCTION__);
474     return;
475   }
476 
477   if (!enabled) {
478     requesting_background_scan_ = false;
479     le_background_scan_ = nullptr;
480     return;
481   }
482 
483   // If a scan is already starting or is in progress, there is nothing to do to
484   // enable the scan.
485   if (requesting_background_scan_ || le_background_scan_) {
486     return;
487   }
488 
489   requesting_background_scan_ = true;
490   adapter()->le()->StartDiscovery(
491       /*active=*/false, {}, [self = weak_self_.GetWeakPtr()](auto session) {
492         if (!self.is_alive()) {
493           return;
494         }
495 
496         // Background scan may have been disabled while discovery was starting.
497         if (!self->requesting_background_scan_) {
498           return;
499         }
500 
501         if (!session) {
502           bt_log(ERROR, "fidl", "failed to start LE background scan");
503           self->le_background_scan_ = nullptr;
504           self->requesting_background_scan_ = false;
505           return;
506         }
507 
508         self->le_background_scan_ = std::move(session);
509         self->requesting_background_scan_ = false;
510       });
511 }
512 
EnablePrivacy(bool enabled)513 void HostServer::EnablePrivacy(bool enabled) {
514   bt_log(INFO,
515          "fidl",
516          "%s: %s LE privacy",
517          __FUNCTION__,
518          (enabled ? "enable" : "disable"));
519   if (adapter()->le()) {
520     adapter()->le()->EnablePrivacy(enabled);
521   }
522 }
523 
SetBrEdrSecurityMode(fsys::BrEdrSecurityMode mode)524 void HostServer::SetBrEdrSecurityMode(fsys::BrEdrSecurityMode mode) {
525   std::optional<bt::gap::BrEdrSecurityMode> gap_mode =
526       BrEdrSecurityModeFromFidl(mode);
527   if (!gap_mode.has_value()) {
528     bt_log(WARN, "fidl", "%s: Unrecognized BR/EDR security mode", __FUNCTION__);
529     return;
530   }
531 
532   bt_log(INFO,
533          "fidl",
534          "%s: %s",
535          __FUNCTION__,
536          BrEdrSecurityModeToString(gap_mode.value()));
537   if (adapter()->bredr()) {
538     adapter()->bredr()->SetBrEdrSecurityMode(gap_mode.value());
539   }
540 }
541 
SetLeSecurityMode(fsys::LeSecurityMode mode)542 void HostServer::SetLeSecurityMode(fsys::LeSecurityMode mode) {
543   bt::gap::LESecurityMode gap_mode = LeSecurityModeFromFidl(mode);
544   bt_log(
545       INFO, "fidl", "%s: %s", __FUNCTION__, LeSecurityModeToString(gap_mode));
546   if (adapter()->le()) {
547     adapter()->le()->SetLESecurityMode(gap_mode);
548   }
549 }
550 
SetPairingDelegate(fsys::InputCapability input,fsys::OutputCapability output,::fidl::InterfaceHandle<fsys::PairingDelegate> delegate)551 void HostServer::SetPairingDelegate(
552     fsys::InputCapability input,
553     fsys::OutputCapability output,
554     ::fidl::InterfaceHandle<fsys::PairingDelegate> delegate) {
555   bool cleared = !delegate;
556   pairing_delegate_.Bind(std::move(delegate));
557 
558   if (cleared) {
559     bt_log(INFO, "fidl", "%s: PairingDelegate cleared", __FUNCTION__);
560     ResetPairingDelegate();
561     return;
562   }
563 
564   io_capability_ = fidl_helpers::IoCapabilityFromFidl(input, output);
565   bt_log(INFO,
566          "fidl",
567          "%s: PairingDelegate assigned (I/O capability: %s)",
568          __FUNCTION__,
569          bt::sm::util::IOCapabilityToString(io_capability_).c_str());
570 
571   auto pairing = weak_pairing_.GetWeakPtr();
572   auto self = weak_self_.GetWeakPtr();
573   adapter()->SetPairingDelegate(pairing);
574   pairing_delegate_.set_error_handler([self, func = __FUNCTION__](
575                                           zx_status_t status) {
576     bt_log(
577         INFO, "fidl", "%s error handler: PairingDelegate disconnected", func);
578     if (self.is_alive()) {
579       self->ResetPairingDelegate();
580     }
581   });
582 }
583 
584 // Attempt to connect to peer identified by |peer_id|. The peer must be
585 // in our peer cache. We will attempt to connect technologies (LowEnergy,
586 // Classic or Dual-Mode) as the peer claims to support when discovered
Connect(fbt::PeerId peer_id,ConnectCallback callback)587 void HostServer::Connect(fbt::PeerId peer_id, ConnectCallback callback) {
588   bt::PeerId id{peer_id.value};
589   bt_log(INFO, "fidl", "%s: (peer: %s)", __FUNCTION__, bt_str(id));
590 
591   auto peer = adapter()->peer_cache()->FindById(id);
592   if (!peer) {
593     // We don't support connecting to peers that are not in our cache
594     bt_log(WARN,
595            "fidl",
596            "%s: peer not found in peer cache (peer: %s)",
597            __FUNCTION__,
598            bt_str(id));
599     callback(fpromise::error(fsys::Error::PEER_NOT_FOUND));
600     return;
601   }
602 
603   // TODO(fxbug.dev/42075069): Dual-mode currently not supported; if the peer
604   // supports BR/EDR we prefer BR/EDR. If a dual-mode peer, we should attempt to
605   // connect both protocols.
606   if (peer->bredr()) {
607     ConnectBrEdr(id, std::move(callback));
608     return;
609   }
610 
611   ConnectLowEnergy(id, std::move(callback));
612 }
613 
614 // Attempt to disconnect the peer identified by |peer_id| from all transports.
615 // If the peer is already not connected, return success. If the peer is
616 // disconnected succesfully, return success.
Disconnect(fbt::PeerId peer_id,DisconnectCallback callback)617 void HostServer::Disconnect(fbt::PeerId peer_id, DisconnectCallback callback) {
618   bt::PeerId id{peer_id.value};
619   bt_log(INFO, "fidl", "%s: (peer: %s)", __FUNCTION__, bt_str(id));
620 
621   bool le_disc = adapter()->le() ? adapter()->le()->Disconnect(id) : true;
622   bool bredr_disc = adapter()->bredr()
623                         ? adapter()->bredr()->Disconnect(
624                               id, bt::gap::DisconnectReason::kApiRequest)
625                         : true;
626   if (le_disc && bredr_disc) {
627     callback(fpromise::ok());
628   } else {
629     bt_log(WARN, "fidl", "%s: failed (peer: %s)", __FUNCTION__, bt_str(id));
630     callback(fpromise::error(fsys::Error::FAILED));
631   }
632 }
633 
ConnectLowEnergy(PeerId peer_id,ConnectCallback callback)634 void HostServer::ConnectLowEnergy(PeerId peer_id, ConnectCallback callback) {
635   auto self = weak_self_.GetWeakPtr();
636   auto on_complete = [self,
637                       callback = std::move(callback),
638                       peer_id,
639                       func = __FUNCTION__](auto result) {
640     if (result.is_error()) {
641       bt_log(INFO,
642              "fidl",
643              "%s: failed to connect LE transport to peer (peer: %s)",
644              func,
645              bt_str(peer_id));
646       callback(fpromise::error(HostErrorToFidl(result.error_value())));
647       return;
648     }
649 
650     // We must be connected and to the right peer
651     auto connection = std::move(result).value();
652     PW_CHECK(connection);
653     PW_CHECK(peer_id == connection->peer_identifier());
654 
655     callback(fpromise::ok());
656 
657     if (self.is_alive())
658       self->RegisterLowEnergyConnection(std::move(connection),
659                                         /*auto_connect=*/false);
660   };
661 
662   adapter()->le()->Connect(
663       peer_id, std::move(on_complete), bt::gap::LowEnergyConnectionOptions());
664 }
665 
666 // Initiate an outgoing Br/Edr connection, unless already connected
667 // Br/Edr connections are host-wide, and stored in BrEdrConnectionManager
ConnectBrEdr(PeerId peer_id,ConnectCallback callback)668 void HostServer::ConnectBrEdr(PeerId peer_id, ConnectCallback callback) {
669   auto on_complete = [callback = std::move(callback),
670                       peer_id,
671                       func = __FUNCTION__](auto status, auto connection) {
672     if (status.is_error()) {
673       PW_CHECK(!connection);
674       bt_log(INFO,
675              "fidl",
676              "%s: failed to connect BR/EDR transport to peer (peer: %s)",
677              func,
678              bt_str(peer_id));
679       callback(fpromise::error(HostErrorToFidl(status.error_value())));
680       return;
681     }
682 
683     // We must be connected and to the right peer
684     PW_CHECK(connection);
685     PW_CHECK(peer_id == connection->peer_id());
686 
687     callback(fpromise::ok());
688   };
689 
690   if (!adapter()->bredr()->Connect(peer_id, std::move(on_complete))) {
691     bt_log(
692         INFO,
693         "fidl",
694         "%s: failed to initiate BR/EDR transport connection to peer (peer: %s)",
695         __FUNCTION__,
696         bt_str(peer_id));
697     callback(fpromise::error(fsys::Error::FAILED));
698   }
699 }
700 
Forget(fbt::PeerId peer_id,ForgetCallback callback)701 void HostServer::Forget(fbt::PeerId peer_id, ForgetCallback callback) {
702   bt::PeerId id{peer_id.value};
703   auto peer = adapter()->peer_cache()->FindById(id);
704   if (!peer) {
705     bt_log(DEBUG, "fidl", "peer %s to forget wasn't found", bt_str(id));
706     callback(fpromise::ok());
707     return;
708   }
709 
710   const bool le_disconnected =
711       adapter()->le() ? adapter()->le()->Disconnect(id) : true;
712   const bool bredr_disconnected =
713       adapter()->bredr() ? adapter()->bredr()->Disconnect(
714                                id, bt::gap::DisconnectReason::kApiRequest)
715                          : true;
716   const bool peer_removed = adapter()->peer_cache()->RemoveDisconnectedPeer(id);
717 
718   if (!le_disconnected || !bredr_disconnected) {
719     const auto message =
720         bt_lib_cpp_string::StringPrintf("link(s) failed to close:%s%s",
721                                         le_disconnected ? "" : " LE",
722                                         bredr_disconnected ? "" : " BR/EDR");
723     callback(fpromise::error(fsys::Error::FAILED));
724   } else {
725     PW_CHECK(peer_removed);
726     callback(fpromise::ok());
727   }
728 }
729 
Pair(fbt::PeerId id,fsys::PairingOptions options,PairCallback callback)730 void HostServer::Pair(fbt::PeerId id,
731                       fsys::PairingOptions options,
732                       PairCallback callback) {
733   auto peer_id = bt::PeerId(id.value);
734   auto peer = adapter()->peer_cache()->FindById(peer_id);
735   if (!peer) {
736     bt_log(WARN, "fidl", "%s: unknown peer %s", __FUNCTION__, bt_str(peer_id));
737     // We don't support pairing to peers that are not in our cache
738     callback(fpromise::error(fsys::Error::PEER_NOT_FOUND));
739     return;
740   }
741 
742   // If options specifies a transport preference for LE or BR/EDR, we use that.
743   // Otherwise, we use whichever transport connection exists, preferring BR/EDR
744   // if both connections exist.
745   if (options.has_transport()) {
746     switch (options.transport()) {
747       case fsys::TechnologyType::CLASSIC:
748         PairBrEdr(peer_id, std::move(callback));
749         return;
750       case fsys::TechnologyType::LOW_ENERGY:
751         PairLowEnergy(peer_id, std::move(options), std::move(callback));
752         return;
753       case fsys::TechnologyType::DUAL_MODE:
754         break;
755     }
756   }
757   if (peer->bredr() && peer->bredr()->connection_state() !=
758                            bt::gap::Peer::ConnectionState::kNotConnected) {
759     PairBrEdr(peer_id, std::move(callback));
760     return;
761   }
762   if (peer->le() && peer->le()->connection_state() !=
763                         bt::gap::Peer::ConnectionState::kNotConnected) {
764     PairLowEnergy(peer_id, std::move(options), std::move(callback));
765     return;
766   }
767   callback(fpromise::error(fsys::Error::PEER_NOT_FOUND));
768 }
769 
PairLowEnergy(PeerId peer_id,fsys::PairingOptions options,PairCallback callback)770 void HostServer::PairLowEnergy(PeerId peer_id,
771                                fsys::PairingOptions options,
772                                PairCallback callback) {
773   std::optional<bt::sm::SecurityLevel> security_level;
774   if (options.has_le_security_level()) {
775     security_level = SecurityLevelFromFidl(options.le_security_level());
776     if (!security_level.has_value()) {
777       bt_log(WARN,
778              "fidl",
779              "%s: pairing options missing LE security level (peer: %s)",
780              __FUNCTION__,
781              bt_str(peer_id));
782       callback(fpromise::error(fsys::Error::INVALID_ARGUMENTS));
783       return;
784     }
785   } else {
786     security_level = bt::sm::SecurityLevel::kAuthenticated;
787   }
788   bt::sm::BondableMode bondable_mode = bt::sm::BondableMode::Bondable;
789   if (options.has_bondable_mode() &&
790       options.bondable_mode() == fsys::BondableMode::NON_BONDABLE) {
791     bondable_mode = bt::sm::BondableMode::NonBondable;
792   }
793   auto on_complete = [peer_id,
794                       callback = std::move(callback),
795                       func = __FUNCTION__](bt::sm::Result<> status) {
796     if (status.is_error()) {
797       bt_log(
798           WARN, "fidl", "%s: failed to pair (peer: %s)", func, bt_str(peer_id));
799       callback(fpromise::error(HostErrorToFidl(status.error_value())));
800     } else {
801       callback(fpromise::ok());
802     }
803   };
804   PW_CHECK(adapter()->le());
805   adapter()->le()->Pair(
806       peer_id, *security_level, bondable_mode, std::move(on_complete));
807 }
808 
PairBrEdr(PeerId peer_id,PairCallback callback)809 void HostServer::PairBrEdr(PeerId peer_id, PairCallback callback) {
810   auto on_complete = [peer_id,
811                       callback = std::move(callback),
812                       func = __FUNCTION__](bt::hci::Result<> status) {
813     if (status.is_error()) {
814       bt_log(
815           WARN, "fidl", "%s: failed to pair (peer: %s)", func, bt_str(peer_id));
816       callback(fpromise::error(HostErrorToFidl(status.error_value())));
817     } else {
818       callback(fpromise::ok());
819     }
820   };
821   // TODO(fxbug.dev/42135898): Add security parameter to Pair and use that here
822   // instead of hardcoding default.
823   bt::gap::BrEdrSecurityRequirements security{.authentication = false,
824                                               .secure_connections = false};
825   PW_CHECK(adapter()->bredr());
826   adapter()->bredr()->Pair(peer_id, security, std::move(on_complete));
827 }
828 
Shutdown()829 void HostServer::Shutdown() {
830   bt_log(INFO, "fidl", "closing FIDL handles");
831 
832   // Invalidate all weak pointers. This will guarantee that all pending tasks
833   // that reference this HostServer will return early if they run in the future.
834   weak_self_.InvalidatePtrs();
835 
836   // Destroy all FIDL bindings.
837   servers_.clear();
838 
839   // Cancel pending requests.
840   requesting_discoverable_ = false;
841   requesting_background_scan_ = false;
842 
843   le_background_scan_ = nullptr;
844   bredr_discoverable_session_ = nullptr;
845 
846   StopDiscovery(ZX_ERR_CANCELED, /*notify_info_change=*/false);
847 
848   // Drop all connections that are attached to this HostServer.
849   le_connections_.clear();
850 
851   if (adapter()->le()) {
852     // Stop background scan if enabled.
853     adapter()->le()->EnablePrivacy(false);
854     adapter()->le()->set_irk(std::nullopt);
855   }
856 
857   // Disallow future pairing.
858   pairing_delegate_ = nullptr;
859   ResetPairingDelegate();
860 
861   // Send adapter state change.
862   if (binding()->is_bound()) {
863     NotifyInfoChange();
864   }
865 }
866 
SetBondingDelegate(::fidl::InterfaceRequest<::fuchsia::bluetooth::host::BondingDelegate> request)867 void HostServer::SetBondingDelegate(
868     ::fidl::InterfaceRequest<::fuchsia::bluetooth::host::BondingDelegate>
869         request) {
870   if (bonding_delegate_server_.has_value()) {
871     request.Close(ZX_ERR_ALREADY_BOUND);
872     return;
873   }
874   bonding_delegate_server_.emplace(std::move(request), this);
875 }
876 
handle_unknown_method(uint64_t ordinal,bool method_has_response)877 void HostServer::handle_unknown_method(uint64_t ordinal,
878                                        bool method_has_response) {
879   bt_log(WARN, "fidl", "Received unknown method with ordinal: %lu", ordinal);
880 }
881 
Stop()882 void HostServer::DiscoverySessionServer::Stop() {
883   host_->OnDiscoverySessionServerClose(this);
884 }
885 
handle_unknown_method(uint64_t ordinal,bool method_has_response)886 void HostServer::DiscoverySessionServer::handle_unknown_method(
887     uint64_t ordinal, bool method_has_response) {
888   bt_log(WARN, "fidl", "Received unknown method with ordinal: %lu", ordinal);
889 }
890 
DiscoverySessionServer(fidl::InterfaceRequest<::fuchsia::bluetooth::host::DiscoverySession> request,HostServer * host)891 HostServer::DiscoverySessionServer::DiscoverySessionServer(
892     fidl::InterfaceRequest<::fuchsia::bluetooth::host::DiscoverySession>
893         request,
894     HostServer* host)
895     : ServerBase(this, std::move(request)), host_(host) {
896   binding()->set_error_handler([this, host](zx_status_t /*status*/) {
897     host->OnDiscoverySessionServerClose(this);
898   });
899 }
900 
PeerWatcherServer(::fidl::InterfaceRequest<::fuchsia::bluetooth::host::PeerWatcher> request,bt::gap::PeerCache * peer_cache,HostServer * host)901 HostServer::PeerWatcherServer::PeerWatcherServer(
902     ::fidl::InterfaceRequest<::fuchsia::bluetooth::host::PeerWatcher> request,
903     bt::gap::PeerCache* peer_cache,
904     HostServer* host)
905     : ServerBase(this, std::move(request)),
906       peer_cache_(peer_cache),
907       host_(host),
908       weak_self_(this) {
909   auto self = weak_self_.GetWeakPtr();
910 
911   peer_updated_callback_id_ =
912       peer_cache_->add_peer_updated_callback([self](const auto& peer) {
913         if (self.is_alive()) {
914           self->OnPeerUpdated(peer);
915         }
916       });
917   peer_cache_->set_peer_removed_callback([self](const auto& identifier) {
918     if (self.is_alive()) {
919       self->OnPeerRemoved(identifier);
920     }
921   });
922 
923   // Initialize the peer watcher with all known connectable peers that are in
924   // the cache.
925   peer_cache_->ForEach(
926       [this](const bt::gap::Peer& peer) { OnPeerUpdated(peer); });
927 
928   binding()->set_error_handler(
929       [this](zx_status_t /*status*/) { host_->peer_watcher_server_.reset(); });
930 }
931 
~PeerWatcherServer()932 HostServer::PeerWatcherServer::~PeerWatcherServer() {
933   // Unregister PeerCache callbacks.
934   peer_cache_->remove_peer_updated_callback(peer_updated_callback_id_);
935   peer_cache_->set_peer_removed_callback(nullptr);
936 }
937 
OnPeerUpdated(const bt::gap::Peer & peer)938 void HostServer::PeerWatcherServer::OnPeerUpdated(const bt::gap::Peer& peer) {
939   if (!peer.connectable()) {
940     return;
941   }
942 
943   updated_.insert(peer.identifier());
944   removed_.erase(peer.identifier());
945   MaybeCallCallback();
946 }
947 
OnPeerRemoved(bt::PeerId id)948 void HostServer::PeerWatcherServer::OnPeerRemoved(bt::PeerId id) {
949   updated_.erase(id);
950   removed_.insert(id);
951   MaybeCallCallback();
952 }
953 
MaybeCallCallback()954 void HostServer::PeerWatcherServer::MaybeCallCallback() {
955   if (!callback_) {
956     return;
957   }
958 
959   if (!removed_.empty()) {
960     Removed removed_fidl;
961     for (const bt::PeerId& id : removed_) {
962       removed_fidl.push_back(fbt::PeerId{id.value()});
963     }
964     removed_.clear();
965     callback_(fhost::PeerWatcher_GetNext_Result::WithResponse(
966         fhost::PeerWatcher_GetNext_Response::WithRemoved(
967             std::move(removed_fidl))));
968     callback_ = nullptr;
969     return;
970   }
971 
972   if (!updated_.empty()) {
973     Updated updated_fidl;
974     for (const bt::PeerId& id : updated_) {
975       bt::gap::Peer* peer = peer_cache_->FindById(id);
976       // All ids in |updated_| are assumed to be valid as they would otherwise
977       // be in |removed_|.
978       PW_CHECK(peer);
979       updated_fidl.push_back(fidl_helpers::PeerToFidl(*peer));
980     }
981     updated_.clear();
982     callback_(fhost::PeerWatcher_GetNext_Result::WithResponse(
983         fhost::PeerWatcher_GetNext_Response::WithUpdated(
984             std::move(updated_fidl))));
985     callback_ = nullptr;
986     return;
987   }
988 }
989 
GetNext(::fuchsia::bluetooth::host::PeerWatcher::GetNextCallback callback)990 void HostServer::PeerWatcherServer::GetNext(
991     ::fuchsia::bluetooth::host::PeerWatcher::GetNextCallback callback) {
992   if (callback_) {
993     binding()->Close(ZX_ERR_BAD_STATE);
994     host_->peer_watcher_server_.reset();
995     return;
996   }
997   callback_ = std::move(callback);
998   MaybeCallCallback();
999 }
1000 
handle_unknown_method(uint64_t ordinal,bool method_has_response)1001 void HostServer::PeerWatcherServer::handle_unknown_method(
1002     uint64_t ordinal, bool method_has_response) {
1003   bt_log(WARN,
1004          "fidl",
1005          "PeerWatcher received unknown method with ordinal %lu",
1006          ordinal);
1007 }
1008 
BondingDelegateServer(::fidl::InterfaceRequest<::fuchsia::bluetooth::host::BondingDelegate> request,HostServer * host)1009 HostServer::BondingDelegateServer::BondingDelegateServer(
1010     ::fidl::InterfaceRequest<::fuchsia::bluetooth::host::BondingDelegate>
1011         request,
1012     HostServer* host)
1013     : ServerBase(this, std::move(request)), host_(host) {
1014   binding()->set_error_handler(
1015       [this](zx_status_t status) { host_->bonding_delegate_server_.reset(); });
1016   // Initialize the peer watcher with all known bonded peers that are in the
1017   // cache.
1018   host_->adapter()->peer_cache()->ForEach([this](const bt::gap::Peer& peer) {
1019     if (peer.bonded()) {
1020       OnNewBondingData(peer);
1021     }
1022   });
1023 }
1024 
OnNewBondingData(const bt::gap::Peer & peer)1025 void HostServer::BondingDelegateServer::OnNewBondingData(
1026     const bt::gap::Peer& peer) {
1027   updated_.push(
1028       fidl_helpers::PeerToFidlBondingData(host_->adapter().get(), peer));
1029   MaybeNotifyWatchBonds();
1030 }
1031 
RestoreBonds(::std::vector<::fuchsia::bluetooth::sys::BondingData> bonds,RestoreBondsCallback callback)1032 void HostServer::BondingDelegateServer::RestoreBonds(
1033     ::std::vector<::fuchsia::bluetooth::sys::BondingData> bonds,
1034     RestoreBondsCallback callback) {
1035   host_->RestoreBonds(std::move(bonds), std::move(callback));
1036 }
WatchBonds(WatchBondsCallback callback)1037 void HostServer::BondingDelegateServer::WatchBonds(
1038     WatchBondsCallback callback) {
1039   if (watch_bonds_cb_) {
1040     binding()->Close(ZX_ERR_ALREADY_EXISTS);
1041     host_->bonding_delegate_server_.reset();
1042     return;
1043   }
1044   watch_bonds_cb_ = std::move(callback);
1045   MaybeNotifyWatchBonds();
1046 }
1047 
handle_unknown_method(uint64_t ordinal,bool method_has_response)1048 void HostServer::BondingDelegateServer::handle_unknown_method(
1049     uint64_t ordinal, bool method_has_response) {
1050   bt_log(WARN,
1051          "fidl",
1052          "BondingDelegate received unknown method with ordinal %lu",
1053          ordinal);
1054 }
1055 
1056 // TODO(fxbug.dev/42158854): Support notifying removed bonds.
MaybeNotifyWatchBonds()1057 void HostServer::BondingDelegateServer::MaybeNotifyWatchBonds() {
1058   if (!watch_bonds_cb_ || updated_.empty()) {
1059     return;
1060   }
1061 
1062   watch_bonds_cb_(fhost::BondingDelegate_WatchBonds_Result::WithResponse(
1063       ::fuchsia::bluetooth::host::BondingDelegate_WatchBonds_Response::
1064           WithUpdated(std::move(updated_.front()))));
1065   updated_.pop();
1066 }
1067 
io_capability() const1068 bt::sm::IOCapability HostServer::io_capability() const {
1069   bt_log(DEBUG,
1070          "fidl",
1071          "I/O capability: %s",
1072          bt::sm::util::IOCapabilityToString(io_capability_).c_str());
1073   return io_capability_;
1074 }
1075 
CompletePairing(PeerId id,bt::sm::Result<> status)1076 void HostServer::CompletePairing(PeerId id, bt::sm::Result<> status) {
1077   bt_log(DEBUG,
1078          "fidl",
1079          "pairing complete for peer: %s, status: %s",
1080          bt_str(id),
1081          bt_str(status));
1082   PW_DCHECK(pairing_delegate_);
1083   pairing_delegate_->OnPairingComplete(fbt::PeerId{id.value()}, status.is_ok());
1084 }
1085 
ConfirmPairing(PeerId id,ConfirmCallback confirm)1086 void HostServer::ConfirmPairing(PeerId id, ConfirmCallback confirm) {
1087   bt_log(
1088       DEBUG, "fidl", "pairing confirmation request for peer: %s", bt_str(id));
1089   DisplayPairingRequest(
1090       id, std::nullopt, fsys::PairingMethod::CONSENT, std::move(confirm));
1091 }
1092 
DisplayPasskey(PeerId id,uint32_t passkey,DisplayMethod method,ConfirmCallback confirm)1093 void HostServer::DisplayPasskey(PeerId id,
1094                                 uint32_t passkey,
1095                                 DisplayMethod method,
1096                                 ConfirmCallback confirm) {
1097   auto fidl_method = fsys::PairingMethod::PASSKEY_DISPLAY;
1098   if (method == DisplayMethod::kComparison) {
1099     bt_log(
1100         DEBUG, "fidl", "compare passkey %06u on peer: %s", passkey, bt_str(id));
1101     fidl_method = fsys::PairingMethod::PASSKEY_COMPARISON;
1102   } else {
1103     bt_log(
1104         DEBUG, "fidl", "enter passkey %06u on peer: %s", passkey, bt_str(id));
1105   }
1106   DisplayPairingRequest(id, passkey, fidl_method, std::move(confirm));
1107 }
1108 
RequestPasskey(PeerId id,PasskeyResponseCallback respond)1109 void HostServer::RequestPasskey(PeerId id, PasskeyResponseCallback respond) {
1110   bt_log(DEBUG, "fidl", "passkey request for peer: %s", bt_str(id));
1111   auto found_peer = adapter()->peer_cache()->FindById(id);
1112   PW_CHECK(found_peer);
1113   auto peer = fidl_helpers::PeerToFidl(*found_peer);
1114 
1115   PW_CHECK(pairing_delegate_);
1116   pairing_delegate_->OnPairingRequest(
1117       std::move(peer),
1118       fsys::PairingMethod::PASSKEY_ENTRY,
1119       0u,
1120       [respond = std::move(respond), id, func = __FUNCTION__](
1121           const bool accept, uint32_t entered_passkey) mutable {
1122         if (!respond) {
1123           bt_log(WARN,
1124                  "fidl",
1125                  "%s: The PairingDelegate invoked the Pairing Request callback "
1126                  "more than once, which "
1127                  "should not happen (peer: %s)",
1128                  func,
1129                  bt_str(id));
1130           return;
1131         }
1132         bt_log(INFO,
1133                "fidl",
1134                "%s: got PairingDelegate response: %s with passkey code \"%u\" "
1135                "(peer: %s)",
1136                func,
1137                accept ? "accept" : "reject",
1138                entered_passkey,
1139                bt_str(id));
1140         if (!accept) {
1141           respond(-1);
1142         } else {
1143           respond(entered_passkey);
1144         }
1145       });
1146 }
1147 
DisplayPairingRequest(bt::PeerId id,std::optional<uint32_t> passkey,fsys::PairingMethod method,ConfirmCallback confirm)1148 void HostServer::DisplayPairingRequest(bt::PeerId id,
1149                                        std::optional<uint32_t> passkey,
1150                                        fsys::PairingMethod method,
1151                                        ConfirmCallback confirm) {
1152   auto found_peer = adapter()->peer_cache()->FindById(id);
1153   PW_CHECK(found_peer);
1154   auto peer = fidl_helpers::PeerToFidl(*found_peer);
1155 
1156   PW_CHECK(pairing_delegate_);
1157   uint32_t displayed_passkey = passkey ? *passkey : 0u;
1158   pairing_delegate_->OnPairingRequest(
1159       std::move(peer),
1160       method,
1161       displayed_passkey,
1162       [confirm = std::move(confirm), id, func = __FUNCTION__](
1163           const bool accept, uint32_t entered_passkey) mutable {
1164         if (!confirm) {
1165           bt_log(WARN,
1166                  "fidl",
1167                  "%s: The PairingDelegate invoked the Pairing Request callback "
1168                  "more than once, which "
1169                  "should not happen (peer: %s)",
1170                  func,
1171                  bt_str(id));
1172           return;
1173         }
1174         bt_log(INFO,
1175                "fidl",
1176                "%s: got PairingDelegate response: %s, \"%u\" (peer: %s)",
1177                func,
1178                accept ? "accept" : "reject",
1179                entered_passkey,
1180                bt_str(id));
1181         confirm(accept);
1182       });
1183 }
1184 
OnConnectionError(Server * server)1185 void HostServer::OnConnectionError(Server* server) {
1186   PW_DCHECK(server);
1187   servers_.erase(server);
1188 }
1189 
ResetPairingDelegate()1190 void HostServer::ResetPairingDelegate() {
1191   io_capability_ = IOCapability::kNoInputNoOutput;
1192   adapter()->SetPairingDelegate(PairingDelegate::WeakPtr());
1193 }
1194 
NotifyInfoChange()1195 void HostServer::NotifyInfoChange() {
1196   info_getter_.Set(fidl_helpers::HostInfoToFidl(adapter().get()));
1197 }
1198 
1199 }  // namespace bthost
1200