diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 21232b0f900..a4aace4d943 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -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 diff --git a/subsys/bluetooth/mesh/access.c b/subsys/bluetooth/mesh/access.c index 8f7bb78a764..e85ab5444f0 100644 --- a/subsys/bluetooth/mesh/access.c +++ b/subsys/bluetooth/mesh/access.c @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -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); +} diff --git a/subsys/bluetooth/mesh/access.h b/subsys/bluetooth/mesh/access.h index 73014afe8c0..3b8b9a6efba 100644 --- a/subsys/bluetooth/mesh/access.h +++ b/subsys/bluetooth/mesh/access.h @@ -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); diff --git a/subsys/bluetooth/mesh/app_keys.c b/subsys/bluetooth/mesh/app_keys.c index 86994f3bd38..a0353e194fb 100644 --- a/subsys/bluetooth/mesh/app_keys.c +++ b/subsys/bluetooth/mesh/app_keys.c @@ -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; + } +} diff --git a/subsys/bluetooth/mesh/app_keys.h b/subsys/bluetooth/mesh/app_keys.h index b9f6862b4af..150679a8332 100644 --- a/subsys/bluetooth/mesh/app_keys.h +++ b/subsys/bluetooth/mesh/app_keys.h @@ -10,28 +10,9 @@ #include #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_ */ diff --git a/subsys/bluetooth/mesh/cdb.c b/subsys/bluetooth/mesh/cdb.c index 3524230e3ab..e648a45ff28 100644 --- a/subsys/bluetooth/mesh/cdb.c +++ b/subsys/bluetooth/mesh/cdb.c @@ -6,6 +6,9 @@ #include #include +#include + +#include #include @@ -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(); + } } diff --git a/subsys/bluetooth/mesh/cdb.h b/subsys/bluetooth/mesh/cdb.h new file mode 100644 index 00000000000..f00aa1af4de --- /dev/null +++ b/subsys/bluetooth/mesh/cdb.h @@ -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); diff --git a/subsys/bluetooth/mesh/cfg.c b/subsys/bluetooth/mesh/cfg.c index 5da2c5e5210..cd0f763ce9b 100644 --- a/subsys/bluetooth/mesh/cfg.c +++ b/subsys/bluetooth/mesh/cfg.c @@ -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(); + } +} diff --git a/subsys/bluetooth/mesh/cfg.h b/subsys/bluetooth/mesh/cfg.h index e11f5d327a9..d7522642e0d 100644 --- a/subsys/bluetooth/mesh/cfg.h +++ b/subsys/bluetooth/mesh/cfg.h @@ -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); diff --git a/subsys/bluetooth/mesh/cfg_srv.c b/subsys/bluetooth/mesh/cfg_srv.c index 040977992c4..c62ebb490c7 100644 --- a/subsys/bluetooth/mesh/cfg_srv.c +++ b/subsys/bluetooth/mesh/cfg_srv.c @@ -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); } } diff --git a/subsys/bluetooth/mesh/heartbeat.c b/subsys/bluetooth/mesh/heartbeat.c index 79087f54901..cfd74b4aef2 100644 --- a/subsys/bluetooth/mesh/heartbeat.c +++ b/subsys/bluetooth/mesh/heartbeat.c @@ -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"); + } +} diff --git a/subsys/bluetooth/mesh/heartbeat.h b/subsys/bluetooth/mesh/heartbeat.h index adaf327baaa..1950855a156 100644 --- a/subsys/bluetooth/mesh/heartbeat.h +++ b/subsys/bluetooth/mesh/heartbeat.h @@ -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); diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index d866cc04d85..5c902d3d13f 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -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)); diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index 48d41811ebb..ffc278a1b35 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -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); + } +} diff --git a/subsys/bluetooth/mesh/net.h b/subsys/bluetooth/mesh/net.h index b2246342dc4..8696fae33ac 100644 --- a/subsys/bluetooth/mesh/net.h +++ b/subsys/bluetooth/mesh/net.h @@ -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) diff --git a/subsys/bluetooth/mesh/provisioner.c b/subsys/bluetooth/mesh/provisioner.c index a7d0aa5f472..74121a069d4 100644 --- a/subsys/bluetooth/mesh/provisioner.c +++ b/subsys/bluetooth/mesh/provisioner.c @@ -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; diff --git a/subsys/bluetooth/mesh/rpl.c b/subsys/bluetooth/mesh/rpl.c index a88de870947..a10e4c02fac 100644 --- a/subsys/bluetooth/mesh/rpl.c +++ b/subsys/bluetooth/mesh/rpl.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -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]); + } + } +} diff --git a/subsys/bluetooth/mesh/rpl.h b/subsys/bluetooth/mesh/rpl.h index 65daee82458..5e598f657a8 100644 --- a/subsys/bluetooth/mesh/rpl.h +++ b/subsys/bluetooth/mesh/rpl.h @@ -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); diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index b03a02507f7..34b639ec883 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -6,20 +6,11 @@ #include #include -#include -#include #include #include -#include #include -#include - -#include -#include -#include - #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_SETTINGS) #define LOG_MODULE_NAME bt_mesh_settings #include "common/log.h" @@ -28,141 +19,21 @@ #include "subnet.h" #include "app_keys.h" #include "net.h" +#include "cdb.h" #include "crypto.h" #include "rpl.h" #include "transport.h" #include "heartbeat.h" #include "access.h" -#include "foundation.h" #include "proxy.h" #include "settings.h" -#include "lpn.h" #include "cfg.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 */ -}; - -static struct key_update key_updates[CONFIG_BT_MESH_APP_KEY_COUNT + - CONFIG_BT_MESH_SUBNET_COUNT]; - static struct k_delayed_work pending_store; +static ATOMIC_DEFINE(pending_flags, BT_MESH_SETTINGS_FLAG_COUNT); -/* Mesh network storage information */ -struct net_val { - uint16_t primary_addr; - uint8_t dev_key[16]; -} __packed; - -/* Sequence number storage */ -struct seq_val { - uint8_t val[3]; -} __packed; - -/* Heartbeat Publication storage */ -struct hb_pub_val { - uint16_t dst; - uint8_t period; - uint8_t ttl; - uint16_t feat; - uint16_t net_idx:12, - indefinite:1; -}; - -/* 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; -}; - -/* IV Index & IV Update storage */ -struct iv_val { - uint32_t iv_index; - uint8_t iv_update:1, - iv_duration:7; -} __packed; - -/* Replay Protection List storage */ -struct rpl_val { - uint32_t seq:24, - old_iv:1; -}; - -/* NetKey storage information */ -struct net_key_val { - uint8_t kr_flag:1, - kr_phase:7; - uint8_t val[2][16]; -} __packed; - -/* AppKey storage information */ -struct app_key_val { - uint16_t net_idx; - bool updated; - uint8_t val[2][16]; -} __packed; - -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; -}; - -/* Virtual Address information */ -struct va_val { - uint16_t ref; - uint16_t addr; - uint8_t uuid[16]; -} __packed; - -struct cdb_net_val { - uint32_t iv_index; - bool iv_update; -} __packed; - -/* Node storage information */ -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; - -struct node_update { - uint16_t addr; - bool clear; -}; - -#if defined(CONFIG_BT_MESH_CDB) -static struct node_update cdb_node_updates[CONFIG_BT_MESH_CDB_NODE_COUNT]; -static struct key_update cdb_key_updates[CONFIG_BT_MESH_CDB_SUBNET_COUNT + - CONFIG_BT_MESH_CDB_APP_KEY_COUNT]; -#else -static struct node_update cdb_node_updates[0]; -static struct key_update cdb_key_updates[0]; -#endif - -static inline int mesh_x_set(settings_read_cb read_cb, void *cb_arg, void *out, - size_t read_len) +int bt_mesh_settings_set(settings_read_cb read_cb, void *cb_arg, + void *out, size_t read_len) { ssize_t len; @@ -182,808 +53,6 @@ static inline int mesh_x_set(settings_read_cb read_cb, void *cb_arg, void *out, return 0; } -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 = mesh_x_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; -} - -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 = mesh_x_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; -} - -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 = mesh_x_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; -} - -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 = mesh_x_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; -} - -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 = mesh_x_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); -} - -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; - } - - len_rd = read_cb(cb_arg, &key, sizeof(key)); - if (len_rd != sizeof(key)) { - 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; -} - -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 = mesh_x_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; -} - -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 = mesh_x_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; -} - -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_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_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; - } - - err = mesh_x_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); -} - -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); -} - -#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 bt_mesh_va *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 = mesh_x_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; -} -#endif - -#if defined(CONFIG_BT_MESH_CDB) -static int cdb_net_set(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) -{ - struct cdb_net_val net; - int err; - - if (len_rd == 0) { - BT_DBG("val (null)"); - return 0; - } - - err = mesh_x_set(read_cb, cb_arg, &net, sizeof(net)); - if (err) { - BT_ERR("Failed to set \'cdb_net\'"); - return err; - } - - bt_mesh_cdb.iv_index = net.iv_index; - - if (net.iv_update) { - atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS); - } - - atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID); - - return 0; -} - -static int cdb_node_set(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) -{ - struct bt_mesh_cdb_node *node; - struct node_val val; - 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 = mesh_x_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 = mesh_x_set(read_cb, cb_arg, &key, sizeof(key)); - if (err) { - BT_ERR("Failed to set \'net-key\'"); - return err; - } - - if (sub) { - BT_DBG("Updating existing NetKeyIndex 0x%03x", net_idx); - - sub->kr_flag = key.kr_flag; - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); - - return 0; - } - - sub = bt_mesh_cdb_subnet_alloc(net_idx); - if (!sub) { - BT_ERR("No space to allocate a new subnet"); - return -ENOMEM; - } - - sub->kr_flag = key.kr_flag; - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); - - BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); - - return 0; -} - -static int cdb_app_key_set(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) -{ - struct bt_mesh_cdb_app_key *app; - struct app_key_val key; - 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 = mesh_x_set(read_cb, cb_arg, &key, sizeof(key)); - if (err) { - BT_ERR("Failed to set \'app-key\'"); - return err; - } - - app = bt_mesh_cdb_app_key_get(app_idx); - if (!app) { - app = bt_mesh_cdb_app_key_alloc(key.net_idx, app_idx); - } - - if (!app) { - BT_ERR("No space for a new app key"); - return -ENOMEM; - } - - memcpy(app->keys[0].app_key, key.val[0], 16); - memcpy(app->keys[1].app_key, key.val[1], 16); - - BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); - - return 0; -} - -static int cdb_set(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) -{ - int len; - const char *next; - - if (!name) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - if (!strcmp(name, "Net")) { - return cdb_net_set(name, len_rd, read_cb, cb_arg); - } - - - len = settings_name_next(name, &next); - - if (!next) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - if (!strncmp(name, "Node", len)) { - return cdb_node_set(next, len_rd, read_cb, cb_arg); - } - - if (!strncmp(name, "Subnet", len)) { - return cdb_subnet_set(next, len_rd, read_cb, cb_arg); - } - - if (!strncmp(name, "AppKey", len)) { - return cdb_app_key_set(next, len_rd, read_cb, cb_arg); - } - - BT_WARN("Unknown module key %s", name); - return -ENOENT; -} -#endif - -const struct mesh_setting { - const char *name; - int (*func)(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg); -} settings[] = { - { "Net", net_set }, - { "IV", iv_set }, - { "Seq", seq_set }, - { "RPL", rpl_set }, - { "NetKey", net_key_set }, - { "AppKey", app_key_set }, - { "HBPub", hb_pub_set }, - { "Cfg", cfg_set }, - { "s", sig_mod_set }, - { "v", vnd_mod_set }, -#if CONFIG_BT_MESH_LABEL_COUNT > 0 - { "Va", va_set }, -#endif -#if defined(CONFIG_BT_MESH_CDB) - { "cdb", cdb_set }, -#endif -}; - -static int mesh_set(const char *name, size_t len_rd, - settings_read_cb read_cb, void *cb_arg) -{ - int i, len; - const char *next; - - if (!name) { - BT_ERR("Insufficient number of arguments"); - return -EINVAL; - } - - len = settings_name_next(name, &next); - - for (i = 0; i < ARRAY_SIZE(settings); i++) { - if (!strncmp(settings[i].name, name, len)) { - return settings[i].func(next, len_rd, read_cb, cb_arg); - } - } - - BT_WARN("No matching handler for key %s", log_strdup(name)); - - return -ENOENT; -} - -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]); - } - } -} - static int mesh_commit(void) { if (!bt_mesh_subnet_next(NULL)) { @@ -995,11 +64,8 @@ static int mesh_commit(void) bt_mesh_proxy_prov_disable(true); } - if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); - } - - bt_mesh_model_foreach(commit_mod, NULL); + bt_mesh_net_settings_commit(); + bt_mesh_model_settings_commit(); atomic_set_bit(bt_mesh.flags, BT_MESH_VALID); @@ -1008,29 +74,32 @@ static int mesh_commit(void) return 0; } -SETTINGS_STATIC_HANDLER_DEFINE(bt_mesh, "bt/mesh", NULL, mesh_set, mesh_commit, +SETTINGS_STATIC_HANDLER_DEFINE(bt_mesh, "bt/mesh", NULL, NULL, mesh_commit, NULL); /* Pending flags that use K_NO_WAIT as the storage timeout */ -#define NO_WAIT_PENDING_BITS (BIT(BT_MESH_NET_PENDING) | \ - BIT(BT_MESH_IV_PENDING) | \ - BIT(BT_MESH_SEQ_PENDING)) +#define NO_WAIT_PENDING_BITS (BIT(BT_MESH_SETTINGS_NET_PENDING) | \ + BIT(BT_MESH_SETTINGS_IV_PENDING) | \ + BIT(BT_MESH_SETTINGS_SEQ_PENDING) | \ + BIT(BT_MESH_SETTINGS_CDB_PENDING)) /* Pending flags that use CONFIG_BT_MESH_STORE_TIMEOUT */ -#define GENERIC_PENDING_BITS (BIT(BT_MESH_KEYS_PENDING) | \ - BIT(BT_MESH_HB_PUB_PENDING) | \ - BIT(BT_MESH_CFG_PENDING) | \ - BIT(BT_MESH_MOD_PENDING)) +#define GENERIC_PENDING_BITS (BIT(BT_MESH_SETTINGS_NET_KEYS_PENDING) | \ + BIT(BT_MESH_SETTINGS_APP_KEYS_PENDING) | \ + BIT(BT_MESH_SETTINGS_HB_PUB_PENDING) | \ + BIT(BT_MESH_SETTINGS_CFG_PENDING) | \ + BIT(BT_MESH_SETTINGS_MOD_PENDING)) -static void schedule_store(int flag) +void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag) { int32_t timeout_ms, remaining; - atomic_set_bit(bt_mesh.flags, flag); + atomic_set_bit(pending_flags, flag); - if (atomic_get(bt_mesh.flags) & NO_WAIT_PENDING_BITS) { + if (atomic_get(pending_flags) & NO_WAIT_PENDING_BITS) { timeout_ms = 0; - } else if (atomic_test_bit(bt_mesh.flags, BT_MESH_RPL_PENDING) && + } else if (atomic_test_bit(pending_flags, + BT_MESH_SETTINGS_RPL_PENDING) && (!(atomic_get(bt_mesh.flags) & GENERIC_PENDING_BITS) || (CONFIG_BT_MESH_RPL_STORE_TIMEOUT < CONFIG_BT_MESH_STORE_TIMEOUT))) { @@ -1050,1229 +119,65 @@ static void schedule_store(int flag) k_delayed_work_submit(&pending_store, K_MSEC(timeout_ms)); } -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 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_store_net(void) -{ - schedule_store(BT_MESH_NET_PENDING); -} - -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_store_iv(bool only_duration) -{ - schedule_store(BT_MESH_IV_PENDING); - - if (!only_duration) { - /* Always update Seq whenever IV changes */ - schedule_store(BT_MESH_SEQ_PENDING); - } -} - -static void store_pending_seq(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_store_seq(void) -{ - if (CONFIG_BT_MESH_SEQ_STORE_RATE && - (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)) { - return; - } - - schedule_store(BT_MESH_SEQ_PENDING); -} - -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, void *user_data) -{ - 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, void *user_data) -{ - BT_DBG(""); - - if (rpl->store) { - rpl->store = false; - store_rpl(rpl); - } -} - -static void store_pending_hb_pub(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"); - } -} - -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"); - } -} - -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 clear_app_key(uint16_t app_idx) -{ - 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 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 void store_app(uint16_t app_idx) -{ - const struct bt_mesh_app_key *app; - struct app_key_val key; - char path[20]; - int err; - - snprintk(path, sizeof(path), "bt/mesh/AppKey/%x", app_idx); - - app = bt_mesh_app_key_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 void store_pending_keys(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(key_updates); i++) { - struct key_update *update = &key_updates[i]; - - if (!update->valid) { - continue; - } - - if (update->clear) { - if (update->app_key) { - clear_app_key(update->key_idx); - } else { - clear_net_key(update->key_idx); - } - } else { - if (update->app_key) { - store_app(update->key_idx); - } else { - store_subnet(update->key_idx); - } - } - - update->valid = 0U; - } -} - -static void clear_cdb(void) -{ - int err; - - err = settings_delete("bt/mesh/cdb/Net"); - if (err) { - BT_ERR("Failed to clear Network"); - } else { - BT_DBG("Cleared Network"); - } -} - -static void store_pending_cdb(void) -{ - struct cdb_net_val net; - int err; - - BT_DBG(""); - - net.iv_index = bt_mesh_cdb.iv_index; - net.iv_update = atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_IVU_IN_PROGRESS); - - err = settings_save_one("bt/mesh/cdb/Net", &net, sizeof(net)); - if (err) { - BT_ERR("Failed to store Network value"); - } else { - BT_DBG("Stored Network value"); - } -} - -static void store_cdb_node(const struct bt_mesh_cdb_node *node) -{ - struct node_val val; - char path[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_pending_cdb_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_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 store_pending_cdb_keys(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { - struct key_update *update = &cdb_key_updates[i]; - - if (!update->valid) { - continue; - } - - if (update->clear) { - if (update->app_key) { - clear_cdb_app_key(update->key_idx); - } else { - clear_cdb_subnet(update->key_idx); - } - } else { - if (update->app_key) { - struct bt_mesh_cdb_app_key *key; - - key = bt_mesh_cdb_app_key_get(update->key_idx); - if (key) { - store_cdb_app_key(key); - } else { - BT_WARN("AppKeyIndex 0x%03x not found", - update->key_idx); - } - } else { - struct bt_mesh_cdb_subnet *sub; - - sub = bt_mesh_cdb_subnet_get(update->key_idx); - if (sub) { - store_cdb_subnet(sub); - } else { - BT_WARN("NetKeyIndex 0x%03x not found", - update->key_idx); - } - } - } - - update->valid = 0U; - } -} - -static struct node_update *cdb_node_update_find(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 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); - } -} - -#define IS_VA_DEL(_label) ((_label)->ref == 0) -static void store_pending_va(void) -{ - struct bt_mesh_va *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)); - } - } -} - static void store_pending(struct k_work *work) { BT_DBG(""); - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_RPL_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_rpl_foreach(store_pending_rpl, NULL); - } else { - bt_mesh_rpl_foreach(clear_rpl, NULL); - } + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_RPL_PENDING)) { + bt_mesh_rpl_pending_store(); } - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_KEYS_PENDING)) { - store_pending_keys(); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_NET_KEYS_PENDING)) { + bt_mesh_subnet_pending_store(); } - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_NET_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_net(); - } else { - clear_net(); - } + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_APP_KEYS_PENDING)) { + bt_mesh_app_key_pending_store(); } - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_IV_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_iv(); - } else { - clear_iv(); - } + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_NET_PENDING)) { + bt_mesh_net_pending_net_store(); } - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_SEQ_PENDING)) { - store_pending_seq(); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_IV_PENDING)) { + bt_mesh_net_pending_iv_store(); } - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_HB_PUB_PENDING)) { - store_pending_hb_pub(); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_SEQ_PENDING)) { + bt_mesh_net_pending_seq_store(); } - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_CFG_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_cfg(); - } else { - clear_cfg(); - } + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_HB_PUB_PENDING)) { + bt_mesh_hb_pub_pending_store(); } - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_MOD_PENDING)) { - bt_mesh_model_foreach(store_pending_mod, NULL); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_CFG_PENDING)) { + bt_mesh_cfg_pending_store(); } - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_VA_PENDING)) { - store_pending_va(); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_MOD_PENDING)) { + bt_mesh_model_pending_store(); } - if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_SUBNET_PENDING)) { - if (atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_VALID)) { - store_pending_cdb(); - } else { - clear_cdb(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_NODES_PENDING)) { - store_pending_cdb_nodes(); - } - - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_KEYS_PENDING)) { - store_pending_cdb_keys(); - } - } -} - -void bt_mesh_store_rpl(struct bt_mesh_rpl *entry) -{ - entry->store = true; - schedule_store(BT_MESH_RPL_PENDING); -} - -static struct key_update *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(key_updates); i++) { - struct key_update *update = &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; - } + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_VA_PENDING)) { + bt_mesh_va_pending_store(); } - return match; -} - -void bt_mesh_store_subnet(uint16_t net_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - update = key_update_find(false, net_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_store(BT_MESH_KEYS_PENDING); - return; + if (IS_ENABLED(CONFIG_BT_MESH_CDB) && + atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_CDB_PENDING)) { + bt_mesh_cdb_pending_store(); } - - if (!free_slot) { - store_subnet(net_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = net_idx; - free_slot->app_key = 0U; - free_slot->clear = 0U; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_store_app_key(uint16_t app_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - update = key_update_find(true, app_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_app(app_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = app_idx; - free_slot->app_key = 1U; - free_slot->clear = 0U; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_store_hb_pub(void) -{ - schedule_store(BT_MESH_HB_PUB_PENDING); -} - -void bt_mesh_store_cfg(void) -{ - schedule_store(BT_MESH_CFG_PENDING); -} - -void bt_mesh_clear_net(void) -{ - schedule_store(BT_MESH_NET_PENDING); - schedule_store(BT_MESH_IV_PENDING); - schedule_store(BT_MESH_CFG_PENDING); -} - -void bt_mesh_clear_subnet(uint16_t net_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - update = key_update_find(false, net_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_net_key(net_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = net_idx; - free_slot->app_key = 0U; - free_slot->clear = 1U; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_clear_app_key(uint16_t app_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - update = key_update_find(true, app_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_app_key(app_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = app_idx; - free_slot->app_key = 1U; - free_slot->clear = 1U; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_clear_rpl(void) -{ - schedule_store(BT_MESH_RPL_PENDING); -} - -void bt_mesh_store_mod_bind(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_BIND_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - -void bt_mesh_store_mod_sub(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_SUB_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - -void bt_mesh_store_mod_pub(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_PUB_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - - -void bt_mesh_store_label(void) -{ - schedule_store(BT_MESH_VA_PENDING); -} - -static void schedule_cdb_store(int flag) -{ - atomic_set_bit(bt_mesh_cdb.flags, flag); - k_delayed_work_submit(&pending_store, K_NO_WAIT); -} - -void bt_mesh_store_cdb(void) -{ - schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING); -} - -void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node) -{ - struct node_update *update, *free_slot; - - BT_DBG("Node 0x%04x", node->addr); - - update = cdb_node_update_find(node->addr, &free_slot); - if (update) { - update->clear = false; - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); - return; - } - - if (!free_slot) { - store_cdb_node(node); - return; - } - - free_slot->addr = node->addr; - free_slot->clear = false; - - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); -} - -void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node) -{ - struct node_update *update, *free_slot; - - BT_DBG("Node 0x%04x", node->addr); - - update = cdb_node_update_find(node->addr, &free_slot); - if (update) { - update->clear = true; - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_node(node->addr); - return; - } - - free_slot->addr = node->addr; - free_slot->clear = true; - - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); -} - -/* TODO: Could be shared with key_update_find? */ -static struct key_update *cdb_key_update_find(bool app_key, 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; -} - -void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); - - update = cdb_key_update_find(false, sub->net_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_cdb_subnet(sub); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; - free_slot->app_key = 0U; - free_slot->clear = 0U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); - - update = cdb_key_update_find(false, sub->net_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_subnet(sub->net_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; - free_slot->app_key = 0U; - free_slot->clear = 1U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *key) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); - - update = cdb_key_update_find(true, key->app_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_cdb_app_key(key); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; - free_slot->app_key = 1U; - free_slot->clear = 0U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *key) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); - - update = cdb_key_update_find(true, key->app_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_app_key(key->app_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; - free_slot->app_key = 1U; - free_slot->clear = 1U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, - 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; } void bt_mesh_settings_init(void) diff --git a/subsys/bluetooth/mesh/settings.h b/subsys/bluetooth/mesh/settings.h index 9060a14a726..d2044145dac 100644 --- a/subsys/bluetooth/mesh/settings.h +++ b/subsys/bluetooth/mesh/settings.h @@ -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); diff --git a/subsys/bluetooth/mesh/shell.c b/subsys/bluetooth/mesh/shell.c index 5e491e0a798..8f1293b5535 100644 --- a/subsys/bluetooth/mesh/shell.c +++ b/subsys/bluetooth/mesh/shell.c @@ -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); diff --git a/subsys/bluetooth/mesh/subnet.c b/subsys/bluetooth/mesh/subnet.c index cac7858bb2e..f3ddfa4968d 100644 --- a/subsys/bluetooth/mesh/subnet.c +++ b/subsys/bluetooth/mesh/subnet.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -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; + } +} diff --git a/subsys/bluetooth/mesh/subnet.h b/subsys/bluetooth/mesh/subnet.h index 647d39d28d6..d0f43837013 100644 --- a/subsys/bluetooth/mesh/subnet.h +++ b/subsys/bluetooth/mesh/subnet.h @@ -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_ */ diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index eb5db791ef6..abc6d0ffc75 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -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)); + } + } +} diff --git a/subsys/bluetooth/mesh/transport.h b/subsys/bluetooth/mesh/transport.h index b40b639112d..314893b2586 100644 --- a/subsys/bluetooth/mesh/transport.h +++ b/subsys/bluetooth/mesh/transport.h @@ -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); diff --git a/tests/bluetooth/tester/src/mesh.c b/tests/bluetooth/tester/src/mesh.c index 9a57233dfe7..7f92401aab4 100644 --- a/tests/bluetooth/tester/src/mesh.c +++ b/tests/bluetooth/tester/src/mesh.c @@ -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;