Bluetooth: Mesh: Add database for managing nodes and keys

Refactor the handling of network nodes and their keys into a separate
Mesh Configuration Database (CDB). This, not only creates a separation
of the local node and the other nodes, but also makes it possible to
implement functions to manage the whole, or at least parts of the mesh
network.

Signed-off-by: Tobias Svehagen <tobias.svehagen@gmail.com>
This commit is contained in:
Tobias Svehagen 2019-11-04 16:14:07 +01:00 committed by Johan Hedberg
commit 46a95f12ad
16 changed files with 1707 additions and 292 deletions

View file

@ -21,5 +21,6 @@
#include <bluetooth/mesh/cfg_cli.h> #include <bluetooth/mesh/cfg_cli.h>
#include <bluetooth/mesh/health_cli.h> #include <bluetooth/mesh/health_cli.h>
#include <bluetooth/mesh/proxy.h> #include <bluetooth/mesh/proxy.h>
#include <bluetooth/mesh/cdb.h>
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */ #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */

View file

@ -0,0 +1,263 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_
#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_
#if defined(CONFIG_BT_MESH_CDB)
#define NODE_COUNT CONFIG_BT_MESH_CDB_NODE_COUNT
#define SUBNET_COUNT CONFIG_BT_MESH_CDB_SUBNET_COUNT
#define APP_KEY_COUNT CONFIG_BT_MESH_CDB_APP_KEY_COUNT
#else
#define NODE_COUNT 0
#define SUBNET_COUNT 0
#define APP_KEY_COUNT 0
#endif
enum {
BT_MESH_CDB_NODE_CONFIGURED,
BT_MESH_CDB_NODE_BLACKLISTED,
BT_MESH_CDB_NODE_FLAG_COUNT
};
struct bt_mesh_cdb_node {
u8_t uuid[16];
u16_t addr;
u16_t net_idx;
u8_t num_elem;
u8_t dev_key[16];
ATOMIC_DEFINE(flags, BT_MESH_CDB_NODE_FLAG_COUNT);
};
struct bt_mesh_cdb_subnet {
u16_t net_idx;
bool kr_flag;
u8_t kr_phase;
struct {
u8_t net_key[16];
} keys[2];
};
struct bt_mesh_cdb_app_key {
u16_t net_idx;
u16_t app_idx;
struct {
u8_t app_key[16];
} keys[2];
};
enum {
BT_MESH_CDB_VALID,
BT_MESH_CDB_SUBNET_PENDING,
BT_MESH_CDB_KEYS_PENDING,
BT_MESH_CDB_NODES_PENDING,
BT_MESH_CDB_IVU_IN_PROGRESS,
BT_MESH_CDB_FLAG_COUNT,
};
struct bt_mesh_cdb {
u32_t iv_index;
ATOMIC_DEFINE(flags, BT_MESH_CDB_FLAG_COUNT);
struct bt_mesh_cdb_node nodes[NODE_COUNT];
struct bt_mesh_cdb_subnet subnets[SUBNET_COUNT];
struct bt_mesh_cdb_app_key app_keys[APP_KEY_COUNT];
};
extern struct bt_mesh_cdb bt_mesh_cdb;
/** @brief Create the Mesh Configuration Database.
*
* Create and initialize the Mesh Configuration Database. A primary subnet,
* ie one with NetIdx 0, will be added and the provided key will be used as
* NetKey for that subnet.
*
* @param key The NetKey to be used for the primary subnet.
*
* @return 0 on success or negative error code on failure.
*/
int bt_mesh_cdb_create(const u8_t key[16]);
/** @brief Clear the Mesh Configuration Database.
*
* Remove all nodes, subnets and app-keys stored in the database and mark
* the database as invalid. The data will be cleared from persistent storage
* if CONFIG_BT_SETTINGS is enabled.
*/
void bt_mesh_cdb_clear(void);
/** @brief Set and store the IV Index and IV Update flag.
*
* The IV Index stored in the CDB will be the one used during provisioning
* of new nodes. This function is generally only used from inside the stack.
*
* This function will store the data to persistent storage if
* CONFIG_BT_SETTINGS is enabled.
*
* @param iv_index The new IV Index to use.
* @param iv_update True if there is an ongoing IV Update procedure.
*/
void bt_mesh_cdb_iv_update(u32_t iv_index, bool iv_update);
/** @brief Allocate a node.
*
* Allocate a new node in the CDB.
*
* @param uuid UUID of the node.
* @param addr Address of the node's primary element. If 0, the lowest
* possible address available will be assigned to the node.
* @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.
*/
struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const u8_t uuid[16], u16_t addr,
u8_t num_elem, u16_t net_idx);
/** @brief Delete a node.
*
* Delete a node from the CDB.
*
* @param node The node to be deleted.
* @param store If true, the node will be cleared from persistent storage.
*/
void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store);
/** @brief Get a node by address.
*
* Try to find the node that has the provided address assigned to one of its
* elements.
*
* @param addr Address of the element to look for.
*
* @return The node that has an element with address addr or NULL if no such
* node exists.
*/
struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(u16_t addr);
/** @brief Store node to persistent storage.
*
* @param node Node to be stored.
*/
void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node);
enum {
BT_MESH_CDB_ITER_STOP = 0,
BT_MESH_CDB_ITER_CONTINUE,
};
/** @typedef bt_mesh_cdb_node_func_t
* @brief Node iterator callback.
*
* @param node Node found.
* @param user_data Data given.
*
* @return BT_MESH_CDB_ITER_CONTINUE to continue to iterate through the nodes
* or BT_MESH_CDB_ITER_STOP to stop.
*/
typedef u8_t (*bt_mesh_cdb_node_func_t)(struct bt_mesh_cdb_node *node,
void *user_data);
/** @brief Node iterator.
*
* Iterate nodes in the Mesh Configuration Database. The callback function
* will only be called for valid, ie allocated, nodes.
*
* @param func Callback function.
* @param user_data Data to pass to the callback.
*/
void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data);
/** @brief Allocate a subnet.
*
* Allocate a new subnet in the CDB.
*
* @param net_idx NetIdx of the subnet.
*
* @return The new subnet or NULL if it cannot be allocated.
*/
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_alloc(u16_t net_idx);
/** @brief Delete a subnet.
*
* Delete a subnet from the CDB.
*
* @param sub The subnet to be deleted.
* @param store If true, the subnet will be cleared from persistent storage.
*/
void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store);
/** @brief Get a subnet by NetIdx
*
* Try to find the subnet with the specified NetIdx.
*
* @param net_idx NetIdx of the subnet to look for.
*
* @return The subnet with the specified NetIdx or NULL if no such subnet
* exists.
*/
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(u16_t net_idx);
/** @brief Store subnet to persistent storage.
*
* @param sub Subnet to be stored.
*/
void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub);
/** @brief Get the flags for a subnet
*
* @param sub The subnet to get flags for.
*
* @return The flags for the subnet.
*/
u8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub);
/** @brief Allocate an application key.
*
* Allocate a new application key in the CDB.
*
* @param net_idx NetIdx of NetKey that the application key is bound to.
* @param app_idx AppIdx of the application key.
*
* @return The new application key or NULL if it cannot be allocated.
*/
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_alloc(u16_t net_idx,
u16_t app_idx);
/** @brief Delete an application key.
*
* Delete an application key from the CDB.
*
* @param key The application key to be deleted.
* @param store If true, the key will be cleared from persistent storage.
*/
void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store);
/** @brief Get an application key by AppIdx
*
* Try to find the application key with the specified AppIdx.
*
* @param app_idx AppIdx of the application key to look for.
*
* @return The application key with the specified AppIdx or NULL if no such key
* exists.
*/
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(u16_t app_idx);
/** @brief Store application key to persistent storage.
*
* @param key Application key to be stored.
*/
void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key);
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_ */

View file

@ -190,10 +190,12 @@ struct bt_mesh_prov {
* the specified NetKeyIndex and primary element address. * the specified NetKeyIndex and primary element address.
* *
* @param net_idx NetKeyIndex given during provisioning. * @param net_idx NetKeyIndex given during provisioning.
* @param uuid UUID of the added node
* @param addr Primary element address. * @param addr Primary element address.
* @param num_elem Number of elements that this node has. * @param num_elem Number of elements that this node has.
*/ */
void (*node_added)(u16_t net_idx, u16_t addr, u8_t num_elem); void (*node_added)(u16_t net_idx, u8_t uuid[16], u16_t addr,
u8_t num_elem);
/** @brief Node has been reset. /** @brief Node has been reset.
* *

View file

@ -33,5 +33,4 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_SELF_TEST test.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_SHELL shell.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_SHELL shell.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROVISIONER nodes.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_CDB cdb.c)

View file

@ -37,17 +37,36 @@ config BT_MESH_PROVISIONER
help help
Enable this option to have support for provisioning remote devices. Enable this option to have support for provisioning remote devices.
if BT_MESH_PROVISIONER config BT_MESH_CDB
bool "Mesh Configuration Database [EXPERIMENTAL]"
config BT_MESH_NODE_COUNT if BT_MESH_CDB
int "Maximum number of saved nodes per network"
config BT_MESH_CDB_NODE_COUNT
int "Maximum number of nodes in the database"
default 1 default 1
range 1 4096 range 1 4096
help help
This option specifies how many nodes each network can at most This option specifies how many nodes each network can at most
save in the provisioning database. save in the configuration database.
endif # BT_MESH_PROVISIONER config BT_MESH_CDB_SUBNET_COUNT
int "Maximum number of subnets in the database"
default 1
range 1 4096
help
This option specifies how many subnets that can at most be
saved in the configuration database.
config BT_MESH_CDB_APP_KEY_COUNT
int "Maximum number of application keys in the database"
default 1
range 1 4096
help
This option specifies how many application keys that can at most
be saved in the configuration database.
endif # BT_MESH_CDB
if BT_CONN if BT_CONN
@ -591,6 +610,12 @@ config BT_MESH_DEBUG_SETTINGS
help help
Use this option to enable persistent settings debug logs. Use this option to enable persistent settings debug logs.
config BT_MESH_DEBUG_CDB
bool "Configuration database debug"
depends on BT_MESH_CDB
help
Use this option to enable configuration database debug logs.
endif # BT_MESH_DEBUG endif # BT_MESH_DEBUG
endif # BT_MESH endif # BT_MESH

382
subsys/bluetooth/mesh/cdb.c Normal file
View file

@ -0,0 +1,382 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <string.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_CDB)
#define LOG_MODULE_NAME bt_mesh_cdb
#include "common/log.h"
#include "mesh.h"
#include "net.h"
#include "settings.h"
struct bt_mesh_cdb bt_mesh_cdb = {
.nodes = {
[0 ... (CONFIG_BT_MESH_CDB_NODE_COUNT - 1)] = {
.addr = BT_MESH_ADDR_UNASSIGNED,
}
},
.subnets = {
[0 ... (CONFIG_BT_MESH_CDB_SUBNET_COUNT - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
.app_keys = {
[0 ... (CONFIG_BT_MESH_CDB_APP_KEY_COUNT - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
};
/*
* Check if an address range from addr_start for addr_start + num_elem - 1 is
* free for use. When a conflict is found, next will be set to the next address
* available after the conflicting range and -EAGAIN will be returned.
*/
static int addr_is_free(u16_t addr_start, u8_t num_elem, u16_t *next)
{
u16_t addr_end = addr_start + num_elem - 1;
u16_t other_start, other_end;
int i;
if (!BT_MESH_ADDR_IS_UNICAST(addr_start) ||
!BT_MESH_ADDR_IS_UNICAST(addr_end) ||
num_elem == 0) {
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) {
struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i];
if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
continue;
}
other_start = node->addr;
other_end = other_start + node->num_elem - 1;
if (!(addr_end < other_start || addr_start > other_end)) {
if (next) {
*next = other_end + 1;
}
return -EAGAIN;
}
}
return 0;
}
/*
* Find the lowest possible starting address that can fit num_elem elements. If
* a free address range cannot be found, BT_MESH_ADDR_UNASSIGNED will be
* returned. Otherwise the first address in the range is returned.
*
* NOTE: This is quite an ineffective algorithm as it might need to look
* through the array of nodes N+2 times. A more effective algorithm
* could be used if the nodes were stored in a sorted list.
*/
static u16_t find_lowest_free_addr(u8_t num_elem)
{
u16_t addr = 1, next;
int err, i;
/*
* It takes a maximum of node count + 2 to find a free address if there
* is any. +1 for our own address and +1 for making sure that the
* address range is valid.
*/
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes) + 2; ++i) {
err = addr_is_free(addr, num_elem, &next);
if (err == 0) {
break;
} else if (err != -EAGAIN) {
addr = BT_MESH_ADDR_UNASSIGNED;
break;
}
addr = next;
}
return addr;
}
int bt_mesh_cdb_create(const u8_t key[16])
{
struct bt_mesh_cdb_subnet *sub;
if (atomic_test_and_set_bit(bt_mesh_cdb.flags,
BT_MESH_CDB_VALID)) {
return -EALREADY;
}
sub = bt_mesh_cdb_subnet_alloc(BT_MESH_KEY_PRIMARY);
if (sub == NULL) {
return -ENOMEM;
}
memcpy(sub->keys[0].net_key, key, 16);
bt_mesh_cdb.iv_index = 0;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_cdb();
bt_mesh_store_cdb_subnet(sub);
}
return 0;
}
void bt_mesh_cdb_clear(void)
{
int i;
atomic_clear_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID);
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) {
if (bt_mesh_cdb.nodes[i].addr != BT_MESH_ADDR_UNASSIGNED) {
bt_mesh_cdb_node_del(&bt_mesh_cdb.nodes[i], true);
}
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
if (bt_mesh_cdb.subnets[i].net_idx != BT_MESH_KEY_UNUSED) {
bt_mesh_cdb_subnet_del(&bt_mesh_cdb.subnets[i], true);
}
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) {
if (bt_mesh_cdb.app_keys[i].net_idx != BT_MESH_KEY_UNUSED) {
bt_mesh_cdb_app_key_del(&bt_mesh_cdb.app_keys[i], true);
}
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_cdb();
}
}
void bt_mesh_cdb_iv_update(u32_t iv_index, bool iv_update)
{
BT_DBG("Updating IV index to %d\n", iv_index);
bt_mesh_cdb.iv_index = iv_index;
atomic_set_bit_to(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS,
iv_update);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_cdb();
}
}
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_alloc(u16_t net_idx)
{
struct bt_mesh_cdb_subnet *sub;
int i;
if (bt_mesh_cdb_subnet_get(net_idx) != NULL) {
return NULL;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
sub = &bt_mesh_cdb.subnets[i];
if (sub->net_idx != BT_MESH_KEY_UNUSED) {
continue;
}
sub->net_idx = net_idx;
return sub;
}
return NULL;
}
void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store)
{
BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store);
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
bt_mesh_clear_cdb_subnet(sub);
}
sub->net_idx = BT_MESH_KEY_UNUSED;
memset(sub->keys, 0, sizeof(sub->keys));
}
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(u16_t net_idx)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
if (bt_mesh_cdb.subnets[i].net_idx == net_idx) {
return &bt_mesh_cdb.subnets[i];
}
}
return NULL;
}
void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub)
{
bt_mesh_store_cdb_subnet(sub);
}
u8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub)
{
u8_t flags = 0x00;
if (sub && sub->kr_flag) {
flags |= BT_MESH_NET_FLAG_KR;
}
if (atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS)) {
flags |= BT_MESH_NET_FLAG_IVU;
}
return flags;
}
struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const u8_t uuid[16], u16_t addr,
u8_t num_elem, u16_t net_idx)
{
int i;
if (addr == BT_MESH_ADDR_UNASSIGNED) {
addr = find_lowest_free_addr(num_elem);
if (addr == BT_MESH_ADDR_UNASSIGNED) {
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);
return NULL;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) {
struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i];
if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
memcpy(node->uuid, uuid, 16);
node->addr = addr;
node->num_elem = num_elem;
node->net_idx = net_idx;
atomic_set(node->flags, 0);
return node;
}
}
return NULL;
}
void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store)
{
BT_DBG("Node addr 0x%04x store %u", node->addr, store);
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
bt_mesh_clear_cdb_node(node);
}
node->addr = BT_MESH_ADDR_UNASSIGNED;
memset(node->dev_key, 0, sizeof(node->dev_key));
}
struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(u16_t addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) {
struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i];
if (addr >= node->addr &&
addr <= node->addr + node->num_elem - 1) {
return node;
}
}
return NULL;
}
void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node)
{
bt_mesh_store_cdb_node(node);
}
void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) {
if (bt_mesh_cdb.nodes[i].addr == BT_MESH_ADDR_UNASSIGNED) {
continue;
}
if (func(&bt_mesh_cdb.nodes[i], user_data) ==
BT_MESH_CDB_ITER_STOP) {
break;
}
}
}
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_alloc(u16_t net_idx,
u16_t app_idx)
{
struct bt_mesh_cdb_app_key *key;
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) {
key = &bt_mesh_cdb.app_keys[i];
if (key->net_idx != BT_MESH_KEY_UNUSED) {
continue;
}
key->net_idx = net_idx;
key->app_idx = app_idx;
return key;
}
return NULL;
}
void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store)
{
BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store);
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
bt_mesh_clear_cdb_app_key(key);
}
key->net_idx = BT_MESH_ADDR_UNASSIGNED;
memset(key->keys, 0, sizeof(key->keys));
}
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(u16_t app_idx)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); i++) {
struct bt_mesh_cdb_app_key *key = &bt_mesh_cdb.app_keys[i];
if (key->net_idx != BT_MESH_KEY_UNUSED &&
key->app_idx == app_idx) {
return key;
}
}
return NULL;
}
void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key)
{
bt_mesh_store_cdb_app_key(key);
}

View file

@ -59,6 +59,53 @@ int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
pb_gatt_enabled = false; pb_gatt_enabled = false;
} }
/*
* FIXME:
* Should net_key and iv_index be over-ridden?
*/
if (IS_ENABLED(CONFIG_BT_MESH_CDB)) {
const struct bt_mesh_comp *comp;
const struct bt_mesh_prov *prov;
struct bt_mesh_cdb_node *node;
if (!atomic_test_bit(bt_mesh_cdb.flags,
BT_MESH_CDB_VALID)) {
BT_ERR("No valid network");
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
return -EINVAL;
}
comp = bt_mesh_comp_get();
if (comp == NULL) {
BT_ERR("Failed to get node composition");
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
return -EINVAL;
}
if (!bt_mesh_cdb_subnet_get(net_idx)) {
BT_ERR("No subnet with idx %d", net_idx);
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
return -ENOENT;
}
prov = bt_mesh_prov_get();
node = bt_mesh_cdb_node_alloc(prov->uuid, addr,
comp->elem_count, net_idx);
if (node == NULL) {
BT_ERR("Failed to allocate database node");
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
return -ENOMEM;
}
addr = node->addr;
iv_index = bt_mesh_cdb.iv_index;
memcpy(node->dev_key, dev_key, 16);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_cdb_node(node);
}
}
err = bt_mesh_net_create(net_idx, flags, net_key, iv_index); err = bt_mesh_net_create(net_idx, flags, net_key, iv_index);
if (err) { if (err) {
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);

View file

@ -83,13 +83,6 @@ struct bt_mesh_net bt_mesh = {
.net_idx = BT_MESH_KEY_UNUSED, .net_idx = BT_MESH_KEY_UNUSED,
} }
}, },
#if defined(CONFIG_BT_MESH_PROVISIONER)
.nodes = {
[0 ... (CONFIG_BT_MESH_NODE_COUNT - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
#endif
}; };
static u32_t dup_cache[4]; static u32_t dup_cache[4];
@ -703,6 +696,10 @@ do_update:
} }
} }
if (IS_ENABLED(CONFIG_BT_MESH_CDB)) {
bt_mesh_cdb_iv_update(iv_index, iv_update);
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_iv(false); bt_mesh_store_iv(false);
} }

View file

@ -222,7 +222,6 @@ enum {
BT_MESH_CFG_PENDING, BT_MESH_CFG_PENDING,
BT_MESH_MOD_PENDING, BT_MESH_MOD_PENDING,
BT_MESH_VA_PENDING, BT_MESH_VA_PENDING,
BT_MESH_NODES_PENDING,
/* Don't touch - intentionally last */ /* Don't touch - intentionally last */
BT_MESH_FLAG_COUNT, BT_MESH_FLAG_COUNT,
@ -255,10 +254,6 @@ struct bt_mesh_net {
u8_t dev_key[16]; u8_t dev_key[16];
#if defined(CONFIG_BT_MESH_PROVISIONER)
struct bt_mesh_node nodes[CONFIG_BT_MESH_NODE_COUNT];
#endif
struct bt_mesh_app_key app_keys[CONFIG_BT_MESH_APP_KEY_COUNT]; struct bt_mesh_app_key app_keys[CONFIG_BT_MESH_APP_KEY_COUNT];
struct bt_mesh_subnet sub[CONFIG_BT_MESH_SUBNET_COUNT]; struct bt_mesh_subnet sub[CONFIG_BT_MESH_SUBNET_COUNT];

View file

@ -1,161 +0,0 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <string.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_PROV)
#define LOG_MODULE_NAME bt_mesh_node
#include "common/log.h"
#include "mesh.h"
#include "net.h"
#include "access.h"
#include "settings.h"
/*
* Check if an address range from addr_start for addr_start + num_elem - 1 is
* free for use. When a conflict is found, next will be set to the next address
* available after the conflicting range and -EAGAIN will be returned.
*/
static int addr_is_free(u16_t addr_start, u8_t num_elem, u16_t *next)
{
const struct bt_mesh_comp *comp = bt_mesh_comp_get();
u16_t addr_end = addr_start + num_elem - 1;
u16_t other_start, other_end;
int i;
if (comp == NULL) {
return -EINVAL;
}
if (!BT_MESH_ADDR_IS_UNICAST(addr_start) ||
!BT_MESH_ADDR_IS_UNICAST(addr_end) ||
num_elem == 0 || next == NULL) {
return -EINVAL;
}
other_start = bt_mesh_primary_addr();
other_end = other_start + comp->elem_count - 1;
/* Compare with local element addresses */
if (!(addr_end < other_start || addr_start > other_end)) {
*next = other_end + 1;
return -EAGAIN;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
struct bt_mesh_node *node = &bt_mesh.nodes[i];
if (node->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
other_start = node->addr;
other_end = other_start + node->num_elem - 1;
if (!(addr_end < other_start || addr_start > other_end)) {
*next = other_end + 1;
return -EAGAIN;
}
}
return 0;
}
/*
* Find the lowest possible starting address that can fit num_elem elements. If
* a free address range cannot be found, BT_MESH_ADDR_UNASSIGNED will be
* returned. Otherwise the first address in the range is returned.
*
* NOTE: This is quite an ineffective algorithm as it might need to look
* through the array of nodes N+2 times. A more effective algorithm
* could be used if the nodes were stored in a sorted list.
*/
static u16_t find_lowest_free_addr(u8_t num_elem)
{
u16_t addr = 1, next;
int err, i;
/*
* It takes a maximum of node count + 2 to find a free address if there
* is any. +1 for our own address and +1 for making sure that the
* address range is valid.
*/
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes) + 2; ++i) {
err = addr_is_free(addr, num_elem, &next);
if (err == 0) {
break;
} else if (err != -EAGAIN) {
addr = BT_MESH_ADDR_UNASSIGNED;
break;
}
addr = next;
}
return addr;
}
struct bt_mesh_node *bt_mesh_node_find(u16_t addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
struct bt_mesh_node *node = &bt_mesh.nodes[i];
if (addr >= node->addr &&
addr <= node->addr + node->num_elem - 1) {
return node;
}
}
return NULL;
}
struct bt_mesh_node *bt_mesh_node_alloc(u16_t addr, u8_t num_elem,
u16_t net_idx)
{
int i;
BT_DBG("");
if (addr == BT_MESH_ADDR_UNASSIGNED) {
addr = find_lowest_free_addr(num_elem);
if (addr == BT_MESH_ADDR_UNASSIGNED) {
return NULL;
}
} else if (!addr_is_free(addr, num_elem, NULL)) {
return NULL;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
struct bt_mesh_node *node = &bt_mesh.nodes[i];
if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
node->addr = addr;
node->num_elem = num_elem;
node->net_idx = net_idx;
return node;
}
}
return NULL;
}
void bt_mesh_node_del(struct bt_mesh_node *node, bool store)
{
BT_DBG("Node addr 0x%04x store %u", node->addr, store);
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
bt_mesh_clear_node(node);
}
node->addr = BT_MESH_ADDR_UNASSIGNED;
(void)memset(node->dev_key, 0, sizeof(node->dev_key));
}

View file

@ -1,10 +0,0 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
struct bt_mesh_node *bt_mesh_node_find(u16_t addr);
struct bt_mesh_node *bt_mesh_node_alloc(u16_t addr, u8_t num_elem,
u16_t net_idx);
void bt_mesh_node_del(struct bt_mesh_node *node, bool store);

View file

@ -34,7 +34,6 @@
#include "proxy.h" #include "proxy.h"
#include "prov.h" #include "prov.h"
#include "settings.h" #include "settings.h"
#include "nodes.h"
/* 3 transmissions, 20ms interval */ /* 3 transmissions, 20ms interval */
#define PROV_XMIT BT_MESH_TRANSMIT(2, 20) #define PROV_XMIT BT_MESH_TRANSMIT(2, 20)
@ -131,10 +130,11 @@ enum {
#endif #endif
struct provisioner_link { struct provisioner_link {
struct bt_mesh_node *node; struct bt_mesh_cdb_node *node;
u16_t addr; u16_t addr;
u16_t net_idx; u16_t net_idx;
u8_t attention_duration; u8_t attention_duration;
u8_t uuid[16];
}; };
struct prov_link { struct prov_link {
@ -234,7 +234,7 @@ static int reset_state(void)
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) && if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
link.provisioner->node != NULL) { link.provisioner->node != NULL) {
bt_mesh_node_del(link.provisioner->node, false); bt_mesh_cdb_node_del(link.provisioner->node, false);
} }
#if defined(CONFIG_BT_MESH_PB_GATT) #if defined(CONFIG_BT_MESH_PB_GATT)
@ -690,9 +690,10 @@ static void prov_capabilities(const u8_t *data)
return; return;
} }
link.provisioner->node = bt_mesh_node_alloc(link.provisioner->addr, link.provisioner->node =
data[0], bt_mesh_cdb_node_alloc(link.provisioner->uuid,
link.provisioner->net_idx); link.provisioner->addr, data[0],
link.provisioner->net_idx);
if (link.provisioner->node == NULL) { if (link.provisioner->node == NULL) {
prov_send_fail_msg(PROV_ERR_RESOURCES); prov_send_fail_msg(PROV_ERR_RESOURCES);
return; return;
@ -1122,7 +1123,7 @@ static void prov_input_complete(const u8_t *data)
static void send_prov_data(void) static void send_prov_data(void)
{ {
PROV_BUF(pdu, 34); PROV_BUF(pdu, 34);
struct bt_mesh_subnet *sub; struct bt_mesh_cdb_subnet *sub;
u8_t session_key[16]; u8_t session_key[16];
u8_t nonce[13]; u8_t nonce[13];
int err; int err;
@ -1155,7 +1156,7 @@ static void send_prov_data(void)
BT_DBG("DevKey: %s", bt_hex(link.provisioner->node->dev_key, 16)); BT_DBG("DevKey: %s", bt_hex(link.provisioner->node->dev_key, 16));
sub = bt_mesh_subnet_get(link.provisioner->node->net_idx); sub = bt_mesh_cdb_subnet_get(link.provisioner->node->net_idx);
if (sub == NULL) { if (sub == NULL) {
BT_ERR("No subnet with net_idx %u", BT_ERR("No subnet with net_idx %u",
link.provisioner->node->net_idx); link.provisioner->node->net_idx);
@ -1164,10 +1165,10 @@ static void send_prov_data(void)
} }
prov_buf_init(&pdu, PROV_DATA); prov_buf_init(&pdu, PROV_DATA);
net_buf_simple_add_mem(&pdu, sub->keys[sub->kr_flag].net, 16); net_buf_simple_add_mem(&pdu, sub->keys[sub->kr_flag].net_key, 16);
net_buf_simple_add_be16(&pdu, link.provisioner->node->net_idx); net_buf_simple_add_be16(&pdu, link.provisioner->node->net_idx);
net_buf_simple_add_u8(&pdu, bt_mesh_net_flags(sub)); net_buf_simple_add_u8(&pdu, bt_mesh_cdb_subnet_flags(sub));
net_buf_simple_add_be32(&pdu, bt_mesh.iv_index); net_buf_simple_add_be32(&pdu, bt_mesh_cdb.iv_index);
net_buf_simple_add_be16(&pdu, link.provisioner->node->addr); net_buf_simple_add_be16(&pdu, link.provisioner->node->addr);
net_buf_simple_add(&pdu, 8); /* For MIC */ net_buf_simple_add(&pdu, 8); /* For MIC */
@ -1197,7 +1198,7 @@ static void prov_complete(const u8_t *data)
return; return;
} }
struct bt_mesh_node *node = link.provisioner->node; struct bt_mesh_cdb_node *node = link.provisioner->node;
#if defined(CONFIG_BT_MESH_PB_ADV) #if defined(CONFIG_BT_MESH_PB_ADV)
u8_t reason = CLOSE_REASON_SUCCESS; u8_t reason = CLOSE_REASON_SUCCESS;
#endif #endif
@ -1207,7 +1208,7 @@ static void prov_complete(const u8_t *data)
node->addr); node->addr);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_node(node); bt_mesh_store_cdb_node(node);
} }
link.provisioner->node = NULL; link.provisioner->node = NULL;
@ -1218,7 +1219,10 @@ static void prov_complete(const u8_t *data)
bearer_ctl_send(LINK_CLOSE, &reason, sizeof(reason)); bearer_ctl_send(LINK_CLOSE, &reason, sizeof(reason));
#endif #endif
bt_mesh_prov_node_added(node->net_idx, node->addr, node->num_elem); if (prov->node_added) {
prov->node_added(node->net_idx, node->uuid, node->addr,
node->num_elem);
}
/* /*
* According to mesh profile spec (5.3.1.4.3), the close message should * According to mesh profile spec (5.3.1.4.3), the close message should
@ -1808,6 +1812,7 @@ int bt_mesh_pb_adv_open(const u8_t uuid[16], u16_t net_idx, u16_t addr,
bt_rand(&link.id, sizeof(link.id)); bt_rand(&link.id, sizeof(link.id));
link.tx.id = 0x7F; link.tx.id = 0x7F;
memcpy(link.provisioner->uuid, uuid, 16);
link.provisioner->addr = addr; link.provisioner->addr = addr;
link.provisioner->net_idx = net_idx; link.provisioner->net_idx = net_idx;
link.provisioner->attention_duration = attention_duration; link.provisioner->attention_duration = attention_duration;
@ -1951,13 +1956,6 @@ void bt_mesh_prov_complete(u16_t net_idx, u16_t addr)
} }
} }
void bt_mesh_prov_node_added(u16_t net_idx, u16_t addr, u8_t num_elem)
{
if (prov->node_added) {
prov->node_added(net_idx, addr, num_elem);
}
}
void bt_mesh_prov_reset(void) void bt_mesh_prov_reset(void)
{ {
if (prov->reset) { if (prov->reset) {

View file

@ -32,19 +32,21 @@
#include "foundation.h" #include "foundation.h"
#include "proxy.h" #include "proxy.h"
#include "settings.h" #include "settings.h"
#include "nodes.h"
/* Tracking of what storage changes are pending for App and Net Keys. We /* Tracking of what storage changes are pending for App and Net Keys. We
* track this in a separate array here instead of within the respective * track this in a separate array here instead of within the respective
* bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key * bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key
* gets deleted its struct becomes invalid and may be reused for other keys. * gets deleted its struct becomes invalid and may be reused for other keys.
*/ */
static struct key_update { struct key_update {
u16_t key_idx:12, /* AppKey or NetKey Index */ u16_t key_idx:12, /* AppKey or NetKey Index */
valid:1, /* 1 if this entry is valid, 0 if not */ valid:1, /* 1 if this entry is valid, 0 if not */
app_key:1, /* 1 if this is an AppKey, 0 if a NetKey */ app_key:1, /* 1 if this is an AppKey, 0 if a NetKey */
clear:1; /* 1 if key needs clearing, 0 if storing */ clear:1; /* 1 if key needs clearing, 0 if storing */
} key_updates[CONFIG_BT_MESH_APP_KEY_COUNT + CONFIG_BT_MESH_SUBNET_COUNT]; };
static struct key_update key_updates[CONFIG_BT_MESH_APP_KEY_COUNT +
CONFIG_BT_MESH_SUBNET_COUNT];
static struct k_delayed_work pending_store; static struct k_delayed_work pending_store;
@ -124,11 +126,19 @@ struct va_val {
u8_t uuid[16]; u8_t uuid[16];
} __packed; } __packed;
struct cdb_net_val {
u32_t iv_index;
bool iv_update;
} __packed;
/* Node storage information */ /* Node storage information */
struct node_val { struct node_val {
u16_t net_idx; u16_t net_idx;
u8_t dev_key[16];
u8_t num_elem; u8_t num_elem;
u8_t flags;
#define F_NODE_CONFIGURED 0x01
u8_t uuid[16];
u8_t dev_key[16];
} __packed; } __packed;
struct node_update { struct node_update {
@ -136,10 +146,13 @@ struct node_update {
bool clear; bool clear;
}; };
#if defined(CONFIG_BT_MESH_PROVISIONER) #if defined(CONFIG_BT_MESH_CDB)
static struct node_update node_updates[CONFIG_BT_MESH_NODE_COUNT]; static struct node_update cdb_node_updates[CONFIG_BT_MESH_CDB_NODE_COUNT];
static struct key_update cdb_key_updates[CONFIG_BT_MESH_CDB_SUBNET_COUNT +
CONFIG_BT_MESH_CDB_APP_KEY_COUNT];
#else #else
static struct node_update node_updates[0]; static struct node_update cdb_node_updates[0];
static struct key_update cdb_key_updates[0];
#endif #endif
/* We need this so we don't overwrite app-hardcoded values in case FCB /* We need this so we don't overwrite app-hardcoded values in case FCB
@ -758,11 +771,39 @@ static int va_set(const char *name, size_t len_rd,
} }
#endif #endif
#if defined(CONFIG_BT_MESH_PROVISIONER) #if defined(CONFIG_BT_MESH_CDB)
static int node_set(const char *name, size_t len_rd, static int cdb_net_set(const char *name, size_t len_rd,
settings_read_cb read_cb, void *cb_arg) settings_read_cb read_cb, void *cb_arg)
{ {
struct bt_mesh_node *node; struct cdb_net_val net;
int err;
if (len_rd == 0) {
BT_DBG("val (null)");
return 0;
}
err = mesh_x_set(read_cb, cb_arg, &net, sizeof(net));
if (err) {
BT_ERR("Failed to set \'cdb_net\'");
return err;
}
bt_mesh_cdb.iv_index = net.iv_index;
if (net.iv_update) {
atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS);
}
atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID);
return 0;
}
static int cdb_node_set(const char *name, size_t len_rd,
settings_read_cb read_cb, void *cb_arg)
{
struct bt_mesh_cdb_node *node;
struct node_val val; struct node_val val;
u16_t addr; u16_t addr;
int err; int err;
@ -778,9 +819,9 @@ static int node_set(const char *name, size_t len_rd,
BT_DBG("val (null)"); BT_DBG("val (null)");
BT_DBG("Deleting node 0x%04x", addr); BT_DBG("Deleting node 0x%04x", addr);
node = bt_mesh_node_find(addr); node = bt_mesh_cdb_node_get(addr);
if (node) { if (node) {
bt_mesh_node_del(node, false); bt_mesh_cdb_node_del(node, false);
} }
return 0; return 0;
@ -792,9 +833,10 @@ static int node_set(const char *name, size_t len_rd,
return err; return err;
} }
node = bt_mesh_node_find(addr); node = bt_mesh_cdb_node_get(addr);
if (!node) { if (!node) {
node = bt_mesh_node_alloc(addr, val.num_elem, val.net_idx); node = bt_mesh_cdb_node_alloc(val.uuid, addr, val.num_elem,
val.net_idx);
} }
if (!node) { if (!node) {
@ -802,12 +844,168 @@ static int node_set(const char *name, size_t len_rd,
return -ENOMEM; return -ENOMEM;
} }
memcpy(node->dev_key, &val.dev_key, 16); if (val.flags & F_NODE_CONFIGURED) {
atomic_set_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED);
}
memcpy(node->uuid, val.uuid, 16);
memcpy(node->dev_key, val.dev_key, 16);
BT_DBG("Node 0x%04x recovered from storage", addr); BT_DBG("Node 0x%04x recovered from storage", addr);
return 0; return 0;
} }
static int cdb_subnet_set(const char *name, size_t len_rd,
settings_read_cb read_cb, void *cb_arg)
{
struct bt_mesh_cdb_subnet *sub;
struct net_key_val key;
u16_t net_idx;
int err;
if (!name) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
net_idx = strtol(name, NULL, 16);
sub = bt_mesh_cdb_subnet_get(net_idx);
if (len_rd == 0) {
BT_DBG("val (null)");
if (!sub) {
BT_ERR("No subnet with NetKeyIndex 0x%03x", net_idx);
return -ENOENT;
}
BT_DBG("Deleting NetKeyIndex 0x%03x", net_idx);
bt_mesh_cdb_subnet_del(sub, false);
return 0;
}
err = mesh_x_set(read_cb, cb_arg, &key, sizeof(key));
if (err) {
BT_ERR("Failed to set \'net-key\'");
return err;
}
if (sub) {
BT_DBG("Updating existing NetKeyIndex 0x%03x", net_idx);
sub->kr_flag = key.kr_flag;
sub->kr_phase = key.kr_phase;
memcpy(sub->keys[0].net_key, &key.val[0], 16);
memcpy(sub->keys[1].net_key, &key.val[1], 16);
return 0;
}
sub = bt_mesh_cdb_subnet_alloc(net_idx);
if (!sub) {
BT_ERR("No space to allocate a new subnet");
return -ENOMEM;
}
sub->kr_flag = key.kr_flag;
sub->kr_phase = key.kr_phase;
memcpy(sub->keys[0].net_key, &key.val[0], 16);
memcpy(sub->keys[1].net_key, &key.val[1], 16);
BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx);
return 0;
}
static int cdb_app_key_set(const char *name, size_t len_rd,
settings_read_cb read_cb, void *cb_arg)
{
struct bt_mesh_cdb_app_key *app;
struct app_key_val key;
u16_t app_idx;
int err;
if (!name) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
app_idx = strtol(name, NULL, 16);
if (len_rd == 0) {
BT_DBG("val (null)");
BT_DBG("Deleting AppKeyIndex 0x%03x", app_idx);
app = bt_mesh_cdb_app_key_get(app_idx);
if (app) {
bt_mesh_cdb_app_key_del(app, false);
}
return 0;
}
err = mesh_x_set(read_cb, cb_arg, &key, sizeof(key));
if (err) {
BT_ERR("Failed to set \'app-key\'");
return err;
}
app = bt_mesh_cdb_app_key_get(app_idx);
if (!app) {
app = bt_mesh_cdb_app_key_alloc(key.net_idx, app_idx);
}
if (!app) {
BT_ERR("No space for a new app key");
return -ENOMEM;
}
memcpy(app->keys[0].app_key, key.val[0], 16);
memcpy(app->keys[1].app_key, key.val[1], 16);
BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx);
return 0;
}
static int cdb_set(const char *name, size_t len_rd,
settings_read_cb read_cb, void *cb_arg)
{
int len;
const char *next;
if (!name) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
if (!strcmp(name, "Net")) {
return cdb_net_set(name, len_rd, read_cb, cb_arg);
}
len = settings_name_next(name, &next);
if (!next) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
if (!strncmp(name, "Node", len)) {
return cdb_node_set(next, len_rd, read_cb, cb_arg);
}
if (!strncmp(name, "Subnet", len)) {
return cdb_subnet_set(next, len_rd, read_cb, cb_arg);
}
if (!strncmp(name, "AppKey", len)) {
return cdb_app_key_set(next, len_rd, read_cb, cb_arg);
}
BT_WARN("Unknown module key %s", name);
return -ENOENT;
}
#endif #endif
const struct mesh_setting { const struct mesh_setting {
@ -828,8 +1026,8 @@ const struct mesh_setting {
#if CONFIG_BT_MESH_LABEL_COUNT > 0 #if CONFIG_BT_MESH_LABEL_COUNT > 0
{ "Va", va_set }, { "Va", va_set },
#endif #endif
#if defined(CONFIG_BT_MESH_PROVISIONER) #if defined(CONFIG_BT_MESH_CDB)
{ "Node", node_set }, { "cdb", cdb_set },
#endif #endif
}; };
@ -975,8 +1173,7 @@ SETTINGS_STATIC_HANDLER_DEFINE(bt_mesh, "bt/mesh", NULL, mesh_set, mesh_commit,
#define GENERIC_PENDING_BITS (BIT(BT_MESH_KEYS_PENDING) | \ #define GENERIC_PENDING_BITS (BIT(BT_MESH_KEYS_PENDING) | \
BIT(BT_MESH_HB_PUB_PENDING) | \ BIT(BT_MESH_HB_PUB_PENDING) | \
BIT(BT_MESH_CFG_PENDING) | \ BIT(BT_MESH_CFG_PENDING) | \
BIT(BT_MESH_MOD_PENDING) | \ BIT(BT_MESH_MOD_PENDING))
BIT(BT_MESH_NODES_PENDING))
static void schedule_store(int flag) static void schedule_store(int flag)
{ {
@ -1360,17 +1557,55 @@ static void store_pending_keys(void)
} }
} }
static void store_node(struct bt_mesh_node *node) static void clear_cdb(void)
{
int err;
err = settings_delete("bt/mesh/cdb/Net");
if (err) {
BT_ERR("Failed to clear Network");
} else {
BT_DBG("Cleared Network");
}
}
static void store_pending_cdb(void)
{
struct cdb_net_val net;
int err;
BT_DBG("");
net.iv_index = bt_mesh_cdb.iv_index;
net.iv_update = atomic_test_bit(bt_mesh_cdb.flags,
BT_MESH_CDB_IVU_IN_PROGRESS);
err = settings_save_one("bt/mesh/cdb/Net", &net, sizeof(net));
if (err) {
BT_ERR("Failed to store Network value");
} else {
BT_DBG("Stored Network value");
}
}
static void store_cdb_node(const struct bt_mesh_cdb_node *node)
{ {
struct node_val val; struct node_val val;
char path[20]; char path[30];
int err; int err;
val.net_idx = node->net_idx; val.net_idx = node->net_idx;
val.num_elem = node->num_elem; val.num_elem = node->num_elem;
val.flags = 0;
if (atomic_test_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED)) {
val.flags |= F_NODE_CONFIGURED;
}
memcpy(val.uuid, node->uuid, 16);
memcpy(val.dev_key, node->dev_key, 16); memcpy(val.dev_key, node->dev_key, 16);
snprintk(path, sizeof(path), "bt/mesh/Node/%x", node->addr); snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", node->addr);
err = settings_save_one(path, &val, sizeof(val)); err = settings_save_one(path, &val, sizeof(val));
if (err) { if (err) {
@ -1380,14 +1615,14 @@ static void store_node(struct bt_mesh_node *node)
} }
} }
static void clear_node(u16_t addr) static void clear_cdb_node(u16_t addr)
{ {
char path[20]; char path[30];
int err; int err;
BT_DBG("Node 0x%04x", addr); BT_DBG("Node 0x%04x", addr);
snprintk(path, sizeof(path), "bt/mesh/Node/%x", addr); snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", addr);
err = settings_delete(path); err = settings_delete(path);
if (err) { if (err) {
BT_ERR("Failed to clear Node 0x%04x", addr); BT_ERR("Failed to clear Node 0x%04x", addr);
@ -1396,25 +1631,27 @@ static void clear_node(u16_t addr)
} }
} }
static void store_pending_nodes(void) static void store_pending_cdb_nodes(void)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(node_updates); ++i) { for (i = 0; i < ARRAY_SIZE(cdb_node_updates); ++i) {
struct node_update *update = &node_updates[i]; struct node_update *update = &cdb_node_updates[i];
if (update->addr == BT_MESH_ADDR_UNASSIGNED) { if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
continue; continue;
} }
if (update->clear) { BT_DBG("addr: 0x%04x, clear: %d", update->addr, update->clear);
clear_node(update->addr);
} else {
struct bt_mesh_node *node;
node = bt_mesh_node_find(update->addr); if (update->clear) {
clear_cdb_node(update->addr);
} else {
struct bt_mesh_cdb_node *node;
node = bt_mesh_cdb_node_get(update->addr);
if (node) { if (node) {
store_node(node); store_cdb_node(node);
} else { } else {
BT_WARN("Node 0x%04x not found", update->addr); BT_WARN("Node 0x%04x not found", update->addr);
} }
@ -1424,8 +1661,128 @@ static void store_pending_nodes(void)
} }
} }
static struct node_update *node_update_find(u16_t addr, static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub)
struct node_update **free_slot) {
struct net_key_val key;
char path[30];
int err;
BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx,
bt_hex(sub->keys[0].net_key, 16));
memcpy(&key.val[0], sub->keys[0].net_key, 16);
memcpy(&key.val[1], sub->keys[1].net_key, 16);
key.kr_flag = sub->kr_flag;
key.kr_phase = sub->kr_phase;
snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", sub->net_idx);
err = settings_save_one(path, &key, sizeof(key));
if (err) {
BT_ERR("Failed to store Subnet value");
} else {
BT_DBG("Stored Subnet value");
}
}
static void clear_cdb_subnet(u16_t net_idx)
{
char path[30];
int err;
BT_DBG("NetKeyIndex 0x%03x", net_idx);
snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", net_idx);
err = settings_delete(path);
if (err) {
BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx);
} else {
BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx);
}
}
static void store_cdb_app_key(const struct bt_mesh_cdb_app_key *app)
{
struct app_key_val key;
char path[30];
int err;
key.net_idx = app->net_idx;
key.updated = false;
memcpy(key.val[0], app->keys[0].app_key, 16);
memcpy(key.val[1], app->keys[1].app_key, 16);
snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app->app_idx);
err = settings_save_one(path, &key, sizeof(key));
if (err) {
BT_ERR("Failed to store AppKey %s value", log_strdup(path));
} else {
BT_DBG("Stored AppKey %s value", log_strdup(path));
}
}
static void clear_cdb_app_key(u16_t app_idx)
{
char path[30];
int err;
snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app_idx);
err = settings_delete(path);
if (err) {
BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx);
} else {
BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx);
}
}
static void store_pending_cdb_keys(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) {
struct key_update *update = &cdb_key_updates[i];
if (!update->valid) {
continue;
}
if (update->clear) {
if (update->app_key) {
clear_cdb_app_key(update->key_idx);
} else {
clear_cdb_subnet(update->key_idx);
}
} else {
if (update->app_key) {
struct bt_mesh_cdb_app_key *key;
key = bt_mesh_cdb_app_key_get(update->key_idx);
if (key) {
store_cdb_app_key(key);
} else {
BT_WARN("AppKeyIndex 0x%03x not found",
update->key_idx);
}
} else {
struct bt_mesh_cdb_subnet *sub;
sub = bt_mesh_cdb_subnet_get(update->key_idx);
if (sub) {
store_cdb_subnet(sub);
} else {
BT_WARN("NetKeyIndex 0x%03x not found",
update->key_idx);
}
}
}
update->valid = 0U;
}
}
static struct node_update *cdb_node_update_find(u16_t addr,
struct node_update **free_slot)
{ {
struct node_update *match; struct node_update *match;
int i; int i;
@ -1433,8 +1790,8 @@ static struct node_update *node_update_find(u16_t addr,
match = NULL; match = NULL;
*free_slot = NULL; *free_slot = NULL;
for (i = 0; i < ARRAY_SIZE(node_updates); i++) { for (i = 0; i < ARRAY_SIZE(cdb_node_updates); i++) {
struct node_update *update = &node_updates[i]; struct node_update *update = &cdb_node_updates[i];
if (update->addr == BT_MESH_ADDR_UNASSIGNED) { if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
*free_slot = update; *free_slot = update;
@ -1665,9 +2022,26 @@ static void store_pending(struct k_work *work)
store_pending_va(); store_pending_va();
} }
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) && if (IS_ENABLED(CONFIG_BT_MESH_CDB)) {
atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_NODES_PENDING)) { if (atomic_test_and_clear_bit(bt_mesh_cdb.flags,
store_pending_nodes(); BT_MESH_CDB_SUBNET_PENDING)) {
if (atomic_test_bit(bt_mesh_cdb.flags,
BT_MESH_CDB_VALID)) {
store_pending_cdb();
} else {
clear_cdb();
}
}
if (atomic_test_and_clear_bit(bt_mesh_cdb.flags,
BT_MESH_CDB_NODES_PENDING)) {
store_pending_cdb_nodes();
}
if (atomic_test_and_clear_bit(bt_mesh_cdb.flags,
BT_MESH_CDB_KEYS_PENDING)) {
store_pending_cdb_keys();
}
} }
} }
@ -1856,51 +2230,196 @@ void bt_mesh_store_label(void)
schedule_store(BT_MESH_VA_PENDING); schedule_store(BT_MESH_VA_PENDING);
} }
void bt_mesh_store_node(struct bt_mesh_node *node) static void schedule_cdb_store(int flag)
{ {
struct node_update *update, *free_slot; atomic_set_bit(bt_mesh_cdb.flags, flag);
k_delayed_work_submit(&pending_store, K_NO_WAIT);
BT_DBG("Node 0x%04x", node->addr);
update = node_update_find(node->addr, &free_slot);
if (update) {
update->clear = false;
schedule_store(BT_MESH_NODES_PENDING);
return;
}
if (!free_slot) {
store_node(node);
return;
}
free_slot->addr = node->addr;
schedule_store(BT_MESH_NODES_PENDING);
} }
void bt_mesh_clear_node(struct bt_mesh_node *node) void bt_mesh_store_cdb(void)
{
schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING);
}
void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node)
{ {
struct node_update *update, *free_slot; struct node_update *update, *free_slot;
BT_DBG("Node 0x%04x", node->addr); BT_DBG("Node 0x%04x", node->addr);
update = node_update_find(node->addr, &free_slot); update = cdb_node_update_find(node->addr, &free_slot);
if (update) { if (update) {
update->clear = true; update->clear = false;
schedule_store(BT_MESH_NODES_PENDING); schedule_cdb_store(BT_MESH_CDB_NODES_PENDING);
return; return;
} }
if (!free_slot) { if (!free_slot) {
clear_node(node->addr); store_cdb_node(node);
return; return;
} }
free_slot->clear = true;
free_slot->addr = node->addr; free_slot->addr = node->addr;
schedule_store(BT_MESH_NODES_PENDING); schedule_cdb_store(BT_MESH_CDB_NODES_PENDING);
}
void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node)
{
struct node_update *update, *free_slot;
BT_DBG("Node 0x%04x", node->addr);
update = cdb_node_update_find(node->addr, &free_slot);
if (update) {
update->clear = true;
schedule_cdb_store(BT_MESH_CDB_NODES_PENDING);
return;
}
if (!free_slot) {
clear_cdb_node(node->addr);
return;
}
free_slot->addr = node->addr;
free_slot->clear = true;
schedule_cdb_store(BT_MESH_CDB_NODES_PENDING);
}
/* TODO: Could be shared with key_update_find? */
static struct key_update *cdb_key_update_find(bool app_key, u16_t key_idx,
struct key_update **free_slot)
{
struct key_update *match;
int i;
match = NULL;
*free_slot = NULL;
for (i = 0; i < ARRAY_SIZE(key_updates); i++) {
struct key_update *update = &cdb_key_updates[i];
if (!update->valid) {
*free_slot = update;
continue;
}
if (update->app_key != app_key) {
continue;
}
if (update->key_idx == key_idx) {
match = update;
}
}
return match;
}
void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub)
{
struct key_update *update, *free_slot;
BT_DBG("NetKeyIndex 0x%03x", sub->net_idx);
update = cdb_key_update_find(false, sub->net_idx, &free_slot);
if (update) {
update->clear = 0U;
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
return;
}
if (!free_slot) {
store_cdb_subnet(sub);
return;
}
free_slot->valid = 1U;
free_slot->key_idx = sub->net_idx;
free_slot->app_key = 0U;
free_slot->clear = 0U;
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
}
void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub)
{
struct key_update *update, *free_slot;
BT_DBG("NetKeyIndex 0x%03x", sub->net_idx);
update = cdb_key_update_find(false, sub->net_idx, &free_slot);
if (update) {
update->clear = 1U;
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
return;
}
if (!free_slot) {
clear_cdb_subnet(sub->net_idx);
return;
}
free_slot->valid = 1U;
free_slot->key_idx = sub->net_idx;
free_slot->app_key = 0U;
free_slot->clear = 1U;
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
}
void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *key)
{
struct key_update *update, *free_slot;
BT_DBG("AppKeyIndex 0x%03x", key->app_idx);
update = cdb_key_update_find(true, key->app_idx, &free_slot);
if (update) {
update->clear = 0U;
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
return;
}
if (!free_slot) {
store_cdb_app_key(key);
return;
}
free_slot->valid = 1U;
free_slot->key_idx = key->app_idx;
free_slot->app_key = 1U;
free_slot->clear = 0U;
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
}
void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *key)
{
struct key_update *update, *free_slot;
BT_DBG("AppKeyIndex 0x%03x", key->app_idx);
update = cdb_key_update_find(true, key->app_idx, &free_slot);
if (update) {
update->clear = 1U;
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
return;
}
if (!free_slot) {
clear_cdb_app_key(key->app_idx);
return;
}
free_slot->valid = 1U;
free_slot->key_idx = key->app_idx;
free_slot->app_key = 1U;
free_slot->clear = 1U;
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
} }
int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,

View file

@ -16,12 +16,17 @@ void bt_mesh_store_mod_bind(struct bt_mesh_model *mod);
void bt_mesh_store_mod_sub(struct bt_mesh_model *mod); void bt_mesh_store_mod_sub(struct bt_mesh_model *mod);
void bt_mesh_store_mod_pub(struct bt_mesh_model *mod); void bt_mesh_store_mod_pub(struct bt_mesh_model *mod);
void bt_mesh_store_label(void); void bt_mesh_store_label(void);
void bt_mesh_store_node(struct bt_mesh_node *node); void bt_mesh_store_cdb(void);
void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node);
void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub);
void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *app);
void bt_mesh_clear_net(void); void bt_mesh_clear_net(void);
void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub); void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub);
void bt_mesh_clear_app_key(struct bt_mesh_app_key *key); void bt_mesh_clear_app_key(struct bt_mesh_app_key *key);
void bt_mesh_clear_rpl(void); void bt_mesh_clear_rpl(void);
void bt_mesh_clear_node(struct bt_mesh_node *node); void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node);
void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub);
void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *app);
void bt_mesh_settings_init(void); void bt_mesh_settings_init(void);

View file

@ -26,6 +26,7 @@
#include "net.h" #include "net.h"
#include "transport.h" #include "transport.h"
#include "foundation.h" #include "foundation.h"
#include "settings.h"
#define CID_NVAL 0xffff #define CID_NVAL 0xffff
@ -217,7 +218,8 @@ static void prov_complete(u16_t net_idx, u16_t addr)
net.dst = addr; net.dst = addr;
} }
static void prov_node_added(u16_t net_idx, u16_t addr, u8_t num_elem) static void prov_node_added(u16_t net_idx, u8_t uuid[16], u16_t addr,
u8_t num_elem)
{ {
shell_print(ctx_shell, "Node provisioned, net_idx 0x%04x address " shell_print(ctx_shell, "Node provisioned, net_idx 0x%04x address "
"0x%04x elements %d", net_idx, addr, num_elem); "0x%04x elements %d", net_idx, addr, num_elem);
@ -796,6 +798,33 @@ static int cmd_beacon(const struct shell *shell, size_t argc, char *argv[])
return 0; return 0;
} }
static void print_unprovisioned_beacon(u8_t uuid[16],
bt_mesh_prov_oob_info_t oob_info,
u32_t *uri_hash)
{
char uuid_hex_str[32 + 1];
bin2hex(uuid, 16, uuid_hex_str, sizeof(uuid_hex_str));
shell_print(ctx_shell, "UUID %s, OOB Info 0x%04x, URI Hash 0x%x",
uuid_hex_str, oob_info,
(uri_hash == NULL ? 0 : *uri_hash));
}
static int cmd_beacon_listen(const struct shell *shell, size_t argc,
char *argv[])
{
u8_t val = str2u8(argv[1]);
if (val) {
prov.unprovisioned_beacon = print_unprovisioned_beacon;
} else {
prov.unprovisioned_beacon = NULL;
}
return 0;
}
static int cmd_ttl(const struct shell *shell, size_t argc, char *argv[]) static int cmd_ttl(const struct shell *shell, size_t argc, char *argv[])
{ {
u8_t ttl; u8_t ttl;
@ -1954,6 +1983,313 @@ static int cmd_del_fault(const struct shell *shell, size_t argc, char *argv[])
return 0; return 0;
} }
#if defined(CONFIG_BT_MESH_CDB)
static int cmd_cdb_create(const struct shell *shell, size_t argc,
char *argv[])
{
u8_t net_key[16];
size_t len;
int err;
if (argc < 2) {
bt_rand(net_key, 16);
} else {
len = hex2bin(argv[1], strlen(argv[1]), net_key,
sizeof(net_key));
memset(net_key + len, 0, sizeof(net_key) - len);
}
err = bt_mesh_cdb_create(net_key);
if (err < 0) {
shell_print(shell, "Failed to create CDB (err %d)", err);
}
return 0;
}
static int cmd_cdb_clear(const struct shell *shell, size_t argc,
char *argv[])
{
bt_mesh_cdb_clear();
shell_print(shell, "Cleared CDB");
return 0;
}
static void cdb_print_nodes(const struct shell *shell)
{
char key_hex_str[32 + 1], uuid_hex_str[32 + 1];
struct bt_mesh_cdb_node *node;
int i, total = 0;
bool configured;
shell_print(shell, "Address Elements Flags %-32s DevKey", "UUID");
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) {
node = &bt_mesh_cdb.nodes[i];
if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
continue;
}
configured = atomic_test_bit(node->flags,
BT_MESH_CDB_NODE_CONFIGURED);
total++;
bin2hex(node->uuid, 16, uuid_hex_str, sizeof(uuid_hex_str));
bin2hex(node->dev_key, 16, key_hex_str, sizeof(key_hex_str));
shell_print(shell, "0x%04x %-8d %-5s %s %s", node->addr,
node->num_elem, configured ? "C" : "-",
uuid_hex_str, key_hex_str);
}
shell_print(shell, "> Total nodes: %d", total);
}
static void cdb_print_subnets(const struct shell *shell)
{
struct bt_mesh_cdb_subnet *subnet;
char key_hex_str[32 + 1];
int i, total = 0;
shell_print(shell, "NetIdx NetKey");
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
subnet = &bt_mesh_cdb.subnets[i];
if (subnet->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
total++;
bin2hex(subnet->keys[0].net_key, 16, key_hex_str,
sizeof(key_hex_str));
shell_print(shell, "0x%03x %s", subnet->net_idx,
key_hex_str);
}
shell_print(shell, "> Total subnets: %d", total);
}
static void cdb_print_app_keys(const struct shell *shell)
{
struct bt_mesh_cdb_app_key *app_key;
char key_hex_str[32 + 1];
int i, total = 0;
shell_print(shell, "NetIdx AppIdx AppKey");
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) {
app_key = &bt_mesh_cdb.app_keys[i];
if (app_key->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
total++;
bin2hex(app_key->keys[0].app_key, 16, key_hex_str,
sizeof(key_hex_str));
shell_print(shell, "0x%03x 0x%03x %s",
app_key->net_idx, app_key->app_idx, key_hex_str);
}
shell_print(shell, "> Total app-keys: %d", total);
}
static int cmd_cdb_show(const struct shell *shell, size_t argc,
char *argv[])
{
if (!atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID)) {
shell_print(shell, "No valid networks");
return 0;
}
shell_print(shell, "Mesh Network Information");
shell_print(shell, "========================");
cdb_print_nodes(shell);
shell_print(shell, "---");
cdb_print_subnets(shell);
shell_print(shell, "---");
cdb_print_app_keys(shell);
return 0;
}
static int cmd_cdb_node_add(const struct shell *shell, size_t argc,
char *argv[])
{
struct bt_mesh_cdb_node *node;
u8_t uuid[16], dev_key[16];
u16_t addr, net_idx;
u8_t num_elem;
size_t len;
len = hex2bin(argv[1], strlen(argv[1]), uuid, sizeof(uuid));
memset(uuid + len, 0, sizeof(uuid) - len);
addr = strtoul(argv[2], NULL, 0);
num_elem = strtoul(argv[3], NULL, 0);
net_idx = strtoul(argv[4], NULL, 0);
if (argc < 6) {
bt_rand(dev_key, 16);
} else {
len = hex2bin(argv[5], strlen(argv[5]), dev_key,
sizeof(dev_key));
memset(dev_key + len, 0, sizeof(dev_key) - len);
}
node = bt_mesh_cdb_node_alloc(uuid, addr, num_elem, net_idx);
if (node == NULL) {
shell_print(shell, "Failed to allocate node");
return 0;
}
memcpy(node->dev_key, dev_key, 16);
if (IS_ENABLED(CONFIG_SETTINGS)) {
bt_mesh_store_cdb_node(node);
}
shell_print(shell, "Added node 0x%04x", addr);
return 0;
}
static int cmd_cdb_node_del(const struct shell *shell, size_t argc,
char *argv[])
{
struct bt_mesh_cdb_node *node;
u16_t addr;
addr = strtoul(argv[1], NULL, 0);
node = bt_mesh_cdb_node_get(addr);
if (node == NULL) {
shell_print(shell, "No node with address 0x%04x", addr);
return 0;
}
bt_mesh_cdb_node_del(node, true);
shell_print(shell, "Deleted node 0x%04x", addr);
return 0;
}
static int cmd_cdb_subnet_add(const struct shell *shell, size_t argc,
char *argv[])
{
struct bt_mesh_cdb_subnet *sub;
u8_t net_key[16];
u16_t net_idx;
size_t len;
net_idx = strtoul(argv[1], NULL, 0);
if (argc < 3) {
bt_rand(net_key, 16);
} else {
len = hex2bin(argv[2], strlen(argv[2]), net_key,
sizeof(net_key));
memset(net_key + len, 0, sizeof(net_key) - len);
}
sub = bt_mesh_cdb_subnet_alloc(net_idx);
if (sub == NULL) {
shell_print(shell, "Could not add subnet");
return 0;
}
memcpy(sub->keys[0].net_key, net_key, 16);
if (IS_ENABLED(CONFIG_SETTINGS)) {
bt_mesh_store_cdb_subnet(sub);
}
shell_print(shell, "Added Subnet 0x%03x", net_idx);
return 0;
}
static int cmd_cdb_subnet_del(const struct shell *shell, size_t argc,
char *argv[])
{
struct bt_mesh_cdb_subnet *sub;
u16_t net_idx;
net_idx = strtoul(argv[1], NULL, 0);
sub = bt_mesh_cdb_subnet_get(net_idx);
if (sub == NULL) {
shell_print(shell, "No subnet with NetIdx 0x%03x", net_idx);
return 0;
}
bt_mesh_cdb_subnet_del(sub, true);
shell_print(shell, "Deleted subnet 0x%03x", net_idx);
return 0;
}
static int cmd_cdb_app_key_add(const struct shell *shell, size_t argc,
char *argv[])
{
struct bt_mesh_cdb_app_key *key;
u16_t net_idx, app_idx;
u8_t app_key[16];
size_t len;
net_idx = strtoul(argv[1], NULL, 0);
app_idx = strtoul(argv[2], NULL, 0);
if (argc < 4) {
bt_rand(app_key, 16);
} else {
len = hex2bin(argv[3], strlen(argv[3]), app_key,
sizeof(app_key));
memset(app_key + len, 0, sizeof(app_key) - len);
}
key = bt_mesh_cdb_app_key_alloc(net_idx, app_idx);
if (key == NULL) {
shell_print(shell, "Could not add AppKey");
return 0;
}
memcpy(key->keys[0].app_key, app_key, 16);
if (IS_ENABLED(CONFIG_SETTINGS)) {
bt_mesh_store_cdb_app_key(key);
}
shell_print(shell, "Added AppKey 0x%03x", app_idx);
return 0;
}
static int cmd_cdb_app_key_del(const struct shell *shell, size_t argc,
char *argv[])
{
struct bt_mesh_cdb_app_key *key;
u16_t app_idx;
app_idx = strtoul(argv[1], NULL, 0);
key = bt_mesh_cdb_app_key_get(app_idx);
if (key == NULL) {
shell_print(shell, "No AppKey 0x%03x", app_idx);
return 0;
}
bt_mesh_cdb_app_key_del(key, true);
shell_print(shell, "Deleted AppKey 0x%03x", app_idx);
return 0;
}
#endif
SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds, SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds,
SHELL_CMD_ARG(init, NULL, NULL, cmd_init, 1, 0), SHELL_CMD_ARG(init, NULL, NULL, cmd_init, 1, 0),
SHELL_CMD_ARG(timeout, NULL, "[timeout in seconds]", cmd_timeout, 1, 1), SHELL_CMD_ARG(timeout, NULL, "[timeout in seconds]", cmd_timeout, 1, 1),
@ -1998,6 +2334,8 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds,
/* Configuration Client Model operations */ /* Configuration Client Model operations */
SHELL_CMD_ARG(get-comp, NULL, "[page]", cmd_get_comp, 1, 1), SHELL_CMD_ARG(get-comp, NULL, "[page]", cmd_get_comp, 1, 1),
SHELL_CMD_ARG(beacon, NULL, "[val: off, on]", cmd_beacon, 2, 1), SHELL_CMD_ARG(beacon, NULL, "[val: off, on]", cmd_beacon, 2, 1),
SHELL_CMD_ARG(beacon-listen, NULL, "[val: off, on]", cmd_beacon_listen,
2, 0),
SHELL_CMD_ARG(ttl, NULL, "[ttl: 0x00, 0x02-0x7f]", cmd_ttl, 1, 1), SHELL_CMD_ARG(ttl, NULL, "[ttl: 0x00, 0x02-0x7f]", cmd_ttl, 1, 1),
SHELL_CMD_ARG(friend, NULL, "[val: off, on]", cmd_friend, 1, 1), SHELL_CMD_ARG(friend, NULL, "[val: off, on]", cmd_friend, 1, 1),
SHELL_CMD_ARG(gatt-proxy, NULL, "[val: off, on]", cmd_gatt_proxy, 1, 1), SHELL_CMD_ARG(gatt-proxy, NULL, "[val: off, on]", cmd_gatt_proxy, 1, 1),
@ -2053,6 +2391,24 @@ SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds,
SHELL_CMD_ARG(add-fault, NULL, "<Fault ID>", cmd_add_fault, 2, 0), SHELL_CMD_ARG(add-fault, NULL, "<Fault ID>", cmd_add_fault, 2, 0),
SHELL_CMD_ARG(del-fault, NULL, "[Fault ID]", cmd_del_fault, 1, 1), SHELL_CMD_ARG(del-fault, NULL, "[Fault ID]", cmd_del_fault, 1, 1),
#if defined(CONFIG_BT_MESH_CDB)
/* Mesh Configuration Database Operations */
SHELL_CMD_ARG(cdb-create, NULL, "[NetKey]", cmd_cdb_create, 1, 1),
SHELL_CMD_ARG(cdb-clear, NULL, NULL, cmd_cdb_clear, 1, 0),
SHELL_CMD_ARG(cdb-show, NULL, NULL, cmd_cdb_show, 1, 0),
SHELL_CMD_ARG(cdb-node-add, NULL, "<UUID> <addr> <num-elem> "
"<NetKeyIdx> [DevKey]", cmd_cdb_node_add, 5, 1),
SHELL_CMD_ARG(cdb-node-del, NULL, "<addr>", cmd_cdb_node_del, 2, 0),
SHELL_CMD_ARG(cdb-subnet-add, NULL, "<NeyKeyIdx> [<NetKey>]",
cmd_cdb_subnet_add, 2, 1),
SHELL_CMD_ARG(cdb-subnet-del, NULL, "<NetKeyIdx>", cmd_cdb_subnet_del,
2, 0),
SHELL_CMD_ARG(cdb-app-key-add, NULL, "<NetKeyIdx> <AppKeyIdx> "
"[<AppKey>]", cmd_cdb_app_key_add, 3, 1),
SHELL_CMD_ARG(cdb-app-key-del, NULL, "<AppKeyIdx>", cmd_cdb_app_key_del,
2, 0),
#endif
SHELL_SUBCMD_SET_END SHELL_SUBCMD_SET_END
); );

View file

@ -34,7 +34,6 @@
#include "foundation.h" #include "foundation.h"
#include "settings.h" #include "settings.h"
#include "transport.h" #include "transport.h"
#include "nodes.h"
/* The transport layer needs at least three buffers for itself to avoid /* The transport layer needs at least three buffers for itself to avoid
* deadlocks. Ensure that there are a sufficient number of advertising * deadlocks. Ensure that there are a sufficient number of advertising
@ -653,7 +652,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, u32_t seq, u8_t hdr,
} }
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) { if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) {
struct bt_mesh_node *node; struct bt_mesh_cdb_node *node;
/* /*
* There is no way of knowing if we should use our * There is no way of knowing if we should use our
@ -661,7 +660,7 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, u32_t seq, u8_t hdr,
* message so we must try both. * message so we must try both.
*/ */
node = bt_mesh_node_find(rx->ctx.addr); node = bt_mesh_cdb_node_get(rx->ctx.addr);
if (node == NULL) { if (node == NULL) {
BT_ERR("No node found for addr 0x%04x", BT_ERR("No node found for addr 0x%04x",
rx->ctx.addr); rx->ctx.addr);
@ -1718,18 +1717,16 @@ int bt_mesh_app_key_get(const struct bt_mesh_subnet *subnet, u16_t app_idx,
{ {
struct bt_mesh_app_key *app_key; struct bt_mesh_app_key *app_key;
if (app_idx == BT_MESH_KEY_DEV_LOCAL || if (app_idx == BT_MESH_KEY_DEV_LOCAL) {
(app_idx == BT_MESH_KEY_DEV_REMOTE &&
bt_mesh_elem_find(addr) != NULL)) {
*aid = 0; *aid = 0;
*key = bt_mesh.dev_key; *key = bt_mesh.dev_key;
return 0; return 0;
} else if (app_idx == BT_MESH_KEY_DEV_REMOTE) { } else if (app_idx == BT_MESH_KEY_DEV_REMOTE) {
if (!IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) { if (!IS_ENABLED(CONFIG_BT_MESH_CDB)) {
return -EINVAL; return -EINVAL;
} }
struct bt_mesh_node *node = bt_mesh_node_find(addr); struct bt_mesh_cdb_node *node = bt_mesh_cdb_node_get(addr);
if (!node) { if (!node) {
return -EINVAL; return -EINVAL;
} }