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_advertising_manager.h"
16
17 #include <pw_assert/check.h>
18
19 #include <map>
20
21 #include "pw_bluetooth_sapphire/internal/host/common/advertising_data.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
24 #include "pw_bluetooth_sapphire/internal/host/hci/connection.h"
25 #include "pw_bluetooth_sapphire/internal/host/hci/fake_local_address_delegate.h"
26 #include "pw_bluetooth_sapphire/internal/host/hci/fake_low_energy_connection.h"
27 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
28 #include "pw_bluetooth_sapphire/internal/host/testing/fake_controller.h"
29 #include "pw_bluetooth_sapphire/internal/host/transport/control_packets.h"
30 #include "pw_bluetooth_sapphire/internal/host/transport/error.h"
31
32 namespace bt {
33 using testing::FakeController;
34
35 namespace gap {
36 namespace {
37 namespace pwemb = pw::bluetooth::emboss;
38 using TestingBase = bt::testing::FakeDispatcherControllerTest<FakeController>;
39
40 constexpr size_t kDefaultMaxAdSize = 23;
41 constexpr size_t kDefaultFakeAdSize = 20;
42 constexpr AdvertisingInterval kTestInterval = AdvertisingInterval::FAST1;
43
44 const DeviceAddress kPublicAddress(DeviceAddress::Type::kLEPublic,
45 {0x01, 0, 0, 0, 0, 0});
46 const DeviceAddress kRandomAddress(DeviceAddress::Type::kLERandom,
47 {0x55, 0x44, 0x33, 0x22, 0x11, 0x00});
48
NopConnectCallback(AdvertisementId,std::unique_ptr<hci::Connection>)49 void NopConnectCallback(AdvertisementId, std::unique_ptr<hci::Connection>) {}
50
51 struct AdvertisementStatus {
52 AdvertisingData data;
53 AdvertisingData scan_rsp;
54 bool anonymous;
55 uint16_t interval_min;
56 uint16_t interval_max;
57 bool extended_pdu;
58 hci::LowEnergyAdvertiser::ConnectionCallback connect_cb;
59 };
60
61 // LowEnergyAdvertiser for testing purposes:
62 // - Reports mas_ad_size supported
63 // - Actually just accepts all ads and stores them in ad_store
64 class FakeLowEnergyAdvertiser final : public hci::LowEnergyAdvertiser {
65 public:
FakeLowEnergyAdvertiser(const hci::Transport::WeakPtr & hci,std::unordered_map<DeviceAddress,AdvertisementStatus> * ad_store)66 FakeLowEnergyAdvertiser(
67 const hci::Transport::WeakPtr& hci,
68 std::unordered_map<DeviceAddress, AdvertisementStatus>* ad_store)
69 : hci::LowEnergyAdvertiser(hci, kDefaultMaxAdSize),
70 ads_(ad_store),
71 hci_(hci) {
72 PW_CHECK(ads_);
73 }
74
75 ~FakeLowEnergyAdvertiser() override = default;
76
MaxAdvertisements() const77 size_t MaxAdvertisements() const override { return 1; }
78
AllowsRandomAddressChange() const79 bool AllowsRandomAddressChange() const override { return true; }
80
StartAdvertising(const DeviceAddress & address,const AdvertisingData & data,const AdvertisingData & scan_rsp,const AdvertisingOptions & options,ConnectionCallback connect_callback,hci::ResultFunction<> result_callback)81 void StartAdvertising(const DeviceAddress& address,
82 const AdvertisingData& data,
83 const AdvertisingData& scan_rsp,
84 const AdvertisingOptions& options,
85 ConnectionCallback connect_callback,
86 hci::ResultFunction<> result_callback) override {
87 if (pending_error_.is_error()) {
88 result_callback(pending_error_);
89 pending_error_ = fit::ok();
90 return;
91 }
92
93 fit::result<HostError> result =
94 CanStartAdvertising(address, data, scan_rsp, options, connect_callback);
95 if (result.is_error()) {
96 result_callback(ToResult(result.error_value()));
97 return;
98 }
99
100 AdvertisementStatus new_status;
101 data.Copy(&new_status.data);
102 scan_rsp.Copy(&new_status.scan_rsp);
103 new_status.connect_cb = std::move(connect_callback);
104 new_status.interval_min = options.interval.min();
105 new_status.interval_max = options.interval.max();
106 new_status.anonymous = options.anonymous;
107 new_status.extended_pdu = options.extended_pdu;
108 ads_->emplace(address, std::move(new_status));
109 result_callback(fit::ok());
110 }
111
StopAdvertising(const DeviceAddress & address,bool)112 void StopAdvertising(const DeviceAddress& address, bool) override {
113 ads_->erase(address);
114 }
115
OnIncomingConnection(hci_spec::ConnectionHandle handle,pwemb::ConnectionRole role,const DeviceAddress & peer_address,const hci_spec::LEConnectionParameters &)116 void OnIncomingConnection(hci_spec::ConnectionHandle handle,
117 pwemb::ConnectionRole role,
118 const DeviceAddress& peer_address,
119 const hci_spec::LEConnectionParameters&) override {
120 // Right now, we call the first callback, because we can't call any other
121 // ones.
122 // TODO(jamuraa): make this send it to the correct callback once we can
123 // determine which one that is.
124 const auto& cb = ads_->begin()->second.connect_cb;
125 if (cb) {
126 cb(std::make_unique<hci::testing::FakeLowEnergyConnection>(
127 handle, ads_->begin()->first, peer_address, role, hci_));
128 }
129 }
130
131 // Sets this faker up to send an error back from the next StartAdvertising
132 // call. Set to success to disable a previously called error.
ErrorOnNext(hci::Result<> error_status)133 void ErrorOnNext(hci::Result<> error_status) {
134 pending_error_ = error_status;
135 }
136
137 private:
BuildEnablePacket(const DeviceAddress &,pw::bluetooth::emboss::GenericEnableParam,bool)138 hci::CommandPacket BuildEnablePacket(
139 const DeviceAddress&,
140 pw::bluetooth::emboss::GenericEnableParam,
141 bool) override {
142 return hci::CommandPacket::New<
143 pwemb::LESetExtendedAdvertisingEnableDataWriter>(
144 hci_spec::kLESetExtendedAdvertisingEnable);
145 }
146
BuildSetAdvertisingParams(const DeviceAddress &,const AdvertisingEventProperties &,pwemb::LEOwnAddressType,const hci::AdvertisingIntervalRange &,bool)147 std::optional<hci::CommandPacket> BuildSetAdvertisingParams(
148 const DeviceAddress&,
149 const AdvertisingEventProperties&,
150 pwemb::LEOwnAddressType,
151 const hci::AdvertisingIntervalRange&,
152 bool) override {
153 return std::nullopt;
154 }
155
BuildSetAdvertisingData(const DeviceAddress &,const AdvertisingData &,AdvFlags,bool)156 std::vector<hci::CommandPacket> BuildSetAdvertisingData(
157 const DeviceAddress&, const AdvertisingData&, AdvFlags, bool) override {
158 hci::CommandPacket packet =
159 hci::CommandPacket::New<pwemb::LESetAdvertisingDataCommandWriter>(
160 hci_spec::kLESetAdvertisingData);
161
162 std::vector<hci::CommandPacket> packets;
163 packets.push_back(std::move(packet));
164 return packets;
165 }
166
BuildUnsetAdvertisingData(const DeviceAddress &,bool)167 hci::CommandPacket BuildUnsetAdvertisingData(const DeviceAddress&,
168 bool) override {
169 return hci::CommandPacket::New<pwemb::LESetAdvertisingDataCommandWriter>(
170 hci_spec::kLESetAdvertisingData);
171 }
172
BuildSetScanResponse(const DeviceAddress &,const AdvertisingData &,bool)173 std::vector<hci::CommandPacket> BuildSetScanResponse(const DeviceAddress&,
174 const AdvertisingData&,
175 bool) override {
176 hci::CommandPacket packet =
177 hci::CommandPacket::New<pwemb::LESetScanResponseDataCommandWriter>(
178 hci_spec::kLESetScanResponseData);
179
180 std::vector<hci::CommandPacket> packets;
181 packets.push_back(std::move(packet));
182 return packets;
183 }
184
BuildUnsetScanResponse(const DeviceAddress &,bool)185 hci::CommandPacket BuildUnsetScanResponse(const DeviceAddress&,
186 bool) override {
187 return hci::CommandPacket::New<pwemb::LESetScanResponseDataCommandWriter>(
188 hci_spec::kLESetScanResponseData);
189 }
190
BuildRemoveAdvertisingSet(const DeviceAddress &,bool)191 hci::CommandPacket BuildRemoveAdvertisingSet(const DeviceAddress&,
192 bool) override {
193 return hci::CommandPacket::New<pwemb::LERemoveAdvertisingSetCommandWriter>(
194 hci_spec::kLERemoveAdvertisingSet);
195 }
196
197 std::unordered_map<DeviceAddress, AdvertisementStatus>* ads_;
198 hci::Result<> pending_error_ = fit::ok();
199 hci::Transport::WeakPtr hci_;
200
201 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(FakeLowEnergyAdvertiser);
202 };
203
204 class LowEnergyAdvertisingManagerTest : public TestingBase {
205 public:
206 LowEnergyAdvertisingManagerTest() = default;
207 ~LowEnergyAdvertisingManagerTest() override = default;
208
209 protected:
SetUp()210 void SetUp() override {
211 TestingBase::SetUp();
212 InitializeACLDataChannel();
213
214 fake_address_delegate_.EnablePrivacy(true);
215 fake_address_delegate_.set_identity_address(kPublicAddress);
216 fake_address_delegate_.set_local_address(kRandomAddress);
217 MakeFakeAdvertiser();
218 MakeAdvertisingManager();
219 }
220
TearDown()221 void TearDown() override {
222 adv_mgr_ = nullptr;
223 advertiser_ = nullptr;
224 TestingBase::TearDown();
225 }
226
227 // Makes some fake advertising data of a specific |packed_size|
CreateFakeAdvertisingData(size_t packed_size=kDefaultFakeAdSize)228 AdvertisingData CreateFakeAdvertisingData(
229 size_t packed_size = kDefaultFakeAdSize) {
230 AdvertisingData result;
231 StaticByteBuffer buffer(
232 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08);
233 size_t bytes_left = packed_size;
234 while (bytes_left > 0) {
235 // Each field to take 10 bytes total, unless the next header (4 bytes)
236 // won't fit. In which case we add enough bytes to finish up.
237 size_t data_bytes = bytes_left < 14 ? (bytes_left - 4) : 6;
238 EXPECT_TRUE(result.SetManufacturerData(0xb000 + bytes_left,
239 buffer.view(0, data_bytes)));
240 bytes_left = packed_size - result.CalculateBlockSize();
241 }
242 return result;
243 }
244
GetErrorCallback()245 LowEnergyAdvertisingManager::AdvertisingStatusCallback GetErrorCallback() {
246 return [this](AdvertisementInstance instance, hci::Result<> status) {
247 EXPECT_EQ(kInvalidAdvertisementId, instance.id());
248 EXPECT_TRUE(status.is_error());
249 last_status_ = status;
250 };
251 }
252
GetSuccessCallback()253 LowEnergyAdvertisingManager::AdvertisingStatusCallback GetSuccessCallback() {
254 return [this](AdvertisementInstance instance, hci::Result<> status) {
255 EXPECT_NE(kInvalidAdvertisementId, instance.id());
256 EXPECT_EQ(fit::ok(), status);
257 last_instance_ = std::move(instance);
258 last_status_ = status;
259 };
260 }
261
MakeFakeAdvertiser()262 void MakeFakeAdvertiser() {
263 advertiser_ = std::make_unique<FakeLowEnergyAdvertiser>(
264 transport()->GetWeakPtr(), &ad_store_);
265 }
266
MakeAdvertisingManager()267 void MakeAdvertisingManager() {
268 adv_mgr_ = std::make_unique<LowEnergyAdvertisingManager>(
269 advertiser(), &fake_address_delegate_);
270 }
271
adv_mgr() const272 LowEnergyAdvertisingManager* adv_mgr() const { return adv_mgr_.get(); }
ad_store()273 const std::unordered_map<DeviceAddress, AdvertisementStatus>& ad_store() {
274 return ad_store_;
275 }
last_ad_id() const276 AdvertisementId last_ad_id() const { return last_instance_.id(); }
277
278 // Returns the currently active advertising state. This is useful for tests
279 // that want to verify advertising parameters when there is a single known
280 // advertisement. Returns nullptr if the number of advertisements are not
281 // equal to one.
current_adv() const282 const AdvertisementStatus* current_adv() const {
283 if (ad_store_.size() != 1u) {
284 return nullptr;
285 }
286 return &ad_store_.begin()->second;
287 }
288
289 // Returns and clears the last callback status. This resets the state to
290 // detect another callback.
last_status()291 std::optional<hci::Result<>> last_status() { return last_status_; }
292
advertiser() const293 FakeLowEnergyAdvertiser* advertiser() const { return advertiser_.get(); }
294
295 private:
296 hci::FakeLocalAddressDelegate fake_address_delegate_{dispatcher()};
297
298 // TODO(armansito): The address mapping is currently broken since the
299 // gap::LEAM always assigns the controller random address. Make this track
300 // each instance by instance ID instead once the layering issues have been
301 // fixed.
302 std::unordered_map<DeviceAddress, AdvertisementStatus> ad_store_;
303 AdvertisementInstance last_instance_;
304 std::optional<hci::Result<>> last_status_;
305 std::unique_ptr<FakeLowEnergyAdvertiser> advertiser_;
306 std::unique_ptr<LowEnergyAdvertisingManager> adv_mgr_;
307
308 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(LowEnergyAdvertisingManagerTest);
309 };
310
311 // Tests:
312 // - When the advertiser succeeds, the callback is called with the success
TEST_F(LowEnergyAdvertisingManagerTest,Success)313 TEST_F(LowEnergyAdvertisingManagerTest, Success) {
314 EXPECT_FALSE(adv_mgr()->advertising());
315 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
316 AdvertisingData(),
317 /*connect_callback=*/nullptr,
318 kTestInterval,
319 /*extended_pdu=*/false,
320 /*anonymous=*/false,
321 /*include_tx_power_level=*/false,
322 /*address_type=*/std::nullopt,
323 GetSuccessCallback());
324
325 RunUntilIdle();
326
327 EXPECT_TRUE(last_status());
328 ASSERT_EQ(1u, ad_store().size());
329 EXPECT_TRUE(adv_mgr()->advertising());
330
331 // Verify that the advertiser uses the requested local address.
332 EXPECT_EQ(kRandomAddress, ad_store().begin()->first);
333 }
334
TEST_F(LowEnergyAdvertisingManagerTest,DataSize)335 TEST_F(LowEnergyAdvertisingManagerTest, DataSize) {
336 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
337 AdvertisingData(),
338 /*connect_callback=*/nullptr,
339 kTestInterval,
340 /*extended_pdu=*/true,
341 /*anonymous=*/false,
342 /*include_tx_power_level=*/false,
343 /*address_type=*/std::nullopt,
344 GetSuccessCallback());
345
346 RunUntilIdle();
347
348 EXPECT_TRUE(last_status());
349 EXPECT_EQ(1u, ad_store().size());
350
351 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(kDefaultMaxAdSize + 1),
352 AdvertisingData(),
353 /*connect_callback=*/nullptr,
354 kTestInterval,
355 /*extended_pdu=*/true,
356 /*anonymous=*/false,
357 /*include_tx_power_level=*/false,
358 /*address_type=*/std::nullopt,
359 GetErrorCallback());
360
361 RunUntilIdle();
362
363 EXPECT_TRUE(last_status());
364 EXPECT_EQ(1u, ad_store().size());
365 }
366
367 // TODO: https://fxbug.dev/42083437 - Revise this test to use multiple
368 // advertising instances when multi-advertising is supported.
369 // - Stopping one that is registered stops it in the advertiser
370 // (and stops the right address)
371 // - Stopping an advertisement that isn't registered returns false
TEST_F(LowEnergyAdvertisingManagerTest,RegisterUnregister)372 TEST_F(LowEnergyAdvertisingManagerTest, RegisterUnregister) {
373 EXPECT_FALSE(adv_mgr()->StopAdvertising(kInvalidAdvertisementId));
374
375 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
376 AdvertisingData(),
377 /*connect_callback=*/nullptr,
378 kTestInterval,
379 /*extended_pdu=*/false,
380 /*anonymous=*/false,
381 /*include_tx_power_level=*/false,
382 /*address_type=*/std::nullopt,
383 GetSuccessCallback());
384
385 RunUntilIdle();
386
387 EXPECT_TRUE(last_status());
388 EXPECT_EQ(1u, ad_store().size());
389 EXPECT_TRUE(adv_mgr()->advertising());
390
391 EXPECT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
392 EXPECT_TRUE(ad_store().empty());
393 EXPECT_FALSE(adv_mgr()->advertising());
394
395 EXPECT_FALSE(adv_mgr()->StopAdvertising(last_ad_id()));
396 EXPECT_TRUE(ad_store().empty());
397 }
398
399 // - When the advertiser returns an error, we return an error
TEST_F(LowEnergyAdvertisingManagerTest,AdvertiserError)400 TEST_F(LowEnergyAdvertisingManagerTest, AdvertiserError) {
401 advertiser()->ErrorOnNext(
402 ToResult(pwemb::StatusCode::INVALID_HCI_COMMAND_PARAMETERS));
403
404 EXPECT_FALSE(adv_mgr()->advertising());
405 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
406 AdvertisingData(),
407 /*connect_callback=*/nullptr,
408 kTestInterval,
409 /*extended_pdu=*/false,
410 /*anonymous=*/false,
411 /*include_tx_power_level=*/false,
412 /*address_type=*/std::nullopt,
413 GetErrorCallback());
414 RunUntilIdle();
415
416 EXPECT_TRUE(last_status());
417 EXPECT_FALSE(adv_mgr()->advertising());
418 }
419
420 // - It calls the connectable callback correctly when connected to
TEST_F(LowEnergyAdvertisingManagerTest,ConnectCallback)421 TEST_F(LowEnergyAdvertisingManagerTest, ConnectCallback) {
422 std::unique_ptr<hci::LowEnergyConnection> link;
423 AdvertisementId advertised_id = kInvalidAdvertisementId;
424
425 auto connect_cb = [&](AdvertisementId connected_id,
426 std::unique_ptr<hci::LowEnergyConnection> cb_link) {
427 link = std::move(cb_link);
428 EXPECT_EQ(advertised_id, connected_id);
429 };
430 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
431 AdvertisingData(),
432 connect_cb,
433 kTestInterval,
434 /*extended_pdu=*/false,
435 /*anonymous=*/false,
436 /*include_tx_power_level=*/false,
437 /*address_type=*/std::nullopt,
438 GetSuccessCallback());
439
440 RunUntilIdle();
441
442 EXPECT_TRUE(last_status());
443 advertised_id = last_ad_id();
444
445 DeviceAddress peer_address(DeviceAddress::Type::kLEPublic,
446 {3, 2, 1, 1, 2, 3});
447 advertiser()->OnIncomingConnection(1,
448 pwemb::ConnectionRole::PERIPHERAL,
449 peer_address,
450 hci_spec::LEConnectionParameters());
451 RunUntilIdle();
452 ASSERT_TRUE(link);
453
454 // Make sure that the link has the correct local and peer addresses
455 // assigned.
456 EXPECT_EQ(kRandomAddress, link->local_address());
457 EXPECT_EQ(peer_address, link->peer_address());
458 }
459
460 // - Error: Connectable and Anonymous at the same time
TEST_F(LowEnergyAdvertisingManagerTest,ConnectAdvertiseError)461 TEST_F(LowEnergyAdvertisingManagerTest, ConnectAdvertiseError) {
462 auto connect_cb = [](AdvertisementId,
463 std::unique_ptr<hci::LowEnergyConnection>) {};
464
465 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
466 AdvertisingData(),
467 connect_cb,
468 kTestInterval,
469 /*extended_pdu=*/false,
470 /*anonymous=*/true,
471 /*include_tx_power_level=*/false,
472 /*address_type=*/std::nullopt,
473 GetErrorCallback());
474
475 EXPECT_TRUE(last_status());
476 }
477
478 // Passes the values for the data on. (anonymous, data, scan_rsp)
TEST_F(LowEnergyAdvertisingManagerTest,SendsCorrectData)479 TEST_F(LowEnergyAdvertisingManagerTest, SendsCorrectData) {
480 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
481 CreateFakeAdvertisingData(/*packed_size=*/21),
482 /*connect_callback=*/nullptr,
483 kTestInterval,
484 /*extended_pdu=*/false,
485 /*anonymous=*/false,
486 /*include_tx_power_level=*/false,
487 /*address_type=*/std::nullopt,
488 GetSuccessCallback());
489
490 RunUntilIdle();
491
492 EXPECT_TRUE(last_status());
493 EXPECT_EQ(1u, ad_store().size());
494
495 auto ad_status = &ad_store().begin()->second;
496
497 AdvertisingData expected_ad = CreateFakeAdvertisingData();
498 AdvertisingData expected_scan_rsp =
499 CreateFakeAdvertisingData(/*packed_size=*/21);
500 EXPECT_EQ(expected_ad, ad_status->data);
501 EXPECT_EQ(expected_scan_rsp, ad_status->scan_rsp);
502 EXPECT_EQ(false, ad_status->anonymous);
503 EXPECT_EQ(nullptr, ad_status->connect_cb);
504 }
505
506 // Test that the AdvertisingInterval values map to the spec defined constants
507 // (NOTE: this might change in the future in favor of a more advanced policy
508 // for managing the intervals; for now they get mapped to recommended values
509 // from Vol 3, Part C, Appendix A).
TEST_F(LowEnergyAdvertisingManagerTest,ConnectableAdvertisingIntervals)510 TEST_F(LowEnergyAdvertisingManagerTest, ConnectableAdvertisingIntervals) {
511 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
512 CreateFakeAdvertisingData(/*packed_size=*/21),
513 NopConnectCallback,
514 AdvertisingInterval::FAST1,
515 /*extended_pdu=*/false,
516 /*anonymous=*/false,
517 /*include_tx_power_level=*/false,
518 /*address_type=*/std::nullopt,
519 GetSuccessCallback());
520 RunUntilIdle();
521 ASSERT_TRUE(last_status());
522 ASSERT_TRUE(current_adv());
523 EXPECT_EQ(kLEAdvertisingFastIntervalMin1, current_adv()->interval_min);
524 EXPECT_EQ(kLEAdvertisingFastIntervalMax1, current_adv()->interval_max);
525 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
526
527 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
528 CreateFakeAdvertisingData(/*packed_size=*/21),
529 NopConnectCallback,
530 AdvertisingInterval::FAST2,
531 /*extended_pdu=*/false,
532 /*anonymous=*/false,
533 /*include_tx_power_level=*/false,
534 /*address_type=*/std::nullopt,
535 GetSuccessCallback());
536 RunUntilIdle();
537 ASSERT_TRUE(last_status());
538 ASSERT_TRUE(current_adv());
539 EXPECT_EQ(kLEAdvertisingFastIntervalMin2, current_adv()->interval_min);
540 EXPECT_EQ(kLEAdvertisingFastIntervalMax2, current_adv()->interval_max);
541 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
542
543 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
544 CreateFakeAdvertisingData(/*packed_size=*/21),
545 NopConnectCallback,
546 AdvertisingInterval::SLOW,
547 /*extended_pdu=*/false,
548 /*anonymous=*/false,
549 /*include_tx_power_level=*/false,
550 /*address_type=*/std::nullopt,
551 GetSuccessCallback());
552 RunUntilIdle();
553 ASSERT_TRUE(last_status());
554 ASSERT_TRUE(current_adv());
555 EXPECT_EQ(kLEAdvertisingSlowIntervalMin, current_adv()->interval_min);
556 EXPECT_EQ(kLEAdvertisingSlowIntervalMax, current_adv()->interval_max);
557 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
558 }
559
TEST_F(LowEnergyAdvertisingManagerTest,NonConnectableAdvertisingIntervals)560 TEST_F(LowEnergyAdvertisingManagerTest, NonConnectableAdvertisingIntervals) {
561 AdvertisingData fake_ad = CreateFakeAdvertisingData();
562 AdvertisingData scan_rsp = CreateFakeAdvertisingData(21 /* size of ad */);
563
564 // We expect FAST1 to fall back to FAST2 due to specification recommendation
565 // (Vol 3, Part C, Appendix A) and lack of support for non-connectable
566 // advertising with FAST1 parameters on certain controllers.
567 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
568 CreateFakeAdvertisingData(/*packed_size=*/21),
569 /*connect_callback=*/nullptr,
570 AdvertisingInterval::FAST1,
571 /*extended_pdu=*/false,
572 /*anonymous=*/false,
573 /*include_tx_power_level=*/false,
574 /*address_type=*/std::nullopt,
575 GetSuccessCallback());
576 RunUntilIdle();
577 ASSERT_TRUE(last_status());
578 ASSERT_TRUE(current_adv());
579 EXPECT_EQ(kLEAdvertisingFastIntervalMin2, current_adv()->interval_min);
580 EXPECT_EQ(kLEAdvertisingFastIntervalMax2, current_adv()->interval_max);
581 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
582
583 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
584 CreateFakeAdvertisingData(/*packed_size=*/21),
585 /*connect_callback=*/nullptr,
586 AdvertisingInterval::FAST2,
587 /*extended_pdu=*/false,
588 /*anonymous=*/false,
589 /*include_tx_power_level=*/false,
590 /*address_type=*/std::nullopt,
591 GetSuccessCallback());
592 RunUntilIdle();
593 ASSERT_TRUE(last_status());
594 ASSERT_TRUE(current_adv());
595 EXPECT_EQ(kLEAdvertisingFastIntervalMin2, current_adv()->interval_min);
596 EXPECT_EQ(kLEAdvertisingFastIntervalMax2, current_adv()->interval_max);
597 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
598
599 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
600 CreateFakeAdvertisingData(/*packed_size=*/21),
601 /*connect_callback=*/nullptr,
602 AdvertisingInterval::SLOW,
603 /*extended_pdu=*/false,
604 /*anonymous=*/false,
605 /*include_tx_power_level=*/false,
606 /*address_type=*/std::nullopt,
607 GetSuccessCallback());
608 RunUntilIdle();
609 ASSERT_TRUE(last_status());
610 ASSERT_TRUE(current_adv());
611 EXPECT_EQ(kLEAdvertisingSlowIntervalMin, current_adv()->interval_min);
612 EXPECT_EQ(kLEAdvertisingSlowIntervalMax, current_adv()->interval_max);
613 ASSERT_TRUE(adv_mgr()->StopAdvertising(last_ad_id()));
614 }
615
TEST_F(LowEnergyAdvertisingManagerTest,AdvertisePublicAddress)616 TEST_F(LowEnergyAdvertisingManagerTest, AdvertisePublicAddress) {
617 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
618 CreateFakeAdvertisingData(/*packed_size=*/21),
619 NopConnectCallback,
620 AdvertisingInterval::FAST1,
621 /*extended_pdu=*/false,
622 /*anonymous=*/false,
623 /*include_tx_power_level=*/false,
624 DeviceAddress::Type::kLEPublic,
625 GetSuccessCallback());
626 RunUntilIdle();
627 ASSERT_TRUE(last_status());
628 ASSERT_EQ(1u, ad_store().size());
629 EXPECT_TRUE(adv_mgr()->advertising());
630
631 // Verify that the advertiser uses the requested local address.
632 EXPECT_EQ(kPublicAddress, ad_store().begin()->first);
633 }
634
TEST_F(LowEnergyAdvertisingManagerTest,AdvertiseRandomAddress)635 TEST_F(LowEnergyAdvertisingManagerTest, AdvertiseRandomAddress) {
636 adv_mgr()->StartAdvertising(CreateFakeAdvertisingData(),
637 CreateFakeAdvertisingData(/*packed_size=*/21),
638 NopConnectCallback,
639 AdvertisingInterval::FAST1,
640 /*extended_pdu=*/false,
641 /*anonymous=*/false,
642 /*include_tx_power_level=*/false,
643 /*address_type=*/std::nullopt,
644 GetSuccessCallback());
645 RunUntilIdle();
646 ASSERT_TRUE(last_status());
647 ASSERT_EQ(1u, ad_store().size());
648 EXPECT_TRUE(adv_mgr()->advertising());
649
650 // Verify that the advertiser uses the requested local address.
651 EXPECT_EQ(kRandomAddress, ad_store().begin()->first);
652 }
653
TEST_F(LowEnergyAdvertisingManagerTest,DestroyingInstanceStopsAdvertisement)654 TEST_F(LowEnergyAdvertisingManagerTest, DestroyingInstanceStopsAdvertisement) {
655 {
656 AdvertisementInstance instance;
657 adv_mgr()->StartAdvertising(AdvertisingData(),
658 AdvertisingData(),
659 /*connect_callback=*/nullptr,
660 AdvertisingInterval::FAST1,
661 /*extended_pdu=*/false,
662 /*anonymous=*/false,
663 /*include_tx_power_level=*/false,
664 /*address_type=*/std::nullopt,
665 [&](AdvertisementInstance i, auto status) {
666 ASSERT_EQ(fit::ok(), status);
667 instance = std::move(i);
668 });
669 RunUntilIdle();
670 EXPECT_TRUE(adv_mgr()->advertising());
671
672 // Destroying |instance| should stop the advertisement.
673 }
674
675 RunUntilIdle();
676 EXPECT_FALSE(adv_mgr()->advertising());
677 }
678
TEST_F(LowEnergyAdvertisingManagerTest,MovingIntoInstanceStopsAdvertisement)679 TEST_F(LowEnergyAdvertisingManagerTest, MovingIntoInstanceStopsAdvertisement) {
680 AdvertisementInstance instance;
681 adv_mgr()->StartAdvertising(AdvertisingData(),
682 AdvertisingData(),
683 /*connect_callback=*/nullptr,
684 AdvertisingInterval::FAST1,
685 /*extended_pdu=*/false,
686 /*anonymous=*/false,
687 /*include_tx_power_level=*/false,
688 /*address_type=*/std::nullopt,
689 [&](AdvertisementInstance i, auto status) {
690 ASSERT_EQ(fit::ok(), status);
691 instance = std::move(i);
692 });
693 RunUntilIdle();
694 EXPECT_TRUE(adv_mgr()->advertising());
695
696 // Destroying |instance| by invoking the move assignment operator should
697 // stop the advertisement.
698 instance = {};
699 RunUntilIdle();
700 EXPECT_FALSE(adv_mgr()->advertising());
701 }
702
TEST_F(LowEnergyAdvertisingManagerTest,MovingInstanceTransfersOwnershipOfAdvertisement)703 TEST_F(LowEnergyAdvertisingManagerTest,
704 MovingInstanceTransfersOwnershipOfAdvertisement) {
705 auto instance = std::make_unique<AdvertisementInstance>();
706 adv_mgr()->StartAdvertising(AdvertisingData(),
707 AdvertisingData(),
708 /*connect_callback=*/nullptr,
709 AdvertisingInterval::FAST1,
710 /*extended_pdu=*/false,
711 /*anonymous=*/false,
712 /*include_tx_power_level=*/false,
713 /*address_type=*/std::nullopt,
714 [&](AdvertisementInstance i, auto status) {
715 ASSERT_EQ(fit::ok(), status);
716 *instance = std::move(i);
717 });
718 RunUntilIdle();
719 EXPECT_TRUE(adv_mgr()->advertising());
720
721 // Moving |instance| should transfer the ownership of the advertisement
722 // (assignment).
723 {
724 AdvertisementInstance move_assigned_instance = std::move(*instance);
725
726 // Explicitly clearing the old instance should have no effect.
727 *instance = {};
728 RunUntilIdle();
729 EXPECT_TRUE(adv_mgr()->advertising());
730
731 *instance = std::move(move_assigned_instance);
732 }
733
734 // Advertisement should not stop when |move_assigned_instance| goes out of
735 // scope as it no longer owns the advertisement.
736 RunUntilIdle();
737 EXPECT_TRUE(adv_mgr()->advertising());
738
739 // Moving |instance| should transfer the ownership of the advertisement
740 // (move-constructor).
741 {
742 AdvertisementInstance move_constructed_instance(std::move(*instance));
743
744 // Explicitly destroying the old instance should have no effect.
745 instance.reset();
746 RunUntilIdle();
747 EXPECT_TRUE(adv_mgr()->advertising());
748 }
749
750 // Advertisement should stop when |move_constructed_instance| goes out of
751 // scope.
752 RunUntilIdle();
753 EXPECT_FALSE(adv_mgr()->advertising());
754 }
755
756 } // namespace
757 } // namespace gap
758 } // namespace bt
759