• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_address_manager.h"
16 
17 #include "pw_bluetooth_sapphire/internal/host/common/log.h"
18 #include "pw_bluetooth_sapphire/internal/host/gap/gap.h"
19 #include "pw_bluetooth_sapphire/internal/host/sm/util.h"
20 
21 namespace bt::gap {
22 
LowEnergyAddressManager(const DeviceAddress & public_address,StateQueryDelegate delegate,hci::CommandChannel::WeakPtr cmd_channel,pw::async::Dispatcher & dispatcher)23 LowEnergyAddressManager::LowEnergyAddressManager(
24     const DeviceAddress& public_address,
25     StateQueryDelegate delegate,
26     hci::CommandChannel::WeakPtr cmd_channel,
27     pw::async::Dispatcher& dispatcher)
28     : dispatcher_(dispatcher),
29       delegate_(std::move(delegate)),
30       cmd_(std::move(cmd_channel)),
31       privacy_enabled_(false),
32       public_(public_address),
33       needs_refresh_(false),
34       refreshing_(false),
35       weak_self_(this) {
36   BT_DEBUG_ASSERT(public_.type() == DeviceAddress::Type::kLEPublic);
37   BT_DEBUG_ASSERT(delegate_);
38   BT_DEBUG_ASSERT(cmd_.is_alive());
39 }
40 
~LowEnergyAddressManager()41 LowEnergyAddressManager::~LowEnergyAddressManager() { CancelExpiry(); }
42 
EnablePrivacy(bool enabled)43 void LowEnergyAddressManager::EnablePrivacy(bool enabled) {
44   if (enabled == privacy_enabled_) {
45     bt_log(DEBUG,
46            "gap-le",
47            "privacy already %s",
48            (enabled ? "enabled" : "disabled"));
49     return;
50   }
51 
52   privacy_enabled_ = enabled;
53 
54   if (!enabled) {
55     CleanUpPrivacyState();
56     ResolveAddressRequests();
57     NotifyAddressUpdate();
58     return;
59   }
60 
61   needs_refresh_ = true;
62 
63   TryRefreshRandomAddress();
64 }
65 
EnsureLocalAddress(AddressCallback callback)66 void LowEnergyAddressManager::EnsureLocalAddress(AddressCallback callback) {
67   BT_DEBUG_ASSERT(callback);
68 
69   // Report the address right away if it doesn't need refreshing.
70   if (!needs_refresh_) {
71     callback(current_address());
72     return;
73   }
74 
75   address_callbacks_.push(std::move(callback));
76   TryRefreshRandomAddress();
77 }
78 
TryRefreshRandomAddress()79 void LowEnergyAddressManager::TryRefreshRandomAddress() {
80   if (!privacy_enabled_ || !needs_refresh_) {
81     bt_log(DEBUG, "gap-le", "address does not need refresh");
82     return;
83   }
84 
85   if (refreshing_) {
86     bt_log(DEBUG, "gap-le", "address update in progress");
87     return;
88   }
89 
90   if (!CanUpdateRandomAddress()) {
91     bt_log(DEBUG,
92            "gap-le",
93            "deferring local address refresh due to ongoing procedures");
94     // Don't stall procedures that requested the current address while in this
95     // state.
96     ResolveAddressRequests();
97     return;
98   }
99 
100   CancelExpiry();
101   refreshing_ = true;
102 
103   DeviceAddress random_addr;
104   if (irk_) {
105     random_addr = sm::util::GenerateRpa(*irk_);
106   } else {
107     random_addr = sm::util::GenerateRandomAddress(/*is_static=*/false);
108   }
109 
110   auto cmd = hci::EmbossCommandPacket::New<
111       pw::bluetooth::emboss::LESetRandomAddressCommandWriter>(
112       hci_spec::kLESetRandomAddress);
113   cmd.view_t().random_address().CopyFrom(random_addr.value().view());
114 
115   auto self = weak_self_.GetWeakPtr();
116   auto cmd_complete_cb = [self, this, random_addr](
117                              auto id, const hci::EventPacket& event) {
118     if (!self.is_alive()) {
119       return;
120     }
121 
122     refreshing_ = false;
123 
124     if (!privacy_enabled_) {
125       bt_log(DEBUG,
126              "gap-le",
127              "ignore random address result while privacy is disabled");
128       return;
129     }
130 
131     if (!hci_is_error(
132             event, TRACE, "gap-le", "failed to update random address")) {
133       needs_refresh_ = false;
134       random_ = random_addr;
135       bt_log(INFO, "gap-le", "random address updated: %s", bt_str(*random_));
136 
137       // Set the new random address to expire in kPrivateAddressTimeout.
138       random_address_expiry_task_.set_function(
139           [this](pw::async::Context /*ctx*/, pw::Status status) {
140             if (status.ok()) {
141               needs_refresh_ = true;
142               TryRefreshRandomAddress();
143             }
144           });
145       random_address_expiry_task_.PostAfter(kPrivateAddressTimeout);
146 
147       // Notify any listeners of the change in device address.
148       NotifyAddressUpdate();
149     }
150 
151     ResolveAddressRequests();
152   };
153 
154   cmd_->SendCommand(std::move(cmd), std::move(cmd_complete_cb));
155 }
156 
CleanUpPrivacyState()157 void LowEnergyAddressManager::CleanUpPrivacyState() {
158   privacy_enabled_ = false;
159   needs_refresh_ = false;
160   CancelExpiry();
161 }
162 
CancelExpiry()163 void LowEnergyAddressManager::CancelExpiry() {
164   random_address_expiry_task_.Cancel();
165 }
166 
CanUpdateRandomAddress() const167 bool LowEnergyAddressManager::CanUpdateRandomAddress() const {
168   BT_DEBUG_ASSERT(delegate_);
169   return delegate_();
170 }
171 
ResolveAddressRequests()172 void LowEnergyAddressManager::ResolveAddressRequests() {
173   auto address = current_address();
174   auto q = std::move(address_callbacks_);
175   bt_log(DEBUG, "gap-le", "using local address %s", address.ToString().c_str());
176   while (!q.empty()) {
177     q.front()(address);
178     q.pop();
179   }
180 }
181 
NotifyAddressUpdate()182 void LowEnergyAddressManager::NotifyAddressUpdate() {
183   auto address = current_address();
184   for (auto& cb : address_changed_callbacks_) {
185     cb(address);
186   }
187 }
188 
189 }  // namespace bt::gap
190