Bluetooth: Mesh: Introduce measures to avoid too frequent flash writes
Both the local sequence number as well as the Replay Protection List (RPL) are states that may potentially change very often. In order not to wear out the flash with these updates it makes sense to try to avoid too frequent writes. For the local sequence number a simple solution is not to write the number on every increment. This patch introduces a new Kconfig option to define after how many increments the sequence number gets written. When the stack gets initialized it automatically adds the configured number to the last stored one, thereby guaranteeing that the node starts off with a number that's larger than the last used one. The RPL is more problematic, since in principle it needs to be updated every single time that we receive and process a message. Especially security sentitive nodes will want this stored immediately to flash. To give some use-case dependent flexibility, this patch introduces a new Kconfig option to specify a timeout after which the RPL gets written to flash. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
parent
43c7ef3959
commit
be7fe55b82
5 changed files with 98 additions and 1 deletions
|
@ -379,6 +379,42 @@ config BT_MESH_SHELL
|
|||
Activate shell module that provides Bluetooth Mesh commands to
|
||||
the console.
|
||||
|
||||
if BT_SETTINGS
|
||||
|
||||
config BT_MESH_SEQ_STORE_RATE
|
||||
int "How often the sequence number gets updated in storage"
|
||||
range 0 1000000
|
||||
default 128
|
||||
help
|
||||
This value defines how often the local sequence number gets
|
||||
updated in persistent storage (i.e. flash). E.g. a value of 100
|
||||
means that the sequence number will be stored to flash on every
|
||||
100th increment. If the node sends messages very frequently a
|
||||
higher value makes more sense, whereas if the node sends
|
||||
infrequently a value as low as 0 (update storage for every
|
||||
increment) can make sense. When the stack gets initialized it
|
||||
will add this number to the last stored one, so that it starts
|
||||
off with a value that's guaranteed to be larger than the last
|
||||
one used before power off.
|
||||
|
||||
config BT_MESH_RPL_STORE_TIMEOUT
|
||||
int "Minimum frequency that the RPL gets updated in storage"
|
||||
range 0 1000000
|
||||
default 5
|
||||
help
|
||||
This value defines in seconds how soon the RPL gets written to
|
||||
persistent storage after a change occurs. If the node receives
|
||||
messages frequently it may make sense to have this set to a
|
||||
large value, whereas if the RPL gets updated infrequently a
|
||||
value as low as 0 (write immediately) may make sense. Note that
|
||||
if the node operates a security sensitive use case, and there's
|
||||
a risk of sudden power loss, it may be a security vulnerability
|
||||
to set this value to anything else than 0 (a power loss before
|
||||
writing to storage exposes the node to potential message
|
||||
replay attacks).
|
||||
|
||||
endif # BT_SETTINGS
|
||||
|
||||
config BT_MESH_DEBUG
|
||||
bool "Enable debug logs"
|
||||
depends on BT_DEBUG
|
||||
|
|
|
@ -200,5 +200,9 @@ int bt_mesh_init(const struct bt_mesh_prov *prov,
|
|||
bt_mesh_proxy_init();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
bt_mesh_settings_init();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,9 @@ struct bt_mesh_subnet {
|
|||
struct bt_mesh_rpl {
|
||||
u16_t src;
|
||||
bool old_iv;
|
||||
#if defined(CONFIG_BT_SETTINGS)
|
||||
bool store;
|
||||
#endif
|
||||
u32_t seq;
|
||||
};
|
||||
|
||||
|
|
|
@ -165,6 +165,14 @@ static int seq_set(int argc, char **argv, char *val)
|
|||
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 - 1;
|
||||
}
|
||||
|
||||
BT_DBG("Sequence Number 0x%06x", bt_mesh.seq);
|
||||
|
||||
return 0;
|
||||
|
@ -548,6 +556,11 @@ void bt_mesh_store_seq(void)
|
|||
struct seq_val seq;
|
||||
char *str;
|
||||
|
||||
if (CONFIG_BT_MESH_SEQ_STORE_RATE &&
|
||||
(bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
seq.val[0] = bt_mesh.seq;
|
||||
seq.val[1] = bt_mesh.seq >> 8;
|
||||
seq.val[2] = bt_mesh.seq >> 16;
|
||||
|
@ -562,7 +575,7 @@ void bt_mesh_store_seq(void)
|
|||
settings_save_one("bt/mesh/Seq", str);
|
||||
}
|
||||
|
||||
void bt_mesh_store_rpl(struct bt_mesh_rpl *entry)
|
||||
static void store_rpl(struct bt_mesh_rpl *entry)
|
||||
{
|
||||
char buf[BT_SETTINGS_SIZE(sizeof(struct rpl_val))];
|
||||
struct rpl_val rpl;
|
||||
|
@ -587,6 +600,38 @@ void bt_mesh_store_rpl(struct bt_mesh_rpl *entry)
|
|||
settings_save_one(path, str);
|
||||
}
|
||||
|
||||
#if CONFIG_BT_MESH_RPL_STORE_TIMEOUT > 0
|
||||
static struct k_delayed_work rpl_store;
|
||||
|
||||
static void rpl_store_timeout(struct k_work *work)
|
||||
{
|
||||
int i;
|
||||
|
||||
BT_DBG("");
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void bt_mesh_store_rpl(struct bt_mesh_rpl *entry)
|
||||
{
|
||||
#if CONFIG_BT_MESH_RPL_STORE_TIMEOUT > 0
|
||||
entry->store = true;
|
||||
k_delayed_work_submit(&rpl_store,
|
||||
K_SECONDS(CONFIG_BT_MESH_RPL_STORE_TIMEOUT));
|
||||
BT_DBG("Waiting %d seconds", CONFIG_BT_MESH_RPL_STORE_TIMEOUT);
|
||||
#else
|
||||
store_rpl(entry);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bt_mesh_store_subnet(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))];
|
||||
|
@ -637,3 +682,10 @@ void bt_mesh_store_app_key(struct bt_mesh_app_key *app)
|
|||
BT_DBG("Saving AppKey %s as value %s", path, str);
|
||||
settings_save_one(path, str);
|
||||
}
|
||||
|
||||
void bt_mesh_settings_init(void)
|
||||
{
|
||||
#if CONFIG_BT_MESH_RPL_STORE_TIMEOUT > 0
|
||||
k_delayed_work_init(&rpl_store, rpl_store_timeout);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -10,3 +10,5 @@ void bt_mesh_store_seq(void);
|
|||
void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl);
|
||||
void bt_mesh_store_subnet(struct bt_mesh_subnet *sub);
|
||||
void bt_mesh_store_app_key(struct bt_mesh_app_key *key);
|
||||
|
||||
void bt_mesh_settings_init(void);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue