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/hci/low_energy_advertiser.h"
16
17 #include "pw_bluetooth_sapphire/internal/host/hci/android_extended_low_energy_advertiser.h"
18 #include "pw_bluetooth_sapphire/internal/host/hci/extended_low_energy_advertiser.h"
19 #include "pw_bluetooth_sapphire/internal/host/hci/legacy_low_energy_advertiser.h"
20 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
21 #include "pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/fake_peer.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
24
25 // LowEnergyAdvertiser has many potential subclasses (e.g.
26 // LegacyLowEnergyAdvertiser, ExtendedLowEnergyAdvertiser,
27 // AndroidExtendedLowEnergyAdvertiser, etc). The unique features of these
28 // subclass are tested individually in their own unittest files. However, there
29 // are some common features that all LowEnergyAdvertisers should follow. This
30 // class implements a type parameterized test to exercise those common features.
31 //
32 // If you add a new subclass of LowEnergyAdvertiser in the future, make sure to
33 // add its type to the list of types below (in the TYPED_TEST_SUITE) so that its
34 // common features are exercised as well.
35
36 namespace bt::hci {
37 namespace {
38
39 using bt::testing::FakeController;
40 using bt::testing::FakePeer;
41
42 using AdvertisingOptions = LowEnergyAdvertiser::AdvertisingOptions;
43 using TestingBase = bt::testing::FakeDispatcherControllerTest<FakeController>;
44
45 constexpr hci_spec::ConnectionHandle kConnectionHandle = 0x0001;
46 constexpr AdvertisingIntervalRange kTestInterval(
47 hci_spec::kLEAdvertisingIntervalMin, hci_spec::kLEAdvertisingIntervalMax);
48
49 const DeviceAddress kPublicAddress(DeviceAddress::Type::kLEPublic, {1});
50 const DeviceAddress kRandomAddress(DeviceAddress::Type::kLERandom, {2});
51
52 // Various parts of the Bluetooth Core Spec require that advertising interval
53 // min and max are not the same value. We shouldn't allow it either. For
54 // example, Core Spec Volume 4, Part E, Section 7.8.5: "The
55 // Advertising_Interval_Min and Advertising_Interval_Max should not be the same
56 // value to enable the Controller to determine the best advertising interval
57 // given other activities."
TEST(AdvertisingIntervalRangeDeathTest,MaxMinNotSame)58 TEST(AdvertisingIntervalRangeDeathTest, MaxMinNotSame) {
59 EXPECT_DEATH(AdvertisingIntervalRange(hci_spec::kLEAdvertisingIntervalMin,
60 hci_spec::kLEAdvertisingIntervalMin),
61 ".*");
62 }
63
TEST(AdvertisingIntervalRangeDeathTest,MinLessThanMax)64 TEST(AdvertisingIntervalRangeDeathTest, MinLessThanMax) {
65 EXPECT_DEATH(AdvertisingIntervalRange(hci_spec::kLEAdvertisingIntervalMax,
66 hci_spec::kLEAdvertisingIntervalMin),
67 ".*");
68 }
69
70 template <typename T>
71 class LowEnergyAdvertiserTest : public TestingBase {
72 public:
73 LowEnergyAdvertiserTest() = default;
74 ~LowEnergyAdvertiserTest() override = default;
75
76 protected:
SetUp()77 void SetUp() override {
78 TestingBase::SetUp();
79
80 // ACL data channel needs to be present for production hci::Connection
81 // objects.
82 TestingBase::InitializeACLDataChannel(
83 hci::DataBufferInfo(),
84 hci::DataBufferInfo(hci_spec::kMaxACLPayloadSize, 10));
85
86 FakeController::Settings settings;
87 settings.ApplyLegacyLEConfig();
88 settings.bd_addr = kPublicAddress;
89 test_device()->set_settings(settings);
90
91 advertiser_ = std::unique_ptr<T>(CreateAdvertiserInternal());
92
93 test_device()->set_num_supported_advertising_sets(0xEF);
94 }
95
TearDown()96 void TearDown() override {
97 advertiser_ = nullptr;
98 TestingBase::TearDown();
99 }
100
101 template <bool same = std::is_same_v<T, AndroidExtendedLowEnergyAdvertiser>>
102 std::enable_if_t<same, AndroidExtendedLowEnergyAdvertiser>*
CreateAdvertiserInternal()103 CreateAdvertiserInternal() {
104 return new AndroidExtendedLowEnergyAdvertiser(transport()->GetWeakPtr(), 1);
105 }
106
107 template <bool same = std::is_same_v<T, ExtendedLowEnergyAdvertiser>>
108 std::enable_if_t<same, ExtendedLowEnergyAdvertiser>*
CreateAdvertiserInternal()109 CreateAdvertiserInternal() {
110 return new ExtendedLowEnergyAdvertiser(transport()->GetWeakPtr());
111 }
112
113 template <bool same = std::is_same_v<T, LegacyLowEnergyAdvertiser>>
114 std::enable_if_t<same, LegacyLowEnergyAdvertiser>*
CreateAdvertiserInternal()115 CreateAdvertiserInternal() {
116 return new LegacyLowEnergyAdvertiser(transport()->GetWeakPtr());
117 }
118
advertiser() const119 LowEnergyAdvertiser* advertiser() const { return advertiser_.get(); }
120
DestroyAdvertiser()121 void DestroyAdvertiser() { advertiser_.reset(); }
122
MakeExpectSuccessCallback()123 ResultFunction<> MakeExpectSuccessCallback() {
124 return [this](Result<> status) {
125 last_status_ = status;
126 EXPECT_EQ(fit::ok(), status);
127 };
128 }
129
MakeExpectErrorCallback()130 ResultFunction<> MakeExpectErrorCallback() {
131 return [this](Result<> status) {
132 last_status_ = status;
133 EXPECT_TRUE(status.is_error());
134 };
135 }
136
GetLastStatus()137 std::optional<Result<>> GetLastStatus() {
138 if (!last_status_) {
139 return std::nullopt;
140 }
141
142 Result<> status = last_status_.value();
143 last_status_.reset();
144 return status;
145 }
146
147 // Makes some fake advertising data.
148 // |include_flags| signals whether to include flag encoding size in the data
149 // calculation.
GetExampleData(bool include_flags=true)150 AdvertisingData GetExampleData(bool include_flags = true) {
151 AdvertisingData result;
152
153 auto name = "fuchsia";
154 EXPECT_TRUE(result.SetLocalName(name));
155
156 auto appearance = 0x1234;
157 result.SetAppearance(appearance);
158
159 EXPECT_LE(result.CalculateBlockSize(include_flags),
160 hci_spec::kMaxLEAdvertisingDataLength);
161 return result;
162 }
163
164 // Makes fake advertising data that is too large.
165 // |include_flags| signals whether to include flag encoding size in the data
166 // calculation.
GetTooLargeExampleData(bool include_flags,std::size_t size=hci_spec::kMaxLEAdvertisingDataLength+1)167 AdvertisingData GetTooLargeExampleData(
168 bool include_flags,
169 std::size_t size = hci_spec::kMaxLEAdvertisingDataLength + 1) {
170 AdvertisingData result;
171
172 if (include_flags) {
173 size -= kTLVFlagsSize;
174 }
175
176 std::ostringstream oss;
177 for (unsigned int i = 0; i <= size; i++) {
178 oss << 'a';
179 }
180
181 EXPECT_TRUE(result.SetLocalName(oss.str()));
182
183 // The maximum advertisement packet is:
184 // |hci_spec::kMaxLEAdvertisingDataLength| = 31, and |result| = 32 bytes.
185 // |result| should be too large to advertise.
186 EXPECT_GT(result.CalculateBlockSize(include_flags),
187 hci_spec::kMaxLEAdvertisingDataLength);
188 return result;
189 }
190
CurrentAdvertisingHandle() const191 std::optional<hci_spec::AdvertisingHandle> CurrentAdvertisingHandle() const {
192 if (std::is_same_v<T, ExtendedLowEnergyAdvertiser>) {
193 auto extended = static_cast<ExtendedLowEnergyAdvertiser*>(advertiser());
194 return extended->LastUsedHandleForTesting();
195 }
196
197 if (std::is_same_v<T, AndroidExtendedLowEnergyAdvertiser>) {
198 auto extended =
199 static_cast<AndroidExtendedLowEnergyAdvertiser*>(advertiser());
200 return extended->LastUsedHandleForTesting();
201 }
202
203 return 0; // non-extended advertising doesn't use handles, we can return
204 // any value
205 }
206
GetControllerAdvertisingState() const207 const FakeController::LEAdvertisingState& GetControllerAdvertisingState()
208 const {
209 if (std::is_same_v<T, LegacyLowEnergyAdvertiser>) {
210 return test_device()->legacy_advertising_state();
211 }
212
213 if (std::is_same_v<T, ExtendedLowEnergyAdvertiser> ||
214 std::is_same_v<T, AndroidExtendedLowEnergyAdvertiser>) {
215 std::optional<hci_spec::AdvertisingHandle> handle =
216 CurrentAdvertisingHandle();
217 if (!handle) {
218 static FakeController::LEAdvertisingState empty;
219 return empty;
220 }
221
222 return test_device()->extended_advertising_state(handle.value());
223 }
224
225 EXPECT_TRUE(false) << "advertiser is of unknown type";
226
227 // return something in order to compile, tests will fail if they get here
228 static FakeController::LEAdvertisingState state;
229 return state;
230 }
231
MaybeSendMultipleAdvertisingPostConnectionEvents(hci_spec::ConnectionHandle conn_handle,hci_spec::AdvertisingHandle adv_handle)232 void MaybeSendMultipleAdvertisingPostConnectionEvents(
233 hci_spec::ConnectionHandle conn_handle,
234 hci_spec::AdvertisingHandle adv_handle) {
235 if (std::is_same_v<T, AndroidExtendedLowEnergyAdvertiser>) {
236 test_device()->SendAndroidLEMultipleAdvertisingStateChangeSubevent(
237 conn_handle, adv_handle);
238 return;
239 }
240
241 if (std::is_same_v<T, ExtendedLowEnergyAdvertiser>) {
242 test_device()->SendLEAdvertisingSetTerminatedEvent(conn_handle,
243 adv_handle);
244 return;
245 }
246 }
247
248 private:
249 std::unique_ptr<LowEnergyAdvertiser> advertiser_;
250 std::optional<Result<>> last_status_;
251
252 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyAdvertiserTest);
253 };
254
255 using Implementations = ::testing::Types<LegacyLowEnergyAdvertiser,
256 ExtendedLowEnergyAdvertiser,
257 AndroidExtendedLowEnergyAdvertiser>;
258 TYPED_TEST_SUITE(LowEnergyAdvertiserTest, Implementations);
259
260 // - Stops the advertisement when an incoming connection comes in
261 // - Possible to restart advertising
262 // - Advertising state cleaned up between calls
TYPED_TEST(LowEnergyAdvertiserTest,ConnectionTest)263 TYPED_TEST(LowEnergyAdvertiserTest, ConnectionTest) {
264 AdvertisingData adv_data = this->GetExampleData();
265 AdvertisingData scan_data = this->GetExampleData();
266 AdvertisingOptions options(kTestInterval,
267 /*anonymous=*/false,
268 kDefaultNoAdvFlags,
269 /*include_tx_power_level=*/false);
270
271 std::unique_ptr<LowEnergyConnection> link;
272 auto conn_cb = [&link](auto cb_link) { link = std::move(cb_link); };
273
274 // Start advertising kPublicAddress
275 this->advertiser()->StartAdvertising(kPublicAddress,
276 adv_data,
277 scan_data,
278 options,
279 conn_cb,
280 this->MakeExpectSuccessCallback());
281 this->RunUntilIdle();
282 EXPECT_TRUE(this->GetLastStatus());
283 EXPECT_TRUE(this->advertiser()->IsAdvertising());
284 EXPECT_TRUE(this->advertiser()->IsAdvertising(kPublicAddress));
285
286 // Accept a connection and ensure that connection state is set up correctly
287 link.reset();
288 this->advertiser()->OnIncomingConnection(
289 kConnectionHandle,
290 pw::bluetooth::emboss::ConnectionRole::PERIPHERAL,
291 kRandomAddress,
292 hci_spec::LEConnectionParameters());
293 std::optional<hci_spec::AdvertisingHandle> handle =
294 this->CurrentAdvertisingHandle();
295 ASSERT_TRUE(handle);
296 this->MaybeSendMultipleAdvertisingPostConnectionEvents(kConnectionHandle,
297 handle.value());
298 this->RunUntilIdle();
299
300 ASSERT_TRUE(link);
301 EXPECT_EQ(kConnectionHandle, link->handle());
302 EXPECT_EQ(kPublicAddress, link->local_address());
303 EXPECT_EQ(kRandomAddress, link->peer_address());
304 EXPECT_FALSE(this->advertiser()->IsAdvertising());
305 EXPECT_FALSE(this->advertiser()->IsAdvertising(kPublicAddress));
306
307 // Advertising state should get cleared on a disconnection
308 link->Disconnect(
309 pw::bluetooth::emboss::StatusCode::REMOTE_USER_TERMINATED_CONNECTION);
310 this->test_device()->SendDisconnectionCompleteEvent(link->handle());
311 this->RunUntilIdle();
312 EXPECT_FALSE(this->GetControllerAdvertisingState().enabled);
313
314 // Restart advertising using a different local address
315 this->advertiser()->StartAdvertising(kRandomAddress,
316 adv_data,
317 scan_data,
318 options,
319 conn_cb,
320 this->MakeExpectSuccessCallback());
321 this->RunUntilIdle();
322 EXPECT_TRUE(this->GetLastStatus());
323 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
324
325 // Accept a connection from kPublicAddress. The internal advertising state
326 // should get assigned correctly with no remnants of the previous advertise.
327 link.reset();
328 this->advertiser()->OnIncomingConnection(
329 kConnectionHandle,
330 pw::bluetooth::emboss::ConnectionRole::PERIPHERAL,
331 kPublicAddress,
332 hci_spec::LEConnectionParameters());
333 handle = this->CurrentAdvertisingHandle();
334 ASSERT_TRUE(handle);
335 this->MaybeSendMultipleAdvertisingPostConnectionEvents(kConnectionHandle,
336 handle.value());
337 this->RunUntilIdle();
338
339 ASSERT_TRUE(link);
340 EXPECT_EQ(kRandomAddress, link->local_address());
341 EXPECT_EQ(kPublicAddress, link->peer_address());
342 }
343
344 // Tests that advertising can be restarted right away in a connection callback.
TYPED_TEST(LowEnergyAdvertiserTest,RestartInConnectionCallback)345 TYPED_TEST(LowEnergyAdvertiserTest, RestartInConnectionCallback) {
346 AdvertisingData ad = this->GetExampleData();
347 AdvertisingData scan_data = this->GetExampleData();
348 AdvertisingOptions options(kTestInterval,
349 /*anonymous=*/false,
350 kDefaultNoAdvFlags,
351 /*include_tx_power_level=*/false);
352
353 std::unique_ptr<LowEnergyConnection> link;
354 auto conn_cb = [&, this](auto cb_link) {
355 link = std::move(cb_link);
356
357 this->advertiser()->StartAdvertising(
358 kPublicAddress,
359 ad,
360 scan_data,
361 options,
362 [](auto) { /*noop*/ },
363 this->MakeExpectSuccessCallback());
364 };
365
366 this->advertiser()->StartAdvertising(kPublicAddress,
367 ad,
368 scan_data,
369 options,
370 conn_cb,
371 this->MakeExpectSuccessCallback());
372 this->RunUntilIdle();
373 EXPECT_TRUE(this->GetLastStatus());
374 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
375
376 bool enabled = true;
377 std::vector<bool> adv_states;
378 this->test_device()->set_advertising_state_callback(
379 [this, &adv_states, &enabled] {
380 bool new_enabled = this->GetControllerAdvertisingState().enabled;
381 if (enabled != new_enabled) {
382 adv_states.push_back(new_enabled);
383 enabled = new_enabled;
384 }
385 });
386
387 this->advertiser()->OnIncomingConnection(
388 kConnectionHandle,
389 pw::bluetooth::emboss::ConnectionRole::PERIPHERAL,
390 kRandomAddress,
391 hci_spec::LEConnectionParameters());
392 std::optional<hci_spec::AdvertisingHandle> handle =
393 this->CurrentAdvertisingHandle();
394 ASSERT_TRUE(handle);
395 this->MaybeSendMultipleAdvertisingPostConnectionEvents(kConnectionHandle,
396 handle.value());
397
398 // Advertising should get disabled and re-enabled.
399 this->RunUntilIdle();
400 ASSERT_EQ(2u, adv_states.size());
401 EXPECT_FALSE(adv_states[0]);
402 EXPECT_TRUE(adv_states[1]);
403
404 this->test_device()->set_advertising_state_callback(nullptr);
405 }
406
407 // An incoming connection when not advertising should get disconnected.
TYPED_TEST(LowEnergyAdvertiserTest,IncomingConnectionWhenNotAdvertising)408 TYPED_TEST(LowEnergyAdvertiserTest, IncomingConnectionWhenNotAdvertising) {
409 std::vector<std::pair<bool, hci_spec::ConnectionHandle>> connection_states;
410 this->test_device()->set_connection_state_callback(
411 [&](const auto& address, auto handle, bool connected, bool canceled) {
412 EXPECT_EQ(kRandomAddress, address);
413 EXPECT_FALSE(canceled);
414 connection_states.push_back(std::make_pair(connected, handle));
415 });
416
417 auto fake_peer = std::make_unique<FakePeer>(
418 kRandomAddress, TestFixture::dispatcher(), true, true);
419 this->test_device()->AddPeer(std::move(fake_peer));
420 this->test_device()->ConnectLowEnergy(
421 kRandomAddress, pw::bluetooth::emboss::ConnectionRole::PERIPHERAL);
422 this->RunUntilIdle();
423
424 ASSERT_EQ(1u, connection_states.size());
425 auto [connection_state, handle] = connection_states[0];
426 EXPECT_TRUE(connection_state);
427
428 // Notify the advertiser of the incoming connection. It should reject it and
429 // the controller should become disconnected.
430 this->advertiser()->OnIncomingConnection(
431 handle,
432 pw::bluetooth::emboss::ConnectionRole::PERIPHERAL,
433 kRandomAddress,
434 hci_spec::LEConnectionParameters());
435 this->MaybeSendMultipleAdvertisingPostConnectionEvents(kConnectionHandle, 0);
436 this->RunUntilIdle();
437 ASSERT_EQ(2u, connection_states.size());
438 auto [connection_state_after_disconnect, disconnected_handle] =
439 connection_states[1];
440 EXPECT_EQ(handle, disconnected_handle);
441 EXPECT_FALSE(connection_state_after_disconnect);
442 }
443
444 // An incoming connection during non-connectable advertising should get
445 // disconnected.
TYPED_TEST(LowEnergyAdvertiserTest,IncomingConnectionWhenNonConnectableAdvertising)446 TYPED_TEST(LowEnergyAdvertiserTest,
447 IncomingConnectionWhenNonConnectableAdvertising) {
448 AdvertisingData ad = this->GetExampleData();
449 AdvertisingData scan_data = this->GetExampleData();
450 AdvertisingOptions options(kTestInterval,
451 /*anonymous=*/false,
452 kDefaultNoAdvFlags,
453 /*include_tx_power_level=*/false);
454 this->advertiser()->StartAdvertising(kPublicAddress,
455 ad,
456 scan_data,
457 options,
458 nullptr,
459 this->MakeExpectSuccessCallback());
460 this->RunUntilIdle();
461 ASSERT_TRUE(this->GetLastStatus());
462
463 std::vector<std::pair<bool, hci_spec::ConnectionHandle>> connection_states;
464 this->test_device()->set_connection_state_callback(
465 [&](const auto& address, auto handle, bool connected, bool canceled) {
466 EXPECT_EQ(kRandomAddress, address);
467 EXPECT_FALSE(canceled);
468 connection_states.push_back(std::make_pair(connected, handle));
469 });
470
471 auto fake_peer = std::make_unique<FakePeer>(
472 kRandomAddress, TestFixture::dispatcher(), true, true);
473 this->test_device()->AddPeer(std::move(fake_peer));
474 this->test_device()->ConnectLowEnergy(
475 kRandomAddress, pw::bluetooth::emboss::ConnectionRole::PERIPHERAL);
476 this->RunUntilIdle();
477
478 ASSERT_EQ(1u, connection_states.size());
479 auto [connection_state, handle] = connection_states[0];
480 EXPECT_TRUE(connection_state);
481
482 // Notify the advertiser of the incoming connection. It should reject it and
483 // the controller should become disconnected.
484 this->advertiser()->OnIncomingConnection(
485 handle,
486 pw::bluetooth::emboss::ConnectionRole::PERIPHERAL,
487 kRandomAddress,
488 hci_spec::LEConnectionParameters());
489 this->MaybeSendMultipleAdvertisingPostConnectionEvents(kConnectionHandle, 0);
490 this->RunUntilIdle();
491 ASSERT_EQ(2u, connection_states.size());
492 auto [connection_state_after_disconnect, disconnected_handle] =
493 connection_states[1];
494 EXPECT_EQ(handle, disconnected_handle);
495 EXPECT_FALSE(connection_state_after_disconnect);
496 }
497
498 // Tests starting and stopping an advertisement.
TYPED_TEST(LowEnergyAdvertiserTest,StartAndStop)499 TYPED_TEST(LowEnergyAdvertiserTest, StartAndStop) {
500 AdvertisingData ad = this->GetExampleData();
501 AdvertisingData scan_data = this->GetExampleData();
502 AdvertisingOptions options(kTestInterval,
503 /*anonymous=*/false,
504 kDefaultNoAdvFlags,
505 /*include_tx_power_level=*/false);
506
507 this->advertiser()->StartAdvertising(kRandomAddress,
508 ad,
509 scan_data,
510 options,
511 nullptr,
512 this->MakeExpectSuccessCallback());
513 this->RunUntilIdle();
514 EXPECT_TRUE(this->GetLastStatus());
515 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
516
517 this->advertiser()->StopAdvertising(kRandomAddress);
518 this->RunUntilIdle();
519 EXPECT_FALSE(this->GetControllerAdvertisingState().enabled);
520 }
521
522 // Tests that an advertisement is configured with the correct parameters.
TYPED_TEST(LowEnergyAdvertiserTest,AdvertisingParameters)523 TYPED_TEST(LowEnergyAdvertiserTest, AdvertisingParameters) {
524 AdvertisingData ad = this->GetExampleData();
525 AdvertisingData scan_data = this->GetExampleData();
526 auto flags = AdvFlag::kLEGeneralDiscoverableMode;
527 AdvertisingOptions options(kTestInterval,
528 /*anonymous=*/false,
529 flags,
530 /*include_tx_power_level=*/false);
531
532 this->advertiser()->StartAdvertising(kRandomAddress,
533 ad,
534 scan_data,
535 options,
536 nullptr,
537 this->MakeExpectSuccessCallback());
538 this->RunUntilIdle();
539 EXPECT_TRUE(this->GetLastStatus());
540
541 // The expected advertisement including the Flags.
542 DynamicByteBuffer expected_ad(ad.CalculateBlockSize(/*include_flags=*/true));
543 ad.WriteBlock(&expected_ad, flags);
544
545 DynamicByteBuffer expected_scan_data(
546 scan_data.CalculateBlockSize(/*include_flags=*/false));
547 scan_data.WriteBlock(&expected_scan_data, std::nullopt);
548
549 std::optional<FakeController::LEAdvertisingState> state =
550 this->GetControllerAdvertisingState();
551 EXPECT_TRUE(state);
552 EXPECT_TRUE(state->enabled);
553 EXPECT_EQ(kTestInterval.min(), state->interval_min);
554 EXPECT_EQ(kTestInterval.max(), state->interval_max);
555 EXPECT_EQ(expected_ad, state->advertised_view());
556 EXPECT_EQ(expected_scan_data, state->scan_rsp_view());
557 EXPECT_EQ(pw::bluetooth::emboss::LEOwnAddressType::RANDOM,
558 state->own_address_type);
559
560 // Restart advertising with a public address and verify that the configured
561 // local address type is correct.
562 this->advertiser()->StopAdvertising(kRandomAddress);
563 AdvertisingOptions new_options(kTestInterval,
564 /*anonymous=*/false,
565 kDefaultNoAdvFlags,
566 /*include_tx_power_level=*/false);
567 this->advertiser()->StartAdvertising(kPublicAddress,
568 ad,
569 scan_data,
570 new_options,
571 nullptr,
572 this->MakeExpectSuccessCallback());
573 this->RunUntilIdle();
574 EXPECT_TRUE(this->GetLastStatus());
575
576 state = this->GetControllerAdvertisingState();
577 EXPECT_TRUE(state);
578 EXPECT_TRUE(state->enabled);
579 EXPECT_EQ(pw::bluetooth::emboss::LEOwnAddressType::PUBLIC,
580 state->own_address_type);
581 }
582
583 // Tests that a previous advertisement's advertising data isn't accidentally
584 // kept around. This test was added to address fxbug.dev/42081491.
TYPED_TEST(LowEnergyAdvertiserTest,PreviousAdvertisingParameters)585 TYPED_TEST(LowEnergyAdvertiserTest, PreviousAdvertisingParameters) {
586 AdvertisingData scan_data = this->GetExampleData();
587 auto flags = AdvFlag::kLEGeneralDiscoverableMode;
588 AdvertisingOptions options(kTestInterval,
589 /*anonymous=*/false,
590 flags,
591 /*include_tx_power_level=*/false);
592
593 // old advertising data: ideally we would fill this completely so that in the
594 // next start advertising call, we can confirm that none of the remnants are
595 // left. However, doing so results in the advertising data being too long.
596 // Instead, we rely on other unit tests within advertising data unittests to
597 // ensure all previous remnants are removed.
598 AdvertisingData ad;
599 ad.SetTxPower(4);
600 ad.SetAppearance(0x4567);
601 EXPECT_TRUE(ad.SetLocalName("fuchsia"));
602
603 this->advertiser()->StartAdvertising(kRandomAddress,
604 ad,
605 scan_data,
606 options,
607 nullptr,
608 this->MakeExpectSuccessCallback());
609 this->RunUntilIdle();
610 EXPECT_TRUE(this->GetLastStatus());
611
612 // new advertising data (with fewer fields filled in)
613 this->advertiser()->StopAdvertising(kRandomAddress);
614 AdvertisingData new_ad = this->GetExampleData();
615 this->advertiser()->StartAdvertising(kRandomAddress,
616 new_ad,
617 scan_data,
618 options,
619 nullptr,
620 this->MakeExpectSuccessCallback());
621 this->RunUntilIdle();
622 EXPECT_TRUE(this->GetLastStatus());
623
624 DynamicByteBuffer expected_ad(
625 new_ad.CalculateBlockSize(/*include_flags=*/true));
626 new_ad.WriteBlock(&expected_ad, flags);
627
628 std::optional<FakeController::LEAdvertisingState> state =
629 this->GetControllerAdvertisingState();
630 EXPECT_EQ(expected_ad, state->advertised_view());
631 }
632
633 // Tests that advertising interval values are capped within the allowed range.
TYPED_TEST(LowEnergyAdvertiserTest,AdvertisingIntervalWithinAllowedRange)634 TYPED_TEST(LowEnergyAdvertiserTest, AdvertisingIntervalWithinAllowedRange) {
635 AdvertisingData ad = this->GetExampleData();
636 AdvertisingData scan_data = this->GetExampleData();
637
638 // Pass min and max values that are outside the allowed range. These should be
639 // capped.
640 constexpr AdvertisingIntervalRange interval(
641 hci_spec::kLEAdvertisingIntervalMin - 1,
642 hci_spec::kLEAdvertisingIntervalMax + 1);
643 AdvertisingOptions options(interval,
644 /*anonymous=*/false,
645 kDefaultNoAdvFlags,
646 /*include_tx_power_level=*/false);
647 this->advertiser()->StartAdvertising(kRandomAddress,
648 ad,
649 scan_data,
650 options,
651 nullptr,
652 this->MakeExpectSuccessCallback());
653 this->RunUntilIdle();
654 EXPECT_TRUE(this->GetLastStatus());
655
656 std::optional<FakeController::LEAdvertisingState> state =
657 this->GetControllerAdvertisingState();
658 EXPECT_TRUE(state);
659 EXPECT_EQ(hci_spec::kLEAdvertisingIntervalMin, state->interval_min);
660 EXPECT_EQ(hci_spec::kLEAdvertisingIntervalMax, state->interval_max);
661
662 // Reconfigure with values that are within the range. These should get passed
663 // down as is.
664 const AdvertisingIntervalRange new_interval(
665 hci_spec::kLEAdvertisingIntervalMin + 1,
666 hci_spec::kLEAdvertisingIntervalMax - 1);
667 AdvertisingOptions new_options(new_interval,
668 /*anonymous=*/false,
669 kDefaultNoAdvFlags,
670 /*include_tx_power_level=*/false);
671 this->advertiser()->StartAdvertising(kRandomAddress,
672 ad,
673 scan_data,
674 new_options,
675 nullptr,
676 this->MakeExpectSuccessCallback());
677 this->RunUntilIdle();
678 EXPECT_TRUE(this->GetLastStatus());
679
680 state = this->GetControllerAdvertisingState();
681 EXPECT_TRUE(state);
682 EXPECT_EQ(new_interval.min(), state->interval_min);
683 EXPECT_EQ(new_interval.max(), state->interval_max);
684 }
685
TYPED_TEST(LowEnergyAdvertiserTest,StartWhileStarting)686 TYPED_TEST(LowEnergyAdvertiserTest, StartWhileStarting) {
687 AdvertisingData ad = this->GetExampleData();
688 AdvertisingData scan_data = this->GetExampleData();
689 DeviceAddress addr = kRandomAddress;
690
691 const AdvertisingIntervalRange old_interval = kTestInterval;
692 AdvertisingOptions old_options(old_interval,
693 /*anonymous=*/false,
694 kDefaultNoAdvFlags,
695 /*include_tx_power_level=*/false);
696 const AdvertisingIntervalRange new_interval(kTestInterval.min() + 1,
697 kTestInterval.max() - 1);
698 AdvertisingOptions new_options(new_interval,
699 /*anonymous=*/false,
700 kDefaultNoAdvFlags,
701 /*include_tx_power_level=*/false);
702
703 this->advertiser()->StartAdvertising(
704 addr, ad, scan_data, old_options, nullptr, [](auto) {});
705 EXPECT_FALSE(this->GetControllerAdvertisingState().enabled);
706
707 // This call should override the previous call and succeed with the new
708 // parameters.
709 this->advertiser()->StartAdvertising(addr,
710 ad,
711 scan_data,
712 new_options,
713 nullptr,
714 this->MakeExpectSuccessCallback());
715 this->RunUntilIdle();
716 EXPECT_TRUE(this->GetLastStatus());
717 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
718 EXPECT_EQ(new_interval.max(),
719 this->GetControllerAdvertisingState().interval_max);
720 }
721
TYPED_TEST(LowEnergyAdvertiserTest,StartWhileStopping)722 TYPED_TEST(LowEnergyAdvertiserTest, StartWhileStopping) {
723 AdvertisingData ad = this->GetExampleData();
724 AdvertisingData scan_data = this->GetExampleData();
725 DeviceAddress addr = kRandomAddress;
726 AdvertisingOptions options(kTestInterval,
727 /*anonymous=*/false,
728 kDefaultNoAdvFlags,
729 /*include_tx_power_level=*/false);
730
731 // Get to a started state.
732 this->advertiser()->StartAdvertising(
733 addr, ad, scan_data, options, nullptr, this->MakeExpectSuccessCallback());
734 this->RunUntilIdle();
735 EXPECT_TRUE(this->GetLastStatus());
736 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
737
738 // Initiate a request to Stop and wait until it's partially in progress.
739 bool enabled = true;
740 bool was_disabled = false;
741 auto adv_state_cb = [&] {
742 enabled = this->GetControllerAdvertisingState().enabled;
743 if (!was_disabled && !enabled) {
744 was_disabled = true;
745
746 // Starting now should cancel the stop sequence and succeed.
747 this->advertiser()->StartAdvertising(addr,
748 ad,
749 scan_data,
750 options,
751 nullptr,
752 this->MakeExpectSuccessCallback());
753 }
754 };
755 this->test_device()->set_advertising_state_callback(adv_state_cb);
756
757 this->advertiser()->StopAdvertising(addr);
758
759 // Advertising should have been momentarily disabled.
760 this->RunUntilIdle();
761 EXPECT_TRUE(was_disabled);
762 EXPECT_TRUE(enabled);
763 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
764
765 this->test_device()->set_advertising_state_callback(nullptr);
766 }
767
TYPED_TEST(LowEnergyAdvertiserTest,StopWhileStarting)768 TYPED_TEST(LowEnergyAdvertiserTest, StopWhileStarting) {
769 AdvertisingData ad = this->GetExampleData();
770 AdvertisingData scan_data = this->GetExampleData();
771 AdvertisingOptions options(kTestInterval,
772 /*anonymous=*/false,
773 kDefaultNoAdvFlags,
774 /*include_tx_power_level=*/false);
775
776 this->advertiser()->StartAdvertising(kPublicAddress,
777 ad,
778 scan_data,
779 options,
780 nullptr,
781 this->MakeExpectErrorCallback());
782 this->advertiser()->StopAdvertising();
783
784 this->RunUntilIdle();
785 EXPECT_TRUE(this->GetLastStatus());
786 EXPECT_FALSE(this->GetControllerAdvertisingState().enabled);
787 }
788
789 // - StopAdvertisement noops when the advertisement address is wrong
790 // - Sets the advertisement data to null when stopped to prevent data leakage
791 // (re-enable advertising without changing data, intercept)
TYPED_TEST(LowEnergyAdvertiserTest,StopAdvertisingConditions)792 TYPED_TEST(LowEnergyAdvertiserTest, StopAdvertisingConditions) {
793 AdvertisingData ad = this->GetExampleData();
794 AdvertisingData scan_data = this->GetExampleData();
795 AdvertisingOptions options(kTestInterval,
796 /*anonymous=*/false,
797 kDefaultNoAdvFlags,
798 /*include_tx_power_level=*/false);
799
800 this->advertiser()->StartAdvertising(kRandomAddress,
801 ad,
802 scan_data,
803 options,
804 nullptr,
805 this->MakeExpectSuccessCallback());
806
807 this->RunUntilIdle();
808
809 EXPECT_TRUE(this->GetLastStatus());
810
811 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
812 DynamicByteBuffer expected_ad(ad.CalculateBlockSize(/*include_flags=*/true));
813 ad.WriteBlock(&expected_ad, kDefaultNoAdvFlags);
814 EXPECT_TRUE(ContainersEqual(
815 this->GetControllerAdvertisingState().advertised_view(), expected_ad));
816
817 this->RunUntilIdle();
818 this->advertiser()->StopAdvertising(kPublicAddress);
819 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
820 EXPECT_TRUE(ContainersEqual(
821 this->GetControllerAdvertisingState().advertised_view(), expected_ad));
822
823 this->advertiser()->StopAdvertising(kRandomAddress);
824
825 this->RunUntilIdle();
826 EXPECT_FALSE(this->GetControllerAdvertisingState().enabled);
827 EXPECT_EQ(0u, this->GetControllerAdvertisingState().advertised_view().size());
828 EXPECT_EQ(0u, this->GetControllerAdvertisingState().scan_rsp_view().size());
829 }
830
831 // - Updates data and params for the same address when advertising already
TYPED_TEST(LowEnergyAdvertiserTest,AdvertiseUpdate)832 TYPED_TEST(LowEnergyAdvertiserTest, AdvertiseUpdate) {
833 AdvertisingData ad = this->GetExampleData();
834 AdvertisingData scan_data = this->GetExampleData();
835 AdvertisingOptions options(kTestInterval,
836 /*anonymous=*/false,
837 kDefaultNoAdvFlags,
838 /*include_tx_power_level=*/false);
839
840 this->advertiser()->StartAdvertising(kRandomAddress,
841 ad,
842 scan_data,
843 options,
844 nullptr,
845 this->MakeExpectSuccessCallback());
846 this->RunUntilIdle();
847
848 EXPECT_TRUE(this->GetLastStatus());
849 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
850
851 // The expected advertising data payload, with the flags.
852 DynamicByteBuffer expected_ad(ad.CalculateBlockSize(/*include_flags=*/true));
853 ad.WriteBlock(&expected_ad, kDefaultNoAdvFlags);
854 EXPECT_TRUE(ContainersEqual(
855 this->GetControllerAdvertisingState().advertised_view(), expected_ad));
856
857 EXPECT_EQ(kTestInterval.min(),
858 this->GetControllerAdvertisingState().interval_min);
859 EXPECT_EQ(kTestInterval.max(),
860 this->GetControllerAdvertisingState().interval_max);
861
862 uint16_t new_appearance = 0x6789;
863 ad.SetAppearance(new_appearance);
864
865 const AdvertisingIntervalRange new_interval(kTestInterval.min() + 1,
866 kTestInterval.max() - 1);
867 AdvertisingOptions new_options(new_interval,
868 /*anonymous=*/false,
869 kDefaultNoAdvFlags,
870 /*include_tx_power_level=*/false);
871 this->advertiser()->StartAdvertising(kRandomAddress,
872 ad,
873 scan_data,
874 new_options,
875 nullptr,
876 this->MakeExpectSuccessCallback());
877 this->RunUntilIdle();
878
879 EXPECT_TRUE(this->GetLastStatus());
880 EXPECT_TRUE(this->GetControllerAdvertisingState().enabled);
881
882 DynamicByteBuffer expected_new_ad(
883 ad.CalculateBlockSize(/*include_flags=*/true));
884 ad.WriteBlock(&expected_new_ad, kDefaultNoAdvFlags);
885 EXPECT_TRUE(
886 ContainersEqual(this->GetControllerAdvertisingState().advertised_view(),
887 expected_new_ad));
888
889 EXPECT_EQ(new_interval.min(),
890 this->GetControllerAdvertisingState().interval_min);
891 EXPECT_EQ(new_interval.max(),
892 this->GetControllerAdvertisingState().interval_max);
893 }
894
895 // Ensures advertising set data is removed from controller memory after
896 // advertising is stopped
TYPED_TEST(LowEnergyAdvertiserTest,StopAdvertisingSingleAdvertisement)897 TYPED_TEST(LowEnergyAdvertiserTest, StopAdvertisingSingleAdvertisement) {
898 AdvertisingData ad = this->GetExampleData();
899 AdvertisingData scan_data = this->GetExampleData();
900
901 // start public address advertising
902 AdvertisingOptions options(kTestInterval,
903 /*anonymous=*/false,
904 kDefaultNoAdvFlags,
905 /*include_tx_power_level=*/false);
906 this->advertiser()->StartAdvertising(kPublicAddress,
907 ad,
908 scan_data,
909 options,
910 nullptr,
911 this->MakeExpectSuccessCallback());
912 this->RunUntilIdle();
913 EXPECT_TRUE(this->GetLastStatus());
914
915 constexpr uint8_t blank[hci_spec::kMaxLEAdvertisingDataLength] = {0};
916
917 // check that advertiser and controller both report the same advertising state
918 EXPECT_TRUE(this->advertiser()->IsAdvertising());
919 EXPECT_TRUE(this->advertiser()->IsAdvertising(kPublicAddress));
920
921 {
922 const FakeController::LEAdvertisingState& state =
923 this->GetControllerAdvertisingState();
924 EXPECT_TRUE(state.enabled);
925 EXPECT_NE(
926 0,
927 std::memcmp(blank, state.data, hci_spec::kMaxLEAdvertisingDataLength));
928 EXPECT_NE(0, state.data_length);
929 EXPECT_NE(
930 0,
931 std::memcmp(blank, state.data, hci_spec::kMaxLEAdvertisingDataLength));
932 EXPECT_NE(0, state.scan_rsp_length);
933 }
934
935 // stop advertising the random address
936 this->advertiser()->StopAdvertising(kPublicAddress);
937 this->RunUntilIdle();
938
939 // check that advertiser and controller both report the same advertising state
940 EXPECT_FALSE(this->advertiser()->IsAdvertising());
941 EXPECT_FALSE(this->advertiser()->IsAdvertising(kPublicAddress));
942
943 {
944 const FakeController::LEAdvertisingState& state =
945 this->GetControllerAdvertisingState();
946 EXPECT_FALSE(state.enabled);
947 EXPECT_EQ(
948 0,
949 std::memcmp(blank, state.data, hci_spec::kMaxLEAdvertisingDataLength));
950 EXPECT_EQ(0, state.data_length);
951 EXPECT_EQ(
952 0,
953 std::memcmp(blank, state.data, hci_spec::kMaxLEAdvertisingDataLength));
954 EXPECT_EQ(0, state.scan_rsp_length);
955 }
956 }
957
958 // - Rejects anonymous advertisement (unsupported)
TYPED_TEST(LowEnergyAdvertiserTest,NoAnonymous)959 TYPED_TEST(LowEnergyAdvertiserTest, NoAnonymous) {
960 AdvertisingData ad = this->GetExampleData();
961 AdvertisingData scan_data = this->GetExampleData();
962 AdvertisingOptions options(kTestInterval,
963 /*anonymous=*/true,
964 kDefaultNoAdvFlags,
965 /*include_tx_power_level=*/false);
966
967 this->advertiser()->StartAdvertising(kRandomAddress,
968 ad,
969 scan_data,
970 options,
971 nullptr,
972 this->MakeExpectErrorCallback());
973 EXPECT_TRUE(this->GetLastStatus());
974 EXPECT_FALSE(this->GetControllerAdvertisingState().enabled);
975 }
976
TYPED_TEST(LowEnergyAdvertiserTest,AdvertisingDataTooLong)977 TYPED_TEST(LowEnergyAdvertiserTest, AdvertisingDataTooLong) {
978 AdvertisingData invalid_ad =
979 this->GetTooLargeExampleData(/*include_flags=*/true);
980 AdvertisingData valid_scan_rsp =
981 this->GetExampleData(/*include_flags=*/false);
982 AdvertisingOptions options(kTestInterval,
983 /*anonymous=*/false,
984 kDefaultNoAdvFlags,
985 /*include_tx_power_level=*/false);
986
987 // Advertising data too large.
988 this->advertiser()->StartAdvertising(kRandomAddress,
989 invalid_ad,
990 valid_scan_rsp,
991 options,
992 nullptr,
993 this->MakeExpectErrorCallback());
994 this->RunUntilIdle();
995 auto status = this->GetLastStatus();
996 ASSERT_TRUE(status);
997 EXPECT_EQ(ToResult(HostError::kAdvertisingDataTooLong), *status);
998 }
999
TYPED_TEST(LowEnergyAdvertiserTest,AdvertisingDataTooLongWithTxPower)1000 TYPED_TEST(LowEnergyAdvertiserTest, AdvertisingDataTooLongWithTxPower) {
1001 AdvertisingData invalid_ad = this->GetTooLargeExampleData(
1002 /*include_flags=*/true,
1003 hci_spec::kMaxLEAdvertisingDataLength - kTLVTxPowerLevelSize + 1);
1004 AdvertisingData valid_scan_rsp =
1005 this->GetExampleData(/*include_flags=*/false);
1006 AdvertisingOptions options(kTestInterval,
1007 /*anonymous=*/false,
1008 kDefaultNoAdvFlags,
1009 /*include_tx_power_level=*/true);
1010
1011 // Advertising data too large.
1012 this->advertiser()->StartAdvertising(kRandomAddress,
1013 invalid_ad,
1014 valid_scan_rsp,
1015 options,
1016 nullptr,
1017 this->MakeExpectErrorCallback());
1018 this->RunUntilIdle();
1019 auto status = this->GetLastStatus();
1020 ASSERT_TRUE(status);
1021 EXPECT_EQ(ToResult(HostError::kAdvertisingDataTooLong), *status);
1022 }
1023
TYPED_TEST(LowEnergyAdvertiserTest,ScanResponseTooLong)1024 TYPED_TEST(LowEnergyAdvertiserTest, ScanResponseTooLong) {
1025 AdvertisingData valid_ad = this->GetExampleData();
1026 AdvertisingData invalid_scan_rsp =
1027 this->GetTooLargeExampleData(/*include_flags=*/false);
1028 AdvertisingOptions options(kTestInterval,
1029 /*anonymous=*/false,
1030 kDefaultNoAdvFlags,
1031 /*include_tx_power_level=*/false);
1032 this->advertiser()->StartAdvertising(kRandomAddress,
1033 valid_ad,
1034 invalid_scan_rsp,
1035 options,
1036 nullptr,
1037 this->MakeExpectErrorCallback());
1038 this->RunUntilIdle();
1039 auto status = this->GetLastStatus();
1040 ASSERT_TRUE(status);
1041 EXPECT_EQ(ToResult(HostError::kScanResponseTooLong), *status);
1042 }
1043
TYPED_TEST(LowEnergyAdvertiserTest,ScanResponseTooLongWithTxPower)1044 TYPED_TEST(LowEnergyAdvertiserTest, ScanResponseTooLongWithTxPower) {
1045 AdvertisingData valid_ad = this->GetExampleData();
1046 AdvertisingData invalid_scan_rsp = this->GetTooLargeExampleData(
1047 /*include_flags=*/false,
1048 hci_spec::kMaxLEAdvertisingDataLength - kTLVTxPowerLevelSize + 1);
1049 AdvertisingOptions options(kTestInterval,
1050 /*anonymous=*/false,
1051 kDefaultNoAdvFlags,
1052 /*include_tx_power_level=*/true);
1053 this->advertiser()->StartAdvertising(kRandomAddress,
1054 valid_ad,
1055 invalid_scan_rsp,
1056 options,
1057 nullptr,
1058 this->MakeExpectErrorCallback());
1059 this->RunUntilIdle();
1060 auto status = this->GetLastStatus();
1061 ASSERT_TRUE(status);
1062 EXPECT_EQ(ToResult(HostError::kScanResponseTooLong), *status);
1063 }
1064
TYPED_TEST(LowEnergyAdvertiserTest,DestroyingTransportBeforeAdvertiserDoesNotCrash)1065 TYPED_TEST(LowEnergyAdvertiserTest,
1066 DestroyingTransportBeforeAdvertiserDoesNotCrash) {
1067 this->DeleteTransport();
1068 this->DestroyAdvertiser();
1069 }
1070
1071 } // namespace
1072 } // namespace bt::hci
1073