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:
parent
8df133e547
commit
46a95f12ad
16 changed files with 1707 additions and 292 deletions
|
@ -21,5 +21,6 @@
|
|||
#include <bluetooth/mesh/cfg_cli.h>
|
||||
#include <bluetooth/mesh/health_cli.h>
|
||||
#include <bluetooth/mesh/proxy.h>
|
||||
#include <bluetooth/mesh/cdb.h>
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */
|
||||
|
|
263
include/bluetooth/mesh/cdb.h
Normal file
263
include/bluetooth/mesh/cdb.h
Normal 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_ */
|
|
@ -190,10 +190,12 @@ struct bt_mesh_prov {
|
|||
* the specified NetKeyIndex and primary element address.
|
||||
*
|
||||
* @param net_idx NetKeyIndex given during provisioning.
|
||||
* @param uuid UUID of the added node
|
||||
* @param addr Primary element address.
|
||||
* @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.
|
||||
*
|
||||
|
|
|
@ -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_PROVISIONER nodes.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_CDB cdb.c)
|
||||
|
|
|
@ -37,17 +37,36 @@ config BT_MESH_PROVISIONER
|
|||
help
|
||||
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
|
||||
int "Maximum number of saved nodes per network"
|
||||
if BT_MESH_CDB
|
||||
|
||||
config BT_MESH_CDB_NODE_COUNT
|
||||
int "Maximum number of nodes in the database"
|
||||
default 1
|
||||
range 1 4096
|
||||
help
|
||||
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
|
||||
|
||||
|
@ -591,6 +610,12 @@ config BT_MESH_DEBUG_SETTINGS
|
|||
help
|
||||
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
|
||||
|
|
382
subsys/bluetooth/mesh/cdb.c
Normal file
382
subsys/bluetooth/mesh/cdb.c
Normal 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);
|
||||
}
|
|
@ -59,6 +59,53 @@ int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
|
|||
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);
|
||||
if (err) {
|
||||
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
|
||||
|
|
|
@ -83,13 +83,6 @@ struct bt_mesh_net bt_mesh = {
|
|||
.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];
|
||||
|
@ -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)) {
|
||||
bt_mesh_store_iv(false);
|
||||
}
|
||||
|
|
|
@ -222,7 +222,6 @@ enum {
|
|||
BT_MESH_CFG_PENDING,
|
||||
BT_MESH_MOD_PENDING,
|
||||
BT_MESH_VA_PENDING,
|
||||
BT_MESH_NODES_PENDING,
|
||||
|
||||
/* Don't touch - intentionally last */
|
||||
BT_MESH_FLAG_COUNT,
|
||||
|
@ -255,10 +254,6 @@ struct bt_mesh_net {
|
|||
|
||||
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_subnet sub[CONFIG_BT_MESH_SUBNET_COUNT];
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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);
|
|
@ -34,7 +34,6 @@
|
|||
#include "proxy.h"
|
||||
#include "prov.h"
|
||||
#include "settings.h"
|
||||
#include "nodes.h"
|
||||
|
||||
/* 3 transmissions, 20ms interval */
|
||||
#define PROV_XMIT BT_MESH_TRANSMIT(2, 20)
|
||||
|
@ -131,10 +130,11 @@ enum {
|
|||
#endif
|
||||
|
||||
struct provisioner_link {
|
||||
struct bt_mesh_node *node;
|
||||
struct bt_mesh_cdb_node *node;
|
||||
u16_t addr;
|
||||
u16_t net_idx;
|
||||
u8_t attention_duration;
|
||||
u8_t uuid[16];
|
||||
};
|
||||
|
||||
struct prov_link {
|
||||
|
@ -234,7 +234,7 @@ static int reset_state(void)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
|
||||
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)
|
||||
|
@ -690,9 +690,10 @@ static void prov_capabilities(const u8_t *data)
|
|||
return;
|
||||
}
|
||||
|
||||
link.provisioner->node = bt_mesh_node_alloc(link.provisioner->addr,
|
||||
data[0],
|
||||
link.provisioner->net_idx);
|
||||
link.provisioner->node =
|
||||
bt_mesh_cdb_node_alloc(link.provisioner->uuid,
|
||||
link.provisioner->addr, data[0],
|
||||
link.provisioner->net_idx);
|
||||
if (link.provisioner->node == NULL) {
|
||||
prov_send_fail_msg(PROV_ERR_RESOURCES);
|
||||
return;
|
||||
|
@ -1122,7 +1123,7 @@ static void prov_input_complete(const u8_t *data)
|
|||
static void send_prov_data(void)
|
||||
{
|
||||
PROV_BUF(pdu, 34);
|
||||
struct bt_mesh_subnet *sub;
|
||||
struct bt_mesh_cdb_subnet *sub;
|
||||
u8_t session_key[16];
|
||||
u8_t nonce[13];
|
||||
int err;
|
||||
|
@ -1155,7 +1156,7 @@ static void send_prov_data(void)
|
|||
|
||||
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) {
|
||||
BT_ERR("No subnet with net_idx %u",
|
||||
link.provisioner->node->net_idx);
|
||||
|
@ -1164,10 +1165,10 @@ static void send_prov_data(void)
|
|||
}
|
||||
|
||||
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_u8(&pdu, bt_mesh_net_flags(sub));
|
||||
net_buf_simple_add_be32(&pdu, bt_mesh.iv_index);
|
||||
net_buf_simple_add_u8(&pdu, bt_mesh_cdb_subnet_flags(sub));
|
||||
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(&pdu, 8); /* For MIC */
|
||||
|
||||
|
@ -1197,7 +1198,7 @@ static void prov_complete(const u8_t *data)
|
|||
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)
|
||||
u8_t reason = CLOSE_REASON_SUCCESS;
|
||||
#endif
|
||||
|
@ -1207,7 +1208,7 @@ static void prov_complete(const u8_t *data)
|
|||
node->addr);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_node(node);
|
||||
bt_mesh_store_cdb_node(node);
|
||||
}
|
||||
|
||||
link.provisioner->node = NULL;
|
||||
|
@ -1218,7 +1219,10 @@ static void prov_complete(const u8_t *data)
|
|||
bearer_ctl_send(LINK_CLOSE, &reason, sizeof(reason));
|
||||
#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
|
||||
|
@ -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));
|
||||
link.tx.id = 0x7F;
|
||||
memcpy(link.provisioner->uuid, uuid, 16);
|
||||
link.provisioner->addr = addr;
|
||||
link.provisioner->net_idx = net_idx;
|
||||
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)
|
||||
{
|
||||
if (prov->reset) {
|
||||
|
|
|
@ -32,19 +32,21 @@
|
|||
#include "foundation.h"
|
||||
#include "proxy.h"
|
||||
#include "settings.h"
|
||||
#include "nodes.h"
|
||||
|
||||
/* 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
|
||||
* 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.
|
||||
*/
|
||||
static struct key_update {
|
||||
struct key_update {
|
||||
u16_t key_idx:12, /* AppKey or NetKey Index */
|
||||
valid:1, /* 1 if this entry is valid, 0 if not */
|
||||
app_key:1, /* 1 if this is an AppKey, 0 if a NetKey */
|
||||
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;
|
||||
|
||||
|
@ -124,11 +126,19 @@ struct va_val {
|
|||
u8_t uuid[16];
|
||||
} __packed;
|
||||
|
||||
struct cdb_net_val {
|
||||
u32_t iv_index;
|
||||
bool iv_update;
|
||||
} __packed;
|
||||
|
||||
/* Node storage information */
|
||||
struct node_val {
|
||||
u16_t net_idx;
|
||||
u8_t dev_key[16];
|
||||
u8_t num_elem;
|
||||
u8_t flags;
|
||||
#define F_NODE_CONFIGURED 0x01
|
||||
u8_t uuid[16];
|
||||
u8_t dev_key[16];
|
||||
} __packed;
|
||||
|
||||
struct node_update {
|
||||
|
@ -136,10 +146,13 @@ struct node_update {
|
|||
bool clear;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PROVISIONER)
|
||||
static struct node_update node_updates[CONFIG_BT_MESH_NODE_COUNT];
|
||||
#if defined(CONFIG_BT_MESH_CDB)
|
||||
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
|
||||
static struct node_update node_updates[0];
|
||||
static struct node_update cdb_node_updates[0];
|
||||
static struct key_update cdb_key_updates[0];
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PROVISIONER)
|
||||
static int node_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
#if defined(CONFIG_BT_MESH_CDB)
|
||||
static int cdb_net_set(const char *name, size_t len_rd,
|
||||
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;
|
||||
u16_t addr;
|
||||
int err;
|
||||
|
@ -778,9 +819,9 @@ static int node_set(const char *name, size_t len_rd,
|
|||
BT_DBG("val (null)");
|
||||
BT_DBG("Deleting node 0x%04x", addr);
|
||||
|
||||
node = bt_mesh_node_find(addr);
|
||||
node = bt_mesh_cdb_node_get(addr);
|
||||
if (node) {
|
||||
bt_mesh_node_del(node, false);
|
||||
bt_mesh_cdb_node_del(node, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -792,9 +833,10 @@ static int node_set(const char *name, size_t len_rd,
|
|||
return err;
|
||||
}
|
||||
|
||||
node = bt_mesh_node_find(addr);
|
||||
node = bt_mesh_cdb_node_get(addr);
|
||||
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) {
|
||||
|
@ -802,12 +844,168 @@ static int node_set(const char *name, size_t len_rd,
|
|||
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);
|
||||
|
||||
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
|
||||
|
||||
const struct mesh_setting {
|
||||
|
@ -828,8 +1026,8 @@ const struct mesh_setting {
|
|||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||
{ "Va", va_set },
|
||||
#endif
|
||||
#if defined(CONFIG_BT_MESH_PROVISIONER)
|
||||
{ "Node", node_set },
|
||||
#if defined(CONFIG_BT_MESH_CDB)
|
||||
{ "cdb", cdb_set },
|
||||
#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) | \
|
||||
BIT(BT_MESH_HB_PUB_PENDING) | \
|
||||
BIT(BT_MESH_CFG_PENDING) | \
|
||||
BIT(BT_MESH_MOD_PENDING) | \
|
||||
BIT(BT_MESH_NODES_PENDING))
|
||||
BIT(BT_MESH_MOD_PENDING))
|
||||
|
||||
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;
|
||||
char path[20];
|
||||
char path[30];
|
||||
int err;
|
||||
|
||||
val.net_idx = node->net_idx;
|
||||
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);
|
||||
|
||||
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));
|
||||
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;
|
||||
|
||||
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);
|
||||
if (err) {
|
||||
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;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(node_updates); ++i) {
|
||||
struct node_update *update = &node_updates[i];
|
||||
for (i = 0; i < ARRAY_SIZE(cdb_node_updates); ++i) {
|
||||
struct node_update *update = &cdb_node_updates[i];
|
||||
|
||||
if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (update->clear) {
|
||||
clear_node(update->addr);
|
||||
} else {
|
||||
struct bt_mesh_node *node;
|
||||
BT_DBG("addr: 0x%04x, clear: %d", update->addr, update->clear);
|
||||
|
||||
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) {
|
||||
store_node(node);
|
||||
store_cdb_node(node);
|
||||
} else {
|
||||
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,
|
||||
struct node_update **free_slot)
|
||||
static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub)
|
||||
{
|
||||
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;
|
||||
int i;
|
||||
|
@ -1433,8 +1790,8 @@ static struct node_update *node_update_find(u16_t addr,
|
|||
match = NULL;
|
||||
*free_slot = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(node_updates); i++) {
|
||||
struct node_update *update = &node_updates[i];
|
||||
for (i = 0; i < ARRAY_SIZE(cdb_node_updates); i++) {
|
||||
struct node_update *update = &cdb_node_updates[i];
|
||||
|
||||
if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
*free_slot = update;
|
||||
|
@ -1665,9 +2022,26 @@ static void store_pending(struct k_work *work)
|
|||
store_pending_va();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
|
||||
atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_NODES_PENDING)) {
|
||||
store_pending_nodes();
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_CDB)) {
|
||||
if (atomic_test_and_clear_bit(bt_mesh_cdb.flags,
|
||||
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);
|
||||
}
|
||||
|
||||
void bt_mesh_store_node(struct bt_mesh_node *node)
|
||||
static void schedule_cdb_store(int flag)
|
||||
{
|
||||
struct node_update *update, *free_slot;
|
||||
|
||||
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);
|
||||
atomic_set_bit(bt_mesh_cdb.flags, flag);
|
||||
k_delayed_work_submit(&pending_store, K_NO_WAIT);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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) {
|
||||
update->clear = true;
|
||||
schedule_store(BT_MESH_NODES_PENDING);
|
||||
update->clear = false;
|
||||
schedule_cdb_store(BT_MESH_CDB_NODES_PENDING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!free_slot) {
|
||||
clear_node(node->addr);
|
||||
store_cdb_node(node);
|
||||
return;
|
||||
}
|
||||
|
||||
free_slot->clear = true;
|
||||
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,
|
||||
|
|
|
@ -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_pub(struct bt_mesh_model *mod);
|
||||
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_subnet(struct bt_mesh_subnet *sub);
|
||||
void bt_mesh_clear_app_key(struct bt_mesh_app_key *key);
|
||||
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);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "net.h"
|
||||
#include "transport.h"
|
||||
#include "foundation.h"
|
||||
#include "settings.h"
|
||||
|
||||
#define CID_NVAL 0xffff
|
||||
|
||||
|
@ -217,7 +218,8 @@ static void prov_complete(u16_t net_idx, u16_t 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 "
|
||||
"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;
|
||||
}
|
||||
|
||||
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[])
|
||||
{
|
||||
u8_t ttl;
|
||||
|
@ -1954,6 +1983,313 @@ static int cmd_del_fault(const struct shell *shell, size_t argc, char *argv[])
|
|||
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_CMD_ARG(init, NULL, NULL, cmd_init, 1, 0),
|
||||
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 */
|
||||
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-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(friend, NULL, "[val: off, on]", cmd_friend, 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(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
|
||||
);
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include "foundation.h"
|
||||
#include "settings.h"
|
||||
#include "transport.h"
|
||||
#include "nodes.h"
|
||||
|
||||
/* The transport layer needs at least three buffers for itself to avoid
|
||||
* 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)) {
|
||||
struct bt_mesh_node *node;
|
||||
struct bt_mesh_cdb_node *node;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
node = bt_mesh_node_find(rx->ctx.addr);
|
||||
node = bt_mesh_cdb_node_get(rx->ctx.addr);
|
||||
if (node == NULL) {
|
||||
BT_ERR("No node found for addr 0x%04x",
|
||||
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;
|
||||
|
||||
if (app_idx == BT_MESH_KEY_DEV_LOCAL ||
|
||||
(app_idx == BT_MESH_KEY_DEV_REMOTE &&
|
||||
bt_mesh_elem_find(addr) != NULL)) {
|
||||
if (app_idx == BT_MESH_KEY_DEV_LOCAL) {
|
||||
*aid = 0;
|
||||
*key = bt_mesh.dev_key;
|
||||
return 0;
|
||||
} 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;
|
||||
}
|
||||
|
||||
struct bt_mesh_node *node = bt_mesh_node_find(addr);
|
||||
struct bt_mesh_cdb_node *node = bt_mesh_cdb_node_get(addr);
|
||||
if (!node) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue