Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68b2d004 authored by Ben's avatar Ben Committed by Ben Lawson
Browse files

le_scanning_manager: Fix scannable advertisement event type

The legacy scan response 'connectable' event type bit was
hardcoded to 'true', which was incorrect for ADV_SCAN_IND
advertisements. This change stores the event type of
the original advertising report so that the 'connectable'
bit can be added to the scan response only if necessary
(for ADV_IND).

Bug: 312883465
Bug: 316013235
Test: atest LeScanningManagerTest
Test: atest LeScanningReassemblerTest
Change-Id: If192a9921ea5c93fac46b7532103163e907b7974
parent 61a68531
Loading
Loading
Loading
Loading
+20 −7
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <memory>
#include <unordered_map>

#include "android_bluetooth_flags.h"
#include "hci/acl_manager.h"
#include "hci/controller.h"
#include "hci/event_checkers.h"
@@ -373,8 +374,15 @@ struct LeScanningManager::impl : public LeAddressManagerCallback {
          extended_event_type = transform_to_extended_event_type({.legacy = true});
          break;
        case AdvertisingEventType::SCAN_RESPONSE:
          if (IS_FLAG_ENABLED(fix_nonconnectable_scannable_advertisement)) {
            // We don't know if the initial advertising report was connectable or not.
            // LeScanningReassembler fixes the connectable field.
            extended_event_type = transform_to_extended_event_type(
                {.scannable = true, .scan_response = true, .legacy = true});
          } else {
            extended_event_type = transform_to_extended_event_type(
                {.connectable = true, .scannable = true, .scan_response = true, .legacy = true});
          }
          break;
        default:
          LOG_WARN("Unsupported event type:%d", (uint16_t)report.event_type_);
@@ -450,10 +458,11 @@ struct LeScanningManager::impl : public LeAddressManagerCallback {
    scanning_reassembler_.SetIgnoreScanResponses(
        filter_policy_ == LeScanningFilterPolicy::FILTER_ACCEPT_LIST_ONLY);

    auto complete_advertising_data = scanning_reassembler_.ProcessAdvertisingReport(
    std::optional<LeScanningReassembler::CompleteAdvertisingData> processed_report =
        scanning_reassembler_.ProcessAdvertisingReport(
            event_type, address_type, address, advertising_sid, advertising_data);

    if (complete_advertising_data.has_value()) {
    if (processed_report.has_value()) {
      switch (address_type) {
        case (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS:
        case (uint8_t)AddressType::PUBLIC_IDENTITY_ADDRESS:
@@ -465,8 +474,12 @@ struct LeScanningManager::impl : public LeAddressManagerCallback {
          break;
      }

      const uint16_t result_event_type = IS_FLAG_ENABLED(fix_nonconnectable_scannable_advertisement)
                                             ? processed_report->extended_event_type
                                             : event_type;

      scanning_callbacks_->OnScanResult(
          event_type,
          result_event_type,
          address_type,
          address,
          primary_phy,
@@ -475,7 +488,7 @@ struct LeScanningManager::impl : public LeAddressManagerCallback {
          tx_power,
          get_rssi_after_calibration(rssi),
          periodic_advertising_interval,
          complete_advertising_data.value());
          std::move(processed_report->data));
    }
  }

+69 −3
Original line number Diff line number Diff line
@@ -29,12 +29,13 @@
#include <queue>
#include <vector>

#include "hci/hci_layer_fake.h"
#include "android_bluetooth_flags.h"
#include "common/bind.h"
#include "hci/acl_manager.h"
#include "hci/address.h"
#include "hci/controller.h"
#include "hci/hci_layer.h"
#include "hci/hci_layer_fake.h"
#include "hci/uuid.h"
#include "os/thread.h"
#include "packet/raw_builder.h"
@@ -51,6 +52,13 @@ using packet::RawBuilder;

namespace {

// Event type fields.
// TODO(b/315496838): Use a common enum for event type bits.
static constexpr uint16_t kConnectable = 0x1;
static constexpr uint16_t kScannable = 0x2;
static constexpr uint16_t kScanResponse = 0x8;
static constexpr uint16_t kLegacy = 0x10;

hci::AdvertisingPacketContentFilterCommand make_filter(const hci::ApcfFilterType& filter_type) {
  hci::AdvertisingPacketContentFilterCommand filter{};
  filter.filter_type = filter_type;
@@ -362,9 +370,11 @@ TEST_F(LeScanningManagerTest, start_scan_test) {
  // Enable scan
  le_scanning_manager->Scan(true);
  ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
  test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
  test_hci_layer_->IncomingEvent(
      LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
  ASSERT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
  test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
  test_hci_layer_->IncomingEvent(
      LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));

  LeAdvertisingResponse report = make_advertising_report();
  EXPECT_CALL(mock_callbacks_, OnScanResult);
@@ -372,6 +382,62 @@ TEST_F(LeScanningManagerTest, start_scan_test) {
  test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report}));
}

TEST_F(LeScanningManagerTest, legacy_adv_scan_ind_report_with_scan_response) {
  start_le_scanning_manager();

  le_scanning_manager->Scan(true);
  ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
  test_hci_layer_->IncomingEvent(
      LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
  ASSERT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
  test_hci_layer_->IncomingEvent(
      LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));

  LeAdvertisingResponse report = make_advertising_report();
  // Scannable & not connectable!
  report.event_type_ = AdvertisingEventType::ADV_SCAN_IND;

  test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report}));

  LeAdvertisingResponse scan_response = make_advertising_report();
  scan_response.event_type_ = AdvertisingEventType::SCAN_RESPONSE;

  // The 'connectable' bit should NOT be set.
  uint16_t extended_event_type = kLegacy | kScannable | kScanResponse;
  if (!IS_FLAG_ENABLED(fix_nonconnectable_scannable_advertisement)) {
    extended_event_type |= kConnectable;
  }
  EXPECT_CALL(mock_callbacks_, OnScanResult(extended_event_type, _, _, _, _, _, _, _, _, _));

  test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({scan_response}));
}

TEST_F(LeScanningManagerTest, legacy_adv_ind_report_with_scan_response) {
  start_le_scanning_manager();

  le_scanning_manager->Scan(true);
  ASSERT_EQ(OpCode::LE_SET_SCAN_PARAMETERS, test_hci_layer_->GetCommand().GetOpCode());
  test_hci_layer_->IncomingEvent(
      LeSetScanParametersCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
  ASSERT_EQ(OpCode::LE_SET_SCAN_ENABLE, test_hci_layer_->GetCommand().GetOpCode());
  test_hci_layer_->IncomingEvent(
      LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));

  LeAdvertisingResponse report = make_advertising_report();
  // Scannable & connectable!
  report.event_type_ = AdvertisingEventType::ADV_IND;

  test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report}));

  LeAdvertisingResponse scan_response = make_advertising_report();
  scan_response.event_type_ = AdvertisingEventType::SCAN_RESPONSE;

  uint16_t extended_event_type = kLegacy | kScannable | kConnectable | kScanResponse;
  EXPECT_CALL(mock_callbacks_, OnScanResult(extended_event_type, _, _, _, _, _, _, _, _, _));

  test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({scan_response}));
}

TEST_F(LeScanningManagerTest, is_ad_type_filter_supported_false_test) {
  start_le_scanning_manager();
  ASSERT_TRUE(fake_registry_.IsStarted(&HciLayer::Factory));
+19 −6
Original line number Diff line number Diff line
@@ -32,7 +32,8 @@

namespace bluetooth::hci {

std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessAdvertisingReport(
std::optional<LeScanningReassembler::CompleteAdvertisingData>
LeScanningReassembler::ProcessAdvertisingReport(
    uint16_t event_type,
    uint8_t address_type,
    Address address,
@@ -67,7 +68,7 @@ std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessAdvertisingRep

  // Concatenate the data with existing fragments.
  std::list<AdvertisingFragment>::iterator advertising_fragment =
      AppendFragment(key, advertising_data);
      AppendFragment(key, event_type, advertising_data);

  // Trim the advertising data when the complete payload is received.
  if (data_status != DataStatus::CONTINUING) {
@@ -89,9 +90,11 @@ std::optional<std::vector<uint8_t>> LeScanningReassembler::ProcessAdvertisingRep

  // Otherwise the full advertising report has been reassembled,
  // removed the cache entry and return the complete advertising data.
  std::vector<uint8_t> complete_advertising_data = std::move(advertising_fragment->data);
  CompleteAdvertisingData result{
      .extended_event_type = advertising_fragment->extended_event_type,
      .data = std::move(advertising_fragment->data)};
  cache_.erase(advertising_fragment);
  return complete_advertising_data;
  return result;
}

/// Trim the advertising data by removing empty or overflowing
@@ -140,9 +143,19 @@ bool LeScanningReassembler::AdvertisingKey::operator==(const AdvertisingKey& oth
/// If the advertiser is unknown a new entry is added, optionally by
/// dropping the oldest advertiser.
std::list<LeScanningReassembler::AdvertisingFragment>::iterator
LeScanningReassembler::AppendFragment(const AdvertisingKey& key, const std::vector<uint8_t>& data) {
LeScanningReassembler::AppendFragment(
    const AdvertisingKey& key, uint16_t extended_event_type, const std::vector<uint8_t>& data) {
  auto it = FindFragment(key);
  if (it != cache_.end()) {
    // Legacy scan responses don't contain a 'connectable' bit, so this adds the
    // 'connectable' bit from the initial report.
    if ((extended_event_type & (1 << kLegacyBit)) &&
        (extended_event_type & (1 << kScanResponseBit))) {
      it->extended_event_type =
          extended_event_type | (it->extended_event_type & (1 << kConnectableBit));
    } else {
      it->extended_event_type = extended_event_type;
    }
    it->data.insert(it->data.end(), data.cbegin(), data.cend());
    return it;
  }
@@ -151,7 +164,7 @@ LeScanningReassembler::AppendFragment(const AdvertisingKey& key, const std::vect
    cache_.pop_back();
  }

  cache_.emplace_front(key, data);
  cache_.emplace_front(key, extended_event_type, data);
  return cache_.begin();
}

+18 −5
Original line number Diff line number Diff line
@@ -29,14 +29,21 @@ namespace bluetooth::hci {

/// The LE Scanning reassembler is responsible for defragmenting
/// LE advertising reports that are too large to fit inside an HCI event
/// and were fragmented by the compiler.
/// and were fragmented by the controller.
/// The reassembler also joins scan response data with the
/// matching advertising data.

class LeScanningReassembler {
 public:
  struct CompleteAdvertisingData {
    uint16_t extended_event_type;
    std::vector<uint8_t> data;
  };

  LeScanningReassembler(){};

  LeScanningReassembler(const LeScanningReassembler&) = delete;

  LeScanningReassembler& operator=(const LeScanningReassembler&) = delete;

  /// Process an incoming advertsing report, extracted from any of the
@@ -44,7 +51,7 @@ class LeScanningReassembler {
  /// events.
  /// Returns the completed advertising data if the event was complete, or the
  /// completion of a fragmented advertising event.
  std::optional<std::vector<uint8_t>> ProcessAdvertisingReport(
  std::optional<CompleteAdvertisingData> ProcessAdvertisingReport(
      uint16_t event_type,
      uint8_t address_type,
      Address address,
@@ -62,6 +69,7 @@ class LeScanningReassembler {
  bool ignore_scan_responses_{false};

  /// Constants for parsing event_type.
  static constexpr uint8_t kConnectableBit = 0;
  static constexpr uint8_t kScannableBit = 1;
  static constexpr uint8_t kDirectedBit = 2;
  static constexpr uint8_t kScanResponseBit = 3;
@@ -89,10 +97,12 @@ class LeScanningReassembler {
  /// Packs incomplete advertising data.
  struct AdvertisingFragment {
    AdvertisingKey key;
    uint16_t extended_event_type;
    std::vector<uint8_t> data;

    AdvertisingFragment(const AdvertisingKey& key, const std::vector<uint8_t>& data)
        : key(key), data(data.begin(), data.end()) {}
    AdvertisingFragment(
        const AdvertisingKey& key, uint16_t extended_event_type, const std::vector<uint8_t>& data)
        : key(key), extended_event_type(extended_event_type), data(data.begin(), data.end()) {}
  };

  /// Advertising cache for de-fragmenting extended advertising reports,
@@ -105,9 +115,12 @@ class LeScanningReassembler {

  /// Advertising cache management methods.
  std::list<AdvertisingFragment>::iterator AppendFragment(
      const AdvertisingKey& key, const std::vector<uint8_t>& data);
      const AdvertisingKey& key, uint16_t extended_event_type, const std::vector<uint8_t>& data);

  void RemoveFragment(const AdvertisingKey& key);

  bool ContainsFragment(const AdvertisingKey& key);

  std::list<AdvertisingFragment>::iterator FindFragment(const AdvertisingKey& key);

  /// Trim the advertising data by removing empty or overflowing
+138 −79
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ using namespace std::chrono_literals;
namespace bluetooth::hci {

// Event type fields.
static constexpr uint16_t kConnectable = 0x1;
static constexpr uint16_t kScannable = 0x2;
static constexpr uint16_t kScanResponse = 0x8;
static constexpr uint16_t kLegacy = 0x10;
@@ -66,16 +67,19 @@ TEST_F(LeScanningReassemblerTest, trim_advertising_data) {
TEST_F(LeScanningReassemblerTest, non_scannable_legacy_advertising) {
  // Test non scannable legacy advertising.
  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kLegacy | kComplete,
              (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
              kTestAddress,
              kSidNotPresent,
          {0x1, 0x2}),
              {0x1, 0x2})
          .value()
          .data,
      std::vector<uint8_t>({0x1, 0x2}));
}

TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) {
TEST_F(LeScanningReassemblerTest, scannable_non_connectable_legacy_advertising) {
  // Test scannable legacy advertising with well formed advertising and
  // scan response payload.
  ASSERT_FALSE(reassembler_
@@ -87,14 +91,15 @@ TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) {
                       {0x1, 0x2})
                   .has_value());

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
  auto processed_report = reassembler_.ProcessAdvertisingReport(
      kLegacy | kScannable | kScanResponse | kComplete,
      (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
      kTestAddress,
      kSidNotPresent,
          {0x3, 0x4, 0x5, 0x6}),
      std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
      {0x3, 0x4, 0x5, 0x6});
  ASSERT_TRUE(processed_report.has_value());
  ASSERT_EQ(processed_report.value().extended_event_type, kLegacy | kScannable | kScanResponse);
  ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));

  // Test scannable legacy advertising with padding after the
  // advertising and scan response data.
@@ -108,15 +113,41 @@ TEST_F(LeScanningReassemblerTest, scannable_legacy_advertising) {
                   .has_value());

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kLegacy | kScannable | kScanResponse | kComplete,
              (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
              kTestAddress,
              kSidNotPresent,
          {0x3, 0x4, 0x5, 0x6, 0x0, 0x0}),
              {0x3, 0x4, 0x5, 0x6, 0x0, 0x0})
          .value()
          .data,
      std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
}

TEST_F(LeScanningReassemblerTest, scannable_connectable_legacy_advertising) {
  ASSERT_FALSE(reassembler_
                   .ProcessAdvertisingReport(
                       kLegacy | kScannable | kConnectable,
                       (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
                       kTestAddress,
                       kSidNotPresent,
                       {0x1, 0x2})
                   .has_value());

  auto processed_report = reassembler_.ProcessAdvertisingReport(
      kLegacy | kScannable | kScanResponse,
      (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
      kTestAddress,
      kSidNotPresent,
      {0x3, 0x4, 0x5, 0x6});
  ASSERT_TRUE(processed_report.has_value());
  ASSERT_EQ(
      processed_report.value().extended_event_type,
      kLegacy | kScannable | kScanResponse | kConnectable);
  ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
}

TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) {
  // Test fragmented non scannable extended advertising.
  // The split may occur in the middle of a GAP entry.
@@ -129,14 +160,15 @@ TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) {
                       {0x1, 0x2, 0x3})
                   .has_value());

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
  auto processed_report = reassembler_.ProcessAdvertisingReport(
      kComplete,
      (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
      kTestAddress,
      kSidNotPresent,
          {0x4, 0x5, 0x6}),
      std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
      {0x4, 0x5, 0x6});
  ASSERT_TRUE(processed_report.has_value());
  ASSERT_EQ(processed_report.value().extended_event_type, kComplete);
  ASSERT_EQ(processed_report.value().data, std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));

  // Test fragmented and truncated non scannable extended advertising.
  // The split may occur in the middle of a GAP entry.
@@ -150,12 +182,15 @@ TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) {
                   .has_value());

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kTruncated,
              (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
              kTestAddress,
              kSidNotPresent,
          {0x4, 0x5, 0x6, 0x7}),
              {0x4, 0x5, 0x6, 0x7})
          .value()
          .data,
      std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));

  // Test fragmented and truncated anonymous, non scannable
@@ -170,12 +205,15 @@ TEST_F(LeScanningReassemblerTest, non_scannable_extended_advertising) {
                   .has_value());

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kTruncated,
              (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
              Address::kEmpty,
              kSidNotPresent,
          {0x4, 0x5, 0x6, 0x7}),
              {0x4, 0x5, 0x6, 0x7})
          .value()
          .data,
      std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6}));
}

@@ -211,12 +249,15 @@ TEST_F(LeScanningReassemblerTest, scannable_extended_advertising) {
                   .has_value());

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kTruncated,
              (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
              kTestAddress,
              kSidNotPresent,
          {0xb, 0xc, 0xd, 0xe, 0x0}),
              {0xb, 0xc, 0xd, 0xe, 0x0})
          .value()
          .data,
      std::vector<uint8_t>({0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe}));
}

@@ -232,23 +273,29 @@ TEST_F(LeScanningReassemblerTest, ignore_scan_responses) {
                   .has_value());

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kComplete,
              (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
              kTestAddress,
              kSidNotPresent,
          {0x1, 0x2}),
              {0x1, 0x2})
          .value()
          .data,
      std::vector<uint8_t>({0x1, 0x2}));

  // The option ignore_scan_responses forces scan responses to be dropped.
  reassembler_.SetIgnoreScanResponses(true);
  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kScannable | kComplete,
              (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
              kTestAddress,
              kSidNotPresent,
          {0x1, 0x2}),
              {0x1, 0x2})
          .value()
          .data,
      std::vector<uint8_t>({0x1, 0x2}));
}

@@ -292,35 +339,47 @@ TEST_F(LeScanningReassemblerTest, interleaved_advertising) {
                   .has_value());

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kComplete,
              (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS,
              kTestAddress,
              kSidNotPresent,
          {0x0}),
              {0x0})
          .value()
          .data,
      std::vector<uint8_t>({0x2, 0x0, 0x0}));

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kComplete,
              (uint8_t)AddressType::RANDOM_DEVICE_ADDRESS,
              kTestAddress,
              kSidNotPresent,
          {0x1}),
              {0x1})
          .value()
          .data,
      std::vector<uint8_t>({0x2, 0x1, 0x1}));

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
          kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, 0x1, {0x2}),
      reassembler_
          .ProcessAdvertisingReport(
              kComplete, (uint8_t)AddressType::PUBLIC_DEVICE_ADDRESS, kTestAddress, 0x1, {0x2})
          .value()
          .data,
      std::vector<uint8_t>({0x2, 0x2, 0x2}));

  ASSERT_EQ(
      reassembler_.ProcessAdvertisingReport(
      reassembler_
          .ProcessAdvertisingReport(
              kComplete,
              (uint8_t)DirectAdvertisingAddressType::NO_ADDRESS_PROVIDED,
              Address::kEmpty,
              0x1,
          {0x3}),
              {0x3})
          .value()
          .data,
      std::vector<uint8_t>({0x2, 0x3, 0x3}));
}