Bluetooth: Mesh: Add support for provisioner role over PB-ADV
Make it possible to provision devices over advertising bearer (PB-ADV). Many messages in the provisioning protocol are the same for provisioner and device so much of the code could be reused by only changing when they are expected to arrive. This introduces to concept of local and remote device keys. The models for cfg_cli and cfg_srv have been updated to reflect this concept. Both the send and receive path in the transport layer have been updated to support encrypting/decrypting with local and remote device keys. When a node has been provisioned it is stored in bt_mesh_net.nodes. If CONFIG_BT_SETTINGS is enabled, they are also saved to settings. If the callback node_added in bt_mesh_prov has been set, it will be called for every node that gets provisioned. This includes when they are retrieved from settings. The configuration CONFIG_BT_MESH_NODE_COUNT controls how many nodes that can be provisioned. Signed-off-by: Tobias Svehagen <tobias.svehagen@gmail.com>
This commit is contained in:
parent
de92d1a83b
commit
80669decce
20 changed files with 965 additions and 100 deletions
|
@ -31,6 +31,12 @@ extern "C" {
|
|||
|
||||
#define BT_MESH_KEY_UNUSED 0xffff
|
||||
#define BT_MESH_KEY_DEV 0xfffe
|
||||
#define BT_MESH_KEY_DEV_LOCAL BT_MESH_KEY_DEV
|
||||
#define BT_MESH_KEY_DEV_REMOTE 0xfffd
|
||||
#define BT_MESH_KEY_DEV_ANY 0xfffc
|
||||
|
||||
#define BT_MESH_IS_DEV_KEY(key) (key == BT_MESH_KEY_DEV_LOCAL || \
|
||||
key == BT_MESH_KEY_DEV_REMOTE)
|
||||
|
||||
/** Helper to define a mesh element within an array.
|
||||
*
|
||||
|
|
|
@ -179,6 +179,18 @@ struct bt_mesh_prov {
|
|||
*/
|
||||
void (*complete)(u16_t net_idx, u16_t addr);
|
||||
|
||||
/** @brief A new node has been added to the provisioning database.
|
||||
*
|
||||
* This callback notifies the application that provisioning has
|
||||
* been successfully completed, and that a node has been assigned
|
||||
* the specified NetKeyIndex and primary element address.
|
||||
*
|
||||
* @param net_idx NetKeyIndex given during provisioning.
|
||||
* @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);
|
||||
|
||||
/** @brief Node has been reset.
|
||||
*
|
||||
* This callback notifies the application that the local node
|
||||
|
|
|
@ -32,3 +32,6 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_HEALTH_CLI health_cli.c)
|
|||
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)
|
||||
|
||||
|
|
|
@ -32,6 +32,26 @@ config BT_MESH_PB_ADV
|
|||
Enable this option to allow the device to be provisioned over
|
||||
the advertising bearer.
|
||||
|
||||
config BT_MESH_PROVISIONER
|
||||
bool "Provisioner support"
|
||||
select BT_ECC
|
||||
select BT_MESH_PROV
|
||||
default n
|
||||
help
|
||||
Enable this option to have support for provisioning remote devices.
|
||||
|
||||
if BT_MESH_PROVISIONER
|
||||
|
||||
config BT_MESH_NODE_COUNT
|
||||
int "Maximum number of saved nodes per network"
|
||||
default 1
|
||||
range 1 4096
|
||||
help
|
||||
This option specifies how many nodes each network can at most
|
||||
save in the provisioning database.
|
||||
|
||||
endif # BT_MESH_PROVISIONER
|
||||
|
||||
if BT_CONN
|
||||
|
||||
# Virtual option enabled whenever any Proxy protocol is needed
|
||||
|
|
|
@ -414,7 +414,9 @@ static bool model_has_key(struct bt_mesh_model *mod, u16_t key)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
|
||||
if (mod->keys[i] == key) {
|
||||
if (mod->keys[i] == key ||
|
||||
(mod->keys[i] == BT_MESH_KEY_DEV_ANY &&
|
||||
BT_MESH_IS_DEV_KEY(key))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -505,8 +505,11 @@ static int cfg_cli_init(struct bt_mesh_model *model)
|
|||
cli = model->user_data;
|
||||
cli->model = model;
|
||||
|
||||
/* Configuration Model security is device-key based */
|
||||
model->keys[0] = BT_MESH_KEY_DEV;
|
||||
/*
|
||||
* Configuration Model security is device-key based and both the local
|
||||
* and remote keys are allowed to access this model.
|
||||
*/
|
||||
model->keys[0] = BT_MESH_KEY_DEV_ANY;
|
||||
|
||||
k_sem_init(&cli->op_sync, 0, 1);
|
||||
|
||||
|
@ -558,7 +561,7 @@ int bt_mesh_cfg_comp_data_get(u16_t net_idx, u16_t addr, u8_t page,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_DEV_COMP_DATA_GET, 1);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -592,7 +595,7 @@ static int get_state_u8(u16_t net_idx, u16_t addr, u32_t op, u32_t rsp,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, DUMMY_2_BYTE_OP, 0);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -621,7 +624,7 @@ static int set_state_u8(u16_t net_idx, u16_t addr, u32_t op, u32_t rsp,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, DUMMY_2_BYTE_OP, 1);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -700,7 +703,7 @@ int bt_mesh_cfg_relay_get(u16_t net_idx, u16_t addr, u8_t *status,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_RELAY_GET, 0);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -733,7 +736,7 @@ int bt_mesh_cfg_relay_set(u16_t net_idx, u16_t addr, u8_t new_relay,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_RELAY_SET, 2);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -768,7 +771,7 @@ int bt_mesh_cfg_net_key_add(u16_t net_idx, u16_t addr, u16_t key_net_idx,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_NET_KEY_ADD, 18);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -809,7 +812,7 @@ int bt_mesh_cfg_app_key_add(u16_t net_idx, u16_t addr, u16_t key_net_idx,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_APP_KEY_ADD, 19);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -851,7 +854,7 @@ static int mod_app_bind(u16_t net_idx, u16_t addr, u16_t elem_addr,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_APP_BIND, 8);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -919,7 +922,7 @@ static int mod_sub(u32_t op, u16_t net_idx, u16_t addr, u16_t elem_addr,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, DUMMY_2_BYTE_OP, 8);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -1026,7 +1029,7 @@ static int mod_sub_va(u32_t op, u16_t net_idx, u16_t addr, u16_t elem_addr,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, DUMMY_2_BYTE_OP, 22);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -1142,7 +1145,7 @@ static int mod_pub_get(u16_t net_idx, u16_t addr, u16_t elem_addr,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_GET, 6);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -1211,7 +1214,7 @@ static int mod_pub_set(u16_t net_idx, u16_t addr, u16_t elem_addr,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_MOD_PUB_SET, 13);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -1284,7 +1287,7 @@ int bt_mesh_cfg_hb_sub_set(u16_t net_idx, u16_t addr,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_SUB_SET, 5);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -1325,7 +1328,7 @@ int bt_mesh_cfg_hb_sub_get(u16_t net_idx, u16_t addr,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_SUB_GET, 0);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -1363,7 +1366,7 @@ int bt_mesh_cfg_hb_pub_set(u16_t net_idx, u16_t addr,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_PUB_SET, 9);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
@ -1406,7 +1409,7 @@ int bt_mesh_cfg_hb_pub_get(u16_t net_idx, u16_t addr,
|
|||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_HEARTBEAT_PUB_GET, 0);
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
|
|
@ -3269,8 +3269,11 @@ static int cfg_srv_init(struct bt_mesh_model *model)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Configuration Model security is device-key based */
|
||||
model->keys[0] = BT_MESH_KEY_DEV;
|
||||
/*
|
||||
* Configuration Model security is device-key based and only the local
|
||||
* device-key is allowed to access this model.
|
||||
*/
|
||||
model->keys[0] = BT_MESH_KEY_DEV_LOCAL;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_RELAY)) {
|
||||
cfg->relay = BT_MESH_RELAY_NOT_SUPPORTED;
|
||||
|
|
|
@ -840,6 +840,12 @@ int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13],
|
|||
return bt_mesh_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8);
|
||||
}
|
||||
|
||||
int bt_mesh_prov_encrypt(const u8_t key[16], u8_t nonce[13],
|
||||
const u8_t data[25], u8_t out[25 + 8])
|
||||
{
|
||||
return bt_mesh_ccm_encrypt(key, nonce, data, 25, NULL, 0, out, 8);
|
||||
}
|
||||
|
||||
int bt_mesh_beacon_auth(const u8_t beacon_key[16], u8_t flags,
|
||||
const u8_t net_id[8], u32_t iv_index,
|
||||
u8_t auth[8])
|
||||
|
|
|
@ -152,3 +152,6 @@ int bt_mesh_prov_conf(const u8_t conf_key[16], const u8_t rand[16],
|
|||
|
||||
int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13],
|
||||
const u8_t data[25 + 8], u8_t out[25]);
|
||||
|
||||
int bt_mesh_prov_encrypt(const u8_t key[16], u8_t nonce[13],
|
||||
const u8_t data[25], u8_t out[25 + 8]);
|
||||
|
|
|
@ -337,10 +337,10 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd,
|
|||
int err;
|
||||
|
||||
meta->subnet = bt_mesh_subnet_get(frnd->net_idx);
|
||||
meta->is_dev_key = (app_idx == BT_MESH_KEY_DEV);
|
||||
meta->is_dev_key = BT_MESH_IS_DEV_KEY(app_idx);
|
||||
bt_mesh_net_header_parse(&buf->b, &meta->net);
|
||||
err = bt_mesh_app_key_get(meta->subnet, app_idx, &meta->key,
|
||||
&meta->aid);
|
||||
err = bt_mesh_app_key_get(meta->subnet, app_idx, meta->net.ctx.recv_dst,
|
||||
&meta->key, &meta->aid);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -84,6 +84,13 @@ 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];
|
||||
|
|
|
@ -33,6 +33,13 @@ struct bt_mesh_app_key {
|
|||
} keys[2];
|
||||
};
|
||||
|
||||
struct bt_mesh_node {
|
||||
u16_t addr;
|
||||
u16_t net_idx;
|
||||
u8_t dev_key[16];
|
||||
u8_t num_elem;
|
||||
};
|
||||
|
||||
struct bt_mesh_subnet {
|
||||
u32_t beacon_sent; /* Timestamp of last sent beacon */
|
||||
u8_t beacons_last; /* Number of beacons during last
|
||||
|
@ -216,6 +223,7 @@ 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,
|
||||
|
@ -248,6 +256,10 @@ 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];
|
||||
|
|
161
subsys/bluetooth/mesh/nodes.c
Normal file
161
subsys/bluetooth/mesh/nodes.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Tobias Svehagen
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <bluetooth/mesh.h>
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_PROV)
|
||||
#define LOG_MODULE_NAME bt_mesh_node
|
||||
#include "common/log.h"
|
||||
|
||||
#include "mesh.h"
|
||||
#include "net.h"
|
||||
#include "access.h"
|
||||
#include "settings.h"
|
||||
|
||||
/*
|
||||
* Check if an address range from addr_start for addr_start + num_elem - 1 is
|
||||
* free for use. When a conflict is found, next will be set to the next address
|
||||
* available after the conflicting range and -EAGAIN will be returned.
|
||||
*/
|
||||
static int addr_is_free(u16_t addr_start, u8_t num_elem, u16_t *next)
|
||||
{
|
||||
const struct bt_mesh_comp *comp = bt_mesh_comp_get();
|
||||
u16_t addr_end = addr_start + num_elem - 1;
|
||||
u16_t other_start, other_end;
|
||||
int i;
|
||||
|
||||
if (comp == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!BT_MESH_ADDR_IS_UNICAST(addr_start) ||
|
||||
!BT_MESH_ADDR_IS_UNICAST(addr_end) ||
|
||||
num_elem == 0 || next == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
other_start = bt_mesh_primary_addr();
|
||||
other_end = other_start + comp->elem_count - 1;
|
||||
|
||||
/* Compare with local element addresses */
|
||||
if (!(addr_end < other_start || addr_start > other_end)) {
|
||||
*next = other_end + 1;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
|
||||
struct bt_mesh_node *node = &bt_mesh.nodes[i];
|
||||
|
||||
if (node->net_idx == BT_MESH_KEY_UNUSED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
other_start = node->addr;
|
||||
other_end = other_start + node->num_elem - 1;
|
||||
|
||||
if (!(addr_end < other_start || addr_start > other_end)) {
|
||||
*next = other_end + 1;
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the lowest possible starting address that can fit num_elem elements. If
|
||||
* a free address range cannot be found, BT_MESH_ADDR_UNASSIGNED will be
|
||||
* returned. Otherwise the first address in the range is returned.
|
||||
*
|
||||
* NOTE: This is quite an ineffective algorithm as it might need to look
|
||||
* through the array of nodes N+2 times. A more effective algorithm
|
||||
* could be used if the nodes were stored in a sorted list.
|
||||
*/
|
||||
static u16_t find_lowest_free_addr(u8_t num_elem)
|
||||
{
|
||||
u16_t addr = 1, next;
|
||||
int err, i;
|
||||
|
||||
/*
|
||||
* It takes a maximum of node count + 2 to find a free address if there
|
||||
* is any. +1 for our own address and +1 for making sure that the
|
||||
* address range is valid.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes) + 2; ++i) {
|
||||
err = addr_is_free(addr, num_elem, &next);
|
||||
if (err == 0) {
|
||||
break;
|
||||
} else if (err != -EAGAIN) {
|
||||
addr = BT_MESH_ADDR_UNASSIGNED;
|
||||
break;
|
||||
}
|
||||
|
||||
addr = next;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
struct bt_mesh_node *bt_mesh_node_find(u16_t addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
|
||||
struct bt_mesh_node *node = &bt_mesh.nodes[i];
|
||||
|
||||
if (addr >= node->addr &&
|
||||
addr <= node->addr + node->num_elem - 1) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct bt_mesh_node *bt_mesh_node_alloc(u16_t addr, u8_t num_elem,
|
||||
u16_t net_idx)
|
||||
{
|
||||
int i;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
if (addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
addr = find_lowest_free_addr(num_elem);
|
||||
if (addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
return NULL;
|
||||
}
|
||||
} else if (!addr_is_free(addr, num_elem, NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
|
||||
struct bt_mesh_node *node = &bt_mesh.nodes[i];
|
||||
|
||||
if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
node->addr = addr;
|
||||
node->num_elem = num_elem;
|
||||
node->net_idx = net_idx;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bt_mesh_node_del(struct bt_mesh_node *node, bool store)
|
||||
{
|
||||
BT_DBG("Node addr 0x%04x store %u", node->addr, store);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
|
||||
bt_mesh_clear_node(node);
|
||||
}
|
||||
|
||||
node->addr = BT_MESH_ADDR_UNASSIGNED;
|
||||
(void)memset(node->dev_key, 0, sizeof(node->dev_key));
|
||||
}
|
10
subsys/bluetooth/mesh/nodes.h
Normal file
10
subsys/bluetooth/mesh/nodes.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* 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);
|
|
@ -33,6 +33,8 @@
|
|||
#include "foundation.h"
|
||||
#include "proxy.h"
|
||||
#include "prov.h"
|
||||
#include "settings.h"
|
||||
#include "nodes.h"
|
||||
|
||||
/* 3 transmissions, 20ms interval */
|
||||
#define PROV_XMIT BT_MESH_TRANSMIT(2, 20)
|
||||
|
@ -108,21 +110,40 @@
|
|||
#define XACT_NVAL 0xff
|
||||
|
||||
enum {
|
||||
REMOTE_PUB_KEY, /* Remote key has been received */
|
||||
WAIT_PUB_KEY, /* Waiting for local PubKey to be generated */
|
||||
LINK_ACTIVE, /* Link has been opened */
|
||||
LINK_ACK_RECVD, /* Ack for link has been received */
|
||||
LINK_CLOSING, /* Link is closing down */
|
||||
SEND_PUB_KEY, /* Waiting to send PubKey */
|
||||
WAIT_NUMBER, /* Waiting for number input from user */
|
||||
WAIT_STRING, /* Waiting for string input from user */
|
||||
NOTIFY_INPUT_COMPLETE, /* Notify that input has been completed. */
|
||||
LINK_INVALID, /* Error occurred during provisioning */
|
||||
PROVISIONER, /* The link was opened as provisioner */
|
||||
|
||||
NUM_FLAGS,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PROVISIONER)
|
||||
#define PROVISIONER_LINK 1
|
||||
#else
|
||||
#define PROVISIONER_LINK 0
|
||||
#endif
|
||||
|
||||
struct provisioner_link {
|
||||
struct bt_mesh_node *node;
|
||||
u16_t addr;
|
||||
u16_t net_idx;
|
||||
u8_t attention_duration;
|
||||
};
|
||||
|
||||
struct prov_link {
|
||||
ATOMIC_DEFINE(flags, NUM_FLAGS);
|
||||
#if defined(CONFIG_BT_MESH_PB_GATT)
|
||||
struct bt_conn *conn; /* GATT connection */
|
||||
#endif
|
||||
struct provisioner_link provisioner[PROVISIONER_LINK];
|
||||
|
||||
u8_t dhkey[32]; /* Calculated DHKey */
|
||||
u8_t expect; /* Next expected PDU */
|
||||
|
||||
|
@ -177,6 +198,7 @@ struct prov_rx {
|
|||
|
||||
#define RETRANSMIT_TIMEOUT K_MSEC(500)
|
||||
#define BUF_TIMEOUT K_MSEC(400)
|
||||
#define CLOSING_TIMEOUT K_SECONDS(3)
|
||||
#define TRANSACTION_TIMEOUT K_SECONDS(30)
|
||||
#define PROTOCOL_TIMEOUT K_SECONDS(60)
|
||||
|
||||
|
@ -210,6 +232,11 @@ static int reset_state(void)
|
|||
bt_mesh_attention(NULL, 0);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
|
||||
link.provisioner->node != NULL) {
|
||||
bt_mesh_node_del(link.provisioner->node, false);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PB_GATT)
|
||||
if (link.conn) {
|
||||
bt_conn_unref(link.conn);
|
||||
|
@ -373,7 +400,7 @@ static void send_reliable(void)
|
|||
}
|
||||
}
|
||||
|
||||
static int bearer_ctl_send(u8_t op, void *data, u8_t data_len)
|
||||
static int bearer_ctl_send(u8_t op, const void *data, u8_t data_len)
|
||||
{
|
||||
struct net_buf *buf;
|
||||
|
||||
|
@ -411,11 +438,20 @@ static u8_t last_seg(u8_t len)
|
|||
|
||||
static inline u8_t next_transaction_id(void)
|
||||
{
|
||||
if (link.tx.id != 0U && link.tx.id != 0xFF) {
|
||||
return ++link.tx.id;
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
if (link.tx.id != 0x7F) {
|
||||
link.tx.id++;
|
||||
} else {
|
||||
link.tx.id = 0;
|
||||
}
|
||||
} else {
|
||||
if (link.tx.id != 0U && link.tx.id != 0xFF) {
|
||||
link.tx.id++;
|
||||
} else {
|
||||
link.tx.id = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
link.tx.id = 0x80;
|
||||
return link.tx.id;
|
||||
}
|
||||
|
||||
|
@ -579,10 +615,58 @@ static void prov_invite(const u8_t *data)
|
|||
link.expect = PROV_START;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PB_ADV)
|
||||
static void send_invite(void)
|
||||
{
|
||||
PROV_BUF(inv, 2);
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
prov_buf_init(&inv, PROV_INVITE);
|
||||
net_buf_simple_add_u8(&inv, link.provisioner->attention_duration);
|
||||
|
||||
link.conf_inputs[0] = link.provisioner->attention_duration;
|
||||
|
||||
if (prov_send(&inv)) {
|
||||
BT_ERR("Failed to send invite");
|
||||
return;
|
||||
}
|
||||
|
||||
link.expect = PROV_CAPABILITIES;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void send_start(void)
|
||||
{
|
||||
PROV_BUF(start, 6);
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
prov_buf_init(&start, PROV_START);
|
||||
|
||||
net_buf_simple_add_u8(&start, PROV_ALG_P256);
|
||||
net_buf_simple_add_u8(&start, PUB_KEY_NO_OOB);
|
||||
net_buf_simple_add_u8(&start, AUTH_METHOD_NO_OOB);
|
||||
memset(link.auth, 0, sizeof(link.auth));
|
||||
|
||||
net_buf_simple_add_u8(&start, 0); /* Auth Action */
|
||||
net_buf_simple_add_u8(&start, 0); /* Auth Size */
|
||||
|
||||
memcpy(&link.conf_inputs[12], &start.data[1], 5);
|
||||
|
||||
if (prov_send(&start)) {
|
||||
BT_ERR("Failed to send start");
|
||||
}
|
||||
}
|
||||
|
||||
static void prov_capabilities(const u8_t *data)
|
||||
{
|
||||
u16_t algorithms, output_action, input_action;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("Elements: %u", data[0]);
|
||||
|
||||
algorithms = sys_get_be16(&data[1]);
|
||||
|
@ -599,6 +683,26 @@ static void prov_capabilities(const u8_t *data)
|
|||
|
||||
input_action = sys_get_be16(&data[9]);
|
||||
BT_DBG("Input OOB Action: 0x%04x", input_action);
|
||||
|
||||
if (data[0] == 0) {
|
||||
BT_ERR("Invalid number of elements");
|
||||
prov_send_fail_msg(PROV_ERR_NVAL_FMT);
|
||||
return;
|
||||
}
|
||||
|
||||
link.provisioner->node = bt_mesh_node_alloc(link.provisioner->addr,
|
||||
data[0],
|
||||
link.provisioner->net_idx);
|
||||
if (link.provisioner->node == NULL) {
|
||||
prov_send_fail_msg(PROV_ERR_RESOURCES);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&link.conf_inputs[1], data, 11);
|
||||
|
||||
atomic_set_bit(link.flags, SEND_PUB_KEY);
|
||||
|
||||
send_start();
|
||||
}
|
||||
|
||||
static bt_mesh_output_action_t output_action(u8_t action)
|
||||
|
@ -816,7 +920,11 @@ static void send_confirm(void)
|
|||
return;
|
||||
}
|
||||
|
||||
link.expect = PROV_RANDOM;
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
link.expect = PROV_CONFIRM;
|
||||
} else {
|
||||
link.expect = PROV_RANDOM;
|
||||
}
|
||||
}
|
||||
|
||||
static void send_input_complete(void)
|
||||
|
@ -860,23 +968,11 @@ int bt_mesh_input_string(const char *str)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void send_pub_key(const u8_t dhkey[32])
|
||||
static void send_pub_key(void)
|
||||
{
|
||||
PROV_BUF(buf, 65);
|
||||
const u8_t *key;
|
||||
|
||||
BT_DBG("%p", dhkey);
|
||||
|
||||
if (!dhkey) {
|
||||
BT_ERR("DHKey generation failed");
|
||||
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
sys_memcpy_swap(link.dhkey, dhkey, 32);
|
||||
|
||||
BT_DBG("DHkey: %s", bt_hex(link.dhkey, 32));
|
||||
|
||||
key = bt_pub_key_get();
|
||||
if (!key) {
|
||||
BT_ERR("No public key available");
|
||||
|
@ -892,33 +988,70 @@ static void send_pub_key(const u8_t dhkey[32])
|
|||
sys_memcpy_swap(net_buf_simple_add(&buf, 32), key, 32);
|
||||
sys_memcpy_swap(net_buf_simple_add(&buf, 32), &key[32], 32);
|
||||
|
||||
memcpy(&link.conf_inputs[81], &buf.data[1], 64);
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
/* PublicKeyProvisioner */
|
||||
memcpy(&link.conf_inputs[17], &buf.data[1], 64);
|
||||
} else {
|
||||
/* PublicKeyRemote */
|
||||
memcpy(&link.conf_inputs[81], &buf.data[1], 64);
|
||||
}
|
||||
|
||||
if (prov_send(&buf)) {
|
||||
BT_ERR("Failed to send Public Key");
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(link.flags, WAIT_NUMBER) || atomic_test_bit(link.flags, WAIT_STRING)) {
|
||||
link.expect = PROV_NO_PDU; /* Wait for input */
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
link.expect = PROV_PUB_KEY;
|
||||
} else {
|
||||
link.expect = PROV_CONFIRM;
|
||||
if (atomic_test_bit(link.flags, WAIT_NUMBER) ||
|
||||
atomic_test_bit(link.flags, WAIT_STRING)) {
|
||||
link.expect = PROV_NO_PDU; /* Wait for input */
|
||||
} else {
|
||||
link.expect = PROV_CONFIRM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void prov_dh_key_cb(const u8_t dhkey[32])
|
||||
{
|
||||
BT_DBG("%p", dhkey);
|
||||
|
||||
if (!dhkey) {
|
||||
BT_ERR("DHKey generation failed");
|
||||
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
sys_memcpy_swap(link.dhkey, dhkey, 32);
|
||||
|
||||
BT_DBG("DHkey: %s", bt_hex(link.dhkey, 32));
|
||||
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
send_confirm();
|
||||
} else {
|
||||
send_pub_key();
|
||||
}
|
||||
}
|
||||
|
||||
static void prov_dh_key_gen(void)
|
||||
{
|
||||
u8_t remote_pk[64];
|
||||
u8_t remote_pk_le[64], *remote_pk;
|
||||
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
remote_pk = &link.conf_inputs[81];
|
||||
} else {
|
||||
remote_pk = &link.conf_inputs[17];
|
||||
}
|
||||
|
||||
/* Copy remote key in little-endian for bt_dh_key_gen().
|
||||
* X and Y halves are swapped independently. Use response
|
||||
* buffer as a temporary storage location. The bt_dh_key_gen()
|
||||
* X and Y halves are swapped independently. The bt_dh_key_gen()
|
||||
* will also take care of validating the remote public key.
|
||||
*/
|
||||
sys_memcpy_swap(remote_pk, &link.conf_inputs[17], 32);
|
||||
sys_memcpy_swap(&remote_pk[32], &link.conf_inputs[49], 32);
|
||||
sys_memcpy_swap(remote_pk_le, remote_pk, 32);
|
||||
sys_memcpy_swap(&remote_pk_le[32], &remote_pk[32], 32);
|
||||
|
||||
if (bt_dh_key_gen(remote_pk, send_pub_key)) {
|
||||
if (bt_dh_key_gen(remote_pk_le, prov_dh_key_cb)) {
|
||||
BT_ERR("Failed to generate DHKey");
|
||||
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
|
||||
}
|
||||
|
@ -928,16 +1061,27 @@ static void prov_pub_key(const u8_t *data)
|
|||
{
|
||||
BT_DBG("Remote Public Key: %s", bt_hex(data, 64));
|
||||
|
||||
memcpy(&link.conf_inputs[17], data, 64);
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
/* PublicKeyDevice */
|
||||
memcpy(&link.conf_inputs[81], data, 64);
|
||||
|
||||
if (!bt_pub_key_get()) {
|
||||
/* Clear retransmit timer */
|
||||
#if defined(CONFIG_BT_MESH_PB_ADV)
|
||||
prov_clear_tx();
|
||||
#endif
|
||||
atomic_set_bit(link.flags, REMOTE_PUB_KEY);
|
||||
BT_WARN("Waiting for local public key");
|
||||
return;
|
||||
} else {
|
||||
/* PublicKeyProvisioner */
|
||||
memcpy(&link.conf_inputs[17], data, 64);
|
||||
|
||||
if (!bt_pub_key_get()) {
|
||||
/* Clear retransmit timer */
|
||||
#if defined(CONFIG_BT_MESH_PB_ADV)
|
||||
prov_clear_tx();
|
||||
#endif
|
||||
|
||||
atomic_set_bit(link.flags, WAIT_PUB_KEY);
|
||||
BT_WARN("Waiting for local public key");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
prov_dh_key_gen();
|
||||
|
@ -952,8 +1096,12 @@ static void pub_key_ready(const u8_t *pkey)
|
|||
|
||||
BT_DBG("Local public key ready");
|
||||
|
||||
if (atomic_test_and_clear_bit(link.flags, REMOTE_PUB_KEY)) {
|
||||
prov_dh_key_gen();
|
||||
if (atomic_test_and_clear_bit(link.flags, WAIT_PUB_KEY)) {
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
send_pub_key();
|
||||
} else {
|
||||
prov_dh_key_gen();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -971,20 +1119,138 @@ static void prov_input_complete(const u8_t *data)
|
|||
notify_input_complete();
|
||||
}
|
||||
|
||||
static void prov_confirm(const u8_t *data)
|
||||
static void send_prov_data(void)
|
||||
{
|
||||
BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
|
||||
PROV_BUF(pdu, 34);
|
||||
struct bt_mesh_subnet *sub;
|
||||
u8_t session_key[16];
|
||||
u8_t nonce[13];
|
||||
int err;
|
||||
|
||||
memcpy(link.conf, data, 16);
|
||||
err = bt_mesh_session_key(link.dhkey, link.prov_salt, session_key);
|
||||
if (err) {
|
||||
BT_ERR("Unable to generate session key");
|
||||
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
notify_input_complete();
|
||||
send_confirm();
|
||||
BT_DBG("SessionKey: %s", bt_hex(session_key, 16));
|
||||
|
||||
err = bt_mesh_prov_nonce(link.dhkey, link.prov_salt, nonce);
|
||||
if (err) {
|
||||
BT_ERR("Unable to generate session nonce");
|
||||
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("Nonce: %s", bt_hex(nonce, 13));
|
||||
|
||||
err = bt_mesh_dev_key(link.dhkey, link.prov_salt,
|
||||
link.provisioner->node->dev_key);
|
||||
if (err) {
|
||||
BT_ERR("Unable to generate device key");
|
||||
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("DevKey: %s", bt_hex(link.provisioner->node->dev_key, 16));
|
||||
|
||||
sub = bt_mesh_subnet_get(link.provisioner->node->net_idx);
|
||||
if (sub == NULL) {
|
||||
BT_ERR("No subnet with net_idx %u",
|
||||
link.provisioner->node->net_idx);
|
||||
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
prov_buf_init(&pdu, PROV_DATA);
|
||||
net_buf_simple_add_mem(&pdu, sub->keys[sub->kr_flag].net, 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_be16(&pdu, link.provisioner->node->addr);
|
||||
net_buf_simple_add(&pdu, 8); /* For MIC */
|
||||
|
||||
BT_DBG("net_idx %u, iv_index 0x%08x, addr 0x%04x",
|
||||
link.provisioner->node->net_idx, bt_mesh.iv_index,
|
||||
link.provisioner->node->addr);
|
||||
|
||||
err = bt_mesh_prov_encrypt(session_key, nonce, &pdu.data[1],
|
||||
&pdu.data[1]);
|
||||
if (err) {
|
||||
BT_ERR("Unable to encrypt provisioning data");
|
||||
prov_send_fail_msg(PROV_ERR_DECRYPT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (prov_send(&pdu)) {
|
||||
BT_ERR("Failed to send Provisioning Data");
|
||||
return;
|
||||
}
|
||||
|
||||
link.expect = PROV_COMPLETE;
|
||||
}
|
||||
|
||||
static void prov_complete(const u8_t *data)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct bt_mesh_node *node = link.provisioner->node;
|
||||
#if defined(CONFIG_BT_MESH_PB_ADV)
|
||||
u8_t reason = CLOSE_REASON_SUCCESS;
|
||||
#endif
|
||||
|
||||
BT_DBG("key %s, net_idx %u, num_elem %u, addr 0x%04x",
|
||||
bt_hex(node->dev_key, 16), node->net_idx, node->num_elem,
|
||||
node->addr);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_node(node);
|
||||
}
|
||||
|
||||
link.provisioner->node = NULL;
|
||||
link.expect = PROV_NO_PDU;
|
||||
atomic_set_bit(link.flags, LINK_CLOSING);
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PB_ADV)
|
||||
bearer_ctl_send(LINK_CLOSE, &reason, sizeof(reason));
|
||||
#endif
|
||||
|
||||
bt_mesh_prov_node_added(node->net_idx, node->addr, node->num_elem);
|
||||
|
||||
/*
|
||||
* According to mesh profile spec (5.3.1.4.3), the close message should
|
||||
* be restransmitted at least three times. Retransmit the LINK_CLOSE
|
||||
* message until CLOSING_TIMEOUT has elapsed instead of resetting the
|
||||
* link here.
|
||||
*/
|
||||
}
|
||||
|
||||
static void send_random(void)
|
||||
{
|
||||
PROV_BUF(rnd, 17);
|
||||
|
||||
prov_buf_init(&rnd, PROV_RANDOM);
|
||||
net_buf_simple_add_mem(&rnd, link.rand, 16);
|
||||
|
||||
if (prov_send(&rnd)) {
|
||||
BT_ERR("Failed to send Provisioning Random");
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
link.expect = PROV_RANDOM;
|
||||
} else {
|
||||
link.expect = PROV_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
static void prov_random(const u8_t *data)
|
||||
{
|
||||
PROV_BUF(rnd, 17);
|
||||
u8_t conf_verify[16];
|
||||
const u8_t *prov_rand, *dev_rand;
|
||||
|
||||
BT_DBG("Remote Random: %s", bt_hex(data, 16));
|
||||
|
||||
|
@ -1002,15 +1268,15 @@ static void prov_random(const u8_t *data)
|
|||
return;
|
||||
}
|
||||
|
||||
prov_buf_init(&rnd, PROV_RANDOM);
|
||||
net_buf_simple_add_mem(&rnd, link.rand, 16);
|
||||
|
||||
if (prov_send(&rnd)) {
|
||||
BT_ERR("Failed to send Provisioning Random");
|
||||
return;
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
prov_rand = link.rand;
|
||||
dev_rand = data;
|
||||
} else {
|
||||
prov_rand = data;
|
||||
dev_rand = link.rand;
|
||||
}
|
||||
|
||||
if (bt_mesh_prov_salt(link.conf_salt, data, link.rand,
|
||||
if (bt_mesh_prov_salt(link.conf_salt, prov_rand, dev_rand,
|
||||
link.prov_salt)) {
|
||||
BT_ERR("Failed to generate provisioning salt");
|
||||
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
|
||||
|
@ -1019,7 +1285,27 @@ static void prov_random(const u8_t *data)
|
|||
|
||||
BT_DBG("ProvisioningSalt: %s", bt_hex(link.prov_salt, 16));
|
||||
|
||||
link.expect = PROV_DATA;
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
|
||||
atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
send_prov_data();
|
||||
} else {
|
||||
send_random();
|
||||
}
|
||||
}
|
||||
|
||||
static void prov_confirm(const u8_t *data)
|
||||
{
|
||||
BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
|
||||
|
||||
memcpy(link.conf, data, 16);
|
||||
|
||||
notify_input_complete();
|
||||
|
||||
if (atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
send_random();
|
||||
} else {
|
||||
send_confirm();
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool is_pb_gatt(void)
|
||||
|
@ -1119,11 +1405,6 @@ static void prov_data(const u8_t *data)
|
|||
}
|
||||
}
|
||||
|
||||
static void prov_complete(const u8_t *data)
|
||||
{
|
||||
BT_DBG("");
|
||||
}
|
||||
|
||||
static void prov_failed(const u8_t *data)
|
||||
{
|
||||
BT_WARN("Error: 0x%02x", data[0]);
|
||||
|
@ -1148,7 +1429,7 @@ static const struct {
|
|||
#if defined(CONFIG_BT_MESH_PB_ADV)
|
||||
static void prov_retransmit(struct k_work *work)
|
||||
{
|
||||
int i;
|
||||
int i, timeout;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
|
@ -1157,7 +1438,13 @@ static void prov_retransmit(struct k_work *work)
|
|||
return;
|
||||
}
|
||||
|
||||
if (k_uptime_get() - link.tx.start > TRANSACTION_TIMEOUT) {
|
||||
if (atomic_test_bit(link.flags, LINK_CLOSING)) {
|
||||
timeout = CLOSING_TIMEOUT;
|
||||
} else {
|
||||
timeout = TRANSACTION_TIMEOUT;
|
||||
}
|
||||
|
||||
if (k_uptime_get() - link.tx.start > timeout) {
|
||||
BT_WARN("Giving up transaction");
|
||||
reset_adv_link();
|
||||
return;
|
||||
|
@ -1227,6 +1514,21 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf)
|
|||
static void link_ack(struct prov_rx *rx, struct net_buf_simple *buf)
|
||||
{
|
||||
BT_DBG("len %u", buf->len);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
|
||||
atomic_test_bit(link.flags, PROVISIONER)) {
|
||||
if (atomic_test_and_set_bit(link.flags, LINK_ACK_RECVD)) {
|
||||
return;
|
||||
}
|
||||
|
||||
prov_clear_tx();
|
||||
|
||||
if (prov->link_open) {
|
||||
prov->link_open(BT_MESH_PROV_ADV);
|
||||
}
|
||||
|
||||
send_invite();
|
||||
}
|
||||
}
|
||||
|
||||
static void link_close(struct prov_rx *rx, struct net_buf_simple *buf)
|
||||
|
@ -1371,7 +1673,21 @@ static void gen_prov_ack(struct prov_rx *rx, struct net_buf_simple *buf)
|
|||
}
|
||||
|
||||
if (rx->xact_id == link.tx.id) {
|
||||
prov_clear_tx();
|
||||
/* Don't clear resending of LINK_CLOSE messages */
|
||||
if (!atomic_test_bit(link.flags, LINK_CLOSING)) {
|
||||
prov_clear_tx();
|
||||
}
|
||||
|
||||
/* Send the PubKey when the the Start message is ACK'ed */
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
|
||||
atomic_test_and_clear_bit(link.flags, SEND_PUB_KEY)) {
|
||||
if (!bt_pub_key_get()) {
|
||||
atomic_set_bit(link.flags, WAIT_PUB_KEY);
|
||||
BT_WARN("Waiting for local public key");
|
||||
} else {
|
||||
send_pub_key();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1478,6 +1794,31 @@ void bt_mesh_pb_adv_recv(struct net_buf_simple *buf)
|
|||
|
||||
gen_prov_recv(&rx, buf);
|
||||
}
|
||||
|
||||
int bt_mesh_pb_adv_open(const u8_t uuid[16], u16_t net_idx, u16_t addr,
|
||||
u8_t attention_duration)
|
||||
{
|
||||
BT_DBG("uuid %s", bt_hex(uuid, 16));
|
||||
|
||||
if (atomic_test_and_set_bit(link.flags, LINK_ACTIVE)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
atomic_set_bit(link.flags, PROVISIONER);
|
||||
|
||||
bt_rand(&link.id, sizeof(link.id));
|
||||
link.tx.id = 0x7F;
|
||||
link.provisioner->addr = addr;
|
||||
link.provisioner->net_idx = net_idx;
|
||||
link.provisioner->attention_duration = attention_duration;
|
||||
|
||||
net_buf_simple_reset(link.rx.buf);
|
||||
|
||||
bearer_ctl_send(LINK_OPEN, uuid, 16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BT_MESH_PB_ADV */
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PB_GATT)
|
||||
|
@ -1610,6 +1951,13 @@ 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) {
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
int bt_mesh_pb_adv_open(const u8_t uuid[16], u16_t net_idx, u16_t addr,
|
||||
u8_t attention_duration);
|
||||
|
||||
void bt_mesh_pb_adv_recv(struct net_buf_simple *buf);
|
||||
|
||||
bool bt_prov_active(void);
|
||||
|
@ -19,4 +22,5 @@ const struct bt_mesh_prov *bt_mesh_prov_get(void);
|
|||
int bt_mesh_prov_init(const struct bt_mesh_prov *prov);
|
||||
|
||||
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);
|
||||
void bt_mesh_prov_reset(void);
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#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
|
||||
|
@ -123,6 +124,24 @@ struct va_val {
|
|||
u8_t uuid[16];
|
||||
} __packed;
|
||||
|
||||
/* Node storage information */
|
||||
struct node_val {
|
||||
u16_t net_idx;
|
||||
u8_t dev_key[16];
|
||||
u8_t num_elem;
|
||||
} __packed;
|
||||
|
||||
struct node_update {
|
||||
u16_t addr;
|
||||
bool clear;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PROVISIONER)
|
||||
static struct node_update node_updates[CONFIG_BT_MESH_NODE_COUNT];
|
||||
#else
|
||||
static struct node_update node_updates[0];
|
||||
#endif
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
@ -740,6 +759,58 @@ 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)
|
||||
{
|
||||
struct bt_mesh_node *node;
|
||||
struct node_val val;
|
||||
u16_t addr;
|
||||
int err;
|
||||
|
||||
if (!name) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
addr = strtol(name, NULL, 16);
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_DBG("val (null)");
|
||||
BT_DBG("Deleting node 0x%04x", addr);
|
||||
|
||||
node = bt_mesh_node_find(addr);
|
||||
if (node) {
|
||||
bt_mesh_node_del(node, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = mesh_x_set(read_cb, cb_arg, &val, sizeof(val));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'node\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
node = bt_mesh_node_find(addr);
|
||||
if (!node) {
|
||||
node = bt_mesh_node_alloc(addr, val.num_elem, val.net_idx);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
BT_ERR("No space for a new node");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(node->dev_key, &val.dev_key, 16);
|
||||
|
||||
BT_DBG("Node 0x%04x recovered from storage", addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct mesh_setting {
|
||||
const char *name;
|
||||
int (*func)(const char *name, size_t len_rd,
|
||||
|
@ -758,6 +829,9 @@ const struct mesh_setting {
|
|||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||
{ "Va", va_set },
|
||||
#endif
|
||||
#if defined(CONFIG_BT_MESH_PROVISIONER)
|
||||
{ "Node", node_set },
|
||||
#endif
|
||||
};
|
||||
|
||||
static int mesh_set(const char *name, size_t len_rd,
|
||||
|
@ -906,7 +980,8 @@ 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_MOD_PENDING) | \
|
||||
BIT(BT_MESH_NODES_PENDING))
|
||||
|
||||
static void schedule_store(int flag)
|
||||
{
|
||||
|
@ -1292,6 +1367,95 @@ static void store_pending_keys(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void store_node(struct bt_mesh_node *node)
|
||||
{
|
||||
struct node_val val;
|
||||
char path[20];
|
||||
int err;
|
||||
|
||||
val.net_idx = node->net_idx;
|
||||
val.num_elem = node->num_elem;
|
||||
memcpy(val.dev_key, node->dev_key, 16);
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/Node/%x", node->addr);
|
||||
|
||||
err = settings_save_one(path, &val, sizeof(val));
|
||||
if (err) {
|
||||
BT_ERR("Failed to store Node %s value", log_strdup(path));
|
||||
} else {
|
||||
BT_DBG("Stored Node %s value", log_strdup(path));
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_node(u16_t addr)
|
||||
{
|
||||
char path[20];
|
||||
int err;
|
||||
|
||||
BT_DBG("Node 0x%04x", addr);
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/Node/%x", addr);
|
||||
err = settings_delete(path);
|
||||
if (err) {
|
||||
BT_ERR("Failed to clear Node 0x%04x", addr);
|
||||
} else {
|
||||
BT_DBG("Cleared Node 0x%04x", addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void store_pending_nodes(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(node_updates); ++i) {
|
||||
struct node_update *update = &node_updates[i];
|
||||
|
||||
if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (update->clear) {
|
||||
clear_node(update->addr);
|
||||
} else {
|
||||
struct bt_mesh_node *node;
|
||||
|
||||
node = bt_mesh_node_find(update->addr);
|
||||
if (node) {
|
||||
store_node(node);
|
||||
} else {
|
||||
BT_WARN("Node 0x%04x not found", update->addr);
|
||||
}
|
||||
}
|
||||
|
||||
update->addr = BT_MESH_ADDR_UNASSIGNED;
|
||||
}
|
||||
}
|
||||
|
||||
static struct node_update *node_update_find(u16_t addr,
|
||||
struct node_update **free_slot)
|
||||
{
|
||||
struct node_update *match;
|
||||
int i;
|
||||
|
||||
match = NULL;
|
||||
*free_slot = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(node_updates); i++) {
|
||||
struct node_update *update = &node_updates[i];
|
||||
|
||||
if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
*free_slot = update;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (update->addr == addr) {
|
||||
match = update;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static void encode_mod_path(struct bt_mesh_model *mod, bool vnd,
|
||||
const char *key, char *path, size_t path_len)
|
||||
{
|
||||
|
@ -1507,6 +1671,11 @@ static void store_pending(struct k_work *work)
|
|||
if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_VA_PENDING)) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_store_rpl(struct bt_mesh_rpl *entry)
|
||||
|
@ -1688,11 +1857,58 @@ void bt_mesh_store_mod_pub(struct bt_mesh_model *mod)
|
|||
schedule_store(BT_MESH_MOD_PENDING);
|
||||
}
|
||||
|
||||
|
||||
void bt_mesh_store_label(void)
|
||||
{
|
||||
schedule_store(BT_MESH_VA_PENDING);
|
||||
}
|
||||
|
||||
void bt_mesh_store_node(struct bt_mesh_node *node)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void bt_mesh_clear_node(struct bt_mesh_node *node)
|
||||
{
|
||||
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 = true;
|
||||
schedule_store(BT_MESH_NODES_PENDING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!free_slot) {
|
||||
clear_node(node->addr);
|
||||
return;
|
||||
}
|
||||
|
||||
free_slot->addr = node->addr;
|
||||
|
||||
schedule_store(BT_MESH_NODES_PENDING);
|
||||
}
|
||||
|
||||
int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,
|
||||
const void *data, size_t data_len)
|
||||
{
|
||||
|
|
|
@ -16,10 +16,12 @@ 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_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_settings_init(void);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#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
|
||||
|
@ -131,7 +132,7 @@ static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu,
|
|||
|
||||
net_buf_reserve(buf, BT_MESH_NET_HDR_LEN);
|
||||
|
||||
if (tx->ctx->app_idx == BT_MESH_KEY_DEV) {
|
||||
if (BT_MESH_IS_DEV_KEY(tx->ctx->app_idx)) {
|
||||
net_buf_add_u8(buf, UNSEG_HDR(0, 0));
|
||||
} else {
|
||||
net_buf_add_u8(buf, UNSEG_HDR(1, tx->aid));
|
||||
|
@ -345,7 +346,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu,
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (net_tx->ctx->app_idx == BT_MESH_KEY_DEV) {
|
||||
if (BT_MESH_IS_DEV_KEY(net_tx->ctx->app_idx)) {
|
||||
seg_hdr = SEG_HDR(0, 0);
|
||||
} else {
|
||||
seg_hdr = SEG_HDR(1, net_tx->aid);
|
||||
|
@ -501,8 +502,8 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg,
|
|||
tx->ctx->app_idx, tx->ctx->addr);
|
||||
BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len));
|
||||
|
||||
err = bt_mesh_app_key_get(tx->sub, tx->ctx->app_idx, &key,
|
||||
&aid);
|
||||
err = bt_mesh_app_key_get(tx->sub, tx->ctx->app_idx,
|
||||
tx->ctx->addr, &key, &aid);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
@ -521,10 +522,9 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg,
|
|||
ad = NULL;
|
||||
}
|
||||
|
||||
err = bt_mesh_app_encrypt(key, tx->ctx->app_idx == BT_MESH_KEY_DEV,
|
||||
tx->aszmic, msg, ad, tx->src,
|
||||
tx->ctx->addr, bt_mesh.seq,
|
||||
BT_MESH_NET_IVI_TX);
|
||||
err = bt_mesh_app_encrypt(key, BT_MESH_IS_DEV_KEY(tx->ctx->app_idx),
|
||||
tx->aszmic, msg, ad, tx->src, tx->ctx->addr,
|
||||
bt_mesh.seq, BT_MESH_NET_IVI_TX);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
@ -644,13 +644,45 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, u32_t seq, u8_t hdr,
|
|||
rx->ctx.recv_dst, seq,
|
||||
BT_MESH_NET_IVI_RX(rx));
|
||||
if (err) {
|
||||
BT_ERR("Unable to decrypt with DevKey");
|
||||
return -EINVAL;
|
||||
BT_WARN("Unable to decrypt with local DevKey");
|
||||
} else {
|
||||
rx->ctx.app_idx = BT_MESH_KEY_DEV_LOCAL;
|
||||
bt_mesh_model_recv(rx, &sdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rx->ctx.app_idx = BT_MESH_KEY_DEV;
|
||||
bt_mesh_model_recv(rx, &sdu);
|
||||
return 0;
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) {
|
||||
struct bt_mesh_node *node;
|
||||
|
||||
/*
|
||||
* There is no way of knowing if we should use our
|
||||
* local DevKey or the remote DevKey to decrypt the
|
||||
* message so we must try both.
|
||||
*/
|
||||
|
||||
node = bt_mesh_node_find(rx->ctx.addr);
|
||||
if (node == NULL) {
|
||||
BT_ERR("No node found for addr 0x%04x",
|
||||
rx->ctx.addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
net_buf_simple_reset(&sdu);
|
||||
err = bt_mesh_app_decrypt(node->dev_key, true, aszmic,
|
||||
buf, &sdu, ad, rx->ctx.addr,
|
||||
rx->ctx.recv_dst, seq,
|
||||
BT_MESH_NET_IVI_RX(rx));
|
||||
if (err) {
|
||||
BT_ERR("Unable to decrypt with node DevKey");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rx->ctx.app_idx = BT_MESH_KEY_DEV_REMOTE;
|
||||
bt_mesh_model_recv(rx, &sdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0U; i < ARRAY_SIZE(bt_mesh.app_keys); i++) {
|
||||
|
@ -1590,14 +1622,29 @@ void bt_mesh_heartbeat_send(void)
|
|||
}
|
||||
|
||||
int bt_mesh_app_key_get(const struct bt_mesh_subnet *subnet, u16_t app_idx,
|
||||
const u8_t **key, u8_t *aid)
|
||||
u16_t addr, const u8_t **key, u8_t *aid)
|
||||
{
|
||||
struct bt_mesh_app_key *app_key;
|
||||
|
||||
if (app_idx == BT_MESH_KEY_DEV) {
|
||||
if (app_idx == BT_MESH_KEY_DEV_LOCAL ||
|
||||
(app_idx == BT_MESH_KEY_DEV_REMOTE &&
|
||||
bt_mesh_elem_find(addr) != NULL)) {
|
||||
*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)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct bt_mesh_node *node = bt_mesh_node_find(addr);
|
||||
if (!node) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*key = node->dev_key;
|
||||
*aid = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!subnet) {
|
||||
|
|
|
@ -99,4 +99,4 @@ void bt_mesh_rpl_clear(void);
|
|||
void bt_mesh_heartbeat_send(void);
|
||||
|
||||
int bt_mesh_app_key_get(const struct bt_mesh_subnet *subnet, u16_t app_idx,
|
||||
const u8_t **key, u8_t *aid);
|
||||
u16_t addr, const u8_t **key, u8_t *aid);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue