• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 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/internal/host/sco/sco_connection.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/hci/fake_sco_connection.h"
18 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
19 #include "pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
20 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
21 #include "pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
22 #include "pw_bluetooth_sapphire/internal/host/transport/fake_sco_data_channel.h"
23 #include "pw_unit_test/framework.h"
24 
25 namespace bt::sco {
26 namespace {
27 
28 hci_spec::ConnectionHandle kConnectionHandle = 1u;
29 hci_spec::ConnectionHandle kConnectionHandle2 = 2u;
30 
31 constexpr uint16_t kHciScoMtu = 1;
32 
33 // Default data buffer information used by ScoDataChannel.
34 static constexpr size_t kMaxScoPacketLength = 255;
35 static constexpr size_t kMaxScoPacketCount = 1;
36 const hci::DataBufferInfo kDataBufferInfo(kMaxScoPacketLength,
37                                           kMaxScoPacketCount);
38 
39 using TestingBase =
40     testing::FakeDispatcherControllerTest<testing::MockController>;
41 class ScoConnectionTest : public TestingBase {
42  public:
43   ScoConnectionTest() = default;
44   ~ScoConnectionTest() override = default;
45 
46  protected:
SetUp()47   void SetUp() override {
48     TestingBase::SetUp();
49     InitializeACLDataChannel();
50     InitializeScoDataChannel(kDataBufferInfo);
51 
52     test_device()->set_configure_sco_cb(
53         [](auto, auto, auto, auto cb) { cb(PW_STATUS_OK); });
54     test_device()->set_reset_sco_cb([](auto cb) { cb(PW_STATUS_OK); });
55 
56     auto conn = std::make_unique<hci::ScoConnection>(kConnectionHandle,
57                                                      DeviceAddress(),
58                                                      DeviceAddress(),
59                                                      transport()->GetWeakPtr());
60     hci_conn_ = conn->GetWeakPtr();
61     deactivated_cb_count_ = 0;
62     sco_conn_ = CreateScoConnection(std::move(conn));
63   }
64 
TearDown()65   void TearDown() override {
66     sco_conn_ = nullptr;
67     TestingBase::TearDown();
68   }
69 
CreateScoConnection(std::unique_ptr<hci::Connection> hci_conn)70   virtual std::unique_ptr<ScoConnection> CreateScoConnection(
71       std::unique_ptr<hci::Connection> hci_conn) {
72     return std::make_unique<ScoConnection>(
73         std::move(hci_conn),
74         [this] { OnDeactivated(); },
75         bt::StaticPacket<
76             pw::bluetooth::emboss::SynchronousConnectionParametersWriter>(),
77         /*channel=*/nullptr);
78   }
79 
OnDeactivated()80   void OnDeactivated() { deactivated_cb_count_++; }
81 
sco_conn()82   ScoConnection* sco_conn() { return sco_conn_.get(); }
83 
hci_conn()84   auto hci_conn() { return hci_conn_; }
85 
deactivated_count() const86   size_t deactivated_count() const { return deactivated_cb_count_; }
87 
88  private:
89   size_t deactivated_cb_count_;
90   std::unique_ptr<ScoConnection> sco_conn_;
91   hci::ScoConnection::WeakPtr hci_conn_;
92 };
93 
94 class HciScoConnectionTest : public ScoConnectionTest {
95  public:
CreateScoConnection(std::unique_ptr<hci::Connection> hci_conn)96   std::unique_ptr<ScoConnection> CreateScoConnection(
97       std::unique_ptr<hci::Connection> hci_conn) override {
98     bt::StaticPacket<
99         pw::bluetooth::emboss::SynchronousConnectionParametersWriter>
100         hci_conn_params;
101     hci_conn_params.view().input_data_path().Write(
102         pw::bluetooth::emboss::ScoDataPath::HCI);
103     hci_conn_params.view().output_data_path().Write(
104         pw::bluetooth::emboss::ScoDataPath::HCI);
105     return std::make_unique<ScoConnection>(
106         std::move(hci_conn),
107         [this] { OnDeactivated(); },
108         hci_conn_params,
109         transport()->sco_data_channel());
110   }
111 };
112 
113 class HciScoConnectionTestWithFakeScoChannel : public ScoConnectionTest {
114  public:
CreateScoConnection(std::unique_ptr<hci::Connection> hci_conn)115   std::unique_ptr<ScoConnection> CreateScoConnection(
116       std::unique_ptr<hci::Connection> hci_conn) override {
117     channel_ = std::make_unique<hci::FakeScoDataChannel>(/*mtu=*/kHciScoMtu);
118 
119     bt::StaticPacket<
120         pw::bluetooth::emboss::SynchronousConnectionParametersWriter>
121         hci_conn_params;
122     hci_conn_params.view().input_data_path().Write(
123         pw::bluetooth::emboss::ScoDataPath::HCI);
124     hci_conn_params.view().output_data_path().Write(
125         pw::bluetooth::emboss::ScoDataPath::HCI);
126     return std::make_unique<ScoConnection>(
127         std::move(hci_conn),
128         [this] { OnDeactivated(); },
129         hci_conn_params,
130         channel_.get());
131   }
132 
fake_sco_chan()133   hci::FakeScoDataChannel* fake_sco_chan() { return channel_.get(); }
134 
135  private:
136   std::unique_ptr<hci::FakeScoDataChannel> channel_;
137 };
138 
TEST_F(ScoConnectionTest,Send)139 TEST_F(ScoConnectionTest, Send) {
140   EXPECT_FALSE(sco_conn()->Send(nullptr));
141   EXPECT_CMD_PACKET_OUT(test_device(),
142                         testing::DisconnectPacket(kConnectionHandle));
143 }
144 
TEST_F(ScoConnectionTest,MaxTxSduSize)145 TEST_F(ScoConnectionTest, MaxTxSduSize) {
146   EXPECT_EQ(sco_conn()->max_tx_sdu_size(), 0u);
147   EXPECT_CMD_PACKET_OUT(test_device(),
148                         testing::DisconnectPacket(kConnectionHandle));
149 }
150 
TEST_F(ScoConnectionTest,ActivateAndDeactivate)151 TEST_F(ScoConnectionTest, ActivateAndDeactivate) {
152   size_t close_count = 0;
153   auto closed_cb = [&] { close_count++; };
154 
155   EXPECT_TRUE(
156       sco_conn()->Activate(/*rx_callback=*/[]() {}, std::move(closed_cb)));
157   EXPECT_EQ(close_count, 0u);
158   EXPECT_TRUE(hci_conn().is_alive());
159 
160   sco_conn()->Deactivate();
161   EXPECT_EQ(close_count, 0u);
162   EXPECT_EQ(deactivated_count(), 1u);
163   EXPECT_FALSE(hci_conn().is_alive());
164 
165   // Deactivating should be idempotent.
166   sco_conn()->Deactivate();
167   EXPECT_EQ(close_count, 0u);
168   EXPECT_EQ(deactivated_count(), 1u);
169   EXPECT_CMD_PACKET_OUT(test_device(),
170                         testing::DisconnectPacket(kConnectionHandle));
171 }
172 
TEST_F(HciScoConnectionTestWithFakeScoChannel,ActivateAndDeactivateRegistersAndUnregistersConnection)173 TEST_F(HciScoConnectionTestWithFakeScoChannel,
174        ActivateAndDeactivateRegistersAndUnregistersConnection) {
175   EXPECT_TRUE(fake_sco_chan()->connections().empty());
176 
177   EXPECT_TRUE(
178       sco_conn()->Activate(/*rx_callback=*/[]() {}, /*closed_callback=*/[] {}));
179   ASSERT_EQ(fake_sco_chan()->connections().size(), 1u);
180   EXPECT_EQ(fake_sco_chan()->connections().begin()->first,
181             sco_conn()->handle());
182 
183   sco_conn()->Deactivate();
184   EXPECT_TRUE(fake_sco_chan()->connections().empty());
185   EXPECT_CMD_PACKET_OUT(test_device(),
186                         testing::DisconnectPacket(kConnectionHandle));
187 }
188 
TEST_F(ScoConnectionTest,ActivateAndClose)189 TEST_F(ScoConnectionTest, ActivateAndClose) {
190   size_t close_count = 0;
191   auto closed_cb = [&] { close_count++; };
192 
193   EXPECT_TRUE(
194       sco_conn()->Activate(/*rx_callback=*/[]() {}, std::move(closed_cb)));
195   EXPECT_EQ(close_count, 0u);
196   EXPECT_TRUE(hci_conn().is_alive());
197 
198   sco_conn()->Close();
199   EXPECT_EQ(close_count, 1u);
200   EXPECT_EQ(deactivated_count(), 0u);
201   EXPECT_FALSE(hci_conn().is_alive());
202 
203   // Closing should be idempotent.
204   sco_conn()->Close();
205   EXPECT_EQ(close_count, 1u);
206   EXPECT_EQ(deactivated_count(), 0u);
207   EXPECT_CMD_PACKET_OUT(test_device(),
208                         testing::DisconnectPacket(kConnectionHandle));
209 }
210 
TEST_F(HciScoConnectionTestWithFakeScoChannel,ActivateAndCloseRegistersAndUnregistersConnection)211 TEST_F(HciScoConnectionTestWithFakeScoChannel,
212        ActivateAndCloseRegistersAndUnregistersConnection) {
213   EXPECT_TRUE(fake_sco_chan()->connections().empty());
214 
215   EXPECT_TRUE(
216       sco_conn()->Activate(/*rx_callback=*/[]() {}, /*closed_callback=*/[] {}));
217   ASSERT_EQ(fake_sco_chan()->connections().size(), 1u);
218   EXPECT_EQ(fake_sco_chan()->connections().begin()->first,
219             sco_conn()->handle());
220 
221   sco_conn()->Close();
222   EXPECT_TRUE(fake_sco_chan()->connections().empty());
223   EXPECT_CMD_PACKET_OUT(test_device(),
224                         testing::DisconnectPacket(kConnectionHandle));
225 }
226 
TEST_F(ScoConnectionTest,UniqueId)227 TEST_F(ScoConnectionTest, UniqueId) {
228   EXPECT_EQ(sco_conn()->unique_id(), kConnectionHandle);
229   EXPECT_CMD_PACKET_OUT(test_device(),
230                         testing::DisconnectPacket(kConnectionHandle));
231 }
232 
TEST_F(ScoConnectionTest,CloseWithoutActivating)233 TEST_F(ScoConnectionTest, CloseWithoutActivating) {
234   EXPECT_TRUE(hci_conn().is_alive());
235   sco_conn()->Close();
236   EXPECT_EQ(deactivated_count(), 0u);
237   EXPECT_FALSE(hci_conn().is_alive());
238   EXPECT_CMD_PACKET_OUT(test_device(),
239                         testing::DisconnectPacket(kConnectionHandle));
240 }
241 
TEST_F(HciScoConnectionTestWithFakeScoChannel,CloseWithoutActivatingDoesNotUnregister)242 TEST_F(HciScoConnectionTestWithFakeScoChannel,
243        CloseWithoutActivatingDoesNotUnregister) {
244   sco_conn()->Close();
245   EXPECT_CMD_PACKET_OUT(test_device(),
246                         testing::DisconnectPacket(kConnectionHandle));
247 }
248 
TEST_F(ScoConnectionTest,ActivateAndPeerDisconnectDeactivates)249 TEST_F(ScoConnectionTest, ActivateAndPeerDisconnectDeactivates) {
250   size_t close_count = 0;
251   auto closed_cb = [&] { close_count++; };
252 
253   EXPECT_TRUE(
254       sco_conn()->Activate(/*rx_callback=*/[]() {}, std::move(closed_cb)));
255   EXPECT_EQ(close_count, 0u);
256   ASSERT_TRUE(hci_conn().is_alive());
257 
258   test_device()->SendCommandChannelPacket(
259       bt::testing::DisconnectionCompletePacket(kConnectionHandle));
260   RunUntilIdle();
261   EXPECT_EQ(close_count, 1u);
262   EXPECT_EQ(deactivated_count(), 0u);
263   EXPECT_FALSE(hci_conn().is_alive());
264 }
265 
TEST_F(HciScoConnectionTestWithFakeScoChannel,ReceiveTwoPackets)266 TEST_F(HciScoConnectionTestWithFakeScoChannel, ReceiveTwoPackets) {
267   size_t close_count = 0;
268   auto closed_cb = [&] { close_count++; };
269 
270   std::vector<std::unique_ptr<hci::ScoDataPacket>> packets;
271   auto rx_callback = [&packets, sco_conn = sco_conn()->GetWeakPtr()]() {
272     std::unique_ptr<hci::ScoDataPacket> packet = sco_conn->Read();
273     ASSERT_TRUE(packet);
274     packets.push_back(std::move(packet));
275   };
276 
277   EXPECT_TRUE(
278       sco_conn()->Activate(std::move(rx_callback), std::move(closed_cb)));
279   ASSERT_EQ(fake_sco_chan()->connections().size(), 1u);
280 
281   EXPECT_FALSE(sco_conn()->Read());
282 
283   StaticByteBuffer packet_buffer_0(
284       LowerBits(kConnectionHandle),
285       UpperBits(kConnectionHandle) |
286           0x30,  // handle + packet status flag: kDataPartiallyLost
287       0x01,      // payload length
288       0x00       // payload
289   );
290   std::unique_ptr<hci::ScoDataPacket> packet_0 =
291       hci::ScoDataPacket::New(/*payload_size=*/1);
292   packet_0->mutable_view()->mutable_data().Write(packet_buffer_0);
293   packet_0->InitializeFromBuffer();
294   sco_conn()->ReceiveInboundPacket(std::move(packet_0));
295 
296   ASSERT_EQ(packets.size(), 1u);
297   EXPECT_FALSE(sco_conn()->Read());
298   StaticByteBuffer payload_buffer_0(0x00);
299   EXPECT_TRUE(
300       ContainersEqual(packets[0]->view().payload_data(), payload_buffer_0));
301   EXPECT_EQ(packets[0]->packet_status_flag(),
302             hci_spec::SynchronousDataPacketStatusFlag::kDataPartiallyLost);
303 
304   StaticByteBuffer packet_buffer_1(
305       LowerBits(kConnectionHandle),
306       UpperBits(kConnectionHandle),  // handle + packet status flag:
307                                      // kCorrectlyReceived
308       0x01,                          // payload length
309       0x01                           // payload
310   );
311   std::unique_ptr<hci::ScoDataPacket> packet_1 =
312       hci::ScoDataPacket::New(/*payload_size=*/1);
313   packet_1->mutable_view()->mutable_data().Write(packet_buffer_1);
314   packet_1->InitializeFromBuffer();
315   sco_conn()->ReceiveInboundPacket(std::move(packet_1));
316 
317   ASSERT_EQ(packets.size(), 2u);
318   EXPECT_FALSE(sco_conn()->Read());
319   auto payload_buffer_1 = StaticByteBuffer(0x01);
320   EXPECT_TRUE(
321       ContainersEqual(packets[1]->view().payload_data(), payload_buffer_1));
322   EXPECT_EQ(packets[1]->packet_status_flag(),
323             hci_spec::SynchronousDataPacketStatusFlag::kCorrectlyReceived);
324   EXPECT_CMD_PACKET_OUT(test_device(),
325                         testing::DisconnectPacket(kConnectionHandle));
326 }
327 
TEST_F(HciScoConnectionTestWithFakeScoChannel,SendPackets)328 TEST_F(HciScoConnectionTestWithFakeScoChannel, SendPackets) {
329   EXPECT_TRUE(
330       sco_conn()->Activate(/*rx_callback=*/[]() {}, /*closed_callback=*/[] {}));
331   ASSERT_EQ(fake_sco_chan()->connections().size(), 1u);
332 
333   const auto packet_buffer_0 =
334       StaticByteBuffer(LowerBits(kConnectionHandle),
335                        UpperBits(kConnectionHandle),  // handle
336                        0x01,                          // payload length
337                        0x00                           // payload
338       );
339   const BufferView payload_view_0 =
340       packet_buffer_0.view(sizeof(hci_spec::SynchronousDataHeader));
341   sco_conn()->Send(std::make_unique<DynamicByteBuffer>(payload_view_0));
342 
343   auto packet_buffer_1 =
344       StaticByteBuffer(LowerBits(kConnectionHandle),
345                        UpperBits(kConnectionHandle),  // handle
346                        0x01,                          // payload length
347                        0x01                           // payload
348       );
349   BufferView payload_view_1 =
350       packet_buffer_1.view(sizeof(hci_spec::SynchronousDataHeader));
351   sco_conn()->Send(std::make_unique<DynamicByteBuffer>(payload_view_1));
352 
353   EXPECT_EQ(fake_sco_chan()->readable_count(), 1u);
354   std::unique_ptr<hci::ScoDataPacket> sent_packet =
355       sco_conn()->GetNextOutboundPacket();
356   ASSERT_TRUE(sent_packet);
357   EXPECT_TRUE(ContainersEqual(packet_buffer_0, sent_packet->view().data()));
358 
359   sent_packet = sco_conn()->GetNextOutboundPacket();
360   ASSERT_TRUE(sent_packet);
361   EXPECT_TRUE(ContainersEqual(packet_buffer_1, sent_packet->view().data()));
362 
363   EXPECT_FALSE(sco_conn()->GetNextOutboundPacket());
364   EXPECT_CMD_PACKET_OUT(test_device(),
365                         testing::DisconnectPacket(kConnectionHandle));
366 }
367 
TEST_F(HciScoConnectionTestWithFakeScoChannel,SendPacketLargerThanMtuGetsDropped)368 TEST_F(HciScoConnectionTestWithFakeScoChannel,
369        SendPacketLargerThanMtuGetsDropped) {
370   EXPECT_TRUE(
371       sco_conn()->Activate(/*rx_callback=*/[]() {}, /*closed_callback=*/[] {}));
372   ASSERT_EQ(fake_sco_chan()->connections().size(), 1u);
373 
374   const auto packet_buffer =
375       StaticByteBuffer(LowerBits(kConnectionHandle),
376                        UpperBits(kConnectionHandle),  // handle
377                        0x02,                          // payload length
378                        0x00,
379                        0x01  // payload
380       );
381   const BufferView payload_view =
382       packet_buffer.view(sizeof(hci_spec::SynchronousDataHeader));
383   EXPECT_GT(payload_view.size(), sco_conn()->max_tx_sdu_size());
384   sco_conn()->Send(std::make_unique<DynamicByteBuffer>(payload_view));
385 
386   EXPECT_EQ(fake_sco_chan()->readable_count(), 0u);
387   EXPECT_FALSE(sco_conn()->GetNextOutboundPacket());
388   EXPECT_CMD_PACKET_OUT(test_device(),
389                         testing::DisconnectPacket(kConnectionHandle));
390 }
391 
TEST_F(HciScoConnectionTestWithFakeScoChannel,OnHciError)392 TEST_F(HciScoConnectionTestWithFakeScoChannel, OnHciError) {
393   int closed_cb_count = 0;
394   EXPECT_TRUE(sco_conn()->Activate(/*rx_callback=*/[]() {}, /*closed_callback=*/
395                                    [&] {
396                                      closed_cb_count++;
397                                      sco_conn()->Deactivate();
398                                    }));
399   ASSERT_EQ(fake_sco_chan()->connections().size(), 1u);
400 
401   sco_conn()->OnHciError();
402   EXPECT_EQ(closed_cb_count, 1);
403   EXPECT_CMD_PACKET_OUT(test_device(),
404                         testing::DisconnectPacket(kConnectionHandle));
405 }
406 
TEST_F(HciScoConnectionTest,ControllerPacketCountClearedOnPeerDisconnect)407 TEST_F(HciScoConnectionTest, ControllerPacketCountClearedOnPeerDisconnect) {
408   size_t close_count_0 = 0;
409   auto closed_cb_0 = [&] { close_count_0++; };
410 
411   EXPECT_TRUE(
412       sco_conn()->Activate(/*rx_callback=*/[]() {}, std::move(closed_cb_0)));
413   EXPECT_EQ(close_count_0, 0u);
414   ASSERT_TRUE(hci_conn().is_alive());
415 
416   // Fill up the controller buffer.
417   ASSERT_EQ(kMaxScoPacketCount, 1u);
418   const StaticByteBuffer packet_buffer_0(
419       LowerBits(kConnectionHandle),
420       UpperBits(kConnectionHandle),  // handle
421       0x01,                          // payload length
422       0x00                           // payload
423   );
424   const BufferView packet_0_payload =
425       packet_buffer_0.view(/*pos=*/sizeof(hci_spec::SynchronousDataHeader));
426   EXPECT_SCO_PACKET_OUT(test_device(), packet_buffer_0);
427   sco_conn()->Send(std::make_unique<DynamicByteBuffer>(packet_0_payload));
428   RunUntilIdle();
429   EXPECT_TRUE(test_device()->AllExpectedScoPacketsSent());
430 
431   // Queue a packet on a second connection.
432   auto hci_conn_1 =
433       std::make_unique<hci::ScoConnection>(kConnectionHandle2,
434                                            DeviceAddress(),
435                                            DeviceAddress(),
436                                            transport()->GetWeakPtr());
437   std::unique_ptr<ScoConnection> sco_conn_1 =
438       CreateScoConnection(std::move(hci_conn_1));
439   size_t close_count_1 = 0;
440   auto closed_cb_1 = [&] { close_count_1++; };
441   EXPECT_TRUE(
442       sco_conn_1->Activate(/*rx_callback=*/[] {}, std::move(closed_cb_1)));
443   const auto packet_buffer_1 =
444       StaticByteBuffer(LowerBits(kConnectionHandle2),
445                        UpperBits(kConnectionHandle2),  // handle
446                        0x01,                           // payload length
447                        0x01                            // payload
448       );
449   const BufferView packet_1_payload =
450       packet_buffer_1.view(/*pos=*/sizeof(hci_spec::SynchronousDataHeader));
451   sco_conn_1->Send(std::make_unique<DynamicByteBuffer>(packet_1_payload));
452   RunUntilIdle();
453 
454   // Disconnecting the first connection should clear the controller packet count
455   // and allow packet_buffer_1 to be sent.
456   test_device()->SendCommandChannelPacket(
457       bt::testing::DisconnectionCompletePacket(kConnectionHandle));
458   EXPECT_SCO_PACKET_OUT(test_device(), packet_buffer_1);
459   RunUntilIdle();
460   EXPECT_EQ(close_count_0, 1u);
461   EXPECT_FALSE(hci_conn().is_alive());
462   EXPECT_EQ(close_count_1, 0u);
463 
464   EXPECT_CMD_PACKET_OUT(test_device(),
465                         testing::DisconnectPacket(kConnectionHandle2));
466   sco_conn_1.reset();
467   RunUntilIdle();
468   EXPECT_EQ(close_count_1, 0u);
469 }
470 
471 }  // namespace
472 }  // namespace bt::sco
473