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