Bluetooth: Mesh: Break up mesh settings
The mesh settings.c module is a giant piece of code responsible for storing the mesh stack configuration. Such approach makes it difficult to control the data to be stored, breaks the stack modules' encapsulation by forcing them to reveal the internal kitchen, which leads to unpleasant issues such as #19799. This commit moves the responsibility of storing the configuration to corresponding modules while keeping control of the moment of storing the configuration and of starting the stack after the settingss loading is completed. This doesn't introduce any abstraction between the mesh settings.c and other modules as it will add more complexity and overhead than necessary for the actual task. Fixes #19850 Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
parent
472febfe69
commit
561a8e4f0e
26 changed files with 2375 additions and 2352 deletions
|
@ -818,6 +818,12 @@ config BT_MESH_DEBUG_CDB
|
|||
help
|
||||
Use this option to enable configuration database debug logs.
|
||||
|
||||
config BT_MESH_DEBUG_CFG
|
||||
bool "Configuration debug"
|
||||
help
|
||||
Use this option to enable node configuration debug logs for the
|
||||
Bluetooth Mesh functionality.
|
||||
|
||||
endif # BT_MESH_DEBUG
|
||||
|
||||
endif # BT_MESH
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <zephyr.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/util.h>
|
||||
#include <sys/byteorder.h>
|
||||
|
||||
|
@ -26,6 +27,26 @@
|
|||
#include "transport.h"
|
||||
#include "access.h"
|
||||
#include "foundation.h"
|
||||
#include "settings.h"
|
||||
|
||||
/* bt_mesh_model.flags */
|
||||
enum {
|
||||
BT_MESH_MOD_BIND_PENDING = BIT(0),
|
||||
BT_MESH_MOD_SUB_PENDING = BIT(1),
|
||||
BT_MESH_MOD_PUB_PENDING = BIT(2),
|
||||
BT_MESH_MOD_NEXT_IS_PARENT = BIT(3),
|
||||
};
|
||||
|
||||
/* Model publication information for persistent storage. */
|
||||
struct mod_pub_val {
|
||||
uint16_t addr;
|
||||
uint16_t key;
|
||||
uint8_t ttl;
|
||||
uint8_t retransmit;
|
||||
uint8_t period;
|
||||
uint8_t period_div:4,
|
||||
cred:1;
|
||||
};
|
||||
|
||||
static const struct bt_mesh_comp *dev_comp;
|
||||
static uint16_t dev_primary_addr;
|
||||
|
@ -840,3 +861,392 @@ int bt_mesh_model_extend(struct bt_mesh_model *mod,
|
|||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mod_set_bind(struct bt_mesh_model *mod, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
ssize_t len;
|
||||
int i;
|
||||
|
||||
/* Start with empty array regardless of cleared or set value */
|
||||
for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
|
||||
mod->keys[i] = BT_MESH_KEY_UNUSED;
|
||||
}
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_DBG("Cleared bindings for model");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = read_cb(cb_arg, mod->keys, sizeof(mod->keys));
|
||||
if (len < 0) {
|
||||
BT_ERR("Failed to read value (err %zd)", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
BT_HEXDUMP_DBG(mod->keys, len, "val");
|
||||
|
||||
BT_DBG("Decoded %zu bound keys for model", len / sizeof(mod->keys[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mod_set_sub(struct bt_mesh_model *mod, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
/* Start with empty array regardless of cleared or set value */
|
||||
(void)memset(mod->groups, 0, sizeof(mod->groups));
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_DBG("Cleared subscriptions for model");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = read_cb(cb_arg, mod->groups, sizeof(mod->groups));
|
||||
if (len < 0) {
|
||||
BT_ERR("Failed to read value (err %zd)", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
BT_HEXDUMP_DBG(mod->groups, len, "val");
|
||||
|
||||
BT_DBG("Decoded %zu subscribed group addresses for model",
|
||||
len / sizeof(mod->groups[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct mod_pub_val pub;
|
||||
int err;
|
||||
|
||||
if (!mod->pub) {
|
||||
BT_WARN("Model has no publication context!");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (len_rd == 0) {
|
||||
mod->pub->addr = BT_MESH_ADDR_UNASSIGNED;
|
||||
mod->pub->key = 0U;
|
||||
mod->pub->cred = 0U;
|
||||
mod->pub->ttl = 0U;
|
||||
mod->pub->period = 0U;
|
||||
mod->pub->retransmit = 0U;
|
||||
mod->pub->count = 0U;
|
||||
|
||||
BT_DBG("Cleared publication for model");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'model-pub\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
mod->pub->addr = pub.addr;
|
||||
mod->pub->key = pub.key;
|
||||
mod->pub->cred = pub.cred;
|
||||
mod->pub->ttl = pub.ttl;
|
||||
mod->pub->period = pub.period;
|
||||
mod->pub->retransmit = pub.retransmit;
|
||||
mod->pub->count = 0U;
|
||||
|
||||
BT_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x",
|
||||
pub.addr, pub.key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mod_data_set(struct bt_mesh_model *mod,
|
||||
const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
const char *next;
|
||||
|
||||
settings_name_next(name, &next);
|
||||
|
||||
if (mod->cb && mod->cb->settings_set) {
|
||||
return mod->cb->settings_set(mod, next, len_rd,
|
||||
read_cb, cb_arg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mod_set(bool vnd, const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct bt_mesh_model *mod;
|
||||
uint8_t elem_idx, mod_idx;
|
||||
uint16_t mod_key;
|
||||
int len;
|
||||
const char *next;
|
||||
|
||||
if (!name) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
mod_key = strtol(name, NULL, 16);
|
||||
elem_idx = mod_key >> 8;
|
||||
mod_idx = mod_key;
|
||||
|
||||
BT_DBG("Decoded mod_key 0x%04x as elem_idx %u mod_idx %u",
|
||||
mod_key, elem_idx, mod_idx);
|
||||
|
||||
mod = bt_mesh_model_get(vnd, elem_idx, mod_idx);
|
||||
if (!mod) {
|
||||
BT_ERR("Failed to get model for elem_idx %u mod_idx %u",
|
||||
elem_idx, mod_idx);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
len = settings_name_next(name, &next);
|
||||
|
||||
if (!next) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!strncmp(next, "bind", len)) {
|
||||
return mod_set_bind(mod, len_rd, read_cb, cb_arg);
|
||||
}
|
||||
|
||||
if (!strncmp(next, "sub", len)) {
|
||||
return mod_set_sub(mod, len_rd, read_cb, cb_arg);
|
||||
}
|
||||
|
||||
if (!strncmp(next, "pub", len)) {
|
||||
return mod_set_pub(mod, len_rd, read_cb, cb_arg);
|
||||
}
|
||||
|
||||
if (!strncmp(next, "data", len)) {
|
||||
return mod_data_set(mod, next, len_rd, read_cb, cb_arg);
|
||||
}
|
||||
|
||||
BT_WARN("Unknown module key %s", next);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int sig_mod_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
return mod_set(false, name, len_rd, read_cb, cb_arg);
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(sig_mod, "s", sig_mod_set);
|
||||
|
||||
static int vnd_mod_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
return mod_set(true, name, len_rd, read_cb, cb_arg);
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(vnd_mod, "v", vnd_mod_set);
|
||||
|
||||
static void encode_mod_path(struct bt_mesh_model *mod, bool vnd,
|
||||
const char *key, char *path, size_t path_len)
|
||||
{
|
||||
uint16_t mod_key = (((uint16_t)mod->elem_idx << 8) | mod->mod_idx);
|
||||
|
||||
if (vnd) {
|
||||
snprintk(path, path_len, "bt/mesh/v/%x/%s", mod_key, key);
|
||||
} else {
|
||||
snprintk(path, path_len, "bt/mesh/s/%x/%s", mod_key, key);
|
||||
}
|
||||
}
|
||||
|
||||
static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd)
|
||||
{
|
||||
uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT];
|
||||
char path[20];
|
||||
int i, count, err;
|
||||
|
||||
for (i = 0, count = 0; i < ARRAY_SIZE(mod->keys); i++) {
|
||||
if (mod->keys[i] != BT_MESH_KEY_UNUSED) {
|
||||
keys[count++] = mod->keys[i];
|
||||
BT_DBG("model key 0x%04x", mod->keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
encode_mod_path(mod, vnd, "bind", path, sizeof(path));
|
||||
|
||||
if (count) {
|
||||
err = settings_save_one(path, keys, count * sizeof(keys[0]));
|
||||
} else {
|
||||
err = settings_delete(path);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
BT_ERR("Failed to store %s value", log_strdup(path));
|
||||
} else {
|
||||
BT_DBG("Stored %s value", log_strdup(path));
|
||||
}
|
||||
}
|
||||
|
||||
static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd)
|
||||
{
|
||||
uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT];
|
||||
char path[20];
|
||||
int i, count, err;
|
||||
|
||||
for (i = 0, count = 0; i < CONFIG_BT_MESH_MODEL_GROUP_COUNT; i++) {
|
||||
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
|
||||
groups[count++] = mod->groups[i];
|
||||
}
|
||||
}
|
||||
|
||||
encode_mod_path(mod, vnd, "sub", path, sizeof(path));
|
||||
|
||||
if (count) {
|
||||
err = settings_save_one(path, groups,
|
||||
count * sizeof(groups[0]));
|
||||
} else {
|
||||
err = settings_delete(path);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
BT_ERR("Failed to store %s value", log_strdup(path));
|
||||
} else {
|
||||
BT_DBG("Stored %s value", log_strdup(path));
|
||||
}
|
||||
}
|
||||
|
||||
static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd)
|
||||
{
|
||||
struct mod_pub_val pub;
|
||||
char path[20];
|
||||
int err;
|
||||
|
||||
encode_mod_path(mod, vnd, "pub", path, sizeof(path));
|
||||
|
||||
if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
err = settings_delete(path);
|
||||
} else {
|
||||
pub.addr = mod->pub->addr;
|
||||
pub.key = mod->pub->key;
|
||||
pub.ttl = mod->pub->ttl;
|
||||
pub.retransmit = mod->pub->retransmit;
|
||||
pub.period = mod->pub->period;
|
||||
pub.period_div = mod->pub->period_div;
|
||||
pub.cred = mod->pub->cred;
|
||||
|
||||
err = settings_save_one(path, &pub, sizeof(pub));
|
||||
}
|
||||
|
||||
if (err) {
|
||||
BT_ERR("Failed to store %s value", log_strdup(path));
|
||||
} else {
|
||||
BT_DBG("Stored %s value", log_strdup(path));
|
||||
}
|
||||
}
|
||||
|
||||
static void store_pending_mod(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_elem *elem, bool vnd,
|
||||
bool primary, void *user_data)
|
||||
{
|
||||
if (!mod->flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mod->flags & BT_MESH_MOD_BIND_PENDING) {
|
||||
mod->flags &= ~BT_MESH_MOD_BIND_PENDING;
|
||||
store_pending_mod_bind(mod, vnd);
|
||||
}
|
||||
|
||||
if (mod->flags & BT_MESH_MOD_SUB_PENDING) {
|
||||
mod->flags &= ~BT_MESH_MOD_SUB_PENDING;
|
||||
store_pending_mod_sub(mod, vnd);
|
||||
}
|
||||
|
||||
if (mod->flags & BT_MESH_MOD_PUB_PENDING) {
|
||||
mod->flags &= ~BT_MESH_MOD_PUB_PENDING;
|
||||
store_pending_mod_pub(mod, vnd);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_model_pending_store(void)
|
||||
{
|
||||
bt_mesh_model_foreach(store_pending_mod, NULL);
|
||||
}
|
||||
|
||||
void bt_mesh_model_bind_store(struct bt_mesh_model *mod)
|
||||
{
|
||||
mod->flags |= BT_MESH_MOD_BIND_PENDING;
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING);
|
||||
}
|
||||
|
||||
void bt_mesh_model_sub_store(struct bt_mesh_model *mod)
|
||||
{
|
||||
mod->flags |= BT_MESH_MOD_SUB_PENDING;
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING);
|
||||
}
|
||||
|
||||
void bt_mesh_model_pub_store(struct bt_mesh_model *mod)
|
||||
{
|
||||
mod->flags |= BT_MESH_MOD_PUB_PENDING;
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING);
|
||||
}
|
||||
|
||||
int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,
|
||||
const char *name, const void *data,
|
||||
size_t data_len)
|
||||
{
|
||||
char path[30];
|
||||
int err;
|
||||
|
||||
encode_mod_path(mod, vnd, "data", path, sizeof(path));
|
||||
if (name) {
|
||||
strcat(path, "/");
|
||||
strncat(path, name, 8);
|
||||
}
|
||||
|
||||
if (data_len) {
|
||||
err = settings_save_one(path, data, data_len);
|
||||
} else {
|
||||
err = settings_delete(path);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
BT_ERR("Failed to store %s value", log_strdup(path));
|
||||
} else {
|
||||
BT_DBG("Stored %s value", log_strdup(path));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
||||
bool vnd, bool primary, void *user_data)
|
||||
{
|
||||
if (mod->pub && mod->pub->update &&
|
||||
mod->pub->addr != BT_MESH_ADDR_UNASSIGNED) {
|
||||
int32_t ms = bt_mesh_model_pub_period_get(mod);
|
||||
|
||||
if (ms > 0) {
|
||||
BT_DBG("Starting publish timer (period %u ms)", ms);
|
||||
k_delayed_work_submit(&mod->pub->timer, K_MSEC(ms));
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(mod->groups); i++) {
|
||||
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
|
||||
bt_mesh_lpn_group_add(mod->groups[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_model_settings_commit(void)
|
||||
{
|
||||
bt_mesh_model_foreach(commit_mod, NULL);
|
||||
}
|
||||
|
|
|
@ -6,14 +6,6 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* bt_mesh_model.flags */
|
||||
enum {
|
||||
BT_MESH_MOD_BIND_PENDING = BIT(0),
|
||||
BT_MESH_MOD_SUB_PENDING = BIT(1),
|
||||
BT_MESH_MOD_PUB_PENDING = BIT(2),
|
||||
BT_MESH_MOD_NEXT_IS_PARENT = BIT(3),
|
||||
};
|
||||
|
||||
/* Tree walk return codes */
|
||||
enum bt_mesh_walk {
|
||||
BT_MESH_WALK_STOP,
|
||||
|
@ -56,3 +48,9 @@ struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_
|
|||
void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf);
|
||||
|
||||
int bt_mesh_comp_register(const struct bt_mesh_comp *comp);
|
||||
|
||||
void bt_mesh_model_pending_store(void);
|
||||
void bt_mesh_model_bind_store(struct bt_mesh_model *mod);
|
||||
void bt_mesh_model_sub_store(struct bt_mesh_model *mod);
|
||||
void bt_mesh_model_pub_store(struct bt_mesh_model *mod);
|
||||
void bt_mesh_model_settings_commit(void);
|
||||
|
|
|
@ -25,21 +25,45 @@
|
|||
#define LOG_MODULE_NAME bt_mesh_app_keys
|
||||
#include "common/log.h"
|
||||
|
||||
static struct bt_mesh_app_key apps[CONFIG_BT_MESH_APP_KEY_COUNT] = {
|
||||
/* Tracking of what storage changes are pending for App Keys. We track this in
|
||||
* a separate array here instead of within the respective bt_mesh_app_key
|
||||
* struct itselve, since once a key gets deleted its struct becomes invalid
|
||||
* and may be reused for other keys.
|
||||
*/
|
||||
struct app_key_update {
|
||||
uint16_t key_idx:12, /* AppKey Index */
|
||||
valid:1, /* 1 if this entry is valid, 0 if not */
|
||||
clear:1; /* 1 if key needs clearing, 0 if storing */
|
||||
};
|
||||
|
||||
/* AppKey information for persistent storage. */
|
||||
struct app_key_val {
|
||||
uint16_t net_idx;
|
||||
bool updated;
|
||||
uint8_t val[2][16];
|
||||
} __packed;
|
||||
|
||||
/** Mesh Application Key. */
|
||||
struct app_key {
|
||||
uint16_t net_idx;
|
||||
uint16_t app_idx;
|
||||
bool updated;
|
||||
struct bt_mesh_app_cred {
|
||||
uint8_t id;
|
||||
uint8_t val[16];
|
||||
} keys[2];
|
||||
};
|
||||
|
||||
static struct app_key_update app_key_updates[CONFIG_BT_MESH_APP_KEY_COUNT];
|
||||
|
||||
static struct app_key apps[CONFIG_BT_MESH_APP_KEY_COUNT] = {
|
||||
[0 ... (CONFIG_BT_MESH_APP_KEY_COUNT - 1)] = {
|
||||
.app_idx = BT_MESH_KEY_UNUSED,
|
||||
.net_idx = BT_MESH_KEY_UNUSED,
|
||||
}
|
||||
};
|
||||
|
||||
static void app_key_evt(struct bt_mesh_app_key *app, enum bt_mesh_key_evt evt)
|
||||
{
|
||||
Z_STRUCT_SECTION_FOREACH(bt_mesh_app_key_cb, cb) {
|
||||
cb->evt_handler(app->app_idx, app->net_idx, evt);
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_mesh_app_key *app_get(uint16_t app_idx)
|
||||
static struct app_key *app_get(uint16_t app_idx)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
|
||||
if (apps[i].app_idx == app_idx) {
|
||||
|
@ -50,9 +74,115 @@ static struct bt_mesh_app_key *app_get(uint16_t app_idx)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct bt_mesh_app_key *app_key_alloc(uint16_t app_idx)
|
||||
static void clear_app_key(uint16_t app_idx)
|
||||
{
|
||||
struct bt_mesh_app_key *app = NULL;
|
||||
char path[20];
|
||||
int err;
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/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_app_key(uint16_t app_idx)
|
||||
{
|
||||
const struct app_key *app;
|
||||
struct app_key_val key;
|
||||
char path[20];
|
||||
int err;
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/AppKey/%x", app_idx);
|
||||
|
||||
app = app_get(app_idx);
|
||||
if (!app) {
|
||||
BT_WARN("ApKeyIndex 0x%03x not found", app_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
key.net_idx = app->net_idx,
|
||||
key.updated = app->updated,
|
||||
|
||||
memcpy(key.val[0], app->keys[0].val, 16);
|
||||
memcpy(key.val[1], app->keys[1].val, 16);
|
||||
|
||||
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 struct app_key_update *app_key_update_find(uint16_t key_idx,
|
||||
struct app_key_update **free_slot)
|
||||
{
|
||||
struct app_key_update *match;
|
||||
int i;
|
||||
|
||||
match = NULL;
|
||||
*free_slot = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(app_key_updates); i++) {
|
||||
struct app_key_update *update = &app_key_updates[i];
|
||||
|
||||
if (!update->valid) {
|
||||
*free_slot = update;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (update->key_idx == key_idx) {
|
||||
match = update;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static void update_app_key_settings(uint16_t app_idx, bool store)
|
||||
{
|
||||
struct app_key_update *update, *free_slot;
|
||||
uint8_t clear = store ? 0U : 1U;
|
||||
|
||||
BT_DBG("AppKeyIndex 0x%03x", app_idx);
|
||||
|
||||
update = app_key_update_find(app_idx, &free_slot);
|
||||
if (update) {
|
||||
update->clear = clear;
|
||||
bt_mesh_settings_store_schedule(
|
||||
BT_MESH_SETTINGS_APP_KEYS_PENDING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!free_slot) {
|
||||
if (store) {
|
||||
store_app_key(app_idx);
|
||||
} else {
|
||||
clear_app_key(app_idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
free_slot->valid = 1U;
|
||||
free_slot->key_idx = app_idx;
|
||||
free_slot->clear = clear;
|
||||
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_APP_KEYS_PENDING);
|
||||
}
|
||||
|
||||
static void app_key_evt(struct app_key *app, enum bt_mesh_key_evt evt)
|
||||
{
|
||||
Z_STRUCT_SECTION_FOREACH(bt_mesh_app_key_cb, cb) {
|
||||
cb->evt_handler(app->app_idx, app->net_idx, evt);
|
||||
}
|
||||
}
|
||||
|
||||
static struct app_key *app_key_alloc(uint16_t app_idx)
|
||||
{
|
||||
struct app_key *app = NULL;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
|
||||
/* Check for already existing app_key */
|
||||
|
@ -68,12 +198,12 @@ static struct bt_mesh_app_key *app_key_alloc(uint16_t app_idx)
|
|||
return app;
|
||||
}
|
||||
|
||||
static void app_key_del(struct bt_mesh_app_key *app)
|
||||
static void app_key_del(struct app_key *app)
|
||||
{
|
||||
BT_DBG("AppIdx 0x%03x", app->app_idx);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_clear_app_key(app->app_idx);
|
||||
update_app_key_settings(app->app_idx, false);
|
||||
}
|
||||
|
||||
app_key_evt(app, BT_MESH_KEY_DELETED);
|
||||
|
@ -83,7 +213,7 @@ static void app_key_del(struct bt_mesh_app_key *app)
|
|||
(void)memset(app->keys, 0, sizeof(app->keys));
|
||||
}
|
||||
|
||||
static void app_key_revoke(struct bt_mesh_app_key *app)
|
||||
static void app_key_revoke(struct app_key *app)
|
||||
{
|
||||
if (!app->updated) {
|
||||
return;
|
||||
|
@ -94,7 +224,7 @@ static void app_key_revoke(struct bt_mesh_app_key *app)
|
|||
app->updated = false;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_app_key(app->app_idx);
|
||||
update_app_key_settings(app->app_idx, true);
|
||||
}
|
||||
|
||||
app_key_evt(app, BT_MESH_KEY_REVOKED);
|
||||
|
@ -103,7 +233,7 @@ static void app_key_revoke(struct bt_mesh_app_key *app)
|
|||
uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx,
|
||||
const uint8_t key[16])
|
||||
{
|
||||
struct bt_mesh_app_key *app;
|
||||
struct app_key *app;
|
||||
|
||||
BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx,
|
||||
bt_hex(key, 16));
|
||||
|
@ -142,7 +272,7 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx,
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
BT_DBG("Storing AppKey persistently");
|
||||
bt_mesh_store_app_key(app->app_idx);
|
||||
update_app_key_settings(app->app_idx, true);
|
||||
}
|
||||
|
||||
app_key_evt(app, BT_MESH_KEY_ADDED);
|
||||
|
@ -150,22 +280,10 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx,
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx)
|
||||
{
|
||||
struct bt_mesh_app_key *app;
|
||||
|
||||
app = app_get(app_idx);
|
||||
if (app) {
|
||||
return app;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx,
|
||||
const uint8_t key[16])
|
||||
{
|
||||
struct bt_mesh_app_key *app;
|
||||
struct app_key *app;
|
||||
struct bt_mesh_subnet *sub;
|
||||
|
||||
BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx,
|
||||
|
@ -213,7 +331,7 @@ uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx,
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
BT_DBG("Storing AppKey persistently");
|
||||
bt_mesh_store_app_key(app->app_idx);
|
||||
update_app_key_settings(app->app_idx, true);
|
||||
}
|
||||
|
||||
app_key_evt(app, BT_MESH_KEY_UPDATED);
|
||||
|
@ -223,7 +341,7 @@ uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx,
|
|||
|
||||
uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx)
|
||||
{
|
||||
struct bt_mesh_app_key *app;
|
||||
struct app_key *app;
|
||||
|
||||
BT_DBG("AppIdx 0x%03x", app_idx);
|
||||
|
||||
|
@ -251,7 +369,7 @@ uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx)
|
|||
int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx,
|
||||
const uint8_t old_key[16], const uint8_t new_key[16])
|
||||
{
|
||||
struct bt_mesh_app_key *app;
|
||||
struct app_key *app;
|
||||
|
||||
app = app_key_alloc(app_idx);
|
||||
if (!app) {
|
||||
|
@ -300,7 +418,7 @@ ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max,
|
|||
size_t count = 0;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
|
||||
struct bt_mesh_app_key *app = &apps[i];
|
||||
struct app_key *app = &apps[i];
|
||||
|
||||
if (app->app_idx == BT_MESH_KEY_UNUSED) {
|
||||
continue;
|
||||
|
@ -329,7 +447,7 @@ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx,
|
|||
struct bt_mesh_subnet **sub,
|
||||
const uint8_t *app_key[16], uint8_t *aid)
|
||||
{
|
||||
struct bt_mesh_app_key *app = NULL;
|
||||
struct app_key *app = NULL;
|
||||
|
||||
if (BT_MESH_IS_DEV_KEY(ctx->app_idx)) {
|
||||
/* With device keys, the application has to decide which subnet
|
||||
|
@ -425,7 +543,7 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid,
|
|||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(apps); i++) {
|
||||
const struct bt_mesh_app_key *app = &apps[i];
|
||||
const struct app_key *app = &apps[i];
|
||||
const struct bt_mesh_app_cred *cred;
|
||||
|
||||
if (app->app_idx == BT_MESH_KEY_UNUSED) {
|
||||
|
@ -464,7 +582,7 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
|
|||
}
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
|
||||
struct bt_mesh_app_key *app = &apps[i];
|
||||
struct app_key *app = &apps[i];
|
||||
|
||||
if (app->app_idx == BT_MESH_KEY_UNUSED) {
|
||||
continue;
|
||||
|
@ -489,10 +607,68 @@ BT_MESH_SUBNET_CB_DEFINE(subnet_evt);
|
|||
void bt_mesh_app_keys_reset(void)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
|
||||
struct bt_mesh_app_key *app = &apps[i];
|
||||
struct app_key *app = &apps[i];
|
||||
|
||||
if (app->app_idx != BT_MESH_KEY_UNUSED) {
|
||||
app_key_del(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int app_key_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct app_key_val key;
|
||||
uint16_t app_idx;
|
||||
int err;
|
||||
|
||||
if (!name) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
app_idx = strtol(name, NULL, 16);
|
||||
|
||||
if (!len_rd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &key, sizeof(key));
|
||||
if (err < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = bt_mesh_app_key_set(app_idx, key.net_idx, key.val[0],
|
||||
key.updated ? key.val[1] : NULL);
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'app-key\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(app, "AppKey", app_key_set);
|
||||
|
||||
void bt_mesh_app_key_pending_store(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(app_key_updates); i++) {
|
||||
struct app_key_update *update = &app_key_updates[i];
|
||||
|
||||
if (!update->valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (update->clear) {
|
||||
clear_app_key(update->key_idx);
|
||||
} else {
|
||||
store_app_key(update->key_idx);
|
||||
}
|
||||
|
||||
update->valid = 0U;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,28 +10,9 @@
|
|||
#include <bluetooth/mesh.h>
|
||||
#include "subnet.h"
|
||||
|
||||
/** Mesh Application. */
|
||||
struct bt_mesh_app_key {
|
||||
uint16_t net_idx;
|
||||
uint16_t app_idx;
|
||||
bool updated;
|
||||
struct bt_mesh_app_cred {
|
||||
uint8_t id;
|
||||
uint8_t val[16];
|
||||
} keys[2];
|
||||
};
|
||||
|
||||
/** @brief Reset the app keys module. */
|
||||
void bt_mesh_app_keys_reset(void);
|
||||
|
||||
/** @brief Get the application key with the given AppIdx.
|
||||
*
|
||||
* @param app_idx App index.
|
||||
*
|
||||
* @return The matching application, or NULL if the application isn't known.
|
||||
*/
|
||||
struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx);
|
||||
|
||||
/** @brief Initialize a new application key with the given parameters.
|
||||
*
|
||||
* @param app_idx AppIndex.
|
||||
|
@ -78,4 +59,7 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid,
|
|||
const uint8_t key[16], void *cb_data),
|
||||
void *cb_data);
|
||||
|
||||
/** @brief Store pending application keys in persistent storage. */
|
||||
void bt_mesh_app_key_pending_store(void);
|
||||
|
||||
#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_APP_KEYS_H_ */
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
#include <zephyr.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <settings/settings.h>
|
||||
|
||||
#include <bluetooth/mesh.h>
|
||||
|
||||
|
@ -13,11 +16,64 @@
|
|||
#define LOG_MODULE_NAME bt_mesh_cdb
|
||||
#include "common/log.h"
|
||||
|
||||
#include "cdb.h"
|
||||
#include "mesh.h"
|
||||
#include "net.h"
|
||||
#include "rpl.h"
|
||||
#include "settings.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.
|
||||
*/
|
||||
struct key_update {
|
||||
uint16_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 */
|
||||
};
|
||||
|
||||
/* Tracking of what storage changes are pending for node settings. */
|
||||
struct node_update {
|
||||
uint16_t addr;
|
||||
bool clear;
|
||||
};
|
||||
|
||||
/* Node information for persistent storage. */
|
||||
struct node_val {
|
||||
uint16_t net_idx;
|
||||
uint8_t num_elem;
|
||||
uint8_t flags;
|
||||
#define F_NODE_CONFIGURED 0x01
|
||||
uint8_t uuid[16];
|
||||
uint8_t dev_key[16];
|
||||
} __packed;
|
||||
|
||||
/* NetKey storage information */
|
||||
struct net_key_val {
|
||||
uint8_t kr_flag:1,
|
||||
kr_phase:7;
|
||||
uint8_t val[2][16];
|
||||
} __packed;
|
||||
|
||||
/* AppKey information for persistent storage. */
|
||||
struct app_key_val {
|
||||
uint16_t net_idx;
|
||||
bool updated;
|
||||
uint8_t val[2][16];
|
||||
} __packed;
|
||||
|
||||
/* IV Index & IV Update information for persistent storage. */
|
||||
struct net_val {
|
||||
uint32_t iv_index;
|
||||
bool iv_update;
|
||||
} __packed;
|
||||
|
||||
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];
|
||||
|
||||
struct bt_mesh_cdb bt_mesh_cdb = {
|
||||
.nodes = {
|
||||
[0 ... (CONFIG_BT_MESH_CDB_NODE_COUNT - 1)] = {
|
||||
|
@ -109,6 +165,520 @@ static uint16_t find_lowest_free_addr(uint8_t num_elem)
|
|||
return addr;
|
||||
}
|
||||
|
||||
static int cdb_net_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct net_val net;
|
||||
int err;
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_DBG("val (null)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_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;
|
||||
uint16_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_cdb_node_get(addr);
|
||||
if (node) {
|
||||
bt_mesh_cdb_node_del(node, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &val, sizeof(val));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'node\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
node = bt_mesh_cdb_node_get(addr);
|
||||
if (!node) {
|
||||
node = bt_mesh_cdb_node_alloc(val.uuid, addr, val.num_elem,
|
||||
val.net_idx);
|
||||
}
|
||||
|
||||
if (!node) {
|
||||
BT_ERR("No space for a new node");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
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;
|
||||
uint16_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 = bt_mesh_settings_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;
|
||||
uint16_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 = bt_mesh_settings_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;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(cdb, "cdb", cdb_set);
|
||||
|
||||
static void store_cdb_node(const struct bt_mesh_cdb_node *node)
|
||||
{
|
||||
struct node_val val;
|
||||
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/cdb/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_cdb_node(uint16_t addr)
|
||||
{
|
||||
char path[30];
|
||||
int err;
|
||||
|
||||
BT_DBG("Node 0x%04x", 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);
|
||||
} else {
|
||||
BT_DBG("Cleared Node 0x%04x", addr);
|
||||
}
|
||||
}
|
||||
|
||||
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(uint16_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(uint16_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 schedule_cdb_store(int flag)
|
||||
{
|
||||
atomic_set_bit(bt_mesh_cdb.flags, flag);
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CDB_PENDING);
|
||||
}
|
||||
|
||||
static void update_cdb_net_settings(void)
|
||||
{
|
||||
schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING);
|
||||
}
|
||||
|
||||
static struct node_update *cdb_node_update_find(uint16_t addr,
|
||||
struct node_update **free_slot)
|
||||
{
|
||||
struct node_update *match;
|
||||
int i;
|
||||
|
||||
match = NULL;
|
||||
*free_slot = NULL;
|
||||
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (update->addr == addr) {
|
||||
match = update;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static void update_cdb_node_settings(const struct bt_mesh_cdb_node *node,
|
||||
bool store)
|
||||
{
|
||||
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 = !store;
|
||||
schedule_cdb_store(BT_MESH_CDB_NODES_PENDING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!free_slot) {
|
||||
if (store) {
|
||||
store_cdb_node(node);
|
||||
} else {
|
||||
clear_cdb_node(node->addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
free_slot->addr = node->addr;
|
||||
free_slot->clear = !store;
|
||||
|
||||
schedule_cdb_store(BT_MESH_CDB_NODES_PENDING);
|
||||
}
|
||||
|
||||
static struct key_update *cdb_key_update_find(bool app_key, uint16_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(cdb_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;
|
||||
}
|
||||
|
||||
static void update_cdb_subnet_settings(const struct bt_mesh_cdb_subnet *sub,
|
||||
bool store)
|
||||
{
|
||||
struct key_update *update, *free_slot;
|
||||
uint8_t clear = store ? 0U : 1U;
|
||||
|
||||
BT_DBG("NetKeyIndex 0x%03x", sub->net_idx);
|
||||
|
||||
update = cdb_key_update_find(false, sub->net_idx, &free_slot);
|
||||
if (update) {
|
||||
update->clear = clear;
|
||||
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!free_slot) {
|
||||
if (store) {
|
||||
store_cdb_subnet(sub);
|
||||
} else {
|
||||
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 = clear;
|
||||
|
||||
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
|
||||
}
|
||||
|
||||
static void update_cdb_app_key_settings(const struct bt_mesh_cdb_app_key *key,
|
||||
bool store)
|
||||
{
|
||||
struct key_update *update, *free_slot;
|
||||
uint8_t clear = store ? 0U : 1U;
|
||||
|
||||
BT_DBG("AppKeyIndex 0x%03x", key->app_idx);
|
||||
|
||||
update = cdb_key_update_find(true, key->app_idx, &free_slot);
|
||||
if (update) {
|
||||
update->clear = clear;
|
||||
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!free_slot) {
|
||||
if (store) {
|
||||
store_cdb_app_key(key);
|
||||
} else {
|
||||
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 = clear;
|
||||
|
||||
schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING);
|
||||
}
|
||||
|
||||
int bt_mesh_cdb_create(const uint8_t key[16])
|
||||
{
|
||||
struct bt_mesh_cdb_subnet *sub;
|
||||
|
@ -127,8 +697,8 @@ int bt_mesh_cdb_create(const uint8_t key[16])
|
|||
bt_mesh_cdb.iv_index = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_cdb();
|
||||
bt_mesh_store_cdb_subnet(sub);
|
||||
update_cdb_net_settings();
|
||||
update_cdb_subnet_settings(sub, true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -159,7 +729,7 @@ void bt_mesh_cdb_clear(void)
|
|||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_cdb();
|
||||
update_cdb_net_settings();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,7 +743,7 @@ void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update)
|
|||
iv_update);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_cdb();
|
||||
update_cdb_net_settings();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,7 +776,7 @@ 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);
|
||||
update_cdb_subnet_settings(sub, false);
|
||||
}
|
||||
|
||||
sub->net_idx = BT_MESH_KEY_UNUSED;
|
||||
|
@ -228,7 +798,9 @@ struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(uint16_t net_idx)
|
|||
|
||||
void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub)
|
||||
{
|
||||
bt_mesh_store_cdb_subnet(sub);
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
update_cdb_subnet_settings(sub, true);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub)
|
||||
|
@ -283,7 +855,7 @@ 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);
|
||||
update_cdb_node_settings(node, false);
|
||||
}
|
||||
|
||||
node->addr = BT_MESH_ADDR_UNASSIGNED;
|
||||
|
@ -308,7 +880,9 @@ struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr)
|
|||
|
||||
void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node)
|
||||
{
|
||||
bt_mesh_store_cdb_node(node);
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
update_cdb_node_settings(node, true);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data)
|
||||
|
@ -354,7 +928,7 @@ 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);
|
||||
update_cdb_app_key_settings(key, false);
|
||||
}
|
||||
|
||||
key->net_idx = BT_MESH_KEY_UNUSED;
|
||||
|
@ -379,5 +953,136 @@ struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx)
|
|||
|
||||
void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key)
|
||||
{
|
||||
bt_mesh_store_cdb_app_key(key);
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
update_cdb_app_key_settings(key, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_cdb_net(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_cdb_pending_net(void)
|
||||
{
|
||||
struct 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_pending_nodes(void)
|
||||
{
|
||||
int 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;
|
||||
}
|
||||
|
||||
BT_DBG("addr: 0x%04x, clear: %d", update->addr, update->clear);
|
||||
|
||||
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_cdb_node(node);
|
||||
} else {
|
||||
BT_WARN("Node 0x%04x not found", update->addr);
|
||||
}
|
||||
}
|
||||
|
||||
update->addr = BT_MESH_ADDR_UNASSIGNED;
|
||||
}
|
||||
}
|
||||
|
||||
static void store_cdb_pending_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;
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_cdb_pending_store(void)
|
||||
{
|
||||
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_cdb_pending_net();
|
||||
} else {
|
||||
clear_cdb_net();
|
||||
}
|
||||
}
|
||||
|
||||
if (atomic_test_and_clear_bit(bt_mesh_cdb.flags,
|
||||
BT_MESH_CDB_NODES_PENDING)) {
|
||||
store_cdb_pending_nodes();
|
||||
}
|
||||
|
||||
if (atomic_test_and_clear_bit(bt_mesh_cdb.flags,
|
||||
BT_MESH_CDB_KEYS_PENDING)) {
|
||||
store_cdb_pending_keys();
|
||||
}
|
||||
}
|
||||
|
|
8
subsys/bluetooth/mesh/cdb.h
Normal file
8
subsys/bluetooth/mesh/cdb.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node);
|
||||
void bt_mesh_cdb_pending_store(void);
|
|
@ -14,6 +14,21 @@
|
|||
#include "friend.h"
|
||||
#include "cfg.h"
|
||||
|
||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_CFG)
|
||||
#define LOG_MODULE_NAME bt_mesh_cfg
|
||||
#include "common/log.h"
|
||||
|
||||
/* Miscellaneous configuration server model states */
|
||||
struct cfg_val {
|
||||
uint8_t net_transmit;
|
||||
uint8_t relay;
|
||||
uint8_t relay_retransmit;
|
||||
uint8_t beacon;
|
||||
uint8_t gatt_proxy;
|
||||
uint8_t frnd;
|
||||
uint8_t default_ttl;
|
||||
};
|
||||
|
||||
void bt_mesh_beacon_set(bool beacon)
|
||||
{
|
||||
if (atomic_test_bit(bt_mesh.flags, BT_MESH_BEACON) == beacon) {
|
||||
|
@ -30,7 +45,7 @@ void bt_mesh_beacon_set(bool beacon)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
bt_mesh_store_cfg();
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +96,7 @@ int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
bt_mesh_store_cfg();
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -110,7 +125,7 @@ int bt_mesh_default_ttl_set(uint8_t default_ttl)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
bt_mesh_store_cfg();
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -138,7 +153,7 @@ int bt_mesh_friend_set(enum bt_mesh_feat_state friendship)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
bt_mesh_store_cfg();
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
|
||||
}
|
||||
|
||||
if (friendship == BT_MESH_FEATURE_DISABLED) {
|
||||
|
@ -167,7 +182,7 @@ void bt_mesh_net_transmit_set(uint8_t xmit)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
bt_mesh_store_cfg();
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,7 +213,7 @@ int bt_mesh_relay_set(enum bt_mesh_feat_state relay, uint8_t xmit)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
bt_mesh_store_cfg();
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -264,3 +279,77 @@ void bt_mesh_cfg_init(void)
|
|||
atomic_set_bit(bt_mesh.flags, BT_MESH_FRIEND);
|
||||
}
|
||||
}
|
||||
|
||||
static int cfg_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct cfg_val cfg;
|
||||
int err;
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_DBG("Cleared configuration state");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &cfg, sizeof(cfg));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'cfg\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
bt_mesh_net_transmit_set(cfg.net_transmit);
|
||||
bt_mesh_relay_set(cfg.relay, cfg.relay_retransmit);
|
||||
bt_mesh_beacon_set(cfg.beacon);
|
||||
bt_mesh_gatt_proxy_set(cfg.gatt_proxy);
|
||||
bt_mesh_friend_set(cfg.frnd);
|
||||
bt_mesh_default_ttl_set(cfg.default_ttl);
|
||||
|
||||
BT_DBG("Restored configuration state");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(cfg, "Cfg", cfg_set);
|
||||
|
||||
static void clear_cfg(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = settings_delete("bt/mesh/Cfg");
|
||||
if (err) {
|
||||
BT_ERR("Failed to clear configuration");
|
||||
} else {
|
||||
BT_DBG("Cleared configuration");
|
||||
}
|
||||
}
|
||||
|
||||
static void store_pending_cfg(void)
|
||||
{
|
||||
struct cfg_val val;
|
||||
int err;
|
||||
|
||||
val.net_transmit = bt_mesh_net_transmit_get();
|
||||
val.relay = bt_mesh_relay_get();
|
||||
val.relay_retransmit = bt_mesh_relay_retransmit_get();
|
||||
val.beacon = bt_mesh_beacon_enabled();
|
||||
val.gatt_proxy = bt_mesh_gatt_proxy_get();
|
||||
val.frnd = bt_mesh_friend_get();
|
||||
val.default_ttl = bt_mesh_default_ttl_get();
|
||||
|
||||
err = settings_save_one("bt/mesh/Cfg", &val, sizeof(val));
|
||||
if (err) {
|
||||
BT_ERR("Failed to store configuration value");
|
||||
} else {
|
||||
BT_DBG("Stored configuration value");
|
||||
BT_HEXDUMP_DBG(&val, sizeof(val), "raw value");
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_cfg_pending_store(void)
|
||||
{
|
||||
if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
store_pending_cfg();
|
||||
} else {
|
||||
clear_cfg();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
*/
|
||||
|
||||
void bt_mesh_cfg_init(void);
|
||||
void bt_mesh_cfg_pending_store(void);
|
||||
|
||||
bool bt_mesh_fixed_group_match(uint16_t addr);
|
||||
|
|
|
@ -205,7 +205,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr,
|
|||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
|
||||
bt_mesh_store_mod_pub(model);
|
||||
bt_mesh_model_pub_store(model);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -247,7 +247,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr,
|
|||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
|
||||
bt_mesh_store_mod_pub(model);
|
||||
bt_mesh_model_pub_store(model);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -275,7 +275,7 @@ static uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx)
|
|||
model->keys[i] = key_idx;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_bind(model);
|
||||
bt_mesh_model_bind_store(model);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -303,7 +303,7 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st
|
|||
model->keys[i] = BT_MESH_KEY_UNUSED;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
|
||||
bt_mesh_store_mod_bind(model);
|
||||
bt_mesh_model_bind_store(model);
|
||||
}
|
||||
|
||||
if (model->pub && model->pub->key == key_idx) {
|
||||
|
@ -1008,7 +1008,7 @@ static void mod_sub_add(struct bt_mesh_model *model,
|
|||
status = STATUS_SUCCESS;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
bt_mesh_model_sub_store(mod);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
|
@ -1078,7 +1078,7 @@ static void mod_sub_del(struct bt_mesh_model *model,
|
|||
*match = BT_MESH_ADDR_UNASSIGNED;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
bt_mesh_model_sub_store(mod);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1150,7 +1150,7 @@ static void mod_sub_overwrite(struct bt_mesh_model *model,
|
|||
status = STATUS_SUCCESS;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
bt_mesh_model_sub_store(mod);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
|
@ -1205,7 +1205,7 @@ static void mod_sub_del_all(struct bt_mesh_model *model,
|
|||
NULL);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
bt_mesh_model_sub_store(mod);
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
@ -1431,7 +1431,7 @@ static void mod_sub_va_add(struct bt_mesh_model *model,
|
|||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
bt_mesh_model_sub_store(mod);
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
@ -1496,7 +1496,7 @@ static void mod_sub_va_del(struct bt_mesh_model *model,
|
|||
*match = BT_MESH_ADDR_UNASSIGNED;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
bt_mesh_model_sub_store(mod);
|
||||
}
|
||||
|
||||
status = STATUS_SUCCESS;
|
||||
|
@ -1557,7 +1557,7 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model,
|
|||
mod->groups[0] = sub_addr;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
bt_mesh_model_sub_store(mod);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||
|
@ -2424,7 +2424,7 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
if (clear_count) {
|
||||
bt_mesh_store_mod_sub(mod);
|
||||
bt_mesh_model_sub_store(mod);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,16 @@
|
|||
#define LOG_MODULE_NAME bt_mesh_hb
|
||||
#include "common/log.h"
|
||||
|
||||
/* Heartbeat Publication information for persistent storage. */
|
||||
struct hb_pub_val {
|
||||
uint16_t dst;
|
||||
uint8_t period;
|
||||
uint8_t ttl;
|
||||
uint16_t feat;
|
||||
uint16_t net_idx:12,
|
||||
indefinite:1;
|
||||
};
|
||||
|
||||
static struct bt_mesh_hb_pub pub;
|
||||
static struct bt_mesh_hb_sub sub;
|
||||
static struct k_delayed_work sub_timer;
|
||||
|
@ -216,7 +226,8 @@ uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
bt_mesh_is_provisioned()) {
|
||||
bt_mesh_store_hb_pub();
|
||||
bt_mesh_settings_store_schedule(
|
||||
BT_MESH_SETTINGS_HB_PUB_PENDING);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -245,7 +256,8 @@ uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub)
|
|||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_hb_pub();
|
||||
bt_mesh_settings_store_schedule(
|
||||
BT_MESH_SETTINGS_HB_PUB_PENDING);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -359,3 +371,64 @@ void bt_mesh_hb_resume(void)
|
|||
k_delayed_work_submit(&pub_timer, K_NO_WAIT);
|
||||
}
|
||||
}
|
||||
|
||||
static int hb_pub_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct bt_mesh_hb_pub pub;
|
||||
struct hb_pub_val hb_val;
|
||||
int err;
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &hb_val, sizeof(hb_val));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'hb_val\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
pub.dst = hb_val.dst;
|
||||
pub.period = bt_mesh_hb_pwr2(hb_val.period);
|
||||
pub.ttl = hb_val.ttl;
|
||||
pub.feat = hb_val.feat;
|
||||
pub.net_idx = hb_val.net_idx;
|
||||
|
||||
if (hb_val.indefinite) {
|
||||
pub.count = 0xffff;
|
||||
} else {
|
||||
pub.count = 0U;
|
||||
}
|
||||
|
||||
(void)bt_mesh_hb_pub_set(&pub);
|
||||
|
||||
BT_DBG("Restored heartbeat publication");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(pub, "HBPub", hb_pub_set);
|
||||
|
||||
void bt_mesh_hb_pub_pending_store(void)
|
||||
{
|
||||
struct bt_mesh_hb_pub pub;
|
||||
struct hb_pub_val val;
|
||||
int err;
|
||||
|
||||
bt_mesh_hb_pub_get(&pub);
|
||||
if (pub.dst == BT_MESH_ADDR_UNASSIGNED) {
|
||||
err = settings_delete("bt/mesh/HBPub");
|
||||
} else {
|
||||
val.indefinite = (pub.count == 0xffff);
|
||||
val.dst = pub.dst;
|
||||
val.period = bt_mesh_hb_log(pub.period);
|
||||
val.ttl = pub.ttl;
|
||||
val.feat = pub.feat;
|
||||
val.net_idx = pub.net_idx;
|
||||
|
||||
err = settings_save_one("bt/mesh/HBPub", &val, sizeof(val));
|
||||
}
|
||||
|
||||
if (err) {
|
||||
BT_ERR("Failed to store Heartbeat Publication");
|
||||
} else {
|
||||
BT_DBG("Stored Heartbeat Publication");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,3 +37,4 @@ void bt_mesh_hb_feature_changed(uint16_t features);
|
|||
uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *hb_pub);
|
||||
uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period);
|
||||
void bt_mesh_hb_sub_reset_count(void);
|
||||
void bt_mesh_hb_pub_pending_store(void);
|
||||
|
|
|
@ -108,7 +108,7 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx,
|
|||
memcpy(node->dev_key, dev_key, 16);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_cdb_node(node);
|
||||
bt_mesh_cdb_node_store(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ void bt_mesh_reset(void)
|
|||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_clear_net();
|
||||
bt_mesh_net_clear();
|
||||
}
|
||||
|
||||
(void)memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
|
||||
|
|
|
@ -62,6 +62,31 @@
|
|||
#define SRC(pdu) (sys_get_be16(&(pdu)[5]))
|
||||
#define DST(pdu) (sys_get_be16(&(pdu)[7]))
|
||||
|
||||
/** Define CONFIG_BT_MESH_SEQ_STORE_RATE even if settings are disabled to
|
||||
* compile the code.
|
||||
*/
|
||||
#ifndef CONFIG_BT_SETTINGS
|
||||
#define CONFIG_BT_MESH_SEQ_STORE_RATE 1
|
||||
#endif
|
||||
|
||||
/* Mesh network information for persistent storage. */
|
||||
struct net_val {
|
||||
uint16_t primary_addr;
|
||||
uint8_t dev_key[16];
|
||||
} __packed;
|
||||
|
||||
/* Sequence number information for persistent storage. */
|
||||
struct seq_val {
|
||||
uint8_t val[3];
|
||||
} __packed;
|
||||
|
||||
/* IV Index & IV Update information for persistent storage. */
|
||||
struct iv_val {
|
||||
uint32_t iv_index;
|
||||
uint8_t iv_update:1,
|
||||
iv_duration:7;
|
||||
} __packed;
|
||||
|
||||
static struct {
|
||||
uint32_t src : 15, /* MSb of source is always 0 */
|
||||
seq : 17;
|
||||
|
@ -121,6 +146,31 @@ static void msg_cache_add(struct bt_mesh_net_rx *rx)
|
|||
msg_cache_next %= ARRAY_SIZE(msg_cache);
|
||||
}
|
||||
|
||||
static void store_net(void)
|
||||
{
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_PENDING);
|
||||
}
|
||||
|
||||
static void store_iv(bool only_duration)
|
||||
{
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_IV_PENDING);
|
||||
|
||||
if (!only_duration) {
|
||||
/* Always update Seq whenever IV changes */
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING);
|
||||
}
|
||||
}
|
||||
|
||||
static void store_seq(void)
|
||||
{
|
||||
if (CONFIG_BT_MESH_SEQ_STORE_RATE &&
|
||||
(bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING);
|
||||
}
|
||||
|
||||
int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16],
|
||||
uint32_t iv_index)
|
||||
{
|
||||
|
@ -156,9 +206,9 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16],
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
BT_DBG("Storing network information persistently");
|
||||
bt_mesh_store_net();
|
||||
bt_mesh_store_subnet(idx);
|
||||
bt_mesh_store_iv(false);
|
||||
store_net();
|
||||
bt_mesh_subnet_store(idx);
|
||||
store_iv(false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -289,7 +339,7 @@ do_update:
|
|||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_iv(false);
|
||||
store_iv(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -300,7 +350,7 @@ uint32_t bt_mesh_next_seq(void)
|
|||
uint32_t seq = bt_mesh.seq++;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_seq();
|
||||
store_seq();
|
||||
}
|
||||
|
||||
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) &&
|
||||
|
@ -813,7 +863,7 @@ static void ivu_refresh(struct k_work *work)
|
|||
|
||||
if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_iv(true);
|
||||
store_iv(true);
|
||||
}
|
||||
|
||||
k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
|
||||
|
@ -824,7 +874,7 @@ static void ivu_refresh(struct k_work *work)
|
|||
bt_mesh_beacon_ivu_initiator(true);
|
||||
bt_mesh_net_iv_update(bt_mesh.iv_index, false);
|
||||
} else if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_iv(true);
|
||||
store_iv(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -834,3 +884,211 @@ void bt_mesh_net_init(void)
|
|||
|
||||
k_work_init(&bt_mesh.local_work, bt_mesh_net_local);
|
||||
}
|
||||
|
||||
static int net_set(const char *name, size_t len_rd, settings_read_cb read_cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct net_val net;
|
||||
int err;
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_DBG("val (null)");
|
||||
|
||||
bt_mesh_comp_unprovision();
|
||||
(void)memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &net, sizeof(net));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'net\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key));
|
||||
bt_mesh_comp_provision(net.primary_addr);
|
||||
|
||||
BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr);
|
||||
BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(net, "Net", net_set);
|
||||
|
||||
static int iv_set(const char *name, size_t len_rd, settings_read_cb read_cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct iv_val iv;
|
||||
int err;
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_DBG("IV deleted");
|
||||
|
||||
bt_mesh.iv_index = 0U;
|
||||
atomic_clear_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &iv, sizeof(iv));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'iv\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
bt_mesh.iv_index = iv.iv_index;
|
||||
atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv.iv_update);
|
||||
bt_mesh.ivu_duration = iv.iv_duration;
|
||||
|
||||
BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours",
|
||||
iv.iv_index, iv.iv_update, iv.iv_duration);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(iv, "IV", iv_set);
|
||||
|
||||
static int seq_set(const char *name, size_t len_rd, settings_read_cb read_cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct seq_val seq;
|
||||
int err;
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_DBG("val (null)");
|
||||
|
||||
bt_mesh.seq = 0U;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &seq, sizeof(seq));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'seq\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
bt_mesh.seq = sys_get_le24(seq.val);
|
||||
|
||||
if (CONFIG_BT_MESH_SEQ_STORE_RATE > 0) {
|
||||
/* Make sure we have a large enough sequence number. We
|
||||
* subtract 1 so that the first transmission causes a write
|
||||
* to the settings storage.
|
||||
*/
|
||||
bt_mesh.seq += (CONFIG_BT_MESH_SEQ_STORE_RATE -
|
||||
(bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE));
|
||||
bt_mesh.seq--;
|
||||
}
|
||||
|
||||
BT_DBG("Sequence Number 0x%06x", bt_mesh.seq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(seq, "Seq", seq_set);
|
||||
|
||||
static void clear_iv(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = settings_delete("bt/mesh/IV");
|
||||
if (err) {
|
||||
BT_ERR("Failed to clear IV");
|
||||
} else {
|
||||
BT_DBG("Cleared IV");
|
||||
}
|
||||
}
|
||||
|
||||
static void store_pending_iv(void)
|
||||
{
|
||||
struct iv_val iv;
|
||||
int err;
|
||||
|
||||
iv.iv_index = bt_mesh.iv_index;
|
||||
iv.iv_update = atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
|
||||
iv.iv_duration = bt_mesh.ivu_duration;
|
||||
|
||||
err = settings_save_one("bt/mesh/IV", &iv, sizeof(iv));
|
||||
if (err) {
|
||||
BT_ERR("Failed to store IV value");
|
||||
} else {
|
||||
BT_DBG("Stored IV value");
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_net_pending_iv_store(void)
|
||||
{
|
||||
if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
store_pending_iv();
|
||||
} else {
|
||||
clear_iv();
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_net(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = settings_delete("bt/mesh/Net");
|
||||
if (err) {
|
||||
BT_ERR("Failed to clear Network");
|
||||
} else {
|
||||
BT_DBG("Cleared Network");
|
||||
}
|
||||
}
|
||||
|
||||
static void store_pending_net(void)
|
||||
{
|
||||
struct net_val net;
|
||||
int err;
|
||||
|
||||
BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(),
|
||||
bt_hex(bt_mesh.dev_key, 16));
|
||||
|
||||
net.primary_addr = bt_mesh_primary_addr();
|
||||
memcpy(net.dev_key, bt_mesh.dev_key, 16);
|
||||
|
||||
err = settings_save_one("bt/mesh/Net", &net, sizeof(net));
|
||||
if (err) {
|
||||
BT_ERR("Failed to store Network value");
|
||||
} else {
|
||||
BT_DBG("Stored Network value");
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_net_pending_net_store(void)
|
||||
{
|
||||
if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
store_pending_net();
|
||||
} else {
|
||||
clear_net();
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_net_pending_seq_store(void)
|
||||
{
|
||||
struct seq_val seq;
|
||||
int err;
|
||||
|
||||
sys_put_le24(bt_mesh.seq, seq.val);
|
||||
|
||||
err = settings_save_one("bt/mesh/Seq", &seq, sizeof(seq));
|
||||
if (err) {
|
||||
BT_ERR("Failed to stor Seq value");
|
||||
} else {
|
||||
BT_DBG("Stored Seq value");
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_net_clear(void)
|
||||
{
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_PENDING);
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_IV_PENDING);
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
|
||||
}
|
||||
|
||||
void bt_mesh_net_settings_commit(void)
|
||||
{
|
||||
if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) {
|
||||
k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,17 +163,6 @@ enum {
|
|||
BT_MESH_IVU_TEST, /* IV Update test mode */
|
||||
BT_MESH_IVU_PENDING, /* Update blocked by SDU in progress */
|
||||
|
||||
/* pending storage actions, must reside within first 32 flags */
|
||||
BT_MESH_RPL_PENDING,
|
||||
BT_MESH_KEYS_PENDING,
|
||||
BT_MESH_NET_PENDING,
|
||||
BT_MESH_IV_PENDING,
|
||||
BT_MESH_SEQ_PENDING,
|
||||
BT_MESH_HB_PUB_PENDING,
|
||||
BT_MESH_CFG_PENDING,
|
||||
BT_MESH_MOD_PENDING,
|
||||
BT_MESH_VA_PENDING,
|
||||
|
||||
/* Feature flags */
|
||||
BT_MESH_RELAY,
|
||||
BT_MESH_BEACON,
|
||||
|
@ -283,6 +272,11 @@ uint32_t bt_mesh_next_seq(void);
|
|||
void bt_mesh_net_init(void);
|
||||
void bt_mesh_net_header_parse(struct net_buf_simple *buf,
|
||||
struct bt_mesh_net_rx *rx);
|
||||
void bt_mesh_net_pending_net_store(void);
|
||||
void bt_mesh_net_pending_iv_store(void);
|
||||
void bt_mesh_net_pending_seq_store(void);
|
||||
void bt_mesh_net_clear(void);
|
||||
void bt_mesh_net_settings_commit(void);
|
||||
|
||||
static inline void send_cb_finalize(const struct bt_mesh_send_cb *cb,
|
||||
void *cb_data)
|
||||
|
|
|
@ -549,7 +549,7 @@ static void prov_complete(const uint8_t *data)
|
|||
node->addr);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_cdb_node(node);
|
||||
bt_mesh_cdb_node_store(node);
|
||||
}
|
||||
|
||||
prov_device.node = NULL;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/util.h>
|
||||
#include <sys/byteorder.h>
|
||||
|
@ -30,8 +31,27 @@
|
|||
#include "rpl.h"
|
||||
#include "settings.h"
|
||||
|
||||
/* Replay Protection List information for persistent storage. */
|
||||
struct rpl_val {
|
||||
uint32_t seq:24,
|
||||
old_iv:1;
|
||||
};
|
||||
|
||||
static struct bt_mesh_rpl replay_list[CONFIG_BT_MESH_CRPL];
|
||||
|
||||
static void schedule_rpl_store(struct bt_mesh_rpl *entry)
|
||||
{
|
||||
#ifdef CONFIG_BT_SETTINGS
|
||||
entry->store = true;
|
||||
#endif
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING);
|
||||
}
|
||||
|
||||
static void schedule_rpl_clear(void)
|
||||
{
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING);
|
||||
}
|
||||
|
||||
void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl,
|
||||
struct bt_mesh_net_rx *rx)
|
||||
{
|
||||
|
@ -40,7 +60,7 @@ void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl,
|
|||
rpl->old_iv = rx->old_iv;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_rpl(rpl);
|
||||
schedule_rpl_store(rpl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,13 +128,13 @@ void bt_mesh_rpl_clear(void)
|
|||
BT_DBG("");
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_clear_rpl();
|
||||
schedule_rpl_clear();
|
||||
} else {
|
||||
(void)memset(replay_list, 0, sizeof(replay_list));
|
||||
}
|
||||
}
|
||||
|
||||
struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src)
|
||||
static struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -127,7 +147,7 @@ struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src)
|
||||
static struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -141,15 +161,6 @@ struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
|
||||
func(&replay_list[i], user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_rpl_reset(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -168,8 +179,129 @@ void bt_mesh_rpl_reset(void)
|
|||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_rpl(rpl);
|
||||
schedule_rpl_store(rpl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int rpl_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct bt_mesh_rpl *entry;
|
||||
struct rpl_val rpl;
|
||||
int err;
|
||||
uint16_t src;
|
||||
|
||||
if (!name) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
src = strtol(name, NULL, 16);
|
||||
entry = bt_mesh_rpl_find(src);
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_DBG("val (null)");
|
||||
if (entry) {
|
||||
(void)memset(entry, 0, sizeof(*entry));
|
||||
} else {
|
||||
BT_WARN("Unable to find RPL entry for 0x%04x", src);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
entry = bt_mesh_rpl_alloc(src);
|
||||
if (!entry) {
|
||||
BT_ERR("Unable to allocate RPL entry for 0x%04x", src);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &rpl, sizeof(rpl));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set `net`");
|
||||
return err;
|
||||
}
|
||||
|
||||
entry->seq = rpl.seq;
|
||||
entry->old_iv = rpl.old_iv;
|
||||
|
||||
BT_DBG("RPL entry for 0x%04x: Seq 0x%06x old_iv %u", entry->src,
|
||||
entry->seq, entry->old_iv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(rpl, "RPL", rpl_set);
|
||||
|
||||
static void store_rpl(struct bt_mesh_rpl *entry)
|
||||
{
|
||||
struct rpl_val rpl;
|
||||
char path[18];
|
||||
int err;
|
||||
|
||||
BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, entry->seq,
|
||||
entry->old_iv);
|
||||
|
||||
rpl.seq = entry->seq;
|
||||
rpl.old_iv = entry->old_iv;
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/RPL/%x", entry->src);
|
||||
|
||||
err = settings_save_one(path, &rpl, sizeof(rpl));
|
||||
if (err) {
|
||||
BT_ERR("Failed to store RPL %s value", log_strdup(path));
|
||||
} else {
|
||||
BT_DBG("Stored RPL %s value", log_strdup(path));
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_rpl(struct bt_mesh_rpl *rpl)
|
||||
{
|
||||
int err;
|
||||
char path[18];
|
||||
|
||||
if (!rpl->src) {
|
||||
return;
|
||||
}
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/RPL/%x", rpl->src);
|
||||
err = settings_delete(path);
|
||||
if (err) {
|
||||
BT_ERR("Failed to clear RPL");
|
||||
} else {
|
||||
BT_DBG("Cleared RPL");
|
||||
}
|
||||
|
||||
(void)memset(rpl, 0, sizeof(*rpl));
|
||||
}
|
||||
|
||||
static void store_pending_rpl(struct bt_mesh_rpl *rpl)
|
||||
{
|
||||
BT_DBG("");
|
||||
|
||||
#ifdef CONFIG_BT_SETTINGS
|
||||
if (!rpl->store) {
|
||||
return;
|
||||
}
|
||||
|
||||
rpl->store = false;
|
||||
#endif
|
||||
store_rpl(rpl);
|
||||
}
|
||||
|
||||
void bt_mesh_rpl_pending_store(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
|
||||
if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
store_pending_rpl(&replay_list[i]);
|
||||
} else {
|
||||
clear_rpl(&replay_list[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,6 @@ void bt_mesh_rpl_reset(void);
|
|||
bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx,
|
||||
struct bt_mesh_rpl **match);
|
||||
void bt_mesh_rpl_clear(void);
|
||||
struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src);
|
||||
struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src);
|
||||
void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data);
|
||||
void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl,
|
||||
struct bt_mesh_net_rx *rx);
|
||||
void bt_mesh_rpl_pending_store(void);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,29 +4,39 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
void bt_mesh_store_net(void);
|
||||
void bt_mesh_store_iv(bool only_duration);
|
||||
void bt_mesh_store_seq(void);
|
||||
void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl);
|
||||
void bt_mesh_store_subnet(uint16_t net_idx);
|
||||
void bt_mesh_store_app_key(uint16_t app_idx);
|
||||
void bt_mesh_store_hb_pub(void);
|
||||
void bt_mesh_store_cfg(void);
|
||||
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_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);
|
||||
/* Pending storage actions. */
|
||||
enum bt_mesh_settings_flag {
|
||||
BT_MESH_SETTINGS_RPL_PENDING,
|
||||
BT_MESH_SETTINGS_NET_KEYS_PENDING,
|
||||
BT_MESH_SETTINGS_APP_KEYS_PENDING,
|
||||
BT_MESH_SETTINGS_NET_PENDING,
|
||||
BT_MESH_SETTINGS_IV_PENDING,
|
||||
BT_MESH_SETTINGS_SEQ_PENDING,
|
||||
BT_MESH_SETTINGS_HB_PUB_PENDING,
|
||||
BT_MESH_SETTINGS_CFG_PENDING,
|
||||
BT_MESH_SETTINGS_MOD_PENDING,
|
||||
BT_MESH_SETTINGS_VA_PENDING,
|
||||
BT_MESH_SETTINGS_CDB_PENDING,
|
||||
|
||||
void bt_mesh_clear_net(void);
|
||||
void bt_mesh_clear_subnet(uint16_t net_idx);
|
||||
void bt_mesh_clear_app_key(uint16_t app_idx);
|
||||
void bt_mesh_clear_rpl(void);
|
||||
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);
|
||||
BT_MESH_SETTINGS_FLAG_COUNT,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BT_SETTINGS
|
||||
#define BT_MESH_SETTINGS_DEFINE(_hname, _subtree, _set) \
|
||||
SETTINGS_STATIC_HANDLER_DEFINE(bt_mesh_##_hname, "bt/mesh/" _subtree, \
|
||||
NULL, _set, NULL, NULL)
|
||||
#else
|
||||
/* Declaring non static settings handler helps avoid unnecessary ifdefs
|
||||
* as well as unused function warning. Since the declared handler structure is
|
||||
* unused, linker will discard it.
|
||||
*/
|
||||
#define BT_MESH_SETTINGS_DEFINE(_hname, _subtree, _set)\
|
||||
const struct settings_handler settings_handler_bt_mesh_ ## _hname = {\
|
||||
.h_set = _set, \
|
||||
}
|
||||
#endif
|
||||
|
||||
void bt_mesh_settings_init(void);
|
||||
void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag);
|
||||
int bt_mesh_settings_set(settings_read_cb read_cb, void *cb_arg,
|
||||
void *out, size_t read_len);
|
||||
|
|
|
@ -2502,7 +2502,7 @@ static int cmd_cdb_node_add(const struct shell *shell, size_t argc,
|
|||
memcpy(node->dev_key, dev_key, 16);
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
bt_mesh_store_cdb_node(node);
|
||||
bt_mesh_cdb_node_store(node);
|
||||
}
|
||||
|
||||
shell_print(shell, "Added node 0x%04x", addr);
|
||||
|
@ -2558,7 +2558,7 @@ static int cmd_cdb_subnet_add(const struct shell *shell, size_t argc,
|
|||
memcpy(sub->keys[0].net_key, net_key, 16);
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
bt_mesh_store_cdb_subnet(sub);
|
||||
bt_mesh_cdb_subnet_store(sub);
|
||||
}
|
||||
|
||||
shell_print(shell, "Added Subnet 0x%03x", net_idx);
|
||||
|
@ -2615,7 +2615,7 @@ static int cmd_cdb_app_key_add(const struct shell *shell, size_t argc,
|
|||
memcpy(key->keys[0].app_key, app_key, 16);
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
bt_mesh_store_cdb_app_key(key);
|
||||
bt_mesh_cdb_app_key_store(key);
|
||||
}
|
||||
|
||||
shell_print(shell, "Added AppKey 0x%03x", app_idx);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/atomic.h>
|
||||
#include <sys/util.h>
|
||||
#include <sys/byteorder.h>
|
||||
|
@ -37,6 +38,26 @@
|
|||
#include "settings.h"
|
||||
#include "prov.h"
|
||||
|
||||
/* Tracking of what storage changes are pending for Net Keys. We track this in
|
||||
* a separate array here instead of within the respective bt_mesh_subnet
|
||||
* struct itselve, since once a key gets deleted its struct becomes invalid
|
||||
* and may be reused for other keys.
|
||||
*/
|
||||
struct net_key_update {
|
||||
uint16_t key_idx:12, /* NetKey Index */
|
||||
valid:1, /* 1 if this entry is valid, 0 if not */
|
||||
clear:1; /* 1 if key needs clearing, 0 if storing */
|
||||
};
|
||||
|
||||
/* NetKey storage information */
|
||||
struct net_key_val {
|
||||
uint8_t kr_flag:1,
|
||||
kr_phase:7;
|
||||
uint8_t val[2][16];
|
||||
} __packed;
|
||||
|
||||
static struct net_key_update net_key_updates[CONFIG_BT_MESH_SUBNET_COUNT];
|
||||
|
||||
static struct bt_mesh_subnet subnets[CONFIG_BT_MESH_SUBNET_COUNT] = {
|
||||
[0 ... (CONFIG_BT_MESH_SUBNET_COUNT - 1)] = {
|
||||
.net_idx = BT_MESH_KEY_UNUSED,
|
||||
|
@ -50,6 +71,77 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
|
|||
}
|
||||
}
|
||||
|
||||
static void clear_net_key(uint16_t net_idx)
|
||||
{
|
||||
char path[20];
|
||||
int err;
|
||||
|
||||
BT_DBG("NetKeyIndex 0x%03x", net_idx);
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/NetKey/%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_subnet(uint16_t net_idx)
|
||||
{
|
||||
const struct bt_mesh_subnet *sub;
|
||||
struct net_key_val key;
|
||||
char path[20];
|
||||
int err;
|
||||
|
||||
sub = bt_mesh_subnet_get(net_idx);
|
||||
if (!sub) {
|
||||
BT_WARN("NetKeyIndex 0x%03x not found", net_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
BT_DBG("NetKeyIndex 0x%03x", net_idx);
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/NetKey/%x", net_idx);
|
||||
|
||||
memcpy(&key.val[0], sub->keys[0].net, 16);
|
||||
memcpy(&key.val[1], sub->keys[1].net, 16);
|
||||
key.kr_flag = 0U; /* Deprecated */
|
||||
key.kr_phase = sub->kr_phase;
|
||||
|
||||
err = settings_save_one(path, &key, sizeof(key));
|
||||
if (err) {
|
||||
BT_ERR("Failed to store NetKey value");
|
||||
} else {
|
||||
BT_DBG("Stored NetKey value");
|
||||
}
|
||||
}
|
||||
|
||||
static struct net_key_update *net_key_update_find(uint16_t key_idx,
|
||||
struct net_key_update **free_slot)
|
||||
{
|
||||
struct net_key_update *match;
|
||||
int i;
|
||||
|
||||
match = NULL;
|
||||
*free_slot = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(net_key_updates); i++) {
|
||||
struct net_key_update *update = &net_key_updates[i];
|
||||
|
||||
if (!update->valid) {
|
||||
*free_slot = update;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (update->key_idx == key_idx) {
|
||||
match = update;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
uint8_t flags = 0x00;
|
||||
|
@ -65,6 +157,42 @@ uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub)
|
|||
return flags;
|
||||
}
|
||||
|
||||
static void update_subnet_settings(uint16_t net_idx, bool store)
|
||||
{
|
||||
struct net_key_update *update, *free_slot;
|
||||
uint8_t clear = store ? 0U : 1U;
|
||||
|
||||
BT_DBG("NetKeyIndex 0x%03x", net_idx);
|
||||
|
||||
update = net_key_update_find(net_idx, &free_slot);
|
||||
if (update) {
|
||||
update->clear = clear;
|
||||
bt_mesh_settings_store_schedule(
|
||||
BT_MESH_SETTINGS_NET_KEYS_PENDING);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!free_slot) {
|
||||
if (store) {
|
||||
store_subnet(net_idx);
|
||||
} else {
|
||||
clear_net_key(net_idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
free_slot->valid = 1U;
|
||||
free_slot->key_idx = net_idx;
|
||||
free_slot->clear = clear;
|
||||
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_KEYS_PENDING);
|
||||
}
|
||||
|
||||
void bt_mesh_subnet_store(uint16_t net_idx)
|
||||
{
|
||||
update_subnet_settings(net_idx, true);
|
||||
}
|
||||
|
||||
static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase)
|
||||
{
|
||||
BT_DBG("Phase 0x%02x -> 0x%02x", sub->kr_phase, new_phase);
|
||||
|
@ -96,7 +224,7 @@ static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
BT_DBG("Storing Updated NetKey persistently");
|
||||
bt_mesh_store_subnet(sub->net_idx);
|
||||
bt_mesh_subnet_store(sub->net_idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,7 +266,7 @@ static struct bt_mesh_subnet *subnet_alloc(uint16_t net_idx)
|
|||
static void subnet_del(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_clear_subnet(sub->net_idx);
|
||||
update_subnet_settings(sub->net_idx, false);
|
||||
}
|
||||
|
||||
bt_mesh_net_loopback_clear(sub->net_idx);
|
||||
|
@ -241,7 +369,7 @@ uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16])
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
BT_DBG("Storing NetKey persistently");
|
||||
bt_mesh_store_subnet(sub->net_idx);
|
||||
bt_mesh_subnet_store(sub->net_idx);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -663,3 +791,52 @@ bool bt_mesh_net_cred_find(struct bt_mesh_net_rx *rx, struct net_buf_simple *in,
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int net_key_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct net_key_val key;
|
||||
int err;
|
||||
uint16_t net_idx;
|
||||
|
||||
if (!name) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
net_idx = strtol(name, NULL, 16);
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &key, sizeof(key));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'net-key\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx);
|
||||
|
||||
return bt_mesh_subnet_set(
|
||||
net_idx, key.kr_phase, key.val[0],
|
||||
(key.kr_phase != BT_MESH_KR_NORMAL) ? key.val[1] : NULL);
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(subnet, "NetKey", net_key_set);
|
||||
|
||||
void bt_mesh_subnet_pending_store(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(net_key_updates); i++) {
|
||||
struct net_key_update *update = &net_key_updates[i];
|
||||
|
||||
if (!update->valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (update->clear) {
|
||||
clear_net_key(update->key_idx);
|
||||
} else {
|
||||
store_subnet(update->key_idx);
|
||||
}
|
||||
|
||||
update->valid = 0U;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,4 +200,13 @@ bt_mesh_subnet_has_new_key(const struct bt_mesh_subnet *sub)
|
|||
return sub->kr_phase != BT_MESH_KR_NORMAL;
|
||||
}
|
||||
|
||||
/** @brief Store the Subnet information in persistent storage.
|
||||
*
|
||||
* @param net_idx Network index to store.
|
||||
*/
|
||||
void bt_mesh_subnet_store(uint16_t net_idx);
|
||||
|
||||
/** @brief Store the pending Subnets in persistent storage. */
|
||||
void bt_mesh_subnet_pending_store(void);
|
||||
|
||||
#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_SUBNET_H_ */
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <zephyr.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/util.h>
|
||||
#include <sys/byteorder.h>
|
||||
|
@ -77,6 +78,20 @@
|
|||
/* How long to wait for available buffers before giving up */
|
||||
#define BUF_TIMEOUT K_NO_WAIT
|
||||
|
||||
struct virtual_addr {
|
||||
uint16_t ref:15,
|
||||
changed:1;
|
||||
uint16_t addr;
|
||||
uint8_t uuid[16];
|
||||
};
|
||||
|
||||
/* Virtual Address information for persistent storage. */
|
||||
struct va_val {
|
||||
uint16_t ref;
|
||||
uint16_t addr;
|
||||
uint8_t uuid[16];
|
||||
} __packed;
|
||||
|
||||
static struct seg_tx {
|
||||
struct bt_mesh_subnet *sub;
|
||||
void *seg[CONFIG_BT_MESH_TX_SEG_MAX];
|
||||
|
@ -123,7 +138,7 @@ static struct seg_rx {
|
|||
|
||||
K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4);
|
||||
|
||||
static struct bt_mesh_va virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT];
|
||||
static struct virtual_addr virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT];
|
||||
|
||||
static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu,
|
||||
const struct bt_mesh_send_cb *cb, void *cb_data,
|
||||
|
@ -1575,6 +1590,11 @@ void bt_mesh_rx_reset(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void store_va_label(void)
|
||||
{
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING);
|
||||
}
|
||||
|
||||
void bt_mesh_trans_reset(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -1597,7 +1617,7 @@ void bt_mesh_trans_reset(void)
|
|||
bt_mesh_rpl_clear();
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_label();
|
||||
store_va_label();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1614,26 +1634,17 @@ void bt_mesh_trans_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
struct bt_mesh_va *bt_mesh_va_get(uint16_t index)
|
||||
{
|
||||
if (index >= ARRAY_SIZE(virtual_addrs)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &virtual_addrs[index];
|
||||
}
|
||||
|
||||
static inline void va_store(struct bt_mesh_va *store)
|
||||
static inline void va_store(struct virtual_addr *store)
|
||||
{
|
||||
store->changed = 1U;
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_store_label();
|
||||
store_va_label();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bt_mesh_va_add(uint8_t uuid[16], uint16_t *addr)
|
||||
{
|
||||
struct bt_mesh_va *va = NULL;
|
||||
struct virtual_addr *va = NULL;
|
||||
int err;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
||||
|
@ -1675,7 +1686,7 @@ uint8_t bt_mesh_va_add(uint8_t uuid[16], uint16_t *addr)
|
|||
|
||||
uint8_t bt_mesh_va_del(uint8_t uuid[16], uint16_t *addr)
|
||||
{
|
||||
struct bt_mesh_va *va = NULL;
|
||||
struct virtual_addr *va = NULL;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
||||
if (virtual_addrs[i].ref &&
|
||||
|
@ -1699,19 +1710,6 @@ uint8_t bt_mesh_va_del(uint8_t uuid[16], uint16_t *addr)
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
struct bt_mesh_va *bt_mesh_va_find(uint8_t uuid[16])
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
||||
if (virtual_addrs[i].ref &&
|
||||
!memcmp(uuid, virtual_addrs[i].uuid,
|
||||
ARRAY_SIZE(virtual_addrs[i].uuid))) {
|
||||
return &virtual_addrs[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *bt_mesh_va_label_get(uint16_t addr)
|
||||
{
|
||||
int i;
|
||||
|
@ -1730,3 +1728,103 @@ uint8_t *bt_mesh_va_label_get(uint16_t addr)
|
|||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct virtual_addr *bt_mesh_va_get(uint16_t index)
|
||||
{
|
||||
if (index >= ARRAY_SIZE(virtual_addrs)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &virtual_addrs[index];
|
||||
}
|
||||
|
||||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||
static int va_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct va_val va;
|
||||
struct virtual_addr *lab;
|
||||
uint16_t index;
|
||||
int err;
|
||||
|
||||
if (!name) {
|
||||
BT_ERR("Insufficient number of arguments");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
index = strtol(name, NULL, 16);
|
||||
|
||||
if (len_rd == 0) {
|
||||
BT_WARN("Mesh Virtual Address length = 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va));
|
||||
if (err) {
|
||||
BT_ERR("Failed to set \'virtual address\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (va.ref == 0) {
|
||||
BT_WARN("Ignore Mesh Virtual Address ref = 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
lab = bt_mesh_va_get(index);
|
||||
if (lab == NULL) {
|
||||
BT_WARN("Out of labels buffers");
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(lab->uuid, va.uuid, 16);
|
||||
lab->addr = va.addr;
|
||||
lab->ref = va.ref;
|
||||
|
||||
BT_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x",
|
||||
lab->addr, lab->ref);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(va, "Va", va_set);
|
||||
#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */
|
||||
|
||||
#define IS_VA_DEL(_label) ((_label)->ref == 0)
|
||||
void bt_mesh_va_pending_store(void)
|
||||
{
|
||||
struct virtual_addr *lab;
|
||||
struct va_val va;
|
||||
char path[18];
|
||||
uint16_t i;
|
||||
int err;
|
||||
|
||||
for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) {
|
||||
if (!lab->changed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lab->changed = 0U;
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/Va/%x", i);
|
||||
|
||||
if (IS_VA_DEL(lab)) {
|
||||
err = settings_delete(path);
|
||||
} else {
|
||||
va.ref = lab->ref;
|
||||
va.addr = lab->addr;
|
||||
memcpy(va.uuid, lab->uuid, 16);
|
||||
|
||||
err = settings_save_one(path, &va, sizeof(va));
|
||||
}
|
||||
|
||||
if (err) {
|
||||
BT_ERR("Failed to %s %s value (err %d)",
|
||||
IS_VA_DEL(lab) ? "delete" : "store",
|
||||
log_strdup(path), err);
|
||||
} else {
|
||||
BT_DBG("%s %s value",
|
||||
IS_VA_DEL(lab) ? "Deleted" : "Stored",
|
||||
log_strdup(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,13 +76,6 @@ struct bt_mesh_ctl_friend_sub_confirm {
|
|||
uint8_t xact;
|
||||
} __packed;
|
||||
|
||||
struct bt_mesh_va {
|
||||
uint16_t ref:15,
|
||||
changed:1;
|
||||
uint16_t addr;
|
||||
uint8_t uuid[16];
|
||||
};
|
||||
|
||||
bool bt_mesh_tx_in_progress(void);
|
||||
|
||||
void bt_mesh_rx_reset(void);
|
||||
|
@ -110,12 +103,10 @@ void bt_mesh_trans_init(void);
|
|||
|
||||
void bt_mesh_trans_reset(void);
|
||||
|
||||
struct bt_mesh_va *bt_mesh_va_get(uint16_t index);
|
||||
|
||||
struct bt_mesh_va *bt_mesh_va_find(uint8_t uuid[16]);
|
||||
|
||||
uint8_t bt_mesh_va_add(uint8_t uuid[16], uint16_t *addr);
|
||||
|
||||
uint8_t bt_mesh_va_del(uint8_t uuid[16], uint16_t *addr);
|
||||
|
||||
uint8_t *bt_mesh_va_label_get(uint16_t addr);
|
||||
|
||||
void bt_mesh_va_pending_store(void);
|
||||
|
|
|
@ -573,7 +573,7 @@ static void net_send(uint8_t *data, uint16_t len)
|
|||
LOG_DBG("ttl 0x%02x dst 0x%04x payload_len %d", ctx.send_ttl,
|
||||
ctx.addr, cmd->payload_len);
|
||||
|
||||
if (!bt_mesh_app_key_get(vnd_app_key_idx)) {
|
||||
if (!bt_mesh_app_key_exists(vnd_app_key_idx)) {
|
||||
(void)bt_mesh_app_key_add(vnd_app_key_idx, net.net_idx,
|
||||
vnd_app_key);
|
||||
vnd_models[0].keys[0] = vnd_app_key_idx;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue