• 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 "emulator.h"
16 
17 #include <fidl/fuchsia.driver.framework/cpp/fidl.h>
18 #include <fidl/fuchsia.hardware.bluetooth/cpp/fidl.h>
19 #include <lib/driver/logging/cpp/logger.h>
20 #include <lib/fdf/cpp/dispatcher.h>
21 
22 #include "emulated_peer.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/random.h"
24 #include "pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
25 #include "pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
26 
27 namespace fhbt = fuchsia_hardware_bluetooth;
28 
29 using bt::DeviceAddress;
30 using bt::testing::FakeController;
31 
32 namespace bt_hci_virtual {
33 
34 namespace {
35 
SettingsFromFidl(const fhbt::EmulatorSettings & input)36 FakeController::Settings SettingsFromFidl(const fhbt::EmulatorSettings& input) {
37   FakeController::Settings settings;
38   if (input.hci_config().has_value() &&
39       input.hci_config().value() == fhbt::HciConfig::kLeOnly) {
40     settings.ApplyLEOnlyDefaults();
41   } else {
42     settings.ApplyDualModeDefaults();
43   }
44 
45   if (input.address().has_value()) {
46     settings.bd_addr =
47         DeviceAddress(DeviceAddress::Type::kBREDR, input.address()->bytes());
48   }
49 
50   // TODO(armansito): Don't ignore "extended_advertising" setting when
51   // supported.
52   if (input.acl_buffer_settings().has_value()) {
53     fhbt::AclBufferSettings acl_settings = input.acl_buffer_settings().value();
54 
55     if (acl_settings.data_packet_length().has_value()) {
56       settings.acl_data_packet_length =
57           acl_settings.data_packet_length().value();
58     }
59 
60     if (acl_settings.total_num_data_packets().has_value()) {
61       settings.total_num_acl_data_packets =
62           acl_settings.total_num_data_packets().value();
63     }
64   }
65 
66   if (input.le_acl_buffer_settings().has_value()) {
67     fhbt::AclBufferSettings le_acl_settings =
68         input.le_acl_buffer_settings().value();
69 
70     if (le_acl_settings.data_packet_length().has_value()) {
71       settings.le_acl_data_packet_length =
72           le_acl_settings.data_packet_length().value();
73     }
74 
75     if (le_acl_settings.total_num_data_packets().has_value()) {
76       settings.le_total_num_acl_data_packets =
77           le_acl_settings.total_num_data_packets().value();
78     }
79   }
80 
81   return settings;
82 }
83 
LeOwnAddressTypeToFidl(pw::bluetooth::emboss::LEOwnAddressType type)84 std::optional<fuchsia_bluetooth::AddressType> LeOwnAddressTypeToFidl(
85     pw::bluetooth::emboss::LEOwnAddressType type) {
86   std::optional<fuchsia_bluetooth::AddressType> res;
87 
88   switch (type) {
89     case pw::bluetooth::emboss::LEOwnAddressType::PUBLIC:
90     case pw::bluetooth::emboss::LEOwnAddressType::PRIVATE_DEFAULT_TO_PUBLIC:
91       res.emplace(fuchsia_bluetooth::AddressType::kPublic);
92       return res;
93     case pw::bluetooth::emboss::LEOwnAddressType::RANDOM:
94     case pw::bluetooth::emboss::LEOwnAddressType::PRIVATE_DEFAULT_TO_RANDOM:
95       res.emplace(fuchsia_bluetooth::AddressType::kRandom);
96       return res;
97   }
98 
99   ZX_PANIC("unsupported own address type");
100   return res;
101 }
102 
103 }  // namespace
104 
EmulatorDevice()105 EmulatorDevice::EmulatorDevice()
106     : pw_dispatcher_(fdf::Dispatcher::GetCurrent()->async_dispatcher()),
107       fake_device_(pw_dispatcher_),
108       emulator_devfs_connector_(
109           fit::bind_member<&EmulatorDevice::ConnectEmulator>(this)),
110       vendor_devfs_connector_(
111           fit::bind_member<&EmulatorDevice::ConnectVendor>(this)) {}
112 
~EmulatorDevice()113 EmulatorDevice::~EmulatorDevice() { fake_device_.Stop(); }
114 
Initialize(std::string_view name,AddChildCallback callback,ShutdownCallback shutdown)115 zx_status_t EmulatorDevice::Initialize(std::string_view name,
116                                        AddChildCallback callback,
117                                        ShutdownCallback shutdown) {
118   shutdown_cb_ = std::move(shutdown);
119 
120   bt::set_random_generator(&rng_);
121 
122   // Initialize |fake_device_|
123   auto init_complete_cb = [](pw::Status status) {
124     if (!status.ok()) {
125       FDF_LOG(WARNING,
126               "FakeController failed to initialize: %s",
127               pw_StatusString(status));
128     }
129   };
130   auto error_cb = [this](pw::Status status) {
131     FDF_LOG(WARNING, "FakeController error: %s", pw_StatusString(status));
132     UnpublishHci();
133   };
134   fake_device_.Initialize(init_complete_cb, error_cb);
135 
136   fake_device_.set_controller_parameters_callback(
137       fit::bind_member<&EmulatorDevice::OnControllerParametersChanged>(this));
138   fake_device_.set_advertising_state_callback(
139       fit::bind_member<&EmulatorDevice::OnLegacyAdvertisingStateChanged>(this));
140   fake_device_.set_connection_state_callback(
141       fit::bind_member<&EmulatorDevice::OnPeerConnectionStateChanged>(this));
142 
143   // Create args to add emulator as a child node on behalf of VirtualController
144   zx::result connector = emulator_devfs_connector_.Bind(
145       fdf::Dispatcher::GetCurrent()->async_dispatcher());
146   if (connector.is_error()) {
147     FDF_LOG(ERROR,
148             "Failed to bind devfs connecter to dispatcher: %u",
149             connector.status_value());
150     return connector.error_value();
151   }
152 
153   fidl::Arena args_arena;
154   auto devfs =
155       fuchsia_driver_framework::wire::DevfsAddArgs::Builder(args_arena)
156           .connector(std::move(connector.value()))
157           .connector_supports(fuchsia_device_fs::ConnectionType::kController)
158           .class_name("bt-emulator")
159           .Build();
160   auto args = fuchsia_driver_framework::wire::NodeAddArgs::Builder(args_arena)
161                   .name(name.data())
162                   .devfs_args(devfs)
163                   .Build();
164   callback(args);
165 
166   return ZX_OK;
167 }
168 
Shutdown()169 void EmulatorDevice::Shutdown() {
170   fake_device_.Stop();
171   peers_.clear();
172 
173   if (shutdown_cb_) {
174     shutdown_cb_();
175   }
176 }
177 
Publish(PublishRequest & request,PublishCompleter::Sync & completer)178 void EmulatorDevice::Publish(PublishRequest& request,
179                              PublishCompleter::Sync& completer) {
180   if (hci_node_controller_.is_valid()) {
181     FDF_LOG(INFO, "bt-hci-device is already published");
182     completer.Reply(fit::error(fhbt::EmulatorError::kHciAlreadyPublished));
183     return;
184   }
185 
186   FakeController::Settings settings = SettingsFromFidl(request);
187   fake_device_.set_settings(settings);
188 
189   zx_status_t status = AddHciDeviceChildNode();
190   if (status != ZX_OK) {
191     FDF_LOG(WARNING, "Failed to publish bt-hci-device node");
192     completer.Reply(fit::error(fhbt::EmulatorError::kFailed));
193   } else {
194     FDF_LOG(INFO, "Successfully published bt-hci-device node");
195     completer.Reply(fit::success());
196   }
197 }
198 
AddLowEnergyPeer(AddLowEnergyPeerRequest & request,AddLowEnergyPeerCompleter::Sync & completer)199 void EmulatorDevice::AddLowEnergyPeer(
200     AddLowEnergyPeerRequest& request,
201     AddLowEnergyPeerCompleter::Sync& completer) {
202   auto result = EmulatedPeer::NewLowEnergy(
203       std::move(request),
204       &fake_device_,
205       fdf::Dispatcher::GetCurrent()->async_dispatcher());
206   if (result.is_error()) {
207     completer.Reply(fit::error(result.error()));
208     return;
209   }
210 
211   AddPeer(result.take_value());
212   completer.Reply(fit::success());
213 }
214 
AddBredrPeer(AddBredrPeerRequest & request,AddBredrPeerCompleter::Sync & completer)215 void EmulatorDevice::AddBredrPeer(AddBredrPeerRequest& request,
216                                   AddBredrPeerCompleter::Sync& completer) {
217   auto result =
218       EmulatedPeer::NewBredr(std::move(request),
219                              &fake_device_,
220                              fdf::Dispatcher::GetCurrent()->async_dispatcher());
221   if (result.is_error()) {
222     completer.Reply(fit::error(result.error()));
223     return;
224   }
225 
226   AddPeer(result.take_value());
227   completer.Reply(fit::success());
228 }
229 
WatchControllerParameters(WatchControllerParametersCompleter::Sync & completer)230 void EmulatorDevice::WatchControllerParameters(
231     WatchControllerParametersCompleter::Sync& completer) {
232   controller_parameters_completer_.emplace(completer.ToAsync());
233   MaybeUpdateControllerParametersChanged();
234 }
235 
WatchLeScanStates(WatchLeScanStatesCompleter::Sync & completer)236 void EmulatorDevice::WatchLeScanStates(
237     WatchLeScanStatesCompleter::Sync& completer) {}
238 
WatchLegacyAdvertisingStates(WatchLegacyAdvertisingStatesCompleter::Sync & completer)239 void EmulatorDevice::WatchLegacyAdvertisingStates(
240     WatchLegacyAdvertisingStatesCompleter::Sync& completer) {
241   legacy_adv_states_completers_.emplace(completer.ToAsync());
242   MaybeUpdateLegacyAdvertisingStates();
243 }
244 
handle_unknown_method(fidl::UnknownMethodMetadata<fhbt::Emulator> metadata,fidl::UnknownMethodCompleter::Sync & completer)245 void EmulatorDevice::handle_unknown_method(
246     fidl::UnknownMethodMetadata<fhbt::Emulator> metadata,
247     fidl::UnknownMethodCompleter::Sync& completer) {
248   FDF_LOG(
249       ERROR,
250       "Unknown method in Emulator request, closing with ZX_ERR_NOT_SUPPORTED");
251   completer.Close(ZX_ERR_NOT_SUPPORTED);
252 }
253 
GetFeatures(GetFeaturesCompleter::Sync & completer)254 void EmulatorDevice::GetFeatures(GetFeaturesCompleter::Sync& completer) {
255   completer.Reply(fuchsia_hardware_bluetooth::wire::VendorFeatures());
256 }
257 
EncodeCommand(EncodeCommandRequestView request,EncodeCommandCompleter::Sync & completer)258 void EmulatorDevice::EncodeCommand(EncodeCommandRequestView request,
259                                    EncodeCommandCompleter::Sync& completer) {
260   completer.ReplyError(ZX_ERR_INVALID_ARGS);
261 }
262 
OpenHciTransport(OpenHciTransportCompleter::Sync & completer)263 void EmulatorDevice::OpenHciTransport(
264     OpenHciTransportCompleter::Sync& completer) {
265   // Sets FakeController to respond with event, ACL, and ISO packet types when
266   // it receives an incoming packet of the appropriate type
267   fake_device_.SetEventFunction(
268       fit::bind_member<&EmulatorDevice::SendEventToHost>(this));
269   fake_device_.SetReceiveAclFunction(
270       fit::bind_member<&EmulatorDevice::SendAclPacketToHost>(this));
271   fake_device_.SetReceiveIsoFunction(
272       fit::bind_member<&EmulatorDevice::SendIsoPacketToHost>(this));
273 
274   auto endpoints = fidl::CreateEndpoints<fhbt::HciTransport>();
275   if (endpoints.is_error()) {
276     FDF_LOG(ERROR,
277             "Failed to create endpoints: %s",
278             zx_status_get_string(endpoints.error_value()));
279     completer.ReplyError(endpoints.error_value());
280     return;
281   }
282 
283   hci_transport_bindings_.AddBinding(
284       fdf::Dispatcher::GetCurrent()->async_dispatcher(),
285       std::move(endpoints->server),
286       this,
287       fidl::kIgnoreBindingClosure);
288   completer.ReplySuccess(std::move(endpoints->client));
289 }
290 
OpenSnoop(OpenSnoopCompleter::Sync & completer)291 void EmulatorDevice::OpenSnoop(OpenSnoopCompleter::Sync& completer) {
292   completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
293 }
294 
handle_unknown_method(fidl::UnknownMethodMetadata<fhbt::Vendor> metadata,fidl::UnknownMethodCompleter::Sync & completer)295 void EmulatorDevice::handle_unknown_method(
296     fidl::UnknownMethodMetadata<fhbt::Vendor> metadata,
297     fidl::UnknownMethodCompleter::Sync& completer) {
298   FDF_LOG(
299       ERROR,
300       "Unknown method in Vendor request, closing with ZX_ERR_NOT_SUPPORTED");
301   completer.Close(ZX_ERR_NOT_SUPPORTED);
302 }
303 
Send(SendRequest & request,SendCompleter::Sync & completer)304 void EmulatorDevice::Send(SendRequest& request,
305                           SendCompleter::Sync& completer) {
306   switch (request.Which()) {
307     case fhbt::SentPacket::Tag::kCommand: {
308       std::vector<uint8_t> command_data = request.command().value();
309       pw::span<const std::byte> buffer = bt::BufferView(command_data).subspan();
310       fake_device_.SendCommand(buffer);
311       completer.Reply();
312       return;
313     }
314     case fhbt::SentPacket::Tag::kAcl: {
315       std::vector<uint8_t> acl_data = request.acl().value();
316       pw::span<const std::byte> buffer = bt::BufferView(acl_data).subspan();
317       fake_device_.SendAclData(buffer);
318       completer.Reply();
319       return;
320     }
321     case fhbt::SentPacket::Tag::kIso: {
322       std::vector<uint8_t> iso_data = request.iso().value();
323       pw::span<const std::byte> buffer = bt::BufferView(iso_data).subspan();
324       fake_device_.SendIsoData(buffer);
325       completer.Reply();
326       return;
327     }
328     default: {
329       FDF_LOG(ERROR,
330               "Received unknown packet type %lu",
331               static_cast<uint64_t>(request.Which()));
332       return;
333     }
334   }
335 }
336 
ConfigureSco(ConfigureScoRequest & request,fidl::Server<fuchsia_hardware_bluetooth::HciTransport>::ConfigureScoCompleter::Sync & completer)337 void EmulatorDevice::ConfigureSco(
338     ConfigureScoRequest& request,
339     fidl::Server<fuchsia_hardware_bluetooth::HciTransport>::
340         ConfigureScoCompleter::Sync& completer) {
341   // This interface is not implemented.
342   completer.Close(ZX_ERR_NOT_SUPPORTED);
343 }
344 
handle_unknown_method(::fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::HciTransport> metadata,::fidl::UnknownMethodCompleter::Sync & completer)345 void EmulatorDevice::handle_unknown_method(
346     ::fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::HciTransport>
347         metadata,
348     ::fidl::UnknownMethodCompleter::Sync& completer) {
349   FDF_LOG(ERROR,
350           "Unknown method in HciTransport request, closing with "
351           "ZX_ERR_NOT_SUPPORTED");
352   completer.Close(ZX_ERR_NOT_SUPPORTED);
353 }
354 
ConnectEmulator(fidl::ServerEnd<fhbt::Emulator> request)355 void EmulatorDevice::ConnectEmulator(fidl::ServerEnd<fhbt::Emulator> request) {
356   emulator_binding_group_.AddBinding(
357       fdf::Dispatcher::GetCurrent()->async_dispatcher(),
358       std::move(request),
359       this,
360       fidl::kIgnoreBindingClosure);
361 }
362 
ConnectVendor(fidl::ServerEnd<fhbt::Vendor> request)363 void EmulatorDevice::ConnectVendor(fidl::ServerEnd<fhbt::Vendor> request) {
364   vendor_binding_group_.AddBinding(
365       fdf::Dispatcher::GetCurrent()->async_dispatcher(),
366       std::move(request),
367       this,
368       fidl::kIgnoreBindingClosure);
369 }
370 
AddHciDeviceChildNode()371 zx_status_t EmulatorDevice::AddHciDeviceChildNode() {
372   // Create args to add bt-hci-device as a child node on behalf of
373   // VirtualController
374   zx::result connector = vendor_devfs_connector_.Bind(
375       fdf::Dispatcher::GetCurrent()->async_dispatcher());
376   if (connector.is_error()) {
377     FDF_LOG(ERROR,
378             "Failed to bind devfs connecter to dispatcher: %u",
379             connector.status_value());
380     return connector.error_value();
381   }
382 
383   fidl::Arena args_arena;
384   auto devfs =
385       fuchsia_driver_framework::wire::DevfsAddArgs::Builder(args_arena)
386           .connector(std::move(connector.value()))
387           .connector_supports(fuchsia_device_fs::ConnectionType::kController)
388           .class_name("bt-hci")
389           .Build();
390   auto args = fuchsia_driver_framework::wire::NodeAddArgs::Builder(args_arena)
391                   .name("bt-hci-device")
392                   .devfs_args(devfs)
393                   .Build();
394 
395   // Create the endpoints of fuchsia_driver_framework::NodeController protocol
396   auto controller_endpoints =
397       fidl::CreateEndpoints<fuchsia_driver_framework::NodeController>();
398   if (controller_endpoints.is_error()) {
399     FDF_LOG(ERROR,
400             "Create node controller endpoints failed: %s",
401             zx_status_get_string(controller_endpoints.error_value()));
402     return controller_endpoints.error_value();
403   }
404 
405   // Create the endpoints of fuchsia_driver_framework::Node protocol for the
406   // child node, and hold the client end of it, because no driver will bind to
407   // the child node.
408   auto child_node_endpoints =
409       fidl::CreateEndpoints<fuchsia_driver_framework::Node>();
410   if (child_node_endpoints.is_error()) {
411     FDF_LOG(ERROR,
412             "Create child node endpoints failed: %s",
413             zx_status_get_string(child_node_endpoints.error_value()));
414     return child_node_endpoints.error_value();
415   }
416 
417   // Add bt-hci-device as a child node of the EmulatorDevice
418   ZX_DEBUG_ASSERT(emulator_child_node()->is_valid());
419   auto child_result = emulator_child_node()->sync()->AddChild(
420       std::move(args),
421       std::move(controller_endpoints->server),
422       std::move(child_node_endpoints->server));
423   if (!child_result.ok()) {
424     FDF_LOG(ERROR,
425             "Failed to add bt-hci-device node, FIDL error: %s",
426             child_result.status_string());
427     return child_result.status();
428   }
429 
430   if (child_result->is_error()) {
431     FDF_LOG(ERROR,
432             "Failed to add bt-hci-device node: %u",
433             static_cast<uint32_t>(child_result->error_value()));
434     return ZX_ERR_INTERNAL;
435   }
436 
437   // |hci_child_node_| does not need to create more child nodes so we do not
438   // need an event_handler and we do not need to worry about it being re-bound
439   hci_child_node_.Bind(std::move(child_node_endpoints->client),
440                        fdf::Dispatcher::GetCurrent()->async_dispatcher());
441   hci_node_controller_.Bind(std::move(controller_endpoints->client),
442                             fdf::Dispatcher::GetCurrent()->async_dispatcher());
443 
444   return ZX_OK;
445 }
446 
AddPeer(std::unique_ptr<EmulatedPeer> peer)447 void EmulatorDevice::AddPeer(std::unique_ptr<EmulatedPeer> peer) {
448   auto address = peer->address();
449   peer->set_closed_callback([this, address] { peers_.erase(address); });
450   peers_[address] = std::move(peer);
451 }
452 
OnControllerParametersChanged()453 void EmulatorDevice::OnControllerParametersChanged() {
454   fhbt::ControllerParameters fidl_value;
455   fidl_value.local_name(fake_device_.local_name());
456 
457   const auto& device_class_bytes = fake_device_.device_class().bytes();
458   uint32_t device_class = 0;
459   device_class |= device_class_bytes[0];
460   device_class |= static_cast<uint32_t>(device_class_bytes[1]) << 8;
461   device_class |= static_cast<uint32_t>(device_class_bytes[2]) << 16;
462 
463   std::optional<fuchsia_bluetooth::DeviceClass> device_class_option =
464       fuchsia_bluetooth::DeviceClass{device_class};
465   fidl_value.device_class(device_class_option);
466 
467   controller_parameters_.emplace(fidl_value);
468   MaybeUpdateControllerParametersChanged();
469 }
470 
MaybeUpdateControllerParametersChanged()471 void EmulatorDevice::MaybeUpdateControllerParametersChanged() {
472   if (!controller_parameters_.has_value() ||
473       !controller_parameters_completer_.has_value()) {
474     return;
475   }
476   controller_parameters_completer_->Reply(
477       std::move(controller_parameters_.value()));
478   controller_parameters_.reset();
479   controller_parameters_completer_.reset();
480 }
481 
OnLegacyAdvertisingStateChanged()482 void EmulatorDevice::OnLegacyAdvertisingStateChanged() {
483   // We have requests to resolve. Construct the FIDL table for the current
484   // state.
485   fhbt::LegacyAdvertisingState fidl_state;
486   const FakeController::LEAdvertisingState& adv_state =
487       fake_device_.legacy_advertising_state();
488   fidl_state.enabled(adv_state.enabled);
489 
490   // Populate the rest only if advertising is enabled.
491   fidl_state.type(static_cast<fhbt::LegacyAdvertisingType>(
492       bt::hci::LowEnergyAdvertiser::
493           AdvertisingEventPropertiesToLEAdvertisingType(adv_state.properties)));
494   fidl_state.address_type(LeOwnAddressTypeToFidl(adv_state.own_address_type));
495 
496   if (adv_state.interval_min) {
497     fidl_state.interval_min(adv_state.interval_min);
498   }
499   if (adv_state.interval_max) {
500     fidl_state.interval_max(adv_state.interval_max);
501   }
502 
503   if (adv_state.data_length) {
504     std::vector<uint8_t> output(adv_state.data,
505                                 adv_state.data + adv_state.data_length);
506 
507     if (!fidl_state.advertising_data().has_value()) {
508       fidl_state.advertising_data() = fhbt::AdvertisingData();
509     }
510     fidl_state.advertising_data()->data(output);
511   }
512   if (adv_state.scan_rsp_length) {
513     std::vector<uint8_t> output(
514         adv_state.scan_rsp_data,
515         adv_state.scan_rsp_data + adv_state.scan_rsp_length);
516     if (!fidl_state.scan_response().has_value()) {
517       fidl_state.scan_response() = fhbt::AdvertisingData();
518     }
519     fidl_state.scan_response()->data(output);
520   }
521 
522   legacy_adv_states_.emplace_back(fidl_state);
523   MaybeUpdateLegacyAdvertisingStates();
524 }
525 
MaybeUpdateLegacyAdvertisingStates()526 void EmulatorDevice::MaybeUpdateLegacyAdvertisingStates() {
527   if (legacy_adv_states_.empty() || legacy_adv_states_completers_.empty()) {
528     return;
529   }
530   while (!legacy_adv_states_completers_.empty()) {
531     legacy_adv_states_completers_.front().Reply(legacy_adv_states_);
532     legacy_adv_states_completers_.pop();
533   }
534   legacy_adv_states_.clear();
535 }
536 
OnPeerConnectionStateChanged(const DeviceAddress & address,bt::hci_spec::ConnectionHandle handle,bool connected,bool canceled)537 void EmulatorDevice::OnPeerConnectionStateChanged(
538     const DeviceAddress& address,
539     bt::hci_spec::ConnectionHandle handle,
540     bool connected,
541     bool canceled) {
542   FDF_LOG(TRACE,
543           "Peer connection state changed: %s (handle: %#.4x) (connected: %s) "
544           "(canceled: %s):\n",
545           address.ToString().c_str(),
546           handle,
547           (connected ? "true" : "false"),
548           (canceled ? "true" : "false"));
549 
550   auto iter = peers_.find(address);
551   if (iter != peers_.end()) {
552     iter->second->UpdateConnectionState(connected);
553   }
554 }
555 
UnpublishHci()556 void EmulatorDevice::UnpublishHci() {
557   // Unpublishing the bt-hci-device child node shuts down the associated bt-host
558   // component
559   auto status = hci_node_controller_->Remove();
560   if (!status.ok()) {
561     FDF_LOG(ERROR,
562             "Could not remove bt-hci-device child node: %s",
563             status.status_string());
564   }
565 }
566 
SendEventToHost(pw::span<const std::byte> buffer)567 void EmulatorDevice::SendEventToHost(pw::span<const std::byte> buffer) {
568   if (hci_transport_bindings_.size() == 0) {
569     FDF_LOG(ERROR, "No HciTransport bindings");
570     return;
571   }
572   // Using HciTransport protocol (i.e. |cmd_channel_| is not set)
573   hci_transport_bindings_.ForEachBinding(
574       [buffer](
575           const fidl::ServerBinding<fuchsia_hardware_bluetooth::HciTransport>&
576               binding) {
577         // Send the event to bt-host
578         std::vector<uint8_t> data = bt::BufferView(buffer).ToVector();
579         fhbt::ReceivedPacket event = fhbt::ReceivedPacket::WithEvent(data);
580         fit::result<::fidl::OneWayError> status =
581             fidl::SendEvent(binding)->OnReceive(event);
582         if (!status.is_ok()) {
583           FDF_LOG(ERROR,
584                   "Failed to send OnReceive event to bt-host: %s",
585                   status.error_value().status_string());
586         }
587       });
588 }
589 
SendAclPacketToHost(pw::span<const std::byte> buffer)590 void EmulatorDevice::SendAclPacketToHost(pw::span<const std::byte> buffer) {
591   if (hci_transport_bindings_.size() == 0) {
592     FDF_LOG(ERROR, "No HciTransport bindings");
593     return;
594   }
595   // Using HciTransport protocol (i.e. |acl_channel_| is not set)
596   hci_transport_bindings_.ForEachBinding(
597       [buffer](
598           const fidl::ServerBinding<fuchsia_hardware_bluetooth::HciTransport>&
599               binding) {
600         // Send the event to bt-host
601         std::vector<uint8_t> data = bt::BufferView(buffer).ToVector();
602         fhbt::ReceivedPacket event = fhbt::ReceivedPacket::WithAcl(data);
603         fit::result<::fidl::OneWayError> status =
604             fidl::SendEvent(binding)->OnReceive(event);
605         if (!status.is_ok()) {
606           FDF_LOG(ERROR,
607                   "Failed to send OnReceive event to bt-host: %s",
608                   status.error_value().status_string());
609         }
610       });
611 }
612 
SendIsoPacketToHost(pw::span<const std::byte> buffer)613 void EmulatorDevice::SendIsoPacketToHost(pw::span<const std::byte> buffer) {
614   if (hci_transport_bindings_.size() == 0) {
615     FDF_LOG(ERROR, "No HciTransport bindings");
616     return;
617   }
618   // Using HciTransport protocol (i.e. |iso_channel_| is not set)
619   hci_transport_bindings_.ForEachBinding(
620       [buffer](
621           const fidl::ServerBinding<fuchsia_hardware_bluetooth::HciTransport>&
622               binding) {
623         // Send the event to bt-host
624         std::vector<uint8_t> data = bt::BufferView(buffer).ToVector();
625         fhbt::ReceivedPacket event = fhbt::ReceivedPacket::WithIso(data);
626         fit::result<::fidl::OneWayError> status =
627             fidl::SendEvent(binding)->OnReceive(event);
628         if (!status.is_ok()) {
629           FDF_LOG(ERROR,
630                   "Failed to send OnReceive event to bt-host: %s",
631                   status.error_value().status_string());
632         }
633       });
634 }
635 
636 }  // namespace bt_hci_virtual
637