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 <fidl/fuchsia.driver.framework/cpp/fidl.h> 18 #include <fidl/fuchsia.hardware.bluetooth/cpp/fidl.h> 19 #include <lib/async-loop/cpp/loop.h> 20 #include <lib/driver/devfs/cpp/connector.h> 21 22 #include <queue> 23 24 #include "lib/async/cpp/wait.h" 25 26 namespace bt_hci_virtual { 27 28 using AddChildCallback = 29 fit::function<void(fuchsia_driver_framework::wire::NodeAddArgs)>; 30 31 class LoopbackDevice : public fidl::Server<fuchsia_hardware_bluetooth::Vendor> { 32 public: 33 static constexpr size_t kMaxSnoopQueueSize = 20; 34 static constexpr size_t kMaxSnoopUnackedPackets = 10; 35 static constexpr size_t kMaxReceiveQueueSize = 40; 36 static constexpr size_t kMaxReceiveUnackedPackets = 10; 37 38 explicit LoopbackDevice(); 39 40 // Methods to control the LoopbackDevice's lifecycle. These are used by the 41 // VirtualController. `channel` speaks the HCI UART protocol. `name` is the 42 // name to be used for the driver framework node. `callback` will be called 43 // with the NodeAddArgs when LoopbackDevice should be added as a child node. 44 zx_status_t Initialize(zx::channel channel, 45 std::string_view name, 46 AddChildCallback callback); 47 48 // Called by driver_devfs::Connector. 49 void Connect(fidl::ServerEnd<fuchsia_hardware_bluetooth::Vendor> request); 50 51 private: 52 // HCI UART packet indicators 53 enum class PacketIndicator : uint8_t { 54 kHciNone = 0, 55 kHciCommand = 1, 56 kHciAclData = 2, 57 kHciSco = 3, 58 kHciEvent = 4, 59 kHciIso = 5, 60 }; 61 62 class SnoopServer : public fidl::Server<fuchsia_hardware_bluetooth::Snoop> { 63 public: 64 SnoopServer(fidl::ServerEnd<fuchsia_hardware_bluetooth::Snoop> server_end, 65 LoopbackDevice* device); 66 67 // `buffer` should NOT have an indicator byte. 68 void QueueSnoopPacket( 69 uint8_t* buffer, 70 size_t length, 71 PacketIndicator indicator, 72 fuchsia_hardware_bluetooth::PacketDirection direction); 73 74 private: 75 struct Packet { 76 std::vector<uint8_t> packet; 77 uint64_t sequence; 78 PacketIndicator indicator; 79 fuchsia_hardware_bluetooth::PacketDirection direction; 80 }; 81 82 void SendSnoopPacket(uint8_t* buffer, 83 size_t length, 84 PacketIndicator indicator, 85 fuchsia_hardware_bluetooth::PacketDirection direction, 86 uint64_t sequence); 87 88 // fidl::Server<fuchsia_hardware_bluetooth::Snoop> overrides: 89 void AcknowledgePackets( 90 AcknowledgePacketsRequest& request, 91 AcknowledgePacketsCompleter::Sync& completer) override; 92 void handle_unknown_method( 93 fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::Snoop> metadata, 94 fidl::UnknownMethodCompleter::Sync& completer) override; 95 96 void OnFidlError(fidl::UnbindInfo error); 97 98 fidl::ServerBinding<fuchsia_hardware_bluetooth::Snoop> binding_; 99 uint64_t next_sequence_ = 1u; 100 uint64_t acked_sequence_ = 0u; 101 uint32_t dropped_sent_ = 0u; 102 uint32_t dropped_received_ = 0u; 103 std::queue<Packet> queued_packets_; 104 LoopbackDevice* device_; 105 }; 106 107 class HciTransportServer 108 : public fidl::Server<fuchsia_hardware_bluetooth::HciTransport> { 109 public: 110 HciTransportServer( 111 LoopbackDevice* device, 112 size_t binding_id, 113 fidl::ServerEnd<fuchsia_hardware_bluetooth::HciTransport> server_end); 114 115 // `buffer` must have an indicator byte. 116 void OnReceive(uint8_t* buffer, size_t length); 117 118 void OnUnbound(fidl::UnbindInfo info); 119 120 private: 121 void SendOnReceive(uint8_t* buffer, size_t length); 122 void MaybeSendQueuedReceivePackets(); 123 124 // fuchsia_hardware_bluetooth::HciTransport overrides: 125 void Send(SendRequest& request, SendCompleter::Sync& completer) override; 126 void AckReceive(AckReceiveCompleter::Sync& completer) override; 127 void ConfigureSco(ConfigureScoRequest& request, 128 ConfigureScoCompleter::Sync& completer) override; 129 void handle_unknown_method( 130 fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::HciTransport> 131 metadata, 132 fidl::UnknownMethodCompleter::Sync& completer) override; 133 134 LoopbackDevice* device_; 135 size_t binding_id_; 136 size_t receive_credits_ = kMaxReceiveUnackedPackets; 137 std::queue<std::vector<uint8_t>> receive_queue_; 138 fidl::ServerBinding<fuchsia_hardware_bluetooth::HciTransport> binding_; 139 }; 140 141 void OnLoopbackChannelSignal(async_dispatcher_t* dispatcher, 142 async::WaitBase* wait, 143 zx_status_t status, 144 const zx_packet_signal_t* signal); 145 146 void OnHciTransportUnbound(size_t binding_id, fidl::UnbindInfo info); 147 148 void ReadLoopbackChannel(); 149 void WriteLoopbackChannel(PacketIndicator indicator, 150 uint8_t* buffer, 151 size_t length); 152 153 // fuchsia_hardware_bluetooth::Vendor overrides: 154 void GetFeatures(GetFeaturesCompleter::Sync& completer) override; 155 void EncodeCommand(EncodeCommandRequest& request, 156 EncodeCommandCompleter::Sync& completer) override; 157 void OpenHci(OpenHciCompleter::Sync& completer) override; 158 void OpenHciTransport(OpenHciTransportCompleter::Sync& completer) override; 159 void OpenSnoop(OpenSnoopCompleter::Sync& completer) override; 160 void handle_unknown_method( 161 fidl::UnknownMethodMetadata<fuchsia_hardware_bluetooth::Vendor> metadata, 162 fidl::UnknownMethodCompleter::Sync& completer) override; 163 164 zx::channel loopback_chan_; 165 async::WaitMethod<LoopbackDevice, &LoopbackDevice::OnLoopbackChannelSignal> 166 loopback_chan_wait_{this}; 167 168 fidl::ServerBindingGroup<fuchsia_hardware_bluetooth::Vendor> 169 vendor_binding_group_; 170 171 // Multiple HciTransport servers need to be supported: at least 1 for bt-host 172 // and 1 for bt-snoop. 173 std::unordered_map<size_t, HciTransportServer> hci_transport_servers_; 174 size_t next_hci_transport_server_id_ = 0u; 175 176 // Only support 1 Snoop binding at a time. 177 std::optional<SnoopServer> snoop_; 178 179 async_dispatcher_t* dispatcher_; 180 181 // +1 for packet indicator 182 std::array<uint8_t, fuchsia_hardware_bluetooth::kAclPacketMax + 1> 183 read_buffer_; 184 185 driver_devfs::Connector<fuchsia_hardware_bluetooth::Vendor> devfs_connector_; 186 }; 187 188 } // namespace bt_hci_virtual 189