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

Commit 877a2276 authored by Rahul Arya's avatar Rahul Arya
Browse files

Use correct address type based on address policy

There is an address policy global to the stack, as well as an address
type passed down from Java. We do not currently handle the various edge
cases caused by combinations of the two states properly in all the
advertising modes.

This CL pulls all that logic into a single function and reuses it across
advertising modes. The behavioral changes are to respect the
own_address_type in non-extended advertising, and to use the correct address
type when doing extended advertising with privacy disabled.

Test: unit
Bug: 268112598
Change-Id: I73f0fb18b6d32d708b081b8afa4e10122a1810c9
parent 39d32583
Loading
Loading
Loading
Loading
+85 −64
Original line number Diff line number Diff line
@@ -54,7 +54,8 @@ enum class AdvertisingFlag : uint8_t {
struct Advertiser {
  os::Handler* handler;
  AddressWithType current_address;
  AdvertiserAddressType requested_address_type;
  // note: may not be the same as the requested_address_type, depending on the address policy
  AdvertiserAddressType address_type;
  base::OnceCallback<void(uint8_t /* status */)> status_callback;
  base::OnceCallback<void(uint8_t /* status */)> timeout_callback;
  common::Callback<void(Address, AddressType)> scan_callback;
@@ -70,6 +71,31 @@ struct Advertiser {
  std::unique_ptr<os::Alarm> address_rotation_alarm;
};

/**
 * Determines the address type to use, based on the requested type and the address manager policy,
 * by selecting the "strictest" of the two. Strictness is defined in ascending order as
 * RPA -> NRPA -> Public. Thus:
 * (1) if the host only supports the public/static address policy, all advertisements will be public
 * (2) if the host supports only non-resolvable addresses, then advertisements will never use RPA
 * (3) if the host supports RPAs, then the requested type will always be honored
 */
AdvertiserAddressType GetAdvertiserAddressTypeFromRequestedTypeAndPolicy(
    AdvertiserAddressType requested_address_type, LeAddressManager::AddressPolicy address_policy) {
  switch (address_policy) {
    case LeAddressManager::AddressPolicy::USE_PUBLIC_ADDRESS:
    case LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS:
      return AdvertiserAddressType::PUBLIC;
    case LeAddressManager::AddressPolicy::USE_RESOLVABLE_ADDRESS:
      return requested_address_type;
    case LeAddressManager::AddressPolicy::USE_NON_RESOLVABLE_ADDRESS:
      return requested_address_type == AdvertiserAddressType::RESOLVABLE_RANDOM
                 ? AdvertiserAddressType::NONRESOLVABLE_RANDOM
                 : requested_address_type;
    default:
      LOG_ALWAYS_FATAL("unreachable");
  }
}

struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallback {
  impl(Module* module) : module_(module), le_advertising_interface_(nullptr), num_instances_(0) {}

@@ -287,22 +313,28 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
    }
  }

  /// Generates a random address for the advertiser, if supported by the address manager
  ///
  /// Note: Ignores whether the requested_address_type is PUBLIC/RANDOM (to match existing behavior
  /// in non-extended advertising where we don't check this) so if this matters (e.g. for extended
  /// advertising), make sure to check it separately
  AddressWithType request_random_advertiser_address(AdvertiserId id) {
    if (le_address_manager_->RotatingAddress()) {
      if (advertising_sets_[id].requested_address_type ==
          AdvertiserAddressType::NONRESOLVABLE_RANDOM) {
        return le_address_manager_->NewNonResolvableAddress();
  /// Generates an address for the advertiser
  AddressWithType new_advertiser_address(AdvertiserId id) {
    switch (advertising_sets_[id].address_type) {
      case AdvertiserAddressType::PUBLIC:
        if (le_address_manager_->GetAddressPolicy() ==
            LeAddressManager::AddressPolicy::USE_STATIC_ADDRESS) {
          return le_address_manager_->GetInitiatorAddress();
        } else {
        return le_address_manager_->NewResolvableAddress();
          return AddressWithType(controller_->GetMacAddress(), AddressType::PUBLIC_DEVICE_ADDRESS);
        }
    } else {
      case AdvertiserAddressType::RESOLVABLE_RANDOM:
        if (advertising_api_type_ == AdvertisingApiType::LEGACY) {
          // we reuse the initiator address if we are a legacy advertiser using privacy,
          // since there's no way to use a different address
          return le_address_manager_->GetInitiatorAddress();
        }
        return le_address_manager_->NewResolvableAddress();
      case AdvertiserAddressType::NONRESOLVABLE_RANDOM:
        return le_address_manager_->NewNonResolvableAddress();
      default:
        LOG_ALWAYS_FATAL("unreachable");
    }
  }

  void create_advertiser(
@@ -324,18 +356,20 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
    advertising_sets_[id].scan_callback = scan_callback;
    advertising_sets_[id].set_terminated_callback = set_terminated_callback;
    advertising_sets_[id].handler = handler;
    advertising_sets_[id].requested_address_type = config.requested_advertiser_address_type;
    advertising_sets_[id].current_address = AddressWithType{};

    if (!address_manager_registered) {
      le_address_manager_->Register(this);
      address_manager_registered = true;
    }

    advertising_sets_[id].address_type = GetAdvertiserAddressTypeFromRequestedTypeAndPolicy(
        config.requested_advertiser_address_type, le_address_manager_->GetAddressPolicy());

    advertising_sets_[id].current_address = new_advertiser_address(id);
    set_parameters(id, config);

    switch (advertising_api_type_) {
      case (AdvertisingApiType::LEGACY): {
        advertising_sets_[id].current_address = request_random_advertiser_address(id);
        set_parameters(id, config);
        if (config.advertising_type == AdvertisingType::ADV_IND ||
            config.advertising_type == AdvertisingType::ADV_NONCONN_IND) {
          set_data(id, true, config.scan_response);
@@ -348,14 +382,12 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
        }
      } break;
      case (AdvertisingApiType::ANDROID_HCI): {
        advertising_sets_[id].current_address = request_random_advertiser_address(id);
        set_parameters(id, config);
        if (config.advertising_type == AdvertisingType::ADV_IND ||
            config.advertising_type == AdvertisingType::ADV_NONCONN_IND) {
          set_data(id, true, config.scan_response);
        }
        set_data(id, false, config.advertisement);
        if (le_address_manager_->RotatingAddress()) {
        if (advertising_sets_[id].address_type != AdvertiserAddressType::PUBLIC) {
          le_advertising_interface_->EnqueueCommand(
              hci::LeMultiAdvtSetRandomAddrBuilder::Create(advertising_sets_[id].current_address.GetAddress(), id),
              module_handler_->BindOnce(impl::check_status<LeMultiAdvtCompleteView>));
@@ -422,14 +454,16 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
    advertising_sets_[id].duration = duration;
    advertising_sets_[id].max_extended_advertising_events = max_ext_adv_events;
    advertising_sets_[id].handler = handler;
    advertising_sets_[id].requested_address_type = config.requested_advertiser_address_type;
    advertising_sets_[id].address_type = GetAdvertiserAddressTypeFromRequestedTypeAndPolicy(
        config.requested_advertiser_address_type, le_address_manager_->GetAddressPolicy());
    advertising_sets_[id].current_address = new_advertiser_address(id);

    switch (config.requested_advertiser_address_type) {
      case AdvertiserAddressType::RESOLVABLE_RANDOM:
      case AdvertiserAddressType::NONRESOLVABLE_RANDOM:
        if (le_address_manager_->RotatingAddress()) {
          advertising_sets_[id].current_address = request_random_advertiser_address(id);
    set_parameters(id, config);

    if (advertising_sets_[id].current_address.GetAddressType() !=
        AddressType::PUBLIC_DEVICE_ADDRESS) {
      // if we aren't using the public address type at the HCI level, we need to set the random
      // address
      le_advertising_interface_->EnqueueCommand(
          hci::LeSetAdvertisingSetRandomAddressBuilder::Create(
              id, advertising_sets_[id].current_address.GetAddress()),
@@ -440,28 +474,16 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
              id,
              advertising_sets_[id].current_address));

      // but we only rotate if the AdvertiserAddressType is non-public (since static random
      // addresses don't rotate)
      if (advertising_sets_[id].address_type != AdvertiserAddressType::PUBLIC) {
        // start timer for random address
        advertising_sets_[id].address_rotation_alarm = std::make_unique<os::Alarm>(module_handler_);
        advertising_sets_[id].address_rotation_alarm->Schedule(
              common::BindOnce(&impl::set_advertising_set_random_address_on_timer, common::Unretained(this), id),
            common::BindOnce(
                &impl::set_advertising_set_random_address_on_timer, common::Unretained(this), id),
            le_address_manager_->GetNextPrivateAddressIntervalMs());
        } else {
          advertising_sets_[id].current_address = le_address_manager_->GetInitiatorAddress();
          le_advertising_interface_->EnqueueCommand(
              hci::LeSetAdvertisingSetRandomAddressBuilder::Create(
                  id, advertising_sets_[id].current_address.GetAddress()),
              module_handler_->BindOnce(impl::check_status<LeSetAdvertisingSetRandomAddressCompleteView>));
          set_parameters(id, config);
      }
        break;
      case AdvertiserAddressType::PUBLIC:
        advertising_sets_[id].current_address =
            AddressWithType(controller_->GetMacAddress(), AddressType::PUBLIC_DEVICE_ADDRESS);
        set_parameters(id, config);
        break;
      default:
        LOG_ALWAYS_FATAL(
            "Unsupported Advertising Type %d", config.requested_advertiser_address_type);
    }
    if (config.advertising_type == AdvertisingType::ADV_IND ||
        config.advertising_type == AdvertisingType::ADV_NONCONN_IND) {
@@ -528,7 +550,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb

  void rotate_advertiser_address(AdvertiserId advertiser_id) {
    if (advertising_api_type_ == AdvertisingApiType::EXTENDED) {
      AddressWithType address_with_type = request_random_advertiser_address(advertiser_id);
      AddressWithType address_with_type = new_advertiser_address(advertiser_id);
      le_advertising_interface_->EnqueueCommand(
          hci::LeSetAdvertisingSetRandomAddressBuilder::Create(advertiser_id, address_with_type.GetAddress()),
          module_handler_->BindOnceOn(
@@ -596,8 +618,7 @@ struct LeAdvertisingManager::impl : public bluetooth::hci::LeAddressManagerCallb
    advertising_sets_[advertiser_id].tx_power = config.tx_power;
    advertising_sets_[advertiser_id].directed = config.directed;

    // note: does not necessarily match config.requested_advertiser_address_type, since we will
    // ignore the config but instead always use PUBLIC if the device does not support privacy
    // based on logic in new_advertiser_address
    auto own_address_type = static_cast<OwnAddressType>(
        advertising_sets_[advertiser_id].current_address.GetAddressType());

+28 −2
Original line number Diff line number Diff line
@@ -324,7 +324,6 @@ class LeAndroidHciAdvertisingAPITest : public LeAndroidHciAdvertisingManagerTest
        SubOcf::SET_PARAM,
        SubOcf::SET_SCAN_RESP,
        SubOcf::SET_DATA,
        SubOcf::SET_RANDOM_ADDR,
        SubOcf::SET_ENABLE,
    };
    EXPECT_CALL(
@@ -522,7 +521,6 @@ TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) {
      SubOcf::SET_PARAM,
      SubOcf::SET_SCAN_RESP,
      SubOcf::SET_DATA,
      SubOcf::SET_RANDOM_ADDR,
      SubOcf::SET_ENABLE,
  };
  EXPECT_CALL(
@@ -1339,6 +1337,34 @@ TEST_F(LeExtendedAdvertisingManagerTest, use_non_resolvable_address) {
  EXPECT_EQ(address.data()[5] >> 6, 0b00);
}

TEST_F(LeExtendedAdvertisingManagerTest, use_public_address_type_if_public_address_policy) {
  // arrange: use PUBLIC address policy
  test_acl_manager_->SetAddressPolicy(LeAddressManager::AddressPolicy::USE_PUBLIC_ADDRESS);

  // act: start advertising set with RPA
  le_advertising_manager_->ExtendedCreateAdvertiser(
      0x00,
      AdvertisingConfig{
          .requested_advertiser_address_type = AdvertiserAddressType::RESOLVABLE_RANDOM,
          .channel_map = 1,
      },
      scan_callback,
      set_terminated_callback,
      0,
      0,
      client_handler_);
  auto command = LeAdvertisingCommandView::Create(test_hci_layer_->GetCommand());

  // assert
  ASSERT_TRUE(command.IsValid());
  EXPECT_EQ(command.GetOpCode(), OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS);

  auto set_parameters_command =
      LeSetExtendedAdvertisingParametersView::Create(LeAdvertisingCommandView::Create(command));
  ASSERT_TRUE(set_parameters_command.IsValid());
  EXPECT_EQ(set_parameters_command.GetOwnAddressType(), OwnAddressType::PUBLIC_DEVICE_ADDRESS);
}

}  // namespace
}  // namespace hci
}  // namespace bluetooth