• 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/gap/low_energy_interrogator.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/gap/peer_cache.h"
18 #include "pw_bluetooth_sapphire/internal/host/hci-spec/protocol.h"
19 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_l2cap.h"
20 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
21 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/mock_controller.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
24 #include "pw_bluetooth_sapphire/internal/host/testing/test_packets.h"
25 #include "pw_bluetooth_sapphire/internal/host/transport/error.h"
26 
27 namespace bt::gap {
28 
29 constexpr hci_spec::ConnectionHandle kConnectionHandle = 0x0BAA;
30 constexpr uint64_t kLEFeaturesHasSca =
31     0x0123456789a |
32     static_cast<uint64_t>(
33         hci_spec::LESupportedFeature::kSleepClockAccuracyUpdates);
34 constexpr uint64_t kLEFeaturesNoSca =
35     0x0123456789a &
36     ~static_cast<uint64_t>(
37         hci_spec::LESupportedFeature::kSleepClockAccuracyUpdates);
38 constexpr auto kDefaultScaRange =
39     pw::bluetooth::emboss::LESleepClockAccuracyRange::PPM_51_TO_75;
40 const DeviceAddress kTestDevAddr(DeviceAddress::Type::kLERandom, {1});
41 
42 const auto kReadRemoteVersionInfoRsp =
43     testing::CommandStatusPacket(hci_spec::kReadRemoteVersionInfo,
44                                  pw::bluetooth::emboss::StatusCode::SUCCESS);
45 const auto kLEReadRemoteFeaturesRsp =
46     testing::CommandStatusPacket(hci_spec::kLEReadRemoteFeatures,
47                                  pw::bluetooth::emboss::StatusCode::SUCCESS);
48 const auto kLERequestPeerScaRsp = testing::CommandStatusPacket(
49     hci_spec::kLERequestPeerSCA, pw::bluetooth::emboss::StatusCode::SUCCESS);
50 
51 using TestingBase =
52     bt::testing::FakeDispatcherControllerTest<bt::testing::MockController>;
53 
54 class LowEnergyInterrogatorTest : public TestingBase {
55  public:
56   LowEnergyInterrogatorTest() = default;
57   ~LowEnergyInterrogatorTest() override = default;
58 
SetUp()59   void SetUp() override {
60     TestingBase::SetUp();
61 
62     peer_cache_ = std::make_unique<PeerCache>(dispatcher());
63 
64     peer_ = peer_cache()->NewPeer(kTestDevAddr, /*connectable=*/true);
65     ASSERT_TRUE(peer_->le());
66     EXPECT_FALSE(peer_->version());
67     EXPECT_FALSE(peer_->le()->feature_interrogation_complete());
68     EXPECT_FALSE(peer_->le()->features());
69     EXPECT_FALSE(peer_->le()->sleep_clock_accuracy());
70 
71     CreateInterrogator(/*supports_sca=*/true);
72   }
73 
TearDown()74   void TearDown() override {
75     RunUntilIdle();
76     test_device()->Stop();
77     interrogator_ = nullptr;
78     peer_cache_ = nullptr;
79     TestingBase::TearDown();
80   }
81 
82  protected:
QueueSuccessfulInterrogation(hci_spec::ConnectionHandle conn,hci_spec::LESupportedFeatures features=0) const83   void QueueSuccessfulInterrogation(
84       hci_spec::ConnectionHandle conn,
85       hci_spec::LESupportedFeatures features = 0) const {
86     const auto remote_version_complete_packet =
87         testing::ReadRemoteVersionInfoCompletePacket(conn);
88 
89     EXPECT_CMD_PACKET_OUT(test_device(),
90                           testing::ReadRemoteVersionInfoPacket(conn),
91                           &kReadRemoteVersionInfoRsp,
92                           &remote_version_complete_packet);
93 
94     const auto le_remote_features_complete_packet =
95         testing::LEReadRemoteFeaturesCompletePacket(conn, features);
96     EXPECT_CMD_PACKET_OUT(test_device(),
97                           testing::LEReadRemoteFeaturesPacket(conn),
98                           &kLEReadRemoteFeaturesRsp,
99                           &le_remote_features_complete_packet);
100 
101     // Expect a SCA request, if supported by the peer and the controller
102     if ((features &
103          static_cast<uint64_t>(
104              hci_spec::LESupportedFeature::kSleepClockAccuracyUpdates)) &&
105         controller_supports_sca_) {
106       const auto le_request_peer_sca_complete_packet =
107           testing::LERequestPeerScaCompletePacket(conn, kDefaultScaRange);
108       EXPECT_CMD_PACKET_OUT(test_device(),
109                             testing::LERequestPeerScaPacket(conn),
110                             &kLERequestPeerScaRsp,
111                             &le_request_peer_sca_complete_packet);
112     }
113   }
114 
CreateInterrogator(bool supports_sca)115   void CreateInterrogator(bool supports_sca) {
116     controller_supports_sca_ = supports_sca;
117     interrogator_ =
118         std::make_unique<LowEnergyInterrogator>(peer_->GetWeakPtr(),
119                                                 kConnectionHandle,
120                                                 cmd_channel()->AsWeakPtr(),
121                                                 supports_sca);
122   }
123 
DestroyInterrogator()124   void DestroyInterrogator() { interrogator_.reset(); }
125 
peer() const126   Peer* peer() const { return peer_; }
127 
peer_cache() const128   PeerCache* peer_cache() const { return peer_cache_.get(); }
129 
interrogator() const130   LowEnergyInterrogator* interrogator() const { return interrogator_.get(); }
131 
132  private:
133   Peer* peer_ = nullptr;
134   std::unique_ptr<PeerCache> peer_cache_;
135   std::unique_ptr<LowEnergyInterrogator> interrogator_;
136   bool controller_supports_sca_;
137 
138   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyInterrogatorTest);
139 };
140 
141 using GAP_LowEnergyInterrogatorTest = LowEnergyInterrogatorTest;
142 
TEST_F(LowEnergyInterrogatorTest,SuccessfulInterrogation)143 TEST_F(LowEnergyInterrogatorTest, SuccessfulInterrogation) {
144   // As of Core Spec v5.4, the Feature Set mask has 44 bits (5.5 bytes) in use.
145   const hci_spec::LESupportedFeatures kFeatures{kLEFeaturesHasSca};
146   QueueSuccessfulInterrogation(kConnectionHandle, kFeatures);
147 
148   std::optional<hci::Result<>> status;
149   interrogator()->Start(
150       [&status](hci::Result<> cb_status) { status = cb_status; });
151   RunUntilIdle();
152 
153   ASSERT_TRUE(status.has_value());
154   EXPECT_EQ(fit::ok(), *status);
155 
156   EXPECT_TRUE(peer()->version());
157   ASSERT_TRUE(peer()->le()->feature_interrogation_complete());
158   ASSERT_TRUE(peer()->le()->features());
159   EXPECT_EQ(kFeatures, peer()->le()->features());
160   ASSERT_TRUE(peer()->le()->sleep_clock_accuracy());
161   EXPECT_EQ(*(peer()->le()->sleep_clock_accuracy()), kDefaultScaRange);
162 }
163 
TEST_F(LowEnergyInterrogatorTest,SuccessfulInterrogationPeerAlreadyHasLEFeatures)164 TEST_F(LowEnergyInterrogatorTest,
165        SuccessfulInterrogationPeerAlreadyHasLEFeatures) {
166   // As of Core Spec v5.4, the Feature Set mask has 44 bits (5.5 bytes) in use.
167   const hci_spec::LESupportedFeatures kFeatures{kLEFeaturesHasSca};
168 
169   const auto remote_version_complete_packet =
170       testing::ReadRemoteVersionInfoCompletePacket(kConnectionHandle);
171   EXPECT_CMD_PACKET_OUT(test_device(),
172                         testing::ReadRemoteVersionInfoPacket(kConnectionHandle),
173                         &kReadRemoteVersionInfoRsp,
174                         &remote_version_complete_packet);
175 
176   // We should still query peer's SCA
177   constexpr auto kScaRange =
178       pw::bluetooth::emboss::LESleepClockAccuracyRange::PPM_0_TO_20;
179   const auto le_request_peer_sca_complete_packet =
180       testing::LERequestPeerScaCompletePacket(kConnectionHandle, kScaRange);
181   EXPECT_CMD_PACKET_OUT(test_device(),
182                         testing::LERequestPeerScaPacket(kConnectionHandle),
183                         &kLERequestPeerScaRsp,
184                         &le_request_peer_sca_complete_packet);
185 
186   peer()->MutLe().SetFeatures(kFeatures);
187   peer()->MutLe().SetFeatureInterrogationComplete();
188 
189   std::optional<hci::Result<>> status;
190   interrogator()->Start(
191       [&status](hci::Result<> cb_status) { status = cb_status; });
192   RunUntilIdle();
193   ASSERT_TRUE(status.has_value());
194   EXPECT_EQ(fit::ok(), *status);
195   ASSERT_TRUE(peer()->le()->feature_interrogation_complete());
196   ASSERT_TRUE(peer()->le()->features());
197   EXPECT_EQ(kFeatures, peer()->le()->features());
198   ASSERT_TRUE(peer()->le()->sleep_clock_accuracy());
199   EXPECT_EQ(*(peer()->le()->sleep_clock_accuracy()), kScaRange);
200 }
201 
TEST_F(LowEnergyInterrogatorTest,SuccessfulReinterrogation)202 TEST_F(LowEnergyInterrogatorTest, SuccessfulReinterrogation) {
203   const hci_spec::LESupportedFeatures kFeatures{kLEFeaturesHasSca};
204   QueueSuccessfulInterrogation(kConnectionHandle, kFeatures);
205 
206   std::optional<hci::Result<>> status;
207   interrogator()->Start(
208       [&status](hci::Result<> cb_status) { status = cb_status; });
209   RunUntilIdle();
210 
211   ASSERT_TRUE(status.has_value());
212   EXPECT_EQ(fit::ok(), *status);
213   status = std::nullopt;
214 
215   // Remote version should always be read, even if already known.
216   const auto remote_version_complete_packet =
217       testing::ReadRemoteVersionInfoCompletePacket(kConnectionHandle);
218   EXPECT_CMD_PACKET_OUT(test_device(),
219                         testing::ReadRemoteVersionInfoPacket(kConnectionHandle),
220                         &kReadRemoteVersionInfoRsp,
221                         &remote_version_complete_packet);
222 
223   // SCA should be read at each connection event.
224   constexpr auto kScaRange =
225       pw::bluetooth::emboss::LESleepClockAccuracyRange::PPM_251_TO_500;
226   const auto le_request_peer_sca_complete_packet =
227       testing::LERequestPeerScaCompletePacket(kConnectionHandle, kScaRange);
228   EXPECT_CMD_PACKET_OUT(test_device(),
229                         testing::LERequestPeerScaPacket(kConnectionHandle),
230                         &kLERequestPeerScaRsp,
231                         &le_request_peer_sca_complete_packet);
232 
233   interrogator()->Start(
234       [&status](hci::Result<> cb_status) { status = cb_status; });
235 
236   RunUntilIdle();
237   ASSERT_TRUE(status.has_value());
238   EXPECT_EQ(fit::ok(), *status);
239   ASSERT_TRUE(peer()->le()->sleep_clock_accuracy());
240   EXPECT_EQ(*(peer()->le()->sleep_clock_accuracy()), kScaRange);
241 }
242 
TEST_F(LowEnergyInterrogatorTest,LEReadRemoteFeaturesErrorStatus)243 TEST_F(LowEnergyInterrogatorTest, LEReadRemoteFeaturesErrorStatus) {
244   const auto remote_version_complete_packet =
245       testing::ReadRemoteVersionInfoCompletePacket(kConnectionHandle);
246   const auto le_read_remote_features_error_status_packet =
247       testing::CommandStatusPacket(
248           hci_spec::kLEReadRemoteFeatures,
249           pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
250   EXPECT_CMD_PACKET_OUT(test_device(),
251                         testing::ReadRemoteVersionInfoPacket(kConnectionHandle),
252                         &kReadRemoteVersionInfoRsp,
253                         &remote_version_complete_packet);
254   EXPECT_CMD_PACKET_OUT(test_device(),
255                         testing::LEReadRemoteFeaturesPacket(kConnectionHandle),
256                         &le_read_remote_features_error_status_packet);
257 
258   std::optional<hci::Result<>> status;
259   interrogator()->Start(
260       [&status](hci::Result<> cb_status) { status = cb_status; });
261   RunUntilIdle();
262   ASSERT_TRUE(status.has_value());
263   EXPECT_FALSE(status->is_ok());
264   EXPECT_TRUE(peer()->le()->feature_interrogation_complete());
265   EXPECT_FALSE(peer()->le()->features().has_value());
266 
267   // When previous operations fail, we shouldn't try to read SCA.
268   EXPECT_FALSE(peer()->le()->sleep_clock_accuracy());
269 }
270 
271 // Test proper operation when a peer doesn't support reading LE remote features
TEST_F(LowEnergyInterrogatorTest,LEReadRemoteFeaturesUnsupported)272 TEST_F(LowEnergyInterrogatorTest, LEReadRemoteFeaturesUnsupported) {
273   const auto remote_version_complete_packet =
274       testing::ReadRemoteVersionInfoCompletePacket(kConnectionHandle);
275   const auto le_read_remote_features_unsupported_status_packet =
276       testing::CommandStatusPacket(
277           hci_spec::kLEReadRemoteFeatures,
278           pw::bluetooth::emboss::StatusCode::UNSUPPORTED_REMOTE_FEATURE);
279   EXPECT_CMD_PACKET_OUT(test_device(),
280                         testing::ReadRemoteVersionInfoPacket(kConnectionHandle),
281                         &kReadRemoteVersionInfoRsp,
282                         &remote_version_complete_packet);
283   EXPECT_CMD_PACKET_OUT(test_device(),
284                         testing::LEReadRemoteFeaturesPacket(kConnectionHandle),
285                         &le_read_remote_features_unsupported_status_packet);
286 
287   std::optional<hci::Result<>> status;
288   interrogator()->Start(
289       [&status](hci::Result<> cb_status) { status = cb_status; });
290   RunUntilIdle();
291   ASSERT_TRUE(status.has_value());
292   EXPECT_TRUE(status->is_ok());
293   EXPECT_TRUE(peer()->le()->feature_interrogation_complete());
294   EXPECT_FALSE(peer()->le()->features().has_value());
295 
296   // When previous operations fail, we shouldn't try to read SCA.
297   EXPECT_FALSE(peer()->le()->sleep_clock_accuracy());
298 }
299 
TEST_F(LowEnergyInterrogatorTest,ReadRemoteVersionErrorStatus)300 TEST_F(LowEnergyInterrogatorTest, ReadRemoteVersionErrorStatus) {
301   const auto remote_version_error_status_packet = testing::CommandStatusPacket(
302       hci_spec::kReadRemoteVersionInfo,
303       pw::bluetooth::emboss::StatusCode::UNKNOWN_COMMAND);
304   const auto le_remote_features_complete_packet =
305       testing::LEReadRemoteFeaturesCompletePacket(kConnectionHandle,
306                                                   /*features=*/0);
307   EXPECT_CMD_PACKET_OUT(test_device(),
308                         testing::ReadRemoteVersionInfoPacket(kConnectionHandle),
309                         &remote_version_error_status_packet);
310   EXPECT_CMD_PACKET_OUT(test_device(),
311                         testing::LEReadRemoteFeaturesPacket(kConnectionHandle),
312                         &kLEReadRemoteFeaturesRsp,
313                         &le_remote_features_complete_packet);
314 
315   std::optional<hci::Result<>> status;
316   interrogator()->Start(
317       [&status](hci::Result<> cb_status) { status = cb_status; });
318   RunUntilIdle();
319   ASSERT_TRUE(status.has_value());
320   EXPECT_FALSE(status->is_ok());
321   EXPECT_FALSE(peer()->version());
322 
323   // When previous operations fail, we shouldn't try to read SCA.
324   EXPECT_FALSE(peer()->le()->sleep_clock_accuracy());
325 }
326 
TEST_F(LowEnergyInterrogatorTest,ReadLERemoteFeaturesCallbackHandlesCanceledInterrogation)327 TEST_F(LowEnergyInterrogatorTest,
328        ReadLERemoteFeaturesCallbackHandlesCanceledInterrogation) {
329   const auto remote_version_complete_packet =
330       testing::ReadRemoteVersionInfoCompletePacket(kConnectionHandle);
331   const auto le_remote_features_complete_packet =
332       testing::LEReadRemoteFeaturesCompletePacket(
333           kConnectionHandle, hci_spec::LESupportedFeatures{0});
334 
335   EXPECT_CMD_PACKET_OUT(test_device(),
336                         testing::ReadRemoteVersionInfoPacket(kConnectionHandle),
337                         &kReadRemoteVersionInfoRsp,
338                         &remote_version_complete_packet);
339   EXPECT_CMD_PACKET_OUT(test_device(),
340                         testing::LEReadRemoteFeaturesPacket(kConnectionHandle),
341                         &kLEReadRemoteFeaturesRsp);
342 
343   std::optional<hci::Result<>> result;
344   interrogator()->Start(
345       [&result](hci::Result<> cb_result) { result = cb_result; });
346   RunUntilIdle();
347   EXPECT_FALSE(result.has_value());
348 
349   interrogator()->Cancel();
350   RunUntilIdle();
351   ASSERT_TRUE(result.has_value());
352   EXPECT_TRUE(result->is_error());
353   EXPECT_EQ(result.value(), ToResult(HostError::kCanceled));
354   result.reset();
355 
356   test_device()->SendCommandChannelPacket(le_remote_features_complete_packet);
357   RunUntilIdle();
358   EXPECT_FALSE(result.has_value());
359   // The read remote features handler should not update the features of a
360   // canceled interrogation.
361   ASSERT_FALSE(peer()->le()->feature_interrogation_complete());
362   EXPECT_FALSE(peer()->le()->features().has_value());
363   EXPECT_FALSE(peer()->le()->sleep_clock_accuracy());
364 }
365 
TEST_F(LowEnergyInterrogatorTest,ReadRemoteVersionCallbackHandlesCanceledInterrogation)366 TEST_F(LowEnergyInterrogatorTest,
367        ReadRemoteVersionCallbackHandlesCanceledInterrogation) {
368   const auto remote_version_complete_packet =
369       testing::ReadRemoteVersionInfoCompletePacket(kConnectionHandle);
370   const auto le_remote_features_complete_packet =
371       testing::LEReadRemoteFeaturesCompletePacket(
372           kConnectionHandle, hci_spec::LESupportedFeatures{0});
373 
374   EXPECT_CMD_PACKET_OUT(test_device(),
375                         testing::ReadRemoteVersionInfoPacket(kConnectionHandle),
376                         &kReadRemoteVersionInfoRsp);
377   EXPECT_CMD_PACKET_OUT(test_device(),
378                         testing::LEReadRemoteFeaturesPacket(kConnectionHandle),
379                         &kLEReadRemoteFeaturesRsp,
380                         &le_remote_features_complete_packet);
381 
382   std::optional<hci::Result<>> result;
383   interrogator()->Start(
384       [&result](hci::Result<> cb_result) { result = cb_result; });
385   RunUntilIdle();
386   EXPECT_FALSE(result.has_value());
387 
388   interrogator()->Cancel();
389   RunUntilIdle();
390   ASSERT_TRUE(result.has_value());
391   EXPECT_TRUE(result->is_error());
392   EXPECT_EQ(result.value(), ToResult(HostError::kCanceled));
393   result.reset();
394 
395   test_device()->SendCommandChannelPacket(remote_version_complete_packet);
396   RunUntilIdle();
397   EXPECT_FALSE(result.has_value());
398   // The read remote version handler should not update the version after a
399   // canceled interrogation.
400   EXPECT_FALSE(peer()->version());
401   EXPECT_FALSE(peer()->le()->sleep_clock_accuracy());
402 }
403 
TEST_F(LowEnergyInterrogatorTest,ScaUpdateNotSupportedOnController)404 TEST_F(LowEnergyInterrogatorTest, ScaUpdateNotSupportedOnController) {
405   CreateInterrogator(/*supports_sca=*/false);
406 
407   const hci_spec::LESupportedFeatures kFeatures{kLEFeaturesHasSca};
408   QueueSuccessfulInterrogation(kConnectionHandle, kFeatures);
409 
410   std::optional<hci::Result<>> status;
411   interrogator()->Start(
412       [&status](hci::Result<> cb_status) { status = cb_status; });
413   RunUntilIdle();
414 
415   ASSERT_TRUE(status.has_value());
416   EXPECT_EQ(fit::ok(), *status);
417 
418   EXPECT_TRUE(peer()->version());
419   ASSERT_TRUE(peer()->le()->feature_interrogation_complete());
420   ASSERT_TRUE(peer()->le()->features());
421   EXPECT_EQ(kFeatures, peer()->le()->features());
422   ASSERT_FALSE(peer()->le()->sleep_clock_accuracy());
423 }
424 
TEST_F(LowEnergyInterrogatorTest,ScaUpdateNotSupportedOnPeer)425 TEST_F(LowEnergyInterrogatorTest, ScaUpdateNotSupportedOnPeer) {
426   // Disable peer support for SCA updates.
427   const hci_spec::LESupportedFeatures kFeatures{kLEFeaturesNoSca};
428   QueueSuccessfulInterrogation(kConnectionHandle, kFeatures);
429 
430   std::optional<hci::Result<>> status;
431   interrogator()->Start(
432       [&status](hci::Result<> cb_status) { status = cb_status; });
433   RunUntilIdle();
434 
435   ASSERT_TRUE(status.has_value());
436   EXPECT_EQ(fit::ok(), *status);
437 
438   EXPECT_TRUE(peer()->version());
439   ASSERT_TRUE(peer()->le()->feature_interrogation_complete());
440   ASSERT_TRUE(peer()->le()->features());
441   EXPECT_EQ(kFeatures, peer()->le()->features());
442   ASSERT_FALSE(peer()->le()->sleep_clock_accuracy());
443 }
444 
TEST_F(LowEnergyInterrogatorTest,DestroyInterrogatorInCompleteCallback)445 TEST_F(LowEnergyInterrogatorTest, DestroyInterrogatorInCompleteCallback) {
446   // As of Core Spec v5.4, the Feature Set mask has 44 bits (5.5 bytes) in use.
447   const hci_spec::LESupportedFeatures kFeatures{kLEFeaturesHasSca};
448   QueueSuccessfulInterrogation(kConnectionHandle, kFeatures);
449 
450   std::optional<hci::Result<>> status;
451   interrogator()->Start([this, &status](hci::Result<> cb_status) {
452     status = cb_status;
453     DestroyInterrogator();
454   });
455   RunUntilIdle();
456   ASSERT_TRUE(status.has_value());
457   EXPECT_TRUE(status->is_ok());
458   ASSERT_TRUE(peer()->le()->feature_interrogation_complete());
459   ASSERT_TRUE(peer()->le()->features());
460   EXPECT_EQ(kFeatures, peer()->le()->features());
461   ASSERT_TRUE(peer()->le()->sleep_clock_accuracy());
462   EXPECT_EQ(*(peer()->le()->sleep_clock_accuracy()), kDefaultScaRange);
463 }
464 
465 }  // namespace bt::gap
466