• 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 "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