host/mesh: Add API to manually store pending RPL entries

The current approach with storing RPL by timeout doesn't solve all
issues as the node may loss power before the timer is fired.
In addition to that this may wear out flash quickly if short timeout is
used.

This change adds an API to store the pending RPL entry upon user
request. Additional Kconfig option allows to completely disable timer
so that the whole storing relies on the user.

The mesh stack still stays responsible for outdating RPL entries in case
of IV Index update as this happens implicitly for the user.

This is port of 65f798a00abb6bbb7c51091e754b926d15405d14
This commit is contained in:
Krzysztof Kopyściński
2021-11-10 06:24:00 +01:00
committed by Krzysztof Kopyściński
parent d9413d20fb
commit 23217d8622
6 changed files with 70 additions and 21 deletions
+13
View File
@@ -565,6 +565,19 @@ void bt_mesh_lpn_set_cb(void (*cb)(uint16_t friend_addr, bool established));
*/
int bt_mesh_friend_terminate(uint16_t lpn_addr);
/** @brief Store pending RPL entry(ies) in the persistent storage.
*
* This API allows the user to store pending RPL entry(ies) in the persistent
* storage without waiting for the timeout.
*
* @note When flash is used as the persistent storage, calling this API too
* frequently may wear it out.
*
* @param addr Address of the node which RPL entry needs to be stored or
* @ref BT_MESH_ADDR_ALL_NODES to store all pending RPL entries.
*/
void bt_mesh_rpl_pending_store(uint16_t addr);
#ifdef __cplusplus
}
#endif
+30 -4
View File
@@ -53,10 +53,17 @@ static void clear_rpl(struct bt_mesh_rpl *rpl)
atomic_clear_bit(store, rpl_idx(rpl));
}
static void schedule_rpl_store(struct bt_mesh_rpl *entry)
static void schedule_rpl_store(struct bt_mesh_rpl *entry, bool force)
{
atomic_set_bit(store, rpl_idx(entry));
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING);
if (force
#ifdef CONFIG_BT_MESH_RPL_STORE_TIMEOUT
|| CONFIG_BT_MESH_RPL_STORE_TIMEOUT >= 0
#endif
) {
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING);
}
}
static void schedule_rpl_clear(void)
@@ -79,7 +86,7 @@ void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl,
rpl->old_iv = rx->old_iv;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
schedule_rpl_store(rpl);
schedule_rpl_store(rpl, false);
}
}
@@ -200,7 +207,7 @@ void bt_mesh_rpl_reset(void)
} else {
rpl->old_iv = true;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
schedule_rpl_store(rpl);
schedule_rpl_store(rpl, true);
}
}
}
@@ -306,16 +313,35 @@ static void store_pending_rpl(struct bt_mesh_rpl *rpl)
}
}
void bt_mesh_rpl_pending_store(void)
void bt_mesh_rpl_pending_store(uint16_t addr)
{
int i;
if (!IS_ENABLED(CONFIG_BT_SETTINGS) ||
(!BT_MESH_ADDR_IS_UNICAST(addr) &&
addr != BT_MESH_ADDR_ALL_NODES)) {
return;
}
if (addr == BT_MESH_ADDR_ALL_NODES) {
bt_mesh_settings_store_cancel(BT_MESH_SETTINGS_RPL_PENDING);
}
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
if (addr != BT_MESH_ADDR_ALL_NODES &&
addr != replay_list[i].src) {
continue;
}
if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
store_pending_rpl(&replay_list[i]);
} else {
clear_rpl(&replay_list[i]);
}
if (addr != BT_MESH_ADDR_ALL_NODES) {
break;
}
}
}
-1
View File
@@ -29,5 +29,4 @@ bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx,
void bt_mesh_rpl_clear(void);
void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl,
struct bt_mesh_net_rx *rx);
void bt_mesh_rpl_pending_store(void);
void bt_mesh_rpl_init(void);
+10 -6
View File
@@ -104,11 +104,9 @@ void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)
if (atomic_get(pending_flags) & NO_WAIT_PENDING_BITS) {
timeout_ms = 0;
} else if (atomic_test_bit(pending_flags,
BT_MESH_SETTINGS_RPL_PENDING) &&
(!(atomic_get(pending_flags) & GENERIC_PENDING_BITS) ||
(CONFIG_BT_MESH_RPL_STORE_TIMEOUT <
CONFIG_BT_MESH_STORE_TIMEOUT))) {
} else if (CONFIG_BT_MESH_RPL_STORE_TIMEOUT >= 0 &&
atomic_test_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING) &&
!(atomic_get(pending_flags) & GENERIC_PENDING_BITS)) {
timeout_ms = CONFIG_BT_MESH_RPL_STORE_TIMEOUT * MSEC_PER_SEC;
} else {
timeout_ms = CONFIG_BT_MESH_STORE_TIMEOUT * MSEC_PER_SEC;
@@ -127,12 +125,18 @@ void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)
k_work_schedule(&pending_store, K_MSEC(timeout_ms));
}
}
void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag)
{
atomic_clear_bit(pending_flags, flag);
}
static void store_pending(struct ble_npl_event *work)
{
BT_DBG("");
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_RPL_PENDING)) {
bt_mesh_rpl_pending_store();
bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
}
if (atomic_test_and_clear_bit(pending_flags,
+1
View File
@@ -23,3 +23,4 @@ enum bt_mesh_settings_flag {
void bt_mesh_settings_init(void);
int settings_name_next(char *name, char **next);
void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag);
void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag);
+16 -10
View File
@@ -619,16 +619,22 @@ syscfg.defs:
BLE_MESH_RPL_STORE_TIMEOUT:
description: >
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).
Minimum interval after which unsaved RPL entries are updated in storage
This value defines in seconds how soon unsaved RPL entries
gets written to the persistent storage. Setting this value
to a large number may lead to security vulnerabilities if a node
gets powered off before the timer is fired. When flash is used
as the persistent storage setting this value to a low number
may wear out flash sooner or later. However, if the RPL gets
updated infrequently a value as low as 0 (write immediately)
may make sense. Setting this value to -1 will disable this timer.
In this case, a user is responsible to store pending RPL entries
using @ref bt_mesh_rpl_pending_store. In the mean time, when
IV Index is updated, the outdated RPL entries will still be
stored by @ref BT_MESH_STORE_TIMEOUT. Finding the right balance
between this timeout and calling @ref bt_mesh_rpl_pending_store
may reduce a risk of security vulnerability and flash wear out.
value: 5
BLE_MESH_DEVICE_NAME: