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.

this is port of 29291bfe9ef5af4e6b7ae630812922f668fd0668
This commit is contained in:
Krzysztof Kopyściński
2021-01-12 14:05:19 +01:00
committed by Łukasz Rymanowski
parent 13c48e27d2
commit 0b1e0d72a8
21 changed files with 2275 additions and 293 deletions
+409
View File
@@ -0,0 +1,409 @@
/* atomic operations */
/*
* Copyright (c) 1997-2015, Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ATOMIC_H__
#define __ATOMIC_H__
#ifdef __cplusplus
extern "C"
{
#endif
typedef int atomic_t;
typedef atomic_t atomic_val_t;
/**
* @defgroup atomic_apis Atomic Services APIs
* @ingroup kernel_apis
* @{
*/
/**
* @brief Atomic compare-and-set.
*
* This routine performs an atomic compare-and-set on @a target. If the current
* value of @a target equals @a old_value, @a target is set to @a new_value.
* If the current value of @a target does not equal @a old_value, @a target
* is left unchanged.
*
* @param target Address of atomic variable.
* @param old_value Original value to compare against.
* @param new_value New value to store.
* @return 1 if @a new_value is written, 0 otherwise.
*/
static inline int atomic_cas(atomic_t *target, atomic_val_t old_value,
atomic_val_t new_value)
{
return __atomic_compare_exchange_n(target, &old_value, new_value,
0, __ATOMIC_SEQ_CST,
__ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic addition.
*
* This routine performs an atomic addition on @a target.
*
* @param target Address of atomic variable.
* @param value Value to add.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic subtraction.
*
* This routine performs an atomic subtraction on @a target.
*
* @param target Address of atomic variable.
* @param value Value to subtract.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic increment.
*
* This routine performs an atomic increment by 1 on @a target.
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_inc(atomic_t *target)
{
return atomic_add(target, 1);
}
/**
*
* @brief Atomic decrement.
*
* This routine performs an atomic decrement by 1 on @a target.
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_dec(atomic_t *target)
{
return atomic_sub(target, 1);
}
/**
*
* @brief Atomic get.
*
* This routine performs an atomic read on @a target.
*
* @param target Address of atomic variable.
*
* @return Value of @a target.
*/
static inline atomic_val_t atomic_get(const atomic_t *target)
{
return __atomic_load_n(target, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic get-and-set.
*
* This routine atomically sets @a target to @a value and returns
* the previous value of @a target.
*
* @param target Address of atomic variable.
* @param value Value to write to @a target.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
{
/* This builtin, as described by Intel, is not a traditional
* test-and-set operation, but rather an atomic exchange operation. It
* writes value into *ptr, and returns the previous contents of *ptr.
*/
return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic clear.
*
* This routine atomically sets @a target to zero and returns its previous
* value. (Hence, it is equivalent to atomic_set(target, 0).)
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_clear(atomic_t *target)
{
return atomic_set(target, 0);
}
/**
*
* @brief Atomic bitwise inclusive OR.
*
* This routine atomically sets @a target to the bitwise inclusive OR of
* @a target and @a value.
*
* @param target Address of atomic variable.
* @param value Value to OR.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise exclusive OR (XOR).
*
* This routine atomically sets @a target to the bitwise exclusive OR (XOR) of
* @a target and @a value.
*
* @param target Address of atomic variable.
* @param value Value to XOR
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise AND.
*
* This routine atomically sets @a target to the bitwise AND of @a target
* and @a value.
*
* @param target Address of atomic variable.
* @param value Value to AND.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise NAND.
*
* This routine atomically sets @a target to the bitwise NAND of @a target
* and @a value. (This operation is equivalent to target = ~(target & value).)
*
* @param target Address of atomic variable.
* @param value Value to NAND.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST);
}
/**
* @brief Initialize an atomic variable.
*
* This macro can be used to initialize an atomic variable. For example,
* @code atomic_t my_var = ATOMIC_INIT(75); @endcode
*
* @param i Value to assign to atomic variable.
*/
#define ATOMIC_INIT(i) (i)
/**
* @cond INTERNAL_HIDDEN
*/
#define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
#define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1)))
#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
/**
* INTERNAL_HIDDEN @endcond
*/
/**
* @brief Define an array of atomic variables.
*
* This macro defines an array of atomic variables containing at least
* @a num_bits bits.
*
* @note
* If used from file scope, the bits of the array are initialized to zero;
* if used from within a function, the bits are left uninitialized.
*
* @param name Name of array of atomic variables.
* @param num_bits Number of bits needed.
*/
#define ATOMIC_DEFINE(name, num_bits) \
atomic_t name[1 + ((num_bits) - 1) / ATOMIC_BITS]
/**
* @brief Atomically test a bit.
*
* This routine tests whether bit number @a bit of @a target is set or not.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return 1 if the bit was set, 0 if it wasn't.
*/
static inline int
atomic_test_bit(const atomic_t *target, int bit)
{
atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
return (1 & (val >> (bit & (ATOMIC_BITS - 1))));
}
/**
* @brief Atomically test and clear a bit.
*
* Atomically clear bit number @a bit of @a target and return its old value.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return 1 if the bit was set, 0 if it wasn't.
*/
static inline int
atomic_test_and_clear_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_val_t old;
old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
return (old & mask) != 0;
}
/**
* @brief Atomically set a bit.
*
* Atomically set bit number @a bit of @a target and return its old value.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return 1 if the bit was set, 0 if it wasn't.
*/
static inline int
atomic_test_and_set_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_val_t old;
old = atomic_or(ATOMIC_ELEM(target, bit), mask);
return (old & mask) != 0;
}
/**
* @brief Atomically clear a bit.
*
* Atomically clear bit number @a bit of @a target.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return N/A
*/
static inline void
atomic_clear_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_and(ATOMIC_ELEM(target, bit), ~mask);
}
/**
* @brief Atomically set a bit.
*
* Atomically set bit number @a bit of @a target.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return N/A
*/
static inline void
atomic_set_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_or(ATOMIC_ELEM(target, bit), mask);
}
/**
* @brief Atomically set a bit to a given value.
*
* Atomically set bit number @a bit of @a target to value @a val.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
* @param val true for 1, false for 0.
*
* @return N/A
*/
static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
{
atomic_val_t mask = ATOMIC_MASK(bit);
if (val) {
(void)atomic_or(ATOMIC_ELEM(target, bit), mask);
} else {
(void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
}
}
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __ATOMIC_H__ */
+265
View File
@@ -0,0 +1,265 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BLUETOOTH_MESH_CDB_H_
#define _BLUETOOTH_MESH_CDB_H_
#if MYNEWT_VAL(BLE_MESH_CDB)
#define NODE_COUNT MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)
#define SUBNET_COUNT MYNEWT_VAL(BLE_MESH_CDB_SUBNET_COUNT)
#define APP_KEY_COUNT MYNEWT_VAL(BLE_MESH_CDB_APP_KEY_COUNT)
#else
#define NODE_COUNT 0
#define SUBNET_COUNT 0
#define APP_KEY_COUNT 0
#endif
#include "atomic.h"
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_ */
+4 -3
View File
@@ -403,14 +403,15 @@ static inline unsigned int find_msb_set(u32_t op)
#define CONFIG_BT_MAX_CONN MYNEWT_VAL(BLE_MAX_CONNECTIONS)
#define CONFIG_BT_MESH_SEQ_STORE_RATE MYNEWT_VAL(BLE_MESH_SEQ_STORE_RATE)
#define CONFIG_BT_MESH_RPL_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_RPL_STORE_TIMEOUT)
#define CONFIG_BT_MESH_APP_KEY_COUNT MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT)
#define CONFIG_BT_MESH_SUBNET_COUNT MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)
#define CONFIG_BT_MESH_APP_KEY_COUNT MYNEWT_VAL(BLE_MESH_CDB_APP_KEY_COUNT)
#define CONFIG_BT_MESH_SUBNET_COUNT MYNEWT_VAL(BLE_MESH_CDB_SUBNET_COUNT)
#define CONFIG_BT_MESH_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_STORE_TIMEOUT)
#define CONFIG_BT_MESH_IVU_DIVIDER MYNEWT_VAL(BLE_MESH_IVU_DIVIDER)
#define CONFIG_BT_DEVICE_NAME MYNEWT_VAL(BLE_MESH_DEVICE_NAME)
#define CONFIG_BT_MESH_TX_SEG_MAX MYNEWT_VAL(BLE_MESH_TX_SEG_MAX)
#define CONFIG_BT_MESH_LABEL_COUNT MYNEWT_VAL(BLE_MESH_LABEL_COUNT)
#define CONFIG_BT_MESH_NODE_COUNT MYNEWT_VAL(BLE_MESH_NODE_COUNT)
#define CONFIG_BT_MESH_NODE_COUNT MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)
#define CONFIG_BT_MESH_CDB BLE_MESH_CDB
#define printk console_printf
+3 -1
View File
@@ -186,10 +186,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.
*
+1
View File
@@ -22,5 +22,6 @@
#include "cfg_cli.h"
#include "health_cli.h"
#include "proxy.h"
#include "cdb.h"
#endif /* __BT_MESH_H */
+1
View File
@@ -21,6 +21,7 @@
#include "crypto.h"
#include "beacon.h"
#include "foundation.h"
#include "atomic.h"
#define UNPROVISIONED_INTERVAL (K_SECONDS(5))
#define PROVISIONED_INTERVAL (K_SECONDS(10))
+385
View File
@@ -0,0 +1,385 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#define BT_DBG_ENABLED MYNEWT_VAL(BLE_MESH_DEBUG_CDB)
#define LOG_MODULE_NAME bt_mesh_cdb
#include "log/log.h"
#include "mesh/mesh.h"
#include "net.h"
#include "settings.h"
#include "mesh_priv.h"
#include "mesh/glue.h"
struct bt_mesh_cdb bt_mesh_cdb = {
.nodes = {
[0 ... (CONFIG_BT_MESH_NODE_COUNT - 1)] = {
.addr = BT_MESH_ADDR_UNASSIGNED,
}
},
.subnets = {
[0 ... (CONFIG_BT_MESH_SUBNET_COUNT - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
.app_keys = {
[0 ... (CONFIG_BT_MESH_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)
{
if MYNEWT_VAL(BLE_MESH_SETTINGS) {
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)
{
if MYNEWT_VAL(BLE_MESH_SETTINGS) {
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)
{
if MYNEWT_VAL(BLE_MESH_SETTINGS) {
bt_mesh_store_cdb_app_key(key);
}
}
-1
View File
@@ -867,4 +867,3 @@ char *settings_str_from_bytes(const void *vp, int vp_len,
}
#endif /* MYNEWT_VAL(BLE_MESH_SETTINGS) */
+47
View File
@@ -30,6 +30,7 @@
#include "mesh_priv.h"
#include "settings.h"
u8_t g_mesh_addr_type;
static struct ble_gap_event_listener mesh_event_listener;
@@ -58,6 +59,52 @@ 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(BLE_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);
+2
View File
@@ -8,6 +8,8 @@
#ifndef __MESH_PRIV_H
#define __MESH_PRIV_H
#include <stdbool.h>
#define BT_MESH_KEY_PRIMARY 0x0000
#define BT_MESH_KEY_ANY 0xffff
+4 -7
View File
@@ -77,13 +77,6 @@ struct bt_mesh_net bt_mesh = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
.nodes = {
[0 ... (CONFIG_BT_MESH_NODE_COUNT - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
#endif
};
static u32_t dup_cache[MYNEWT_VAL(BLE_MESH_MSG_CACHE_SIZE)];
@@ -700,6 +693,10 @@ do_update:
}
}
if (MYNEWT_VAL(BLE_MESH_CDB)) {
bt_mesh_cdb_iv_update(iv_index, iv_update);
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_iv(false);
}
-5
View File
@@ -230,7 +230,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,
@@ -263,10 +262,6 @@ struct bt_mesh_net {
u8_t dev_key[16];
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
struct bt_mesh_node nodes[MYNEWT_VAL(BLE_MESH_NODE_COUNT)];
#endif
struct bt_mesh_app_key app_keys[MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT)];
struct bt_mesh_subnet sub[MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)];
-161
View File
@@ -1,161 +0,0 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_PROV_LOG
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
#include "mesh/mesh.h"
#include "mesh_priv.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));
}
#endif
-10
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);
+19 -21
View File
@@ -26,7 +26,6 @@
#include "prov.h"
#include "testing.h"
#include "settings.h"
#include "nodes.h"
/* 3 transmissions, 20ms interval */
#define PROV_XMIT BT_MESH_TRANSMIT(2, 20)
@@ -123,10 +122,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 {
@@ -227,7 +227,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 (MYNEWT_VAL(BLE_MESH_PB_ADV))
@@ -699,9 +699,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;
@@ -1142,7 +1143,7 @@ static void prov_input_complete(const u8_t *data)
static void send_prov_data(void)
{
struct os_mbuf *pdu = PROV_BUF(34);
struct bt_mesh_subnet *sub;
struct bt_mesh_cdb_subnet *sub;
u8_t session_key[16];
u8_t nonce[13];
int err;
@@ -1175,7 +1176,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);
@@ -1184,10 +1185,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 */
@@ -1220,7 +1221,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 MYNEWT_VAL(BLE_MESH_PB_ADV)
u8_t reason = CLOSE_REASON_SUCCESS;
#endif
@@ -1230,7 +1231,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;
@@ -1241,7 +1242,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
@@ -1849,6 +1853,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;
@@ -2005,13 +2010,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) {
+632 -71
View File
@@ -9,6 +9,7 @@
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
#include "mesh_priv.h"
#include "mesh/mesh.h"
#include "mesh/glue.h"
#include "net.h"
@@ -18,8 +19,6 @@
#include "foundation.h"
#include "proxy.h"
#include "settings.h"
#include "nodes.h"
#include "mesh_priv.h"
#include "config/config.h"
@@ -28,12 +27,15 @@
* 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;
@@ -113,11 +115,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 {
@@ -125,12 +135,48 @@ struct node_update {
bool clear;
};
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
static struct node_update node_updates[CONFIG_BT_MESH_NODE_COUNT];
#if MYNEWT_VAL(BLE_MESH_CDB)
static struct node_update cdb_node_updates[MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)];
static struct key_update cdb_key_updates[
MYNEWT_VAL(BLE_MESH_CDB_SUBNET_COUNT) +
MYNEWT_VAL(BLE_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
int settings_name_next(char *name, char **next)
{
int rc = 0;
if (next) {
*next = NULL;
}
if (!name) {
return 0;
}
/* name might come from flash directly, in flash the name would end
* with '=' or '\0' depending how storage is done. Flash reading is
* limited to what can be read
*/
while ((*name != '\0') && (*name != '=') &&
(*name != '/')) {
rc++;
name++;
}
if (*name == '/') {
if (next) {
*next = name + 1;
}
return rc;
}
return rc;
}
/* We need this so we don't overwrite app-hardcoded values in case FCB
* contains a history of changes but then has a NULL at the end.
*/
@@ -759,10 +805,33 @@ static int va_set(int argc, char **argv, char *val)
}
#endif
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
static int node_set(int argc, char **argv, char *str)
#if MYNEWT_VAL(BLE_MESH_CDB)
static int cdb_net_set(int argc, char *val)
{
struct bt_mesh_node *node;
struct cdb_net_val net;
int len, err;
len = sizeof(net);
err = settings_bytes_from_str(val, &net, &len);
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(int argc, char *str)
{
struct bt_mesh_cdb_node *node;
struct node_val val;
u16_t addr;
int len, err;
@@ -772,15 +841,16 @@ static int node_set(int argc, char **argv, char *str)
return -ENOENT;
}
addr = strtol(argv[0], NULL, 16);
addr = strtol(str, NULL, 16);
len = sizeof(str);
if (str == NULL) {
if (argc < 1) {
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;
@@ -797,9 +867,10 @@ static int node_set(int argc, char **argv, char *str)
return -EINVAL;
}
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) {
@@ -807,12 +878,163 @@ static int node_set(int argc, char **argv, char *str)
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(int argc, char *name)
{
struct bt_mesh_cdb_subnet *sub;
struct net_key_val key;
u16_t net_idx;
int len, len_rd, err;
if (!name) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
len_rd = sizeof(sub);
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;
}
len = sizeof(key);
err = settings_bytes_from_str(name, &key, &len);
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(int argc, char *name)
{
struct bt_mesh_cdb_app_key *app;
struct app_key_val key;
u16_t app_idx;
int len_rd, err;
app_idx = strtol(name, NULL, 16);
len_rd = sizeof(key);
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 = settings_bytes_from_str(name, &key, &len_rd);
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(int argc, char **argv, char *name)
{
int len;
char *next;
if (argc < 1) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
if (!strcmp(name, "Net")) {
return cdb_net_set(1, name);
}
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(1, next);
}
if (!strncmp(name, "Subnet", len)) {
return cdb_subnet_set(1, next);
}
if (!strncmp(name, "AppKey", len)) {
return cdb_app_key_set(1, next);
}
BT_WARN("Unknown module key %s", name);
return -ENOENT;
}
#endif
const struct mesh_setting {
@@ -832,8 +1054,8 @@ const struct mesh_setting {
#if CONFIG_BT_MESH_LABEL_COUNT > 0
{ "Va", va_set },
#endif
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
{ "Node", node_set },
#if MYNEWT_VAL(BLE_MESH_CDB)
{ "cdb", cdb_set },
#endif
};
@@ -979,8 +1201,7 @@ static int mesh_commit(void)
#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)
{
@@ -1440,19 +1661,64 @@ static void store_pending_keys(void)
}
}
static void store_node(struct bt_mesh_node *node)
static void clear_cdb(void)
{
int err;
err = settings_save_one("bt/mesh/cdb/Net", NULL);
if (err) {
BT_ERR("Failed to clear Network");
} else {
BT_DBG("Cleared Network");
}
}
static void store_pending_cdb(void)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct cdb_net_val))];
struct cdb_net_val net;
int err;
char *str;
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);
str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf));
if (!str) {
BT_ERR("Unable to encode Network as value");
return;
}
err = settings_save_one("bt/mesh/cdb/Net", str);
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)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct node_val))];
struct node_val val;
char path[20];
char path[30];
char *str;
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);
str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf));
if (!str) {
@@ -1469,14 +1735,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_save_one(path, NULL);
if (err) {
BT_ERR("Failed to clear Node 0x%04x", addr);
@@ -1485,25 +1751,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);
}
@@ -1513,8 +1781,139 @@ 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)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))];
struct net_key_val key;
char path[30];
int err;
char *str;
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);
str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf));
if (!str) {
BT_ERR("Unable to encode Subnet as value");
return;
}
err = settings_save_one(path, str);
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_save_one(path, NULL);
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)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))];
struct app_key_val key;
char path[30];
int err;
char *str;
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);
str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf));
err = settings_save_one(path, str);
if (err) {
BT_ERR("Failed to store AppKey");
} else {
BT_DBG("Stored AppKey");
}
}
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_save_one(path, NULL);
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;
@@ -1522,8 +1921,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;
@@ -1786,9 +2185,26 @@ static void store_pending(struct ble_npl_event *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();
}
}
}
@@ -1977,51 +2393,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,
+7 -2
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_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);
+451 -1
View File
@@ -310,6 +310,53 @@ static u8_t hex2val(char c)
}
}
int char2hex(char c, uint8_t *x)
{
if (c >= '0' && c <= '9') {
*x = c - '0';
} else if (c >= 'a' && c <= 'f') {
*x = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
*x = c - 'A' + 10;
} else {
return -EINVAL;
}
return 0;
}
int hex2char(uint8_t x, char *c)
{
if (x <= 9) {
*c = x + '0';
} else if (x <= 15) {
*c = x - 10 + 'a';
} else {
return -EINVAL;
}
return 0;
}
size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen)
{
if ((hexlen + 1) < buflen * 2) {
return 0;
}
for (size_t i = 0; i < buflen; i++) {
if (hex2char(buf[i] >> 4, &hex[2 * i]) < 0) {
return 0;
}
if (hex2char(buf[i] & 0xf, &hex[2 * i + 1]) < 0) {
return 0;
}
}
hex[2 * buflen] = '\0';
return 2 * buflen;
}
static size_t hex2bin(const char *hex, u8_t *bin, size_t bin_len)
{
size_t len = 0;
@@ -337,7 +384,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)
{
printk("Node provisioned, net_idx 0x%04x address "
"0x%04x elements %d", net_idx, addr, num_elem);
@@ -1054,10 +1102,40 @@ static int cmd_beacon(int 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));
printk("UUID %s, OOB Info 0x%04x, URI Hash 0x%lx",
uuid_hex_str, oob_info,
(uri_hash == NULL ? 0 : *uri_hash));
}
static int cmd_beacon_listen(int argc, char *argv[])
{
u8_t val = str2u8(argv[1]);
if (val) {
prov.unprovisioned_beacon = print_unprovisioned_beacon;
} else {
prov.unprovisioned_beacon = NULL;
}
return 0;
}
struct shell_cmd_help cmd_beacon_help = {
NULL, "[val: off, on]", NULL
};
struct shell_cmd_help cmd_beacon_listen_help = {
NULL, "[val: off, on]", NULL
};
static int cmd_ttl(int argc, char *argv[])
{
u8_t ttl;
@@ -2261,6 +2339,333 @@ struct shell_cmd_help cmd_del_fault_help = {
NULL, "[Fault ID]", NULL
};
#if defined(CONFIG_BT_MESH_CDB)
struct shell_cmd_help cmd_cdb_create_help = {
NULL, "[NetKey]", NULL
};
struct shell_cmd_help cmd_cdb_clear_help = {
NULL, NULL, NULL
};
struct shell_cmd_help cmd_cdb_show_help = {
NULL, NULL, NULL
};
struct shell_cmd_help cmd_cdb_node_add_help = {
NULL, "<UUID> <addr> <num-elem> "
"<NetKeyIdx> [DevKey]", NULL
};
struct shell_cmd_help cmd_cdb_node_del_help = {
NULL, "<addr>", NULL
};
struct shell_cmd_help cmd_cdb_subnet_add_help = {
NULL, "<NeyKeyIdx> [<NetKey>]", NULL
};
struct shell_cmd_help cmd_cdb_subnet_del_help = {
NULL, "<NetKeyIdx>", NULL
};
struct shell_cmd_help cmd_cdb_app_key_add_help = {
NULL, "<NetKeyIdx> <AppKeyIdx> [<AppKey>]", NULL
};
struct shell_cmd_help cmd_cdb_app_key_del_help = {
NULL, "<AppKeyIdx>", NULL
};
static int cmd_cdb_create(int 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], net_key, sizeof(net_key));
memset(net_key + len, 0, sizeof(net_key) - len);
}
err = bt_mesh_cdb_create(net_key);
if (err < 0) {
printk("Failed to create CDB (err %d)", err);
}
return 0;
}
static int cmd_cdb_clear(int argc, char *argv[])
{
bt_mesh_cdb_clear();
printk("Cleared CDB");
return 0;
}
static void cdb_print_nodes(void)
{
char key_hex_str[32 + 1], uuid_hex_str[32 + 1];
struct bt_mesh_cdb_node *node;
int i, total = 0;
bool configured;
printk("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));
printk("0x%04x %-8d %-5s %s %s", node->addr,
node->num_elem, configured ? "C" : "-",
uuid_hex_str, key_hex_str);
}
printk("> Total nodes: %d", total);
}
static void cdb_print_subnets(void)
{
struct bt_mesh_cdb_subnet *subnet;
char key_hex_str[32 + 1];
int i, total = 0;
printk("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));
printk("0x%03x %s", subnet->net_idx,
key_hex_str);
}
printk("> Total subnets: %d", total);
}
static void cdb_print_app_keys(void)
{
struct bt_mesh_cdb_app_key *app_key;
char key_hex_str[32 + 1];
int i, total = 0;
printk("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));
printk("0x%03x 0x%03x %s",
app_key->net_idx, app_key->app_idx, key_hex_str);
}
printk("> Total app-keys: %d", total);
}
static int cmd_cdb_show(int argc, char *argv[])
{
if (!atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID)) {
printk("No valid networks");
return 0;
}
printk("Mesh Network Information");
printk("========================");
cdb_print_nodes();
printk("---");
cdb_print_subnets();
printk("---");
cdb_print_app_keys();
return 0;
}
static int cmd_cdb_node_add(int 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], 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], 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) {
printk("Failed to allocate node");
return 0;
}
memcpy(node->dev_key, dev_key, 16);
if (IS_ENABLED(CONFIG_SETTINGS)) {
bt_mesh_store_cdb_node(node);
}
printk("Added node 0x%04x", addr);
return 0;
}
static int cmd_cdb_node_del(int 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) {
printk("No node with address 0x%04x", addr);
return 0;
}
bt_mesh_cdb_node_del(node, true);
printk("Deleted node 0x%04x", addr);
return 0;
}
static int cmd_cdb_subnet_add(int 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], 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) {
printk("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);
}
printk("Added Subnet 0x%03x", net_idx);
return 0;
}
static int cmd_cdb_subnet_del(int 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) {
printk("No subnet with NetIdx 0x%03x", net_idx);
return 0;
}
bt_mesh_cdb_subnet_del(sub, true);
printk("Deleted subnet 0x%03x", net_idx);
return 0;
}
static int cmd_cdb_app_key_add(int 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], 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) {
printk("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);
}
printk("Added AppKey 0x%03x", app_idx);
return 0;
}
static int cmd_cdb_app_key_del(int 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) {
printk("No AppKey 0x%03x", app_idx);
return 0;
}
bt_mesh_cdb_app_key_del(key, true);
printk("Deleted AppKey 0x%03x", app_idx);
return 0;
}
#endif
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
static int cmd_gen_onoff_get(int argc, char *argv[])
{
@@ -2605,6 +3010,11 @@ static const struct shell_cmd mesh_commands[] = {
.sc_cmd_func = cmd_beacon,
.help = &cmd_beacon_help,
},
{
.sc_cmd = "beacon-listen",
.sc_cmd_func = cmd_beacon_listen,
.help = &cmd_beacon_listen_help,
},
{
.sc_cmd = "ttl",
.sc_cmd_func = cmd_ttl,
@@ -2748,6 +3158,46 @@ static const struct shell_cmd mesh_commands[] = {
.help = &cmd_del_fault_help,
},
#if MYNEWT_VAL(BLE_MESH_CDB)
{
.sc_cmd = "cdb-create",
.sc_cmd_func = cmd_cdb_create,
.help = &cmd_cdb_create_help,
},{
.sc_cmd = "cdb-clear",
.sc_cmd_func = cmd_cdb_clear,
.help = &cmd_cdb_clear_help,
},{
.sc_cmd = "cdb-show",
.sc_cmd_func = cmd_cdb_show,
.help = &cmd_cdb_show_help,
},{
.sc_cmd = "cdb-node-add",
.sc_cmd_func = cmd_cdb_node_add,
.help = &cmd_cdb_node_add_help,
},{
.sc_cmd = "cdb-node-del",
.sc_cmd_func = cmd_cdb_node_del,
.help = &cmd_cdb_node_del_help,
},{
.sc_cmd = "cdb-subnet-add",
.sc_cmd_func = cmd_cdb_subnet_add,
.help = &cmd_cdb_subnet_add_help,
},{
.sc_cmd = "cdb-subnet-del",
.sc_cmd_func = cmd_cdb_subnet_del,
.help = &cmd_cdb_subnet_del_help,
},{
.sc_cmd = "cdb-app-key-add",
.sc_cmd_func = cmd_cdb_app_key_add,
.help = &cmd_cdb_app_key_add_help,
},{
.sc_cmd = "cdb-app-key-add",
.sc_cmd_func = cmd_cdb_app_key_del,
.help = &cmd_cdb_app_key_del_help,
},
#endif
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
/* Generic Client Model Operations */
{
+5 -8
View File
@@ -25,7 +25,6 @@
#include "settings.h"
#include "transport.h"
#include "testing.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
@@ -643,7 +642,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
@@ -651,7 +650,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);
@@ -1724,18 +1723,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;
}
+24 -2
View File
@@ -36,10 +36,32 @@ syscfg.defs:
restrictions:
- (BLE_MESH_PROV)
BLE_MESH_NODE_COUNT:
BLE_MESH_CDB:
description: >
Mesh Configuration Database [EXPERIMENTAL]
value: 1
BLE_MESH_CDB_NODE_COUNT:
description: >
This option specifies how many nodes each network can at most
save in the provisioning database. Range 1-4096
save in the configuration database.
value: 1
BLE_MESH_CDB_SUBNET_COUNT:
description: >
This option specifies how many subnets that can at most be
saved in the configuration database.
value: 1
BLE_MESH_CDB_APP_KEY_COUNT:
description: >
This option specifies how many application keys that can at most
be saved in the configuration database.
value: 1
BLE_MESH_DEBUG_CDB:
description:
Use this option to enable configuration database debug logs.
value: 1
BLE_MESH_PROXY:
@@ -1020,6 +1020,22 @@
#define MYNEWT_VAL_BLE_MESH_PROVISIONER (0)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_CDB
#define MYNEWT_VAL_BLE_MESH_CDB (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT
#define MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT
#define MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT
#define MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL (1)
#endif