diff --git a/include/bluetooth/mesh.h b/include/bluetooth/mesh.h index ef4e2982d17..0a461383f6e 100644 --- a/include/bluetooth/mesh.h +++ b/include/bluetooth/mesh.h @@ -21,5 +21,6 @@ #include #include #include +#include #endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */ diff --git a/include/bluetooth/mesh/cdb.h b/include/bluetooth/mesh/cdb.h new file mode 100644 index 00000000000..c8c20b9b23d --- /dev/null +++ b/include/bluetooth/mesh/cdb.h @@ -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_ */ diff --git a/include/bluetooth/mesh/main.h b/include/bluetooth/mesh/main.h index 492f79dec5d..02cb572bf14 100644 --- a/include/bluetooth/mesh/main.h +++ b/include/bluetooth/mesh/main.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. * diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 3a286f7854b..7506b6a3df1 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -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) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index ff8d9d04b4f..39d5115fc86 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -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 diff --git a/subsys/bluetooth/mesh/cdb.c b/subsys/bluetooth/mesh/cdb.c new file mode 100644 index 00000000000..b857931f4db --- /dev/null +++ b/subsys/bluetooth/mesh/cdb.c @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2019 Tobias Svehagen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#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); +} diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index b5e58a0ed57..17bf6f51e42 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -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); diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 17652bdd050..739b1ec49cd 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -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); } diff --git a/subsys/bluetooth/mesh/net.h b/subsys/bluetooth/mesh/net.h index a7e7361997b..86116fd4b6e 100644 --- a/subsys/bluetooth/mesh/net.h +++ b/subsys/bluetooth/mesh/net.h @@ -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]; diff --git a/subsys/bluetooth/mesh/nodes.c b/subsys/bluetooth/mesh/nodes.c deleted file mode 100644 index 4d6f3d639bf..00000000000 --- a/subsys/bluetooth/mesh/nodes.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2019 Tobias Svehagen - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include - -#include - -#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)); -} diff --git a/subsys/bluetooth/mesh/nodes.h b/subsys/bluetooth/mesh/nodes.h deleted file mode 100644 index c1b8c6c79d5..00000000000 --- a/subsys/bluetooth/mesh/nodes.h +++ /dev/null @@ -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); diff --git a/subsys/bluetooth/mesh/prov.c b/subsys/bluetooth/mesh/prov.c index b9c1e9d06d2..a39f99e94e6 100644 --- a/subsys/bluetooth/mesh/prov.c +++ b/subsys/bluetooth/mesh/prov.c @@ -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) { diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index 4cb6f35487b..896a2997305 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -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, diff --git a/subsys/bluetooth/mesh/settings.h b/subsys/bluetooth/mesh/settings.h index c630814e518..2718cb5e3a2 100644 --- a/subsys/bluetooth/mesh/settings.h +++ b/subsys/bluetooth/mesh/settings.h @@ -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); diff --git a/subsys/bluetooth/mesh/shell.c b/subsys/bluetooth/mesh/shell.c index bddfa6417a4..dcf212a92ce 100644 --- a/subsys/bluetooth/mesh/shell.c +++ b/subsys/bluetooth/mesh/shell.c @@ -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, "", 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, " " + " [DevKey]", cmd_cdb_node_add, 5, 1), + SHELL_CMD_ARG(cdb-node-del, NULL, "", cmd_cdb_node_del, 2, 0), + SHELL_CMD_ARG(cdb-subnet-add, NULL, " []", + cmd_cdb_subnet_add, 2, 1), + SHELL_CMD_ARG(cdb-subnet-del, NULL, "", cmd_cdb_subnet_del, + 2, 0), + SHELL_CMD_ARG(cdb-app-key-add, NULL, " " + "[]", cmd_cdb_app_key_add, 3, 1), + SHELL_CMD_ARG(cdb-app-key-del, NULL, "", cmd_cdb_app_key_del, + 2, 0), +#endif + SHELL_SUBCMD_SET_END ); diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index bcc8ee35c52..2641c4756e2 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -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; }