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 "loopback.h"
16
17 #include <lib/driver/logging/cpp/logger.h>
18 #include <lib/driver/testing/cpp/driver_runtime.h>
19
20 #include "gtest/gtest.h"
21
22 namespace fhb = fuchsia_hardware_bluetooth;
23
24 namespace bt_hci_virtual {
25
26 // TODO: https://pwbug.dev/369120118 - Use ScopedGlobalLogger when it is
27 // available in the SDK. See fxr/1110057.
28
29 class LoopbackTest : public ::testing::Test,
30 public fidl::AsyncEventHandler<fhb::HciTransport>,
31 public fidl::AsyncEventHandler<fhb::Snoop> {
32 public:
SetUp()33 void SetUp() override {
34 zx::channel loopback_channel_device_end;
35 zx::channel::create(0, &loopback_chan_, &loopback_channel_device_end);
36 int add_child_cb_count = 0;
37 auto add_child_cb = [&](fuchsia_driver_framework::wire::NodeAddArgs) {
38 add_child_cb_count++;
39 };
40 zx_status_t status =
41 loopback_device_.Initialize(std::move(loopback_channel_device_end),
42 "loopback",
43 std::move(add_child_cb));
44 ASSERT_EQ(status, ZX_OK);
45 ASSERT_EQ(add_child_cb_count, 1);
46
47 loopback_chan_wait_.set_object(loopback_chan_.get());
48 loopback_chan_wait_.set_trigger(ZX_CHANNEL_READABLE |
49 ZX_CHANNEL_PEER_CLOSED);
50 zx_status_t wait_begin_status = loopback_chan_wait_.Begin(dispatcher());
51 ASSERT_EQ(wait_begin_status, ZX_OK);
52
53 // There's no driver instance to set up the logger for this test, so create
54 // a driver logger for this test.
55 InitializeLogger();
56
57 OpenHciTransport();
58 OpenSnoop();
59
60 fdf_testing_run_until_idle();
61 }
62
TearDown()63 void TearDown() override {
64 loopback_chan_wait_.Cancel();
65 fdf_testing_run_until_idle();
66 runtime_.ShutdownAllDispatchers(fdf::Dispatcher::GetCurrent()->get());
67 fdf::Logger::SetGlobalInstance(nullptr);
68 }
69
dispatcher()70 async_dispatcher_t* dispatcher() {
71 return fdf::Dispatcher::GetCurrent()->async_dispatcher();
72 }
73
device()74 LoopbackDevice& device() { return loopback_device_; }
75
chan()76 zx::channel& chan() { return loopback_chan_; }
77
hci_client()78 fidl::Client<fhb::HciTransport>& hci_client() { return hci_client_; }
79
snoop_client()80 fidl::Client<fhb::Snoop>& snoop_client() { return snoop_client_; }
81
snoop_packets() const82 const std::vector<fidl::Event<fhb::Snoop::OnObservePacket>>& snoop_packets()
83 const {
84 return snoop_packets_;
85 }
86
87 const std::vector<fidl::Event<fhb::Snoop::OnDroppedPackets>>&
dropped_snoop_packets()88 dropped_snoop_packets() {
89 return dropped_snoop_packets_;
90 }
91
92 // Packets received on the loopback channel (i.e. packets sent by
93 // LoopbackDevice).
sent_packets() const94 const std::vector<std::vector<uint8_t>>& sent_packets() const {
95 return sent_packets_;
96 }
97
received_packets() const98 const std::vector<fhb::ReceivedPacket>& received_packets() const {
99 return received_packets_;
100 }
101
102 private:
103 // fidl::AsyncEventHandler<fhb::HciTransport> overrides:
OnReceive(::fidl::Event<::fuchsia_hardware_bluetooth::HciTransport::OnReceive> & event)104 void OnReceive(
105 ::fidl::Event<::fuchsia_hardware_bluetooth::HciTransport::OnReceive>&
106 event) override {
107 received_packets_.emplace_back(std::move(event));
108 }
handle_unknown_event(fidl::UnknownEventMetadata<fhb::HciTransport> metadata)109 void handle_unknown_event(
110 fidl::UnknownEventMetadata<fhb::HciTransport> metadata) override {}
111
112 // fidl::AsyncEventHandler<fhb::Snoop> overrides:
OnObservePacket(fidl::Event<fhb::Snoop::OnObservePacket> & event)113 void OnObservePacket(
114 fidl::Event<fhb::Snoop::OnObservePacket>& event) override {
115 snoop_packets_.emplace_back(std::move(event));
116 }
OnDroppedPackets(fidl::Event<fhb::Snoop::OnDroppedPackets> & event)117 void OnDroppedPackets(
118 fidl::Event<fhb::Snoop::OnDroppedPackets>& event) override {
119 dropped_snoop_packets_.emplace_back(std::move(event));
120 }
handle_unknown_event(fidl::UnknownEventMetadata<fhb::Snoop> metadata)121 void handle_unknown_event(
122 fidl::UnknownEventMetadata<fhb::Snoop> metadata) override {}
123
OpenHciTransport()124 void OpenHciTransport() {
125 auto vendor_endpoints = fidl::CreateEndpoints<fhb::Vendor>();
126 loopback_device_.Connect(std::move(vendor_endpoints->server));
127 vendor_client_.Bind(std::move(vendor_endpoints->client), dispatcher());
128
129 fdf_testing_run_until_idle();
130 std::optional<fidl::Result<fhb::Vendor::GetFeatures>> features;
131 vendor_client_->GetFeatures().Then(
132 [&features](fidl::Result<fhb::Vendor::GetFeatures>& result) {
133 features = std::move(result);
134 });
135 fdf_testing_run_until_idle();
136 ASSERT_TRUE(features.has_value());
137 ASSERT_TRUE(features->is_ok());
138 EXPECT_EQ(features->value(), fhb::VendorFeatures());
139
140 vendor_client_->OpenHciTransport().Then(
141 [this](fidl::Result<fhb::Vendor::OpenHciTransport>& result) {
142 ASSERT_TRUE(result.is_ok());
143 hci_client_.Bind(std::move(result.value().channel()),
144 dispatcher(),
145 /*event_handler=*/this);
146 });
147 fdf_testing_run_until_idle();
148 ASSERT_TRUE(hci_client_.is_valid());
149 }
150
OpenSnoop()151 void OpenSnoop() {
152 auto vendor_endpoints = fidl::CreateEndpoints<fhb::Vendor>();
153 loopback_device_.Connect(std::move(vendor_endpoints->server));
154 snoop_vendor_client_.Bind(std::move(vendor_endpoints->client),
155 dispatcher());
156 snoop_vendor_client_->OpenSnoop().Then(
157 [this](fidl::Result<fhb::Vendor::OpenSnoop>& result) {
158 ASSERT_TRUE(result.is_ok());
159 snoop_client_.Bind(std::move(result.value().channel()),
160 dispatcher(),
161 /*event_handler=*/this);
162 });
163 fdf_testing_run_until_idle();
164 ASSERT_TRUE(snoop_vendor_client_.is_valid());
165
166 // Simulate bt-snoop dropping the Vendor client after getting a Snoop
167 // client.
168 auto _ = snoop_vendor_client_.UnbindMaybeGetEndpoint();
169 }
170
InitializeLogger()171 void InitializeLogger() {
172 std::vector<fuchsia_component_runner::ComponentNamespaceEntry> entries;
173 zx::result open_result = component::OpenServiceRoot();
174 ZX_ASSERT(open_result.is_ok());
175
176 ::fidl::ClientEnd<::fuchsia_io::Directory> svc = std::move(*open_result);
177 entries.emplace_back(fuchsia_component_runner::ComponentNamespaceEntry{{
178 .path = "/svc",
179 .directory = std::move(svc),
180 }});
181
182 // Create Namespace object from the entries.
183 auto ns = fdf::Namespace::Create(entries);
184 ZX_ASSERT(ns.is_ok());
185
186 // Create Logger with dispatcher and namespace.
187 logger_ = fdf::Logger::Create2(*ns, dispatcher(), "vendor-hci-logger");
188 ZX_ASSERT(logger_);
189 fdf::Logger::SetGlobalInstance(logger_.get());
190 }
191
OnChannelReady(async_dispatcher_t *,async::WaitBase * wait,zx_status_t status,const zx_packet_signal_t * signal)192 void OnChannelReady(async_dispatcher_t*,
193 async::WaitBase* wait,
194 zx_status_t status,
195 const zx_packet_signal_t* signal) {
196 if (status == ZX_ERR_CANCELED) {
197 return;
198 }
199 ASSERT_EQ(status, ZX_OK) << zx_status_get_string(status);
200
201 if (signal->observed & ZX_CHANNEL_READABLE) {
202 // Make byte buffer arbitrarily large enough to hold test packets.
203 std::vector<uint8_t> bytes(255);
204 uint32_t actual_bytes;
205 zx_status_t read_status = loopback_chan_.read(
206 /*flags=*/0,
207 bytes.data(),
208 /*handles=*/nullptr,
209 static_cast<uint32_t>(bytes.size()),
210 /*num_handles=*/0,
211 &actual_bytes,
212 /*actual_handles=*/nullptr);
213 ASSERT_EQ(read_status, ZX_OK) << zx_status_get_string(read_status);
214 bytes.resize(actual_bytes);
215 sent_packets_.push_back(std::move(bytes));
216 }
217
218 if (signal->observed & ZX_CHANNEL_PEER_CLOSED) {
219 FDF_LOG(INFO, "Loopback channel peer closed");
220 return;
221 }
222
223 // The wait needs to be restarted.
224 zx_status_t wait_begin_status = loopback_chan_wait_.Begin(dispatcher());
225 ASSERT_EQ(wait_begin_status, ZX_OK)
226 << zx_status_get_string(wait_begin_status);
227 }
228
229 // Attaches a foreground dispatcher for us automatically.
230 fdf_testing::DriverRuntime runtime_;
231 std::unique_ptr<fdf::Logger> logger_;
232
233 zx::channel loopback_chan_;
234 LoopbackDevice loopback_device_;
235
236 fidl::Client<fhb::Vendor> vendor_client_;
237 fidl::Client<fhb::HciTransport> hci_client_;
238
239 fidl::Client<fhb::Vendor> snoop_vendor_client_;
240 fidl::Client<fhb::Snoop> snoop_client_;
241 std::vector<fidl::Event<fhb::Snoop::OnObservePacket>> snoop_packets_;
242 std::vector<fidl::Event<fhb::Snoop::OnDroppedPackets>> dropped_snoop_packets_;
243
244 std::vector<std::vector<uint8_t>> sent_packets_;
245 std::vector<fhb::ReceivedPacket> received_packets_;
246 async::WaitMethod<LoopbackTest, &LoopbackTest::OnChannelReady>
247 loopback_chan_wait_{this};
248 };
249
TEST_F(LoopbackTest,SendManyCommandPackets)250 TEST_F(LoopbackTest, SendManyCommandPackets) {
251 int send_cb_count = 0;
252 for (uint8_t i = 0; i < 10; i++) {
253 fidl::Request<fhb::HciTransport::Send> request =
254 fidl::Request<fhb::HciTransport::Send>::WithCommand({i, 0x07, 0x08});
255 hci_client()->Send(request).Then(
256 [&send_cb_count](fidl::Result<fhb::HciTransport::Send>& result) {
257 send_cb_count++;
258 });
259 }
260 fdf_testing_run_until_idle();
261 EXPECT_EQ(send_cb_count, 10);
262
263 ASSERT_EQ(sent_packets().size(), 10u);
264 for (uint8_t i = 0; i < 10; i++) {
265 auto& packet = sent_packets()[i];
266 std::vector<uint8_t> expected = {0x01, // packet indicator (command)
267 i,
268 0x07,
269 0x08};
270 EXPECT_EQ(packet, expected);
271 }
272
273 ASSERT_EQ(snoop_packets().size(), 10u);
274 for (uint8_t i = 0; i < 10; i++) {
275 auto& packet = snoop_packets()[i];
276 EXPECT_EQ(packet.direction(), fhb::PacketDirection::kHostToController);
277 EXPECT_EQ(packet.sequence(), i + 1);
278 ASSERT_EQ(packet.packet()->Which(), fhb::SnoopPacket::Tag::kCommand);
279 std::vector<uint8_t> expected = {i, 0x07, 0x08};
280 EXPECT_EQ(packet.packet()->command().value(), expected);
281 }
282 }
283
TEST_F(LoopbackTest,SendManyAclPackets)284 TEST_F(LoopbackTest, SendManyAclPackets) {
285 int send_cb_count = 0;
286 for (uint8_t i = 0; i < 10; i++) {
287 fidl::Request<fhb::HciTransport::Send> request =
288 fidl::Request<fhb::HciTransport::Send>::WithAcl({i, 0x07, 0x08});
289 hci_client()->Send(request).Then(
290 [&send_cb_count](fidl::Result<fhb::HciTransport::Send>& result) {
291 send_cb_count++;
292 });
293 }
294 fdf_testing_run_until_idle();
295 EXPECT_EQ(send_cb_count, 10);
296
297 ASSERT_EQ(sent_packets().size(), 10u);
298 for (uint8_t i = 0; i < 10; i++) {
299 auto& packet = sent_packets()[i];
300 std::vector<uint8_t> expected = {0x02, // packet indicator (ACL)
301 i,
302 0x07,
303 0x08};
304 EXPECT_EQ(packet, expected);
305 }
306
307 ASSERT_EQ(snoop_packets().size(), 10u);
308 for (uint8_t i = 0; i < 10; i++) {
309 auto& packet = snoop_packets()[i];
310 EXPECT_EQ(packet.direction(), fhb::PacketDirection::kHostToController);
311 EXPECT_EQ(packet.sequence(), i + 1);
312 ASSERT_EQ(packet.packet()->Which(), fhb::SnoopPacket::Tag::kAcl);
313 std::vector<uint8_t> expected = {i, 0x07, 0x08};
314 EXPECT_EQ(packet.packet()->acl().value(), expected);
315 }
316 }
317
TEST_F(LoopbackTest,ReceiveManyEventPackets)318 TEST_F(LoopbackTest, ReceiveManyEventPackets) {
319 for (uint8_t i = 0; i < LoopbackDevice::kMaxReceiveUnackedPackets; i++) {
320 std::array<uint8_t, 3> packet = {0x04, // packet indicator (event),
321 i,
322 0x05};
323 zx_status_t status = chan().write(/*flags=*/0,
324 packet.data(),
325 static_cast<uint32_t>(packet.size()),
326 /*handles=*/nullptr,
327 /*num_handles=*/0);
328 ASSERT_EQ(status, ZX_OK);
329 }
330
331 fdf_testing_run_until_idle();
332
333 ASSERT_EQ(received_packets().size(),
334 LoopbackDevice::kMaxReceiveUnackedPackets);
335 for (uint8_t i = 0; i < LoopbackDevice::kMaxReceiveUnackedPackets; i++) {
336 auto& packet = received_packets()[i];
337 ASSERT_EQ(packet.Which(), fhb::ReceivedPacket::Tag::kEvent);
338 std::vector<uint8_t> expected = {i, 0x05};
339 EXPECT_EQ(packet.event().value(), expected);
340 }
341
342 ASSERT_EQ(snoop_packets().size(), LoopbackDevice::kMaxReceiveUnackedPackets);
343 for (uint8_t i = 0; i < LoopbackDevice::kMaxReceiveUnackedPackets; i++) {
344 auto& packet = snoop_packets()[i];
345 EXPECT_EQ(packet.direction(), fhb::PacketDirection::kControllerToHost);
346 EXPECT_EQ(packet.sequence(), i + 1);
347 ASSERT_EQ(packet.packet()->Which(), fhb::SnoopPacket::Tag::kEvent);
348 std::vector<uint8_t> expected = {i, 0x05};
349 EXPECT_EQ(packet.packet()->event().value(), expected);
350 }
351 }
352
TEST_F(LoopbackTest,ReceiveAndQueueAndAckManyAclPackets)353 TEST_F(LoopbackTest, ReceiveAndQueueAndAckManyAclPackets) {
354 const uint8_t arbitrary_value = 0x05;
355 // 2 packets should be queued
356 const size_t num_packets_sent = LoopbackDevice::kMaxReceiveUnackedPackets + 2;
357 for (uint8_t i = 0; i < num_packets_sent; i++) {
358 std::array<uint8_t, 3> packet = {0x02, // packet indicator (acl),
359 i,
360 arbitrary_value};
361 zx_status_t status = chan().write(/*flags=*/0,
362 packet.data(),
363 static_cast<uint32_t>(packet.size()),
364 /*handles=*/nullptr,
365 /*num_handles=*/0);
366 ASSERT_EQ(status, ZX_OK);
367 }
368
369 fdf_testing_run_until_idle();
370
371 ASSERT_EQ(received_packets().size(),
372 LoopbackDevice::kMaxReceiveUnackedPackets);
373 for (uint8_t i = 0; i < LoopbackDevice::kMaxReceiveUnackedPackets; i++) {
374 auto& packet = received_packets()[i];
375 ASSERT_EQ(packet.Which(), fhb::ReceivedPacket::Tag::kAcl);
376 std::vector<uint8_t> expected = {i, arbitrary_value};
377 EXPECT_EQ(packet.acl().value(), expected);
378 }
379
380 ASSERT_EQ(snoop_packets().size(), LoopbackDevice::kMaxSnoopUnackedPackets);
381 for (uint8_t i = 0; i < LoopbackDevice::kMaxSnoopUnackedPackets; i++) {
382 auto& packet = snoop_packets()[i];
383 EXPECT_EQ(packet.direction(), fhb::PacketDirection::kControllerToHost);
384 EXPECT_EQ(packet.sequence(), i + 1);
385 ASSERT_EQ(packet.packet()->Which(), fhb::SnoopPacket::Tag::kAcl);
386 std::vector<uint8_t> expected = {i, arbitrary_value};
387 EXPECT_EQ(packet.packet()->acl().value(), expected);
388 }
389
390 // Ack 2x so that the 2 queued packets are sent.
391 fit::result<fidl::OneWayError> result = hci_client()->AckReceive();
392 ASSERT_TRUE(result.is_ok());
393 result = hci_client()->AckReceive();
394 ASSERT_TRUE(result.is_ok());
395 fdf_testing_run_until_idle();
396
397 ASSERT_EQ(received_packets().size(), num_packets_sent);
398 for (uint8_t i = 0; i < num_packets_sent; i++) {
399 auto& packet = received_packets()[i];
400 ASSERT_EQ(packet.Which(), fhb::ReceivedPacket::Tag::kAcl);
401 std::vector<uint8_t> expected = {i, arbitrary_value};
402 EXPECT_EQ(packet.acl().value(), expected);
403 }
404
405 // Ack 2x so that the 2 queued packets are sent.
406 result = snoop_client()->AcknowledgePackets(
407 fhb::SnoopAcknowledgePacketsRequest(2));
408 ASSERT_TRUE(result.is_ok());
409 fdf_testing_run_until_idle();
410
411 ASSERT_EQ(snoop_packets().size(), num_packets_sent);
412 for (uint8_t i = 0; i < num_packets_sent; i++) {
413 auto& packet = snoop_packets()[i];
414 EXPECT_EQ(packet.direction(), fhb::PacketDirection::kControllerToHost);
415 EXPECT_EQ(packet.sequence(), i + 1);
416 ASSERT_EQ(packet.packet()->Which(), fhb::SnoopPacket::Tag::kAcl);
417 std::vector<uint8_t> expected = {i, arbitrary_value};
418 EXPECT_EQ(packet.packet()->acl().value(), expected);
419 }
420 }
421
TEST_F(LoopbackTest,DropSnoopPackets)422 TEST_F(LoopbackTest, DropSnoopPackets) {
423 // 2 packets should get dropped
424 const size_t num_dropped = 2;
425 const size_t num_packets_sent = LoopbackDevice::kMaxSnoopUnackedPackets +
426 LoopbackDevice::kMaxSnoopQueueSize +
427 num_dropped;
428 size_t send_cb_count = 0;
429 for (uint8_t i = 0; i < num_packets_sent; i++) {
430 fidl::Request<fhb::HciTransport::Send> request =
431 fidl::Request<fhb::HciTransport::Send>::WithAcl({i, 0x07, 0x08});
432 hci_client()->Send(request).Then(
433 [&send_cb_count](fidl::Result<fhb::HciTransport::Send>& result) {
434 send_cb_count++;
435 });
436 }
437 fdf_testing_run_until_idle();
438 EXPECT_EQ(send_cb_count, num_packets_sent);
439
440 ASSERT_EQ(snoop_packets().size(), LoopbackDevice::kMaxSnoopUnackedPackets);
441
442 fit::result<fidl::OneWayError> result =
443 snoop_client()->AcknowledgePackets(fhb::SnoopAcknowledgePacketsRequest(
444 LoopbackDevice::kMaxSnoopUnackedPackets));
445 ASSERT_TRUE(result.is_ok());
446 fdf_testing_run_until_idle();
447 ASSERT_EQ(snoop_packets().size(),
448 2 * LoopbackDevice::kMaxSnoopUnackedPackets - num_dropped);
449 for (uint8_t i = LoopbackDevice::kMaxSnoopUnackedPackets;
450 static_cast<size_t>(i) < snoop_packets().size();
451 i++) {
452 auto& packet = snoop_packets()[i];
453 EXPECT_EQ(packet.direction(), fhb::PacketDirection::kHostToController);
454 EXPECT_EQ(packet.sequence(), i + 1 + num_dropped);
455 ASSERT_EQ(packet.packet()->Which(), fhb::SnoopPacket::Tag::kAcl);
456 std::vector<uint8_t> expected = {
457 static_cast<uint8_t>(i + num_dropped), 0x07, 0x08};
458 EXPECT_EQ(packet.packet()->acl().value(), expected);
459 }
460
461 ASSERT_EQ(dropped_snoop_packets().size(), 1u);
462 EXPECT_EQ(dropped_snoop_packets()[0].sent(), 2u);
463 EXPECT_EQ(dropped_snoop_packets()[0].received(), 0u);
464 }
465
466 } // namespace bt_hci_virtual
467