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 #pragma once 16 #include <optional> 17 #include <queue> 18 19 #include "pw_bluetooth_sapphire/internal/host/common/device_address.h" 20 #include "pw_bluetooth_sapphire/internal/host/common/macros.h" 21 #include "pw_bluetooth_sapphire/internal/host/common/smart_task.h" 22 #include "pw_bluetooth_sapphire/internal/host/common/uint128.h" 23 #include "pw_bluetooth_sapphire/internal/host/hci/local_address_delegate.h" 24 #include "pw_bluetooth_sapphire/internal/host/transport/command_channel.h" 25 #include "pw_bluetooth_sapphire/internal/host/transport/error.h" 26 27 namespace bt { 28 29 namespace gap { 30 31 // Manages the local LE device address used in scan, legacy advertising, and 32 // connection initiation procedures. The primary purpose of this class is to 33 // defer updating the random device address if we believe that doing so is 34 // disallowed by the controller. This is the case when scanning or legacy 35 // advertising is enabled, according to the Core Spec v5.3, Vol 4, Part E, 36 // 7.8.4. 37 // 38 // Procedures that need to know the value of the local address (both connection 39 // and advertising procedures need to assign this to any resultant 40 // hci::Connection object for SMP pairing to function correctly) should call the 41 // EnsureLocalAddress() method to obtain it and to lazily refresh the address 42 // if required. 43 // 44 // The type and value of the local address depends on whether or not the privacy 45 // feature is in use. The potential states are as follows: 46 // 47 // * When privacy is DISABLED, the local address type and its value match 48 // the public device address that this object gets initialized with. 49 // 50 // * When privacy is ENABLED, the exact type and value depends on the state of 51 // link layer procedures at that time. The "HCI LE Set Random Address" 52 // command is used to assign the controller a random address, which it will 53 // use for the next active scan, legacy advertising, or initiation command 54 // with a random address type. A new local random address will be generated 55 // at a regular interval (see kPrivateAddressTimeout in gap.h). 56 // 57 // According to Vol 2, Part E, 7.8.4 the "HCI LE Set Random Address" 58 // command is disallowed when scanning or legacy advertising are enabled. 59 // Before any one of these procedures gets started, the EnsureLocalAddress() 60 // method should be called to update the random address if it is allowed by 61 // the controller (and the address needs a refresh). This function 62 // asynchronously returns the device address that should be used by the 63 // procedure. 64 // 65 // The state requested by EnablePrivacy() (enabled or disabled) may not take 66 // effect immediately if a scan, advertising, or connection procedure is in 67 // progress. The requested address type (public or private) will apply 68 // eventually when the controller allows it. 69 class LowEnergyAddressManager final : public hci::LocalAddressDelegate { 70 public: 71 // Function called when privacy is in use to determine if it is allowed to 72 // assign a new random address to the controller. This must return false if 73 // if scan, legacy advertising, and/or initiation procedures are in progress. 74 using StateQueryDelegate = fit::function<bool()>; 75 76 LowEnergyAddressManager(const DeviceAddress& public_address, 77 StateQueryDelegate delegate, 78 hci::CommandChannel::WeakPtr cmd_channel, 79 pw::async::Dispatcher& dispatcher); 80 ~LowEnergyAddressManager(); 81 82 // Assigns the IRK to generate a RPA for the next address refresh when privacy 83 // is enabled. set_irk(const std::optional<UInt128> & irk)84 void set_irk(const std::optional<UInt128>& irk) { irk_ = irk; } 85 86 // Enable or disable the privacy feature. When enabled, the controller will be 87 // configured to use a new random address if it is currently allowed to do so. 88 // If setting the random address is not allowed the update will be deferred 89 // until the the next successful attempt triggered by a call to 90 // TryRefreshRandomAddress(). 91 // 92 // If an IRK has been assigned and |enabled| is true, then the generated 93 // random addresses will each be a Resolvable Private Address that can be 94 // resolved with the IRK. Otherwise, Non-resolvable Private Addresses will be 95 // used. 96 void EnablePrivacy(bool enabled); 97 98 // Returns true if the privacy feature is currently enabled. PrivacyEnabled()99 bool PrivacyEnabled() const { return privacy_enabled_; } 100 101 // LocalAddressDelegate overrides: irk()102 std::optional<UInt128> irk() const override { return irk_; } identity_address()103 DeviceAddress identity_address() const override { return public_; } 104 void EnsureLocalAddress(std::optional<DeviceAddress::Type> address_type, 105 AddressCallback callback) override; 106 107 // Assign a callback to be notified any time the LE address changes. register_address_changed_callback(AddressCallback callback)108 void register_address_changed_callback(AddressCallback callback) { 109 address_changed_callbacks_.emplace_back(std::move(callback)); 110 } 111 112 // Return the current address. current_address()113 const DeviceAddress current_address() const { 114 return (privacy_enabled_ && random_) ? *random_ : public_; 115 } 116 public_address()117 const DeviceAddress public_address() const { return public_; } 118 119 private: 120 // Attempt to reconfigure the current random device address. 121 void TryRefreshRandomAddress(); 122 123 // Clears all privacy related state such that the random address will not be 124 // refreshed until privacy is re-enabled. |random_| is not modified and 125 // continues to reflect the most recently configured random address. 126 void CleanUpPrivacyState(); 127 128 void CancelExpiry(); 129 bool CanUpdateRandomAddress() const; 130 void ResolveAddressRequests(); 131 132 // Notifies all address changed listeners of the change in device address. 133 void NotifyAddressUpdate(); 134 135 pw::async::Dispatcher& dispatcher_; 136 137 StateQueryDelegate delegate_; 138 hci::CommandChannel::WeakPtr cmd_; 139 bool privacy_enabled_; 140 141 // The public device address (i.e. BD_ADDR) that is assigned to the 142 // controller. 143 const DeviceAddress public_; 144 145 // The random device address assigned to the controller by the most recent 146 // successful HCI_LE_Set_Random_Address command. std::nullopt if the command 147 // was never run successfully. 148 std::optional<DeviceAddress> random_; 149 150 // True if the random address needs a refresh. This is the case when 151 // a. Privacy is enabled and the random device address needs to get rotated; 152 // or 153 // b. Privacy has recently been enabled and the controller hasn't been 154 // programmed with the new address yet 155 bool needs_refresh_; 156 157 // True if a HCI command to update the random address is in progress. 158 bool refreshing_; 159 160 // The local identity resolving key. If present, it is used to generate RPAs 161 // when privacy is enabled. 162 std::optional<UInt128> irk_; 163 164 // Callbacks waiting to be notified of the local address. 165 std::queue<AddressCallback> address_callbacks_; 166 // Callbacks waiting to be notified of a change in the local address. 167 std::vector<AddressCallback> address_changed_callbacks_; 168 169 // The task that executes when a random address expires and needs to be 170 // refreshed. 171 SmartTask random_address_expiry_task_{dispatcher_}; 172 173 WeakSelf<LowEnergyAddressManager> weak_self_; 174 175 BT_DISALLOW_COPY_ASSIGN_AND_MOVE(LowEnergyAddressManager); 176 }; 177 178 } // namespace gap 179 } // namespace bt 180