/* * Copyright (c) 2018 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include "adaptation.h" #include "mesh_net.h" #include "mesh_crypto.h" #include "mesh_transport.h" #include "access.h" #include "foundation.h" #include "proxy.h" #include "mesh_settings.h" #include "syscfg/syscfg_id.h" #define LOG_TAG "[MESH-settings]" /* #define LOG_INFO_ENABLE */ /* #define LOG_DEBUG_ENABLE */ /* #define LOG_WARN_ENABLE */ /* #define LOG_ERROR_ENABLE */ /* #define LOG_DUMP_ENABLE */ #include "mesh_log.h" #if MESH_RAM_AND_CODE_MAP_DETAIL #ifdef SUPPORT_MS_EXTENSIONS #pragma bss_seg(".ble_mesh_settings_bss") #pragma data_seg(".ble_mesh_settings_data") #pragma const_seg(".ble_mesh_settings_const") #pragma code_seg(".ble_mesh_settings_code") #endif #else /* MESH_RAM_AND_CODE_MAP_DETAIL */ #pragma bss_seg(".ble_mesh_bss") #pragma data_seg(".ble_mesh_data") #pragma const_seg(".ble_mesh_const") #pragma code_seg(".ble_mesh_code") #endif /* MESH_RAM_AND_CODE_MAP_DETAIL */ #define MAX_MODEL_NUMS 6 typedef enum _NODE_INFO_SETTING_INDEX { /* NODE_MAC_ADDR_INDEX = 0, */ NET_INDEX = VM_BLE_MESH_IDX_BEGIN, IV_INDEX, SEQ_INDEX, RPL_INDEX, NET_KEY_INDEX = RPL_INDEX + CONFIG_BT_MESH_CRPL, APP_KEY_INDEX = NET_KEY_INDEX + CONFIG_BT_MESH_SUBNET_COUNT, HB_PUB_INDEX = APP_KEY_INDEX + CONFIG_BT_MESH_APP_KEY_COUNT, CFG_INDEX, MOD_BIND_INDEX, //143 MOD_SUB_INDEX = MOD_BIND_INDEX + MAX_MODEL_NUMS, MOD_PUB_INDEX = MOD_SUB_INDEX + MAX_MODEL_NUMS, VND_MOD_BIND_INDEX = MOD_PUB_INDEX + MAX_MODEL_NUMS, VND_MOD_SUB_INDEX = VND_MOD_BIND_INDEX + MAX_MODEL_NUMS, VND_MOD_PUB_INDEX = VND_MOD_SUB_INDEX + MAX_MODEL_NUMS, #if defined(CONFIG_BT_MESH_CDB) /* CDB_INDEX = VND_MOD_PUB_INDEX + MAX_MODEL_NUMS, */ CDB_INDEX = VM_BLE_MESH_CDB_IDX_BEGIN, CDB_NODE_INDEX, CDB_APP_KEY_INDEX = CDB_NODE_INDEX + CONFIG_BT_MESH_CDB_NODE_COUNT, CDB_SUBNET_INDEX = CDB_APP_KEY_INDEX + CONFIG_BT_MESH_CDB_SUBNET_COUNT + CONFIG_BT_MESH_CDB_APP_KEY_COUNT, CDB_MAX_INDEX = CDB_SUBNET_INDEX + CONFIG_BT_MESH_CDB_SUBNET_COUNT + CONFIG_BT_MESH_CDB_APP_KEY_COUNT, #endif } NODE_INFO_SETTING_INDEX; /* Tracking of what storage changes are pending for App and Net Keys. We * track this in a separate array here instead of within the respective * bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key * gets deleted its struct becomes invalid and may be reused for other keys. */ static struct key_update { u16_t key_idx: 12, /* AppKey or NetKey Index */ valid: 1, /* 1 if this entry is valid, 0 if not */ app_key: 1, /* 1 if this is an AppKey, 0 if a NetKey */ clear: 1; /* 1 if key needs clearing, 0 if storing */ } key_updates[CONFIG_BT_MESH_APP_KEY_COUNT + CONFIG_BT_MESH_SUBNET_COUNT]; struct net_val { u16_t primary_addr; u8_t dev_key[16]; } __packed; /* Sequence number storage */ struct seq_val { u8_t val[3]; } __packed; /* Heartbeat Publication storage */ struct hb_pub_val { u16_t dst; u8_t period; u8_t ttl; u16_t feat; u16_t net_idx: 12, indefinite: 1; }; /* Miscelaneous configuration server model states */ struct cfg_val { u8_t net_transmit; u8_t relay; u8_t relay_retransmit; u8_t beacon; u8_t gatt_proxy; u8_t frnd; u8_t default_ttl; }; /* IV Index & IV Update storage */ struct iv_val { u32_t iv_index; u8_t iv_update: 1, iv_duration: 7; } __packed; /* Replay Protection List storage */ struct rpl_val { u32_t seq: 24, old_iv: 1; }; /* NetKey storage information */ struct net_key_val { u8_t net_idx; u8_t kr_flag: 1, kr_phase: 7; u8_t val[2][16]; } __packed; /* AppKey storage information */ struct app_key_val { u16_t app_idx; u16_t net_idx; bool updated; u8_t val[2][16]; } __packed; struct mod_pub_val { u16_t addr; u16_t key; u8_t ttl; u8_t retransmit; u8_t period; u8_t period_div: 4, cred: 1; }; /* We need this so we don't overwrite app-hardcoded values in case FCB * contains a history of changes but then has a NULL at the end. */ static struct { bool valid; struct cfg_val cfg; } stored_cfg; struct __rpl_val { u16_t src; struct rpl_val rpl; }; struct __mod_bind { u16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT]; }; struct __mod_sub { u16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT]; }; struct __mod_pub { struct mod_pub_val pub; }; static void store_pending(void); extern void node_info_store(int index, void *buf, u16 len); extern void node_info_clear(int index, u16 len); extern bool node_info_load(int index, void *buf, u16 len); #if CONFIG_BT_MESH_PROVISIONER /* Node storage information */ struct node_val { u16_t net_idx; u8_t num_elem; u8_t flags; #define F_NODE_CONFIGURED 0x01 u8_t uuid[16]; u8_t dev_key[16]; u16_t addr; } __packed; struct node_update { u16_t addr; bool clear; }; struct cdb_net_val { u32_t iv_index; bool iv_update; } __packed; #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 void cdb_set(void); static void clear_cdb(void); static void store_pending_cdb(void); static void store_pending_cdb_nodes(void); static void store_pending_cdb_keys(void); #endif /* CONFIG_BT_MESH_PROVISIONER */ static struct { u16_t app_idx; u8 use_flag; } mesh_app_key_store_info[CONFIG_BT_MESH_SUBNET_COUNT]; static u8 get_model_store_index(bool vnd, u8 elem_idx, u8 mod_idx) { u8 i; u8 store_index = 0; for (i = 0; i < elem_idx; i++) { if (vnd) { store_index += bt_mesh_each_elem_vendor_model_numbers_get(i); } else { store_index += bt_mesh_each_elem_sig_model_numbers_get(i); } } store_index += mod_idx; return store_index; } static u8 bt_mesh_model_numbers_get(bool vnd) { u8 model_count = 0; for (u8 i = 0; i < bt_mesh_elem_count(); i++) { if (vnd) { model_count += bt_mesh_each_elem_vendor_model_numbers_get(i); } else { model_count += bt_mesh_each_elem_sig_model_numbers_get(i); } } ASSERT(model_count <= MAX_MODEL_NUMS, "real model numbers:%d", model_count); return model_count; } static void get_elem_and_mod_idx(bool vnd, u8 model_count, u8 *elem_idx, u8 *mod_idx) { u8 i; u8 each_elem_model_numbers = 0; *elem_idx = 0; *mod_idx = 0; for (i = 0; i < bt_mesh_elem_count(); i++) { if (vnd) { each_elem_model_numbers = bt_mesh_each_elem_vendor_model_numbers_get(i); } else { each_elem_model_numbers = bt_mesh_each_elem_sig_model_numbers_get(i); } if (model_count >= each_elem_model_numbers) { model_count -= each_elem_model_numbers; } else { break; } } *elem_idx = i; *mod_idx = model_count; } static void net_set(void) { BT_INFO("\n < --%s-- >", __FUNCTION__); struct net_val net; int err; err = node_info_load(NET_INDEX, &net, sizeof(net)); if (err) { bt_mesh_comp_unprovision(); (void)memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); BT_ERR(" load not exist"); return; } 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)); } static void iv_set(void) { struct iv_val iv; int err; BT_INFO("\n < --%s-- >", __FUNCTION__); err = node_info_load(IV_INDEX, &iv, sizeof(iv)); if (err) { bt_mesh.iv_index = 0; bt_mesh.iv_update = 0; BT_ERR(" load not exist"); return; } bt_mesh.iv_index = iv.iv_index; bt_mesh.iv_update = iv.iv_update; bt_mesh.ivu_duration = iv.iv_duration; BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours", bt_mesh.iv_index, bt_mesh.iv_update, bt_mesh.ivu_duration); } static void seq_set(void) { struct seq_val seq; int err; BT_INFO("\n < --%s-- >", __FUNCTION__); err = node_info_load(SEQ_INDEX, &seq, sizeof(seq)); if (err) { bt_mesh.seq = 0; BT_ERR(" load not exist"); return; } bt_mesh.seq = ((u32_t)seq.val[0] | ((u32_t)seq.val[1] << 8) | ((u32_t)seq.val[2] << 16)); 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); } static struct bt_mesh_rpl *rpl_find(u16_t src) { int i; for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { if (bt_mesh.rpl[i].src == src) { return &bt_mesh.rpl[i]; } } return NULL; } static struct bt_mesh_rpl *rpl_alloc(u16_t src) { int i; for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { if (!bt_mesh.rpl[i].src) { bt_mesh.rpl[i].src = src; return &bt_mesh.rpl[i]; } } return NULL; } static void rpl_set(void) { struct bt_mesh_rpl *entry; struct __rpl_val __rpl; int err; u8 index; BT_INFO("\n < --%s-- >", __FUNCTION__); for (index = 0; index < CONFIG_BT_MESH_CRPL; index++) { err = node_info_load(RPL_INDEX + index, &__rpl, sizeof(__rpl)); if (err) { BT_ERR(" memory load fail for index:0x%x", index); continue; } entry = rpl_find(__rpl.src); if (!entry) { entry = rpl_alloc(__rpl.src); if (!entry) { BT_ERR("Unable to allocate RPL entry for 0x%04x", __rpl.src); return; } } entry->seq = __rpl.rpl.seq; entry->old_iv = __rpl.rpl.old_iv; BT_DBG("RPL entry for 0x%04x: Seq 0x%06x old_iv %u", entry->src, entry->seq, entry->old_iv); } } static void net_key_set(void) { struct bt_mesh_subnet *sub; struct net_key_val key; int i, err; u16_t net_idx; BT_INFO("\n < --%s-- >", __FUNCTION__); for (net_idx = 0; net_idx < CONFIG_BT_MESH_SUBNET_COUNT; net_idx++) { err = node_info_load(NET_KEY_INDEX + net_idx, &key, sizeof(key)); if (err) { BT_ERR(" memory load fail for net_idx:0x%x", net_idx); continue; } sub = bt_mesh_subnet_get(net_idx); 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.val[0], 16); memcpy(sub->keys[1].net, &key.val[1], 16); continue; } for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { if (bt_mesh.sub[i].net_idx == BT_MESH_KEY_UNUSED) { sub = &bt_mesh.sub[i]; break; } } if (!sub) { BT_ERR("No space to allocate a new subnet"); return; } sub->net_idx = net_idx; sub->kr_flag = key.kr_flag; sub->kr_phase = key.kr_phase; memcpy(sub->keys[0].net, &key.val[0], 16); memcpy(sub->keys[1].net, &key.val[1], 16); BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); } } static void app_key_set(void) { struct bt_mesh_app_key *app; struct app_key_val key; u16_t app_idx; int err; BT_INFO("\n < --%s-- >", __FUNCTION__); for (app_idx = 0; app_idx < CONFIG_BT_MESH_SUBNET_COUNT; app_idx++) { err = node_info_load(APP_KEY_INDEX + app_idx, &key, sizeof(key)); if (err) { BT_ERR(" memory load fail for net_idx:0x%x", app_idx); continue; } app = bt_mesh_app_key_find(app_idx); if (!app) { app = bt_mesh_app_key_alloc(app_idx); } if (!app) { BT_ERR("No space for a new app key"); return; } mesh_app_key_store_info[app_idx].app_idx = key.app_idx; mesh_app_key_store_info[app_idx].use_flag = 1; app->net_idx = key.net_idx; app->app_idx = key.app_idx; app->updated = key.updated; memcpy(app->keys[0].val, key.val[0], 16); memcpy(app->keys[1].val, key.val[1], 16); bt_mesh_app_id(app->keys[0].val, &app->keys[0].id); bt_mesh_app_id(app->keys[1].val, &app->keys[1].id); BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); } } static void hb_pub_set(void) { struct bt_mesh_hb_pub *pub = bt_mesh_hb_pub_get(); struct hb_pub_val hb_val; int err; BT_INFO("\n < --%s-- >", __FUNCTION__); if (!pub) { BT_ERR("no heartbeat will set"); return; } err = node_info_load(HB_PUB_INDEX, &hb_val, sizeof(hb_val)); if (err) { pub->dst = BT_MESH_ADDR_UNASSIGNED; pub->count = 0; pub->ttl = 0; pub->period = 0; pub->feat = 0; BT_ERR("Cleared heartbeat publication"); return; } pub->dst = hb_val.dst; pub->period = 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 = 0; } BT_DBG("Restored heartbeat publication"); } static void cfg_set(void) { struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); int err; BT_INFO("\n < --%s-- >", __FUNCTION__); if (!cfg) { BT_ERR("no cfg will set"); return; } err = node_info_load(CFG_INDEX, &stored_cfg.cfg, sizeof(stored_cfg.cfg)); if (err) { stored_cfg.valid = false; BT_ERR("Cleared configuration state"); return; } stored_cfg.valid = true; BT_DBG("Restored configuration state"); } static void mod_set_bind(bool vnd, u8 model_count) { int err; struct bt_mesh_model *mod; u8_t elem_idx, mod_idx; struct __mod_bind _mod_bind; u8 load_index = vnd ? VND_MOD_BIND_INDEX : MOD_BIND_INDEX; BT_INFO("< --%s-- >", __FUNCTION__); for (u8 i = 0; i < model_count; i++) { err = node_info_load(load_index + i, &_mod_bind, sizeof(_mod_bind)); if (err) { BT_ERR("%s load not exist", vnd ? "Vendor" : "SIG"); continue; } get_elem_and_mod_idx(vnd, i, &elem_idx, &mod_idx); BT_DBG("Decoded elem_idx:%u; mod_idx:%u", elem_idx, mod_idx); mod = bt_mesh_model_get(vnd, elem_idx, mod_idx); memcpy((u8 *)mod->keys, (u8 *)_mod_bind.keys, sizeof(mod->keys)); BT_DBG("Decoded %u bound keys for model", sizeof(mod->keys) / sizeof(mod->keys[0])); BT_DBG("Restored model bind, keys[0]:0x%x, keys[1]:0x%x ", _mod_bind.keys[0], _mod_bind.keys[1]); } } static void mod_set_sub(bool vnd, u8 model_count) { int err; struct bt_mesh_model *mod; u8_t elem_idx, mod_idx; struct __mod_sub _mod_sub; BT_INFO("< --%s-- >", __FUNCTION__); u8 load_index = vnd ? VND_MOD_SUB_INDEX : MOD_SUB_INDEX; for (u8 i = 0; i < model_count; i++) { err = node_info_load(load_index + i, &_mod_sub, sizeof(_mod_sub)); if (err) { BT_ERR("%s load not exist", vnd ? "Vendor" : "SIG"); continue; } get_elem_and_mod_idx(vnd, i, &elem_idx, &mod_idx); BT_INFO("Decoded elem_idx:%u; mod_idx:%u", elem_idx, mod_idx); mod = bt_mesh_model_get(vnd, elem_idx, mod_idx); memcpy((u8 *)mod->groups, (u8 *)_mod_sub.groups, sizeof(mod->groups)); BT_INFO("Decoded %u subscribed group addresses for model", sizeof(mod->groups) / sizeof(mod->groups[0])); BT_INFO("Restored model subscribed, groups[0]:0x%x, groups[1]:0x%x ", _mod_sub.groups[0], _mod_sub.groups[1]); } } static void mod_set_pub(bool vnd, u8 model_count) { int len, err; struct bt_mesh_model *mod; u8_t elem_idx, mod_idx; struct __mod_pub _mod_pub; u8 load_index = vnd ? VND_MOD_PUB_INDEX : MOD_PUB_INDEX; BT_INFO("< --%s-- >", __FUNCTION__); for (u8 i = 0; i < model_count; i++) { err = node_info_load(load_index + i, &_mod_pub, sizeof(_mod_pub)); if (err) { BT_ERR("%s load not exist", vnd ? "Vendor" : "SIG"); continue; } get_elem_and_mod_idx(vnd, i, &elem_idx, &mod_idx); BT_INFO("Decoded elem_idx:%u; mod_idx:%u", elem_idx, mod_idx); mod = bt_mesh_model_get(vnd, elem_idx, mod_idx); mod->pub->addr = _mod_pub.pub.addr; mod->pub->key = _mod_pub.pub.key; mod->pub->cred = _mod_pub.pub.cred; mod->pub->ttl = _mod_pub.pub.ttl; mod->pub->period = _mod_pub.pub.period; mod->pub->retransmit = _mod_pub.pub.retransmit; mod->pub->count = 0; BT_INFO("Restored model publication, dst 0x%04x app_idx 0x%03x", _mod_pub.pub.addr, _mod_pub.pub.key); } } static void mod_set(bool vnd, u8 model_count) { mod_set_bind(vnd, model_count); mod_set_sub(vnd, model_count); mod_set_pub(vnd, model_count); } static void sig_mod_set(void) { BT_INFO("\n < --%s-- >", __FUNCTION__); u8 model_count = bt_mesh_model_numbers_get(false); if (model_count) { mod_set(false, model_count); } else { BT_INFO("no sig model exist"); } } static void vnd_mod_set(void) { BT_INFO("\n < --%s-- >", __FUNCTION__); u8 model_count = bt_mesh_model_numbers_get(true); if (model_count) { mod_set(true, model_count); } else { BT_INFO("no vendor model exist"); } } const struct mesh_setting { void (*func)(void); } settings[] = { net_set, iv_set, seq_set, rpl_set, net_key_set, app_key_set, hb_pub_set, cfg_set, sig_mod_set, vnd_mod_set, #if defined(CONFIG_BT_MESH_CDB) cdb_set, #endif }; static void mesh_set(void) { BT_INFO("--func=%s", __FUNCTION__); for (int i = 0; i < ARRAY_SIZE(settings); i++) { settings[i].func(); } } static int subnet_init(struct bt_mesh_subnet *sub) { int err; err = bt_mesh_net_keys_create(&sub->keys[0], sub->keys[0].net); if (err) { BT_ERR("Unable to generate keys for subnet"); return -EIO; } if (sub->kr_phase != BT_MESH_KR_NORMAL) { err = bt_mesh_net_keys_create(&sub->keys[1], sub->keys[1].net); if (err) { BT_ERR("Unable to generate keys for subnet"); (void)memset(&sub->keys[0], 0, sizeof(sub->keys[0])); return -EIO; } } if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && BT_MESH_FEATURES_IS_SUPPORT(BT_MESH_FEAT_PROXY)) { sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED; } else { sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED; } /* Make sure we have valid beacon data to be sent */ bt_mesh_net_beacon_update(sub); return 0; } 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) { s32_t ms = bt_mesh_model_pub_period_get(mod); if (ms) { BT_DBG("Starting publish timer (period %u ms)", ms); } } } static int mesh_commit(void) { struct bt_mesh_hb_pub *hb_pub; struct bt_mesh_cfg_srv *cfg; int i; BT_INFO("--func=%s", __FUNCTION__); BT_DBG("sub[0].net_idx=0x%x", bt_mesh.sub[0].net_idx); if (bt_mesh.sub[0].net_idx == BT_MESH_KEY_UNUSED) { /* Nothing to do since we're not yet provisioned */ return 0; } if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { bt_mesh_proxy_prov_disable(true); } for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) { struct bt_mesh_subnet *sub = &bt_mesh.sub[i]; int err; if (sub->net_idx == BT_MESH_KEY_UNUSED) { continue; } err = subnet_init(sub); if (err) { BT_ERR("Failed to init subnet 0x%03x", sub->net_idx); } } if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { // ....to do } bt_mesh_model_foreach(commit_mod, NULL); hb_pub = bt_mesh_hb_pub_get(); if (hb_pub && hb_pub->dst != BT_MESH_ADDR_UNASSIGNED && hb_pub->count && hb_pub->period) { BT_DBG("Starting heartbeat publication"); // ....to do } cfg = bt_mesh_cfg_get(); if (cfg && stored_cfg.valid) { cfg->net_transmit = stored_cfg.cfg.net_transmit; cfg->relay = stored_cfg.cfg.relay; cfg->relay_retransmit = stored_cfg.cfg.relay_retransmit; cfg->beacon = stored_cfg.cfg.beacon; cfg->gatt_proxy = stored_cfg.cfg.gatt_proxy; cfg->frnd = stored_cfg.cfg.frnd; cfg->default_ttl = stored_cfg.cfg.default_ttl; } bt_mesh.valid = 1; if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && BT_MESH_FEATURES_IS_SUPPORT(BT_MESH_FEAT_PROXY)) { bt_mesh_proxy_identity_enable(); } bt_mesh_net_start(); return 0; } static void schedule_store(int flag) { s32_t timeout; atomic_set_bit(bt_mesh.flags, flag); #if 0 if (atomic_test_bit(bt_mesh.flags, BT_MESH_NET_PENDING) || atomic_test_bit(bt_mesh.flags, BT_MESH_IV_PENDING) || atomic_test_bit(bt_mesh.flags, BT_MESH_SEQ_PENDING)) { timeout = K_NO_WAIT; } else if (atomic_test_bit(bt_mesh.flags, BT_MESH_RPL_PENDING) && (CONFIG_BT_MESH_RPL_STORE_TIMEOUT < CONFIG_BT_MESH_STORE_TIMEOUT)) { timeout = K_SECONDS(CONFIG_BT_MESH_RPL_STORE_TIMEOUT); } else { timeout = K_SECONDS(CONFIG_BT_MESH_STORE_TIMEOUT); } BT_DBG("Waiting %d seconds", timeout / MSEC_PER_SEC); #endif /* OS_ENTER_CRITICAL(); */ store_pending(); /* OS_EXIT_CRITICAL(); */ } static void clear_iv(void) { BT_INFO("--func=%s", __FUNCTION__); node_info_clear(IV_INDEX, sizeof(struct iv_val)); } static void clear_net(void) { BT_INFO("--func=%s", __FUNCTION__); node_info_clear(NET_INDEX, sizeof(struct net_val)); } static void store_pending_net(void) { struct net_val net; BT_INFO("--func=%s", __FUNCTION__); 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); node_info_store(NET_INDEX, &net, sizeof(net)); } void bt_mesh_store_net(void) { schedule_store(BT_MESH_NET_PENDING); } static void store_pending_iv(void) { BT_INFO("--func=%s", __FUNCTION__); struct iv_val iv; iv.iv_index = bt_mesh.iv_index; iv.iv_update = bt_mesh.iv_update; iv.iv_duration = bt_mesh.ivu_duration; node_info_store(IV_INDEX, &iv, sizeof(iv)); } 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) { BT_INFO("--func=%s", __FUNCTION__); struct seq_val seq; seq.val[0] = bt_mesh.seq; seq.val[1] = bt_mesh.seq >> 8; seq.val[2] = bt_mesh.seq >> 16; node_info_store(SEQ_INDEX, &seq, sizeof(seq)); } 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, u8 index) { struct __rpl_val __rpl; BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, entry->seq, entry->old_iv); __rpl.rpl.seq = entry->seq; __rpl.rpl.old_iv = entry->old_iv; __rpl.src = entry->src; node_info_store(RPL_INDEX + index, &__rpl, sizeof(__rpl)); } void clear_rpl(void) { int i; BT_INFO("--func=%s", __FUNCTION__); for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; if (!rpl->src) { continue; } node_info_clear(RPL_INDEX + i, sizeof(struct __rpl_val)); (void)memset(rpl, 0, sizeof(*rpl)); } } static void store_pending_rpl(void) { int i; BT_INFO("--func=%s", __FUNCTION__); for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) { struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i]; if (rpl->store) { rpl->store = false; store_rpl(rpl, i); } } } static void store_pending_hb_pub(void) { BT_INFO("--func=%s", __FUNCTION__); struct bt_mesh_hb_pub *pub = bt_mesh_hb_pub_get(); struct hb_pub_val val; if (!pub) { return; } if (pub->dst == BT_MESH_ADDR_UNASSIGNED) { node_info_clear(HB_PUB_INDEX, sizeof(struct hb_pub_val)); } else { val.indefinite = (pub->count = 0xffff); val.dst = pub->dst; val.period = pub->period; val.ttl = pub->ttl; val.feat = pub->feat; val.net_idx = pub->net_idx; node_info_store(HB_PUB_INDEX, &val, sizeof(val)); } } static void store_pending_cfg(void) { BT_INFO("--func=%s", __FUNCTION__); struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get(); struct cfg_val val; if (!cfg) { return; } val.net_transmit = cfg->net_transmit; val.relay = cfg->relay; val.relay_retransmit = cfg->relay_retransmit; val.beacon = cfg->beacon; val.gatt_proxy = cfg->gatt_proxy; val.frnd = cfg->frnd; val.default_ttl = cfg->default_ttl; node_info_store(CFG_INDEX, &val, sizeof(val)); } static void clear_cfg(void) { BT_INFO("--func=%s", __FUNCTION__); node_info_clear(CFG_INDEX, sizeof(struct cfg_val)); } static void clear_app_key(u16_t app_idx) { BT_INFO("--func=%s", __FUNCTION__); BT_DBG("AppKeyIndex 0x%03x", app_idx); for (int i = 0; i < CONFIG_BT_MESH_SUBNET_COUNT; i++) { if (mesh_app_key_store_info[i].app_idx != app_idx) { continue; } if (i == CONFIG_BT_MESH_SUBNET_COUNT) { BT_ERR("clear app_key no found!!!"); return; } mesh_app_key_store_info[i].use_flag = 0; node_info_clear(APP_KEY_INDEX + i, sizeof(struct app_key_val)); } } static void clear_net_key(u16_t net_idx) { BT_INFO("--func=%s", __FUNCTION__); BT_DBG("NetKeyIndex 0x%03x", net_idx); node_info_clear(NET_KEY_INDEX + net_idx, sizeof(struct net_key_val)); } static void store_net_key(struct bt_mesh_subnet *sub) { struct net_key_val key; BT_INFO("--func=%s", __FUNCTION__); BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, bt_hex(sub->keys[0].net, 16)); memcpy(&key.val[0], sub->keys[0].net, 16); memcpy(&key.val[1], sub->keys[1].net, 16); key.kr_flag = sub->kr_flag; key.kr_phase = sub->kr_phase; BT_INFO("sub->net_idx=0x%x", sub->net_idx); node_info_store(NET_KEY_INDEX + sub->net_idx, &key, sizeof(key)); } static void store_app_key(struct bt_mesh_app_key *app) { struct app_key_val key; BT_INFO("--func=%s", __FUNCTION__); key.net_idx = app->net_idx; key.updated = app->updated; key.app_idx = app->app_idx; memcpy(key.val[0], app->keys[0].val, 16); memcpy(key.val[1], app->keys[1].val, 16); BT_INFO("app->net_idx=0x%x", app->net_idx); BT_INFO("app->app_idx=0x%x", app->app_idx); for (int i = 0; i < CONFIG_BT_MESH_SUBNET_COUNT; i++) { if (mesh_app_key_store_info[i].use_flag) { continue; } if (i == CONFIG_BT_MESH_SUBNET_COUNT) { BT_ERR("app_key_store_full!!!"); return; } mesh_app_key_store_info[i].use_flag = 1; mesh_app_key_store_info[i].app_idx = key.app_idx; BT_INFO("app_key store i:%d, id:%d", i, APP_KEY_INDEX + i); node_info_store(APP_KEY_INDEX + i, &key, sizeof(key)); break; } } static void store_pending_keys(void) { int i; BT_INFO("--func=%s", __FUNCTION__); 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) { struct bt_mesh_app_key *key; key = bt_mesh_app_key_find(update->key_idx); if (key) { store_app_key(key); } else { BT_WARN("AppKeyIndex 0x%03x not found", update->key_idx); } } else { struct bt_mesh_subnet *sub; sub = bt_mesh_subnet_get(update->key_idx); if (sub) { store_net_key(sub); } else { BT_WARN("NetKeyIndex 0x%03x not found", update->key_idx); } } } update->valid = 0; } } static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd) { int i, count; struct __mod_bind _mod_bind; u8 store_index; BT_INFO("--func=%s", __FUNCTION__); for (i = 0, count = 0; i < ARRAY_SIZE(mod->keys); i++) { _mod_bind.keys[i] = BT_MESH_KEY_UNUSED; if (mod->keys[i] != BT_MESH_KEY_UNUSED) { _mod_bind.keys[count++] = mod->keys[i]; } } store_index = get_model_store_index(vnd, mod->elem_idx, mod->mod_idx); store_index += vnd ? VND_MOD_BIND_INDEX : MOD_BIND_INDEX; if (count) { node_info_store(store_index, &_mod_bind, sizeof(_mod_bind)); } else { node_info_clear(store_index, sizeof(struct __mod_bind)); } } static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) { int i, count; struct __mod_sub _mod_sub; u8 store_index; BT_INFO("--func=%s", __FUNCTION__); for (i = 0, count = 0; i < ARRAY_SIZE(mod->groups); i++) { _mod_sub.groups[i] = BT_MESH_ADDR_UNASSIGNED; if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { _mod_sub.groups[count++] = mod->groups[i]; } } store_index = get_model_store_index(vnd, mod->elem_idx, mod->mod_idx); store_index += vnd ? VND_MOD_SUB_INDEX : MOD_SUB_INDEX; if (count) { node_info_store(store_index, &_mod_sub, sizeof(_mod_sub)); } else { node_info_clear(store_index, sizeof(struct __mod_sub)); } } static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) { struct __mod_pub _mod_pub; u8 store_index; BT_INFO("--func=%s", __FUNCTION__); store_index = get_model_store_index(vnd, mod->elem_idx, mod->mod_idx); store_index += vnd ? VND_MOD_PUB_INDEX : MOD_PUB_INDEX; if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) { node_info_clear(store_index, sizeof(struct __mod_pub)); } else { _mod_pub.pub.addr = mod->pub->addr; _mod_pub.pub.key = mod->pub->key; _mod_pub.pub.ttl = mod->pub->ttl; _mod_pub.pub.retransmit = mod->pub->retransmit; _mod_pub.pub.period = mod->pub->period; _mod_pub.pub.period_div = mod->pub->period_div; _mod_pub.pub.cred = mod->pub->cred; node_info_store(store_index, &_mod_pub, sizeof(_mod_pub)); } } 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); } } static void store_pending(void) { BT_INFO("--func=%s", __FUNCTION__); if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_RPL_PENDING)) { if (bt_mesh.valid) { store_pending_rpl(); } else { clear_rpl(); } } if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_KEYS_PENDING)) { store_pending_keys(); } if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_NET_PENDING)) { if (bt_mesh.valid) { store_pending_net(); } else { clear_net(); } } if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_IV_PENDING)) { if (bt_mesh.valid) { store_pending_iv(); } else { clear_iv(); } } if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_SEQ_PENDING)) { store_pending_seq(); } if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_HB_PUB_PENDING)) { store_pending_hb_pub(); } if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_CFG_PENDING)) { if (bt_mesh.valid) { store_pending_cfg(); } else { clear_cfg(); } } if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_MOD_PENDING)) { bt_mesh_model_foreach(store_pending_mod, NULL); } #if CONFIG_BT_MESH_PROVISIONER 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(); } } #endif /* CONFIG_BT_MESH_PROVISIONER */ } 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, u16_t key_idx, struct key_update **free_slot) { struct key_update *match; int i; match = NULL; *free_slot = NULL; for (i = 0; i < ARRAY_SIZE(key_updates); i++) { struct key_update *update = &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_subnet(struct bt_mesh_subnet *sub) { struct key_update *update, *free_slot; BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); update = key_update_find(false, sub->net_idx, &free_slot); if (update) { update->clear = 0; schedule_store(BT_MESH_KEYS_PENDING); return; } if (!free_slot) { store_net_key(sub); return; } free_slot->valid = 1; free_slot->key_idx = sub->net_idx; free_slot->app_key = 0; free_slot->clear = 0; schedule_store(BT_MESH_KEYS_PENDING); } void bt_mesh_store_app_key(struct bt_mesh_app_key *key) { struct key_update *update, *free_slot; BT_DBG("AppKeyIndex 0x%03x", key->app_idx); update = key_update_find(true, key->app_idx, &free_slot); if (update) { update->clear = 0; schedule_store(BT_MESH_KEYS_PENDING); return; } if (!free_slot) { store_app_key(key); return; } free_slot->valid = 1; free_slot->key_idx = key->app_idx; free_slot->app_key = 1; free_slot->clear = 0; 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(struct bt_mesh_subnet *sub) { struct key_update *update, *free_slot; BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); update = key_update_find(false, sub->net_idx, &free_slot); if (update) { update->clear = 1; schedule_store(BT_MESH_KEYS_PENDING); return; } if (!free_slot) { clear_net_key(sub->net_idx); return; } free_slot->valid = 1; free_slot->key_idx = sub->net_idx; free_slot->app_key = 0; free_slot->clear = 1; schedule_store(BT_MESH_KEYS_PENDING); } void bt_mesh_clear_app_key(struct bt_mesh_app_key *key) { struct key_update *update, *free_slot; BT_DBG("AppKeyIndex 0x%03x", key->app_idx); update = key_update_find(true, key->app_idx, &free_slot); if (update) { update->clear = 1; schedule_store(BT_MESH_KEYS_PENDING); return; } if (!free_slot) { clear_app_key(key->app_idx); return; } free_slot->valid = 1; free_slot->key_idx = key->app_idx; free_slot->app_key = 1; free_slot->clear = 1; 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_settings_init(void) { } void settings_load(void) { mesh_set(); mesh_commit(); } #if CONFIG_BT_MESH_PROVISIONER static void cdb_net_set(void) { BT_INFO("\n < --%s-- >", __FUNCTION__); struct cdb_net_val net; int err; err = node_info_load(CDB_INDEX, &net, sizeof(net)); if (err) { BT_ERR(" load fail, index:0x%x", index); return; } 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); } static void cdb_node_set(void) { BT_INFO("\n < --%s-- >", __FUNCTION__); struct bt_mesh_cdb_node *node; struct node_val val; u16_t addr; int err; for (u8 index = 0; index < CONFIG_BT_MESH_CDB_NODE_COUNT; index++) { err = node_info_load(CDB_NODE_INDEX + index, &val, sizeof(val)); addr = val.addr; if (err) { /* BT_ERR("Failed to set \'node\'"); */ /* BT_DBG("Deleting node 0x%04x", addr); */ /* node = bt_mesh_cdb_node_get(addr); */ /* if (node) { */ /* bt_mesh_cdb_node_del(node, false); */ /* } */ BT_ERR(" load fail, index:0x%x", index); continue; } 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; } 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); } } static void cdb_subnet_set(void) { struct bt_mesh_cdb_subnet *sub; struct net_key_val key; u16_t net_idx; int err; for (u8 index = 0; index < (CONFIG_BT_MESH_CDB_SUBNET_COUNT + CONFIG_BT_MESH_CDB_APP_KEY_COUNT); index++) { err = node_info_load(CDB_SUBNET_INDEX + index, &key, sizeof(key)); if (err) { /* BT_ERR("Failed to set \'net-key\'"); */ /* BT_DBG("Deleting NetKeyIndex 0x%03x", net_idx); */ /* bt_mesh_cdb_subnet_del(sub, false); */ BT_ERR(" load fail, index:0x%x", index); continue; } net_idx = key.net_idx; sub = bt_mesh_cdb_subnet_get(net_idx); 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); continue; } sub = bt_mesh_cdb_subnet_alloc(net_idx); if (!sub) { BT_ERR("No space to allocate a new subnet"); return; } 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); } } static void cdb_app_key_set(void) { struct bt_mesh_cdb_app_key *app; struct app_key_val key; u16_t app_idx; int err; for (u8 index = 0; index < (CONFIG_BT_MESH_CDB_SUBNET_COUNT + CONFIG_BT_MESH_CDB_APP_KEY_COUNT); index++) { err = node_info_load(CDB_APP_KEY_INDEX + index, &key, sizeof(key)); if (err) { /* BT_ERR("Failed to set \'app-key\'"); */ /* 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); */ /* } */ BT_ERR(" load fail, index:0x%x", index); continue; } app_idx = key.app_idx; 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; } 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); } } static void cdb_set(void) { cdb_net_set(); cdb_node_set(); cdb_subnet_set(); cdb_app_key_set(); } static void clear_cdb(void) { BT_INFO("--func=%s", __FUNCTION__); node_info_clear(CDB_INDEX, sizeof(struct cdb_net_val)); } static void store_pending_cdb(void) { struct cdb_net_val net; BT_INFO("--func=%s", __FUNCTION__); net.iv_index = bt_mesh_cdb.iv_index; net.iv_update = atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS); node_info_store(CDB_INDEX, &net, sizeof(net)); BT_DBG("Stored Network value"); } static void clear_cdb_node(u16_t addr) { BT_INFO("--func=%s", __FUNCTION__); u8 index = bt_mesh_cdb_node_get(addr) - bt_mesh_cdb.nodes; BT_DBG("clear index 0x%x", index); node_info_clear(CDB_NODE_INDEX + index, sizeof(struct node_val)); BT_DBG("Cleared Node 0x%04x", addr); } static void store_cdb_node(const struct bt_mesh_cdb_node *node) { BT_INFO("--func=%s", __FUNCTION__); struct node_val val; u8 index = node - bt_mesh_cdb.nodes; BT_DBG("store index 0x%x", index); val.net_idx = node->net_idx; val.num_elem = node->num_elem; val.flags = 0; val.addr = node->addr; 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); node_info_store(CDB_NODE_INDEX + index, &val, sizeof(val)); BT_DBG("Store Node 0x%04x", val.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 clear_cdb_app_key(u16_t app_idx) { BT_INFO("--func=%s", __FUNCTION__); node_info_clear(CDB_APP_KEY_INDEX + app_idx, sizeof(struct app_key_val)); BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); } static void store_cdb_app_key(const struct bt_mesh_cdb_app_key *app) { BT_INFO("--func=%s", __FUNCTION__); struct app_key_val key; key.net_idx = app->net_idx; key.updated = false; key.app_idx = app->app_idx; memcpy(key.val[0], app->keys[0].app_key, 16); memcpy(key.val[1], app->keys[1].app_key, 16); node_info_store(CDB_APP_KEY_INDEX + app->app_idx, &key, sizeof(key)); } static void clear_cdb_subnet(u16_t net_idx) { BT_INFO("--func=%s", __FUNCTION__); node_info_clear(CDB_SUBNET_INDEX + net_idx, sizeof(struct net_key_val)); BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); } static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) { BT_INFO("--func=%s", __FUNCTION__); struct net_key_val key; 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; key.net_idx = sub->net_idx; node_info_store(CDB_SUBNET_INDEX + sub->net_idx, &key, sizeof(key)); } 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 void schedule_cdb_store(int flag) { atomic_set_bit(bt_mesh_cdb.flags, flag); store_pending(); } void bt_mesh_store_cdb(void) { schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING); } /* TODO: Could be shared with key_update_find? */ static struct key_update *cdb_key_update_find(bool app_key, u16_t key_idx, struct key_update **free_slot) { struct key_update *match; int i; match = NULL; *free_slot = NULL; for (i = 0; i < ARRAY_SIZE(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); } static struct node_update *cdb_node_update_find(u16_t addr, struct node_update **free_slot) { struct node_update *match; int i; match = NULL; *free_slot = NULL; for (i = 0; i < ARRAY_SIZE(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; } 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); } 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_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); } 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); } #endif /* CONFIG_BT_MESH_PROVISIONER */