Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions nimble/host/include/host/ble_store.h
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ int ble_store_util_count(int type, int *out_count);
* Non-zero on error.
*/
int ble_store_util_status_rr(struct ble_store_status_event *event, void *arg);
int ble_store_util_status_lru(struct ble_store_status_event *event, void *arg);

/** @} */

Expand Down
163 changes: 163 additions & 0 deletions nimble/host/src/ble_store_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,166 @@ ble_store_util_status_rr(struct ble_store_status_event *event, void *arg)
return BLE_HS_EUNKNOWN;
}
}

struct ble_store_util_lru_peer {
ble_addr_t peer_addr;
uint16_t bond_count;
int found;
const ble_addr_t *except;
};

/**
* Iterator callback that selects the least-recently-used bonded peer.
*
* Recency is determined by ble_store_value_sec.bond_count, which the config
* store increments on each persist of a security record. A lower bond_count
* means the peer was used less recently.
*/
static int
ble_store_util_iter_lru_peer(int obj_type,
union ble_store_value *val,
void *arg)
{
struct ble_store_util_lru_peer *lru;

BLE_HS_DBG_ASSERT(obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC);

lru = arg;

if (lru->except != NULL &&
ble_addr_cmp(lru->except, &val->sec.peer_addr) == 0) {
return 0;
}

if (!lru->found || val->sec.bond_count < lru->bond_count) {
lru->peer_addr = val->sec.peer_addr;
lru->bond_count = val->sec.bond_count;
lru->found = 1;
}

return 0;
}

/**
* Finds the least-recently-used bonded peer.
*
* @param out_peer_addr On success, identity address of the LRU peer.
* @param except Optional peer to exclude from selection;
* may be NULL.
*
* @return 0 on success;
* BLE_HS_ENOENT if no suitable peer exists;
* Other nonzero on error.
*/
static int
ble_store_util_find_lru_peer(ble_addr_t *out_peer_addr,
const ble_addr_t *except)
{
struct ble_store_util_lru_peer lru = {
.found = 0,
.except = except,
};
int rc;

rc = ble_store_iterate(BLE_STORE_OBJ_TYPE_OUR_SEC,
ble_store_util_iter_lru_peer,
&lru);
if (rc != 0) {
return rc;
}

if (!lru.found) {
return BLE_HS_ENOENT;
}

*out_peer_addr = lru.peer_addr;
return 0;
}

/**
* Unpairs the least-recently-used bonded peer.
*
* @return 0 on success;
* Other nonzero on error.
*/
static int
ble_store_util_unpair_lru_peer(void)
{
ble_addr_t peer_addr;
int rc;

rc = ble_store_util_find_lru_peer(&peer_addr, NULL);
if (rc != 0) {
return rc;
}

return ble_gap_unpair(&peer_addr);
}

/**
* Unpairs the least-recently-used bonded peer, excluding the specified peer.
*
* @param except Peer address that must not be unpaired.
*
* @return 0 on success;
* Other nonzero on error.
*/
static int
ble_store_util_unpair_lru_except(const ble_addr_t *except)
{
ble_addr_t peer_addr;
int rc;

rc = ble_store_util_find_lru_peer(&peer_addr, except);
if (rc != 0) {
return rc;
}

return ble_gap_unpair(&peer_addr);
}

/**
* LRU status callback. If there is insufficient storage capacity for a new
* record, delete the least-recently-used bond and proceed with the persist
* operation.
*
* Recency is tracked via bond_count in persisted security records (updated on
* each write by the config store). Prefer this over ble_store_util_status_rr
* when recently used bonds should be retained.
*
* Register from the application with:
* ble_hs_cfg.store_status_cb = ble_store_util_status_lru;
*/
int
ble_store_util_status_lru(struct ble_store_status_event *event, void *arg)
{
switch (event->event_code) {
case BLE_STORE_EVENT_OVERFLOW:
switch (event->overflow.obj_type) {
case BLE_STORE_OBJ_TYPE_OUR_SEC:
case BLE_STORE_OBJ_TYPE_PEER_SEC:
case BLE_STORE_OBJ_TYPE_PEER_ADDR:
return ble_store_util_unpair_lru_peer();
case BLE_STORE_OBJ_TYPE_CCCD:
case BLE_STORE_OBJ_TYPE_CSFC:
/* Try unpairing LRU peer except current peer */
return ble_store_util_unpair_lru_except(
&event->overflow.value->cccd.peer_addr);
#if MYNEWT_VAL(ENC_ADV_DATA)
case BLE_STORE_OBJ_TYPE_ENC_ADV_DATA:
return ble_store_util_delete_ead_oldest_peer();
#endif
default:
return BLE_HS_EUNKNOWN;
}

case BLE_STORE_EVENT_FULL:
/* Just proceed with the operation. If it results in an overflow,
* we'll delete a record when the overflow occurs.
*/
return 0;

default:
return BLE_HS_EUNKNOWN;
}
}
Loading