Skip to content

Commit

Permalink
Bluetooth: Mesh: Prevent CDB reusing address of deleted nodes
Browse files Browse the repository at this point in the history
According to MshPRFv1.0.1, section 3.10.7, the Provisioner shall only
use reuse addresses of the deleted nodes after IV Index is updated.

This change prevents CDB reusing addresses of the deleted nodes until IV
Index is updated. Due to a high range of the unicast addresses, CDB only
stores the highest deleted address once a node is deleted. This creates
a limitation where allocating a node with the high primary unicast
address and then deleting it will make CDB skip big range of address
until next IV Index update.

Signed-off-by: Pavel Vasilyev <[email protected]>
  • Loading branch information
PavelVPV authored and fabiobaltieri committed Sep 12, 2022
1 parent 1df3de4 commit 33b9f3e
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 12 deletions.
12 changes: 10 additions & 2 deletions include/zephyr/bluetooth/mesh/cdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ enum {

struct bt_mesh_cdb {
uint32_t iv_index;
uint16_t lowest_avail_addr;

ATOMIC_DEFINE(flags, BT_MESH_CDB_FLAG_COUNT);

Expand Down Expand Up @@ -123,14 +124,21 @@ void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update);
* @param num_elem Number of elements that the node has.
* @param net_idx NetIdx that the node was provisioned to.
*
* @return The new node or NULL if it cannot be allocated.
* @return The new node or NULL if CDB has already allocated
* :kconfig:option:`CONFIG_BT_MESH_CDB_NODE_COUNT` nodes, or reached the
* end of the unicast address range, or if @c addr is non-zero and less
* than the lowest available address or collide with the allocated addresses.
*/
struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const uint8_t uuid[16], uint16_t addr,
uint8_t num_elem, uint16_t net_idx);

/** @brief Delete a node.
*
* Delete a node from the CDB.
* Delete a node from the CDB. When deleting the node and the address of the
* last element of the deleted node is greater than the lowest available
* address, CDB will update the lowest available address. The lowest
* available address is reset and the deleted addresses can be reused only
* after IV Index update.
*
* @param node The node to be deleted.
* @param store If true, the node will be cleared from persistent storage.
Expand Down
49 changes: 39 additions & 10 deletions subsys/bluetooth/mesh/cdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,13 @@ struct app_key_val {
uint8_t val[2][16];
} __packed;

/* IV Index & IV Update information for persistent storage. */
/* Network information for persistent storage. */
struct net_val {
uint32_t iv_index;
bool iv_update;
struct __packed {
uint32_t index;
bool update;
} iv;
uint16_t lowest_avail_addr;
} __packed;

static struct node_update cdb_node_updates[CONFIG_BT_MESH_CDB_NODE_COUNT];
Expand Down Expand Up @@ -142,7 +145,8 @@ static int addr_is_free(uint16_t addr_start, uint8_t num_elem, uint16_t *next)
*/
static uint16_t find_lowest_free_addr(uint8_t num_elem)
{
uint16_t addr = 1, next;
uint16_t addr = bt_mesh_cdb.lowest_avail_addr;
uint16_t next;
int err, i;

/*
Expand Down Expand Up @@ -178,16 +182,24 @@ static int cdb_net_set(const char *name, size_t len_rd,

err = bt_mesh_settings_set(read_cb, cb_arg, &net, sizeof(net));
if (err) {
BT_ERR("Failed to set \'cdb_net\'");
return err;
/* Try to recover previous version of the network settings without address. */
err = bt_mesh_settings_set(read_cb, cb_arg, &net, sizeof(net.iv));
if (err) {
BT_ERR("Failed to set \'cdb_net\'");
return err;
}

net.lowest_avail_addr = 1;
}

bt_mesh_cdb.iv_index = net.iv_index;
bt_mesh_cdb.iv_index = net.iv.index;

if (net.iv_update) {
if (net.iv.update) {
atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS);
}

bt_mesh_cdb.lowest_avail_addr = net.lowest_avail_addr;

atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID);

return 0;
Expand Down Expand Up @@ -693,6 +705,7 @@ int bt_mesh_cdb_create(const uint8_t key[16])

memcpy(sub->keys[0].net_key, key, 16);
bt_mesh_cdb.iv_index = 0;
bt_mesh_cdb.lowest_avail_addr = 1;

if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
update_cdb_net_settings();
Expand Down Expand Up @@ -736,6 +749,11 @@ void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update)
{
BT_DBG("Updating IV index to %d\n", iv_index);

/* Reset the last deleted addr when IV Index is updated or recovered. */
if (!iv_update || iv_index > bt_mesh_cdb.iv_index + 1) {
bt_mesh_cdb.lowest_avail_addr = 1;
}

bt_mesh_cdb.iv_index = iv_index;

atomic_set_bit_to(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS,
Expand Down Expand Up @@ -827,6 +845,8 @@ struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const uint8_t uuid[16], uint16_t
if (addr == BT_MESH_ADDR_UNASSIGNED) {
return NULL;
}
} else if (addr < bt_mesh_cdb.lowest_avail_addr) {
return NULL;
} else if (addr_is_free(addr, num_elem, NULL) < 0) {
BT_DBG("Address range 0x%04x-0x%04x is not free", addr,
addr + num_elem - 1);
Expand Down Expand Up @@ -857,6 +877,14 @@ void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store)
update_cdb_node_settings(node, false);
}

if (store && node->addr + node->num_elem > bt_mesh_cdb.lowest_avail_addr) {
bt_mesh_cdb.lowest_avail_addr = node->addr + node->num_elem;

if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
update_cdb_net_settings();
}
}

node->addr = BT_MESH_ADDR_UNASSIGNED;
memset(node->dev_key, 0, sizeof(node->dev_key));
}
Expand Down Expand Up @@ -976,9 +1004,10 @@ static void store_cdb_pending_net(void)

BT_DBG("");

net.iv_index = bt_mesh_cdb.iv_index;
net.iv_update = atomic_test_bit(bt_mesh_cdb.flags,
net.iv.index = bt_mesh_cdb.iv_index;
net.iv.update = atomic_test_bit(bt_mesh_cdb.flags,
BT_MESH_CDB_IVU_IN_PROGRESS);
net.lowest_avail_addr = bt_mesh_cdb.lowest_avail_addr;

err = settings_save_one("bt/mesh/cdb/Net", &net, sizeof(net));
if (err) {
Expand Down

0 comments on commit 33b9f3e

Please sign in to comment.