mirror of https://github.com/ARMmbed/mbed-os.git
746 lines
21 KiB
C++
746 lines
21 KiB
C++
/* mbed Microcontroller Library
|
|
* Copyright (c) 2020 ARM Limited
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#if BLE_FEATURE_PRIVACY
|
|
|
|
#include "PrivateAddressController.h"
|
|
|
|
namespace ble {
|
|
|
|
PrivateAddressController::PrivateAddressController(
|
|
PalPrivateAddressController &address_generator,
|
|
PalEventQueue &event_queue,
|
|
ble::resolvable_address_timeout_t rotation_timeout
|
|
) :
|
|
_pal(address_generator) ,
|
|
_event_queue(event_queue),
|
|
_rotation_timeout(rotation_timeout)
|
|
{
|
|
_pal.initialize();
|
|
_pal.set_event_handler(this);
|
|
|
|
#if BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
auto** next = &_free_resolution_entries;
|
|
for (auto &entry : _resolution_list) {
|
|
*next = &entry;
|
|
next = &entry.next;
|
|
}
|
|
#endif // BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
}
|
|
|
|
PrivateAddressController::~PrivateAddressController()
|
|
{
|
|
clear_privacy_control_blocks();
|
|
_pal.terminate();
|
|
}
|
|
|
|
void PrivateAddressController::set_local_irk(const irk_t &local_irk)
|
|
{
|
|
_local_irk = local_irk;
|
|
generate_resolvable_address();
|
|
}
|
|
|
|
void PrivateAddressController::set_timeout(ble::resolvable_address_timeout_t rotation_timeout)
|
|
{
|
|
_rotation_timeout = rotation_timeout;
|
|
_pal.set_ll_resolvable_private_address_timeout(rotation_timeout);
|
|
if (_generation_started) {
|
|
stop_private_address_generation();
|
|
start_private_address_generation();
|
|
}
|
|
}
|
|
|
|
const address_t& PrivateAddressController::get_resolvable_private_address()
|
|
{
|
|
return _resolvable_address;
|
|
}
|
|
|
|
const address_t& PrivateAddressController::get_non_resolvable_private_address()
|
|
{
|
|
return _non_resolvable_address;
|
|
}
|
|
|
|
void PrivateAddressController::set_event_handler(EventHandler *handler)
|
|
{
|
|
_event_handler = handler;
|
|
}
|
|
|
|
void PrivateAddressController::start_private_address_generation()
|
|
{
|
|
if (_generation_started) {
|
|
return;
|
|
}
|
|
|
|
// non resolvable private address generation has been delayed until now,
|
|
// generate it.
|
|
generate_non_resolvable_address();
|
|
|
|
_address_rotation_ticker.attach([this] {
|
|
_event_queue.post([this]{
|
|
generate_resolvable_address();
|
|
generate_non_resolvable_address();
|
|
});
|
|
}, _rotation_timeout.valueChrono());
|
|
_generation_started = true;
|
|
}
|
|
|
|
void PrivateAddressController::stop_private_address_generation()
|
|
{
|
|
if (_generation_started) {
|
|
_address_rotation_ticker.detach();
|
|
_generation_started = false;
|
|
}
|
|
}
|
|
|
|
void PrivateAddressController::generate_resolvable_address()
|
|
{
|
|
if (_local_irk != irk_t{}) {
|
|
_pal.generate_resolvable_private_address(_local_irk);
|
|
}
|
|
}
|
|
|
|
void PrivateAddressController::on_resolvable_private_address_generated(const address_t &rpa)
|
|
{
|
|
_resolvable_address = rpa;
|
|
if (_event_handler) {
|
|
_event_handler->on_resolvable_private_addresses_generated(_resolvable_address);
|
|
}
|
|
}
|
|
|
|
void PrivateAddressController::generate_non_resolvable_address()
|
|
{
|
|
_non_resolvable_address = _pal.generate_non_resolvable_private_address();
|
|
_event_queue.post([this] {
|
|
if (_event_handler) {
|
|
_event_handler->on_non_resolvable_private_addresses_generated(_non_resolvable_address);
|
|
}
|
|
});
|
|
}
|
|
|
|
bool PrivateAddressController::is_controller_privacy_supported()
|
|
{
|
|
return _pal.is_ll_privacy_supported();
|
|
}
|
|
|
|
#if !BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
ble_error_t PrivateAddressController::enable_controller_address_resolution(bool enable)
|
|
{
|
|
MBED_ASSERT(is_controller_privacy_supported());
|
|
return _pal.set_ll_address_resolution(enable);
|
|
}
|
|
#endif // !BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
|
|
uint8_t PrivateAddressController::read_resolving_list_capacity()
|
|
{
|
|
#if BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
return BLE_SECURITY_DATABASE_MAX_ENTRIES;
|
|
#else
|
|
if (is_controller_privacy_supported()) {
|
|
return _pal.read_resolving_list_capacity();
|
|
} else {
|
|
return 0;
|
|
}
|
|
#endif //BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
}
|
|
|
|
uint8_t PrivateAddressController::read_resolving_list_size()
|
|
{
|
|
return _resolving_list_size;
|
|
}
|
|
|
|
ble_error_t PrivateAddressController::add_device_to_resolving_list(
|
|
target_peer_address_type_t peer_address_type,
|
|
const address_t &peer_identity_address,
|
|
const irk_t& peer_irk
|
|
)
|
|
{
|
|
if (_local_irk == irk_t{}) {
|
|
return BLE_ERROR_INVALID_STATE;
|
|
}
|
|
|
|
#if BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
// ensure an entry is not added twice
|
|
for (auto &entry : _resolving_list) {
|
|
if (entry.populated &&
|
|
entry.peer_address_type == peer_address_type &&
|
|
entry.peer_address == peer_identity_address &&
|
|
entry.peer_irk == peer_irk
|
|
) {
|
|
return BLE_ERROR_NONE;
|
|
}
|
|
}
|
|
|
|
bool entry_added = false;
|
|
for (auto &entry : _resolving_list) {
|
|
if (entry.populated == false) {
|
|
entry.peer_address_type = peer_address_type;
|
|
entry.peer_address = peer_identity_address;
|
|
entry.peer_irk = peer_irk;
|
|
entry.populated = true;
|
|
entry_added = true;
|
|
_resolving_list_size++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!entry_added) {
|
|
return BLE_ERROR_NO_MEM;
|
|
}
|
|
|
|
|
|
// Remove unresolved entries from the resolved list
|
|
remove_resolution_entry_from_cache(
|
|
[&](resolution_entry_t &entry) {
|
|
return entry.identity == nullptr;
|
|
}
|
|
);
|
|
|
|
// reset pending resolution request
|
|
restart_resolution_process_on_host();
|
|
|
|
return BLE_ERROR_NO_MEM;
|
|
#else
|
|
if (is_controller_privacy_supported()) {
|
|
return queue_add_device_to_resolving_list(
|
|
peer_address_type,
|
|
peer_identity_address,
|
|
peer_irk
|
|
);
|
|
} else {
|
|
return BLE_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
#endif // BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
}
|
|
|
|
ble_error_t PrivateAddressController::remove_device_from_resolving_list(
|
|
target_peer_address_type_t peer_address_type,
|
|
const address_t &peer_identity_address
|
|
)
|
|
{
|
|
#if BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
for (auto &entry : _resolving_list) {
|
|
if (entry.populated &&
|
|
entry.peer_address_type == peer_address_type &&
|
|
entry.peer_address == peer_identity_address
|
|
) {
|
|
remove_resolution_entry_from_cache([&](resolution_entry_t& cache_entry) {
|
|
return cache_entry.identity == &entry;
|
|
});
|
|
|
|
entry.populated = false;
|
|
_resolving_list_size--;
|
|
|
|
restart_resolution_process_on_host();
|
|
}
|
|
}
|
|
return BLE_ERROR_NONE;
|
|
#else
|
|
if (is_controller_privacy_supported()) {
|
|
return queue_remove_device_from_resolving_list(peer_address_type, peer_identity_address);
|
|
} else {
|
|
return BLE_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
#endif // BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
}
|
|
|
|
ble_error_t PrivateAddressController::clear_resolving_list()
|
|
{
|
|
#if BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
// Remove entry from the resolving list
|
|
for (auto &entry : _resolving_list) {
|
|
entry.populated = false;
|
|
}
|
|
// Remove all resolved entries from the cache
|
|
remove_resolution_entry_from_cache([&](resolution_entry_t& entry) {
|
|
return entry.identity != nullptr;
|
|
});
|
|
_resolving_list_size = 0;
|
|
|
|
restart_resolution_process_on_host();
|
|
|
|
return BLE_ERROR_NONE;
|
|
#else
|
|
if (is_controller_privacy_supported()) {
|
|
return queue_clear_resolving_list();
|
|
} else {
|
|
return BLE_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
#endif // BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
}
|
|
|
|
#if BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
|
|
bool PrivateAddressController::resolve_address_in_host_cache(
|
|
const address_t &peer_address,
|
|
target_peer_address_type_t *retrieved_address_type,
|
|
const address_t **retrieved_address
|
|
)
|
|
{
|
|
// An LRU cache is used, we first traverse the list of resolved address
|
|
// and return any match
|
|
auto *entry = _resolved_list;
|
|
decltype(entry) previous = nullptr;
|
|
while (entry) {
|
|
if (entry->address == peer_address) {
|
|
// The list contains resolved addresses AND unresolved addresses.
|
|
// Fill input parameters accordingly
|
|
if (entry->identity) {
|
|
*retrieved_address = &entry->identity->peer_address;
|
|
*retrieved_address_type = entry->identity->peer_address_type;
|
|
} else {
|
|
*retrieved_address = nullptr;
|
|
}
|
|
// update cache if we're not at the first entry
|
|
if (previous) {
|
|
previous->next = entry->next;
|
|
entry->next = _resolved_list;
|
|
_resolved_list = entry;
|
|
}
|
|
return true;
|
|
}
|
|
previous = entry;
|
|
entry = entry->next;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ble_error_t PrivateAddressController::resolve_address_on_host(
|
|
const address_t &peer_address,
|
|
bool *resolution_complete,
|
|
target_peer_address_type_t *retrieved_address_type,
|
|
const address_t **retrieved_address
|
|
)
|
|
{
|
|
*resolution_complete = resolve_address_in_host_cache(peer_address, retrieved_address_type, retrieved_address);
|
|
|
|
// In the case the address has not been resolved, we start the resolution
|
|
// process.
|
|
if (*resolution_complete) {
|
|
return BLE_ERROR_NONE;
|
|
} else {
|
|
return queue_resolve_address_on_host(peer_address);
|
|
}
|
|
}
|
|
#endif // BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
|
|
void PrivateAddressController::on_resolving_list_action_complete()
|
|
{
|
|
process_privacy_control_blocks(true);
|
|
}
|
|
|
|
struct PrivateAddressController::PrivacyControlBlock {
|
|
PrivacyControlBlock() : _next(nullptr)
|
|
{
|
|
}
|
|
|
|
virtual ~PrivacyControlBlock() = default;
|
|
|
|
// return trie if the handler has completed and false otherwise.
|
|
virtual bool execute(PrivateAddressController& self) = 0;
|
|
|
|
void set_next(PrivacyControlBlock *next)
|
|
{
|
|
_next = next;
|
|
}
|
|
|
|
PrivacyControlBlock *next() const
|
|
{
|
|
return _next;
|
|
}
|
|
|
|
private:
|
|
PrivacyControlBlock *_next;
|
|
};
|
|
|
|
#if !BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
struct PrivateAddressController::PrivacyAddDevToResListControlBlock final :
|
|
PrivateAddressController::PrivacyControlBlock {
|
|
PrivacyAddDevToResListControlBlock(
|
|
advertising_peer_address_type_t peer_identity_address_type,
|
|
const address_t &peer_identity_address,
|
|
const irk_t &peer_irk
|
|
) : PrivacyControlBlock(),
|
|
_peer_identity_address_type(peer_identity_address_type),
|
|
_peer_identity_address(peer_identity_address),
|
|
_peer_irk(peer_irk)
|
|
{
|
|
}
|
|
|
|
bool execute(PrivateAddressController& self) final
|
|
{
|
|
// Execute command
|
|
self._pal.add_device_to_resolving_list(
|
|
_peer_identity_address_type,
|
|
_peer_identity_address,
|
|
_peer_irk,
|
|
self._local_irk
|
|
);
|
|
self._resolving_list_size++;
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
advertising_peer_address_type_t _peer_identity_address_type;
|
|
address_t _peer_identity_address;
|
|
irk_t _peer_irk;
|
|
};
|
|
|
|
ble_error_t PrivateAddressController::queue_add_device_to_resolving_list(
|
|
advertising_peer_address_type_t peer_identity_address_type,
|
|
const address_t &peer_identity_address,
|
|
const irk_t &peer_irk
|
|
)
|
|
{
|
|
auto *cb = new(std::nothrow) PrivacyAddDevToResListControlBlock(
|
|
peer_identity_address_type,
|
|
peer_identity_address,
|
|
peer_irk
|
|
);
|
|
if (cb == nullptr) {
|
|
// Cannot go further
|
|
return BLE_ERROR_NO_MEM;
|
|
}
|
|
|
|
queue_privacy_control_block(cb);
|
|
|
|
return BLE_ERROR_NONE;
|
|
}
|
|
|
|
struct PrivateAddressController::PrivacyRemoveDevFromResListControlBlock final :
|
|
PrivateAddressController::PrivacyControlBlock {
|
|
PrivacyRemoveDevFromResListControlBlock(
|
|
advertising_peer_address_type_t peer_identity_address_type,
|
|
const address_t &peer_identity_address
|
|
) : PrivacyControlBlock(),
|
|
_peer_identity_address_type(peer_identity_address_type),
|
|
_peer_identity_address(peer_identity_address)
|
|
{
|
|
}
|
|
|
|
bool execute(PrivateAddressController& self) final
|
|
{
|
|
// Execute command
|
|
self._pal.remove_device_from_resolving_list(
|
|
_peer_identity_address_type,
|
|
_peer_identity_address
|
|
);
|
|
self._resolving_list_size--;
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
advertising_peer_address_type_t _peer_identity_address_type;
|
|
address_t _peer_identity_address;
|
|
};
|
|
|
|
ble_error_t PrivateAddressController::queue_remove_device_from_resolving_list(
|
|
advertising_peer_address_type_t peer_identity_address_type,
|
|
const address_t &peer_identity_address
|
|
)
|
|
{
|
|
auto *cb = new(std::nothrow) PrivacyRemoveDevFromResListControlBlock(
|
|
peer_identity_address_type,
|
|
peer_identity_address
|
|
);
|
|
if (cb == nullptr) {
|
|
// Cannot go further
|
|
return BLE_ERROR_NO_MEM;
|
|
}
|
|
|
|
queue_privacy_control_block(cb);
|
|
return BLE_ERROR_NONE;
|
|
}
|
|
|
|
struct PrivateAddressController::PrivacyClearResListControlBlock final :
|
|
PrivateAddressController::PrivacyControlBlock {
|
|
PrivacyClearResListControlBlock() : PrivacyControlBlock()
|
|
{
|
|
}
|
|
|
|
bool execute(PrivateAddressController& self) final
|
|
{
|
|
// Execute command
|
|
self._pal.clear_resolving_list();
|
|
self._resolving_list_size = 0;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
ble_error_t PrivateAddressController::queue_clear_resolving_list()
|
|
{
|
|
// Remove any pending control blocks, there's no point executing them as we're about to queue the list
|
|
clear_privacy_control_blocks();
|
|
|
|
auto *cb = new(std::nothrow) PrivacyClearResListControlBlock();
|
|
if (cb == nullptr) {
|
|
// Cannot go further
|
|
return BLE_ERROR_NO_MEM;
|
|
}
|
|
|
|
queue_privacy_control_block(cb);
|
|
return BLE_ERROR_NONE;
|
|
}
|
|
#endif // !BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
|
|
#if BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
struct PrivateAddressController::PrivacyResolveAddressOnHost final :
|
|
PrivateAddressController::PrivacyControlBlock {
|
|
PrivacyResolveAddressOnHost(const address_t &peer_address) :
|
|
PrivacyControlBlock(),
|
|
peer_address(peer_address)
|
|
{
|
|
}
|
|
|
|
bool execute(PrivateAddressController& self) final
|
|
{
|
|
if (!self._resolving_list[resolving_list_index].populated) {
|
|
// no entry at index 0, move to the next
|
|
return start_next_resolution_round(self);
|
|
} else {
|
|
// start the resolution process with the first entry on the list
|
|
start_resolution(self);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool on_resolution_complete(PrivateAddressController& self, bool resolved)
|
|
{
|
|
if (require_restart) {
|
|
require_restart = false;
|
|
resolving_list_index = 0;
|
|
return execute(self);
|
|
} else if (resolved) {
|
|
notify_completion(
|
|
self, peer_address, resolved,
|
|
&self._resolving_list[resolving_list_index]
|
|
);
|
|
return true;
|
|
} else {
|
|
return start_next_resolution_round(self);
|
|
}
|
|
}
|
|
|
|
void invalidate() {
|
|
require_restart = true;
|
|
}
|
|
|
|
private:
|
|
bool start_next_resolution_round(PrivateAddressController& self) {
|
|
do {
|
|
++resolving_list_index;
|
|
if (resolving_list_index == BLE_SECURITY_DATABASE_MAX_ENTRIES) {
|
|
notify_completion(self, peer_address,false,nullptr);
|
|
return true;
|
|
}
|
|
} while (!self._resolving_list[resolving_list_index].populated);
|
|
|
|
start_resolution(self);
|
|
return false;
|
|
}
|
|
|
|
void start_resolution(PrivateAddressController& self) {
|
|
self._pal.resolve_private_address(
|
|
peer_address,
|
|
self._resolving_list[resolving_list_index].peer_irk
|
|
);
|
|
}
|
|
|
|
void notify_completion(
|
|
PrivateAddressController& self,
|
|
const address_t &peer_resolvable_address,
|
|
bool resolved,
|
|
resolving_list_entry_t* identity
|
|
)
|
|
{
|
|
// First we had the device to the resolution list
|
|
self.add_resolution_entry_to_cache(peer_resolvable_address, identity);
|
|
|
|
if (!self._event_handler) {
|
|
return;
|
|
}
|
|
self._event_handler->on_address_resolution_completed(
|
|
peer_resolvable_address,
|
|
resolved,
|
|
identity ? identity->peer_address_type : target_peer_address_type_t::PUBLIC,
|
|
identity ? identity->peer_address : address_t{}
|
|
);
|
|
}
|
|
|
|
size_t resolving_list_index = 0;
|
|
address_t peer_address;
|
|
bool require_restart = false;
|
|
};
|
|
|
|
ble_error_t PrivateAddressController::queue_resolve_address_on_host(const address_t &peer_address)
|
|
{
|
|
auto *cb = new(std::nothrow) PrivacyResolveAddressOnHost(peer_address);
|
|
if (cb == nullptr) {
|
|
// Cannot go further
|
|
return BLE_ERROR_NO_MEM;
|
|
}
|
|
|
|
_event_queue.post([this, cb] {
|
|
queue_privacy_control_block(cb);
|
|
});
|
|
|
|
return BLE_ERROR_NONE;
|
|
}
|
|
|
|
void PrivateAddressController::restart_resolution_process_on_host()
|
|
{
|
|
// if processing is active, restart the one running.
|
|
if (_processing_privacy_control_block && _pending_privacy_control_blocks) {
|
|
static_cast<PrivacyResolveAddressOnHost*>(_pending_privacy_control_blocks)->invalidate();
|
|
}
|
|
}
|
|
|
|
void PrivateAddressController::on_private_address_resolved(bool success)
|
|
{
|
|
if (_pending_privacy_control_blocks == nullptr ||
|
|
_processing_privacy_control_block == false
|
|
) {
|
|
return;
|
|
}
|
|
|
|
auto* cb = static_cast<PrivacyResolveAddressOnHost*>(_pending_privacy_control_blocks);
|
|
bool completed = cb->on_resolution_complete(*this, success);
|
|
process_privacy_control_blocks(completed);
|
|
}
|
|
#endif // BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
|
|
void PrivateAddressController::clear_privacy_control_blocks()
|
|
{
|
|
while (_pending_privacy_control_blocks != nullptr) {
|
|
PrivacyControlBlock *next = _pending_privacy_control_blocks->next();
|
|
delete _pending_privacy_control_blocks;
|
|
_pending_privacy_control_blocks = next;
|
|
}
|
|
}
|
|
|
|
void PrivateAddressController::queue_privacy_control_block(PrivacyControlBlock *block)
|
|
{
|
|
if (_pending_privacy_control_blocks == nullptr) {
|
|
_pending_privacy_control_blocks = block;
|
|
} else {
|
|
PrivacyControlBlock *node = _pending_privacy_control_blocks;
|
|
while (node->next() != nullptr) {
|
|
node = node->next();
|
|
}
|
|
node->set_next(block);
|
|
}
|
|
|
|
process_privacy_control_blocks(false);
|
|
}
|
|
|
|
// If cb_completed is set to true, it means the previous control block has completed
|
|
|
|
void PrivateAddressController::process_privacy_control_blocks(bool cb_completed)
|
|
{
|
|
if ((_processing_privacy_control_block == true) && !cb_completed) {
|
|
// Busy, cannot process next control block for now
|
|
return;
|
|
}
|
|
|
|
if (cb_completed && _pending_privacy_control_blocks) {
|
|
auto *next = _pending_privacy_control_blocks->next();
|
|
delete _pending_privacy_control_blocks;
|
|
_pending_privacy_control_blocks = next;
|
|
}
|
|
|
|
auto *cb = _pending_privacy_control_blocks;
|
|
if (cb == nullptr) {
|
|
// All control blocks processed
|
|
_processing_privacy_control_block = false;
|
|
return;
|
|
}
|
|
|
|
while (cb) {
|
|
bool completed = cb->execute(*this);
|
|
if (completed) {
|
|
auto *next = cb->next();
|
|
delete cb;
|
|
cb = next;
|
|
} else {
|
|
_processing_privacy_control_block = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
_pending_privacy_control_blocks = cb;
|
|
}
|
|
|
|
#if BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
|
|
template<typename Pred>
|
|
void PrivateAddressController::remove_resolution_entry_from_cache(const Pred &predicate)
|
|
{
|
|
resolution_entry_t* previous = nullptr;
|
|
resolution_entry_t* entry = _resolved_list;
|
|
while (entry) {
|
|
if (predicate(*entry)) {
|
|
if (previous) {
|
|
previous->next = entry->next;
|
|
} else {
|
|
_resolved_list = entry->next;
|
|
}
|
|
entry->next = _free_resolution_entries;
|
|
_free_resolution_entries = entry;
|
|
if (previous) {
|
|
entry = previous->next;
|
|
} else {
|
|
entry = _resolved_list;
|
|
}
|
|
} else {
|
|
previous = entry;
|
|
entry = entry->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PrivateAddressController::add_resolution_entry_to_cache(
|
|
const address_t& address, resolving_list_entry_t* identity
|
|
)
|
|
{
|
|
resolution_entry_t* entry = nullptr;
|
|
if (_free_resolution_entries) {
|
|
entry = _free_resolution_entries;
|
|
_free_resolution_entries = entry->next;
|
|
} else {
|
|
// retrieve the last entry in the resolved list
|
|
entry = _resolved_list;
|
|
resolution_entry_t *previous = nullptr;
|
|
while (entry->next) {
|
|
previous = entry;
|
|
entry = entry->next;
|
|
}
|
|
previous->next = nullptr;
|
|
}
|
|
|
|
// Update the entry and insert it at the top of the list
|
|
entry->address = address;
|
|
entry->identity = identity;
|
|
entry->next = _resolved_list;
|
|
_resolved_list = entry;
|
|
}
|
|
|
|
#endif // BLE_GAP_HOST_BASED_PRIVATE_ADDRESS_RESOLUTION
|
|
|
|
} // namespace ble
|
|
|
|
#endif // BLE_FEATURE_PRIVACY
|