zephyr/subsys/net/lib/openthread/platform/settings.c
Lukasz Maciejonczyk c5afc2e1f2 net: openthread: add assert which checks settings wipe failure
If settings wipe fails we are not informed about this what can lead to
bugs which are hard to investigate.
This commit adds log and/or assert which is triggered by this failure.

Signed-off-by: Lukasz Maciejonczyk <lukasz.maciejonczyk@nordicsemi.no>
2022-02-24 08:33:30 -06:00

324 lines
6.8 KiB
C

/*
* Copyright (c) 2019 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <logging/log.h>
#include <settings/settings.h>
#include <random/rand32.h>
#include <openthread/platform/settings.h>
LOG_MODULE_REGISTER(net_otPlat_settings, CONFIG_OPENTHREAD_L2_LOG_LEVEL);
#define OT_SETTINGS_ROOT_KEY "ot"
#define OT_SETTINGS_MAX_PATH_LEN 32
struct ot_setting_delete_ctx {
/* Setting subtree to delete. */
const char *subtree;
/* Current entry index, used to iterate over multiple setting
* instances.
*/
int index;
/* Target index to delete. -1 to delete entire subtree. */
int target_index;
/* Operation result. */
int status;
};
static int ot_setting_delete_cb(const char *key, size_t len,
settings_read_cb read_cb, void *cb_arg,
void *param)
{
int ret;
char path[OT_SETTINGS_MAX_PATH_LEN];
struct ot_setting_delete_ctx *ctx =
(struct ot_setting_delete_ctx *)param;
ARG_UNUSED(len);
ARG_UNUSED(read_cb);
ARG_UNUSED(cb_arg);
if ((ctx->target_index != -1) && (ctx->target_index != ctx->index)) {
ctx->index++;
return 0;
}
ret = snprintk(path, sizeof(path), "%s%s%s", ctx->subtree,
key ? "/" : "", key ? key : "");
__ASSERT(ret < sizeof(path), "Setting path buffer too small.");
LOG_DBG("Removing: %s", log_strdup(path));
ret = settings_delete(path);
if (ret != 0) {
LOG_ERR("Failed to remove setting %s, ret %d", log_strdup(path),
ret);
}
ctx->status = 0;
if (ctx->target_index == ctx->index) {
/* Break the loop on index match, otherwise it was -1
* (delete all).
*/
return 1;
}
return 0;
}
static int ot_setting_delete_subtree(int key, int index)
{
int ret;
char subtree[OT_SETTINGS_MAX_PATH_LEN];
struct ot_setting_delete_ctx delete_ctx = {
.subtree = subtree,
.status = -ENOENT,
.target_index = index
};
if (key == -1) {
ret = snprintk(subtree, sizeof(subtree), "%s",
OT_SETTINGS_ROOT_KEY);
} else {
ret = snprintk(subtree, sizeof(subtree), "%s/%x",
OT_SETTINGS_ROOT_KEY, key);
}
__ASSERT(ret < sizeof(subtree), "Setting path buffer too small.");
ret = settings_load_subtree_direct(subtree, ot_setting_delete_cb,
&delete_ctx);
if (ret != 0) {
LOG_ERR("Failed to delete OT subtree %s, index %d, ret %d",
subtree, index, ret);
}
return delete_ctx.status;
}
static int ot_setting_exists_cb(const char *key, size_t len,
settings_read_cb read_cb, void *cb_arg,
void *param)
{
bool *exists = (bool *)param;
ARG_UNUSED(len);
ARG_UNUSED(read_cb);
ARG_UNUSED(cb_arg);
ARG_UNUSED(key);
*exists = true;
return 1;
}
static bool ot_setting_exists(const char *path)
{
bool exists = false;
(void)settings_load_subtree_direct(path, ot_setting_exists_cb, &exists);
return exists;
}
struct ot_setting_read_ctx {
/* Buffer for the setting. */
uint8_t *value;
/* Buffer length on input, setting length read on output. */
uint16_t *length;
/* Current entry index, used to iterate over multiple setting
* instances.
*/
int index;
/* Target instnace to read. */
int target_index;
/* Operation result. */
int status;
};
static int ot_setting_read_cb(const char *key, size_t len,
settings_read_cb read_cb, void *cb_arg,
void *param)
{
int ret;
struct ot_setting_read_ctx *ctx = (struct ot_setting_read_ctx *)param;
ARG_UNUSED(len);
ARG_UNUSED(read_cb);
ARG_UNUSED(cb_arg);
if (ctx->target_index != ctx->index) {
ctx->index++;
return 0;
}
/* Found setting, break the loop. */
if ((ctx->value == NULL) || (ctx->length == NULL)) {
goto out;
}
if (*(ctx->length) < len) {
len = *(ctx->length);
}
ret = read_cb(cb_arg, ctx->value, len);
if (ret <= 0) {
LOG_ERR("Failed to read the setting, ret: %d", ret);
ctx->status = -EIO;
return 1;
}
out:
if (ctx->length != NULL) {
*(ctx->length) = len;
}
ctx->status = 0;
return 1;
}
/* OpenThread APIs */
void otPlatSettingsInit(otInstance *aInstance)
{
int ret;
ARG_UNUSED(aInstance);
ret = settings_subsys_init();
if (ret != 0) {
LOG_ERR("settings_subsys_init failed (ret %d)", ret);
}
}
otError otPlatSettingsGet(otInstance *aInstance, uint16_t aKey, int aIndex,
uint8_t *aValue, uint16_t *aValueLength)
{
int ret;
char path[OT_SETTINGS_MAX_PATH_LEN];
struct ot_setting_read_ctx read_ctx = {
.value = aValue,
.length = (uint16_t *)aValueLength,
.status = -ENOENT,
.target_index = aIndex
};
ARG_UNUSED(aInstance);
LOG_DBG("%s Entry aKey %u aIndex %d", __func__, aKey, aIndex);
ret = snprintk(path, sizeof(path), "%s/%x", OT_SETTINGS_ROOT_KEY, aKey);
__ASSERT(ret < sizeof(path), "Setting path buffer too small.");
ret = settings_load_subtree_direct(path, ot_setting_read_cb, &read_ctx);
if (ret != 0) {
LOG_ERR("Failed to load OT setting aKey %d, aIndex %d, ret %d",
aKey, aIndex, ret);
}
if (read_ctx.status != 0) {
LOG_DBG("aKey %u aIndex %d not found", aKey, aIndex);
return OT_ERROR_NOT_FOUND;
}
return OT_ERROR_NONE;
}
otError otPlatSettingsSet(otInstance *aInstance, uint16_t aKey,
const uint8_t *aValue, uint16_t aValueLength)
{
int ret;
char path[OT_SETTINGS_MAX_PATH_LEN];
ARG_UNUSED(aInstance);
LOG_DBG("%s Entry aKey %u", __func__, aKey);
(void)ot_setting_delete_subtree(aKey, -1);
ret = snprintk(path, sizeof(path), "%s/%x/%08x", OT_SETTINGS_ROOT_KEY,
aKey, sys_rand32_get());
__ASSERT(ret < sizeof(path), "Setting path buffer too small.");
ret = settings_save_one(path, aValue, aValueLength);
if (ret != 0) {
LOG_ERR("Failed to store setting %d, ret %d", aKey, ret);
return OT_ERROR_NO_BUFS;
}
return OT_ERROR_NONE;
}
otError otPlatSettingsAdd(otInstance *aInstance, uint16_t aKey,
const uint8_t *aValue, uint16_t aValueLength)
{
int ret;
char path[OT_SETTINGS_MAX_PATH_LEN];
ARG_UNUSED(aInstance);
LOG_DBG("%s Entry aKey %u", __func__, aKey);
do {
ret = snprintk(path, sizeof(path), "%s/%x/%08x",
OT_SETTINGS_ROOT_KEY, aKey, sys_rand32_get());
__ASSERT(ret < sizeof(path), "Setting path buffer too small.");
} while (ot_setting_exists(path));
ret = settings_save_one(path, aValue, aValueLength);
if (ret != 0) {
LOG_ERR("Failed to store setting %d, ret %d", aKey, ret);
return OT_ERROR_NO_BUFS;
}
return OT_ERROR_NONE;
}
otError otPlatSettingsDelete(otInstance *aInstance, uint16_t aKey, int aIndex)
{
int ret;
ARG_UNUSED(aInstance);
LOG_DBG("%s Entry aKey %u aIndex %d", __func__, aKey, aIndex);
ret = ot_setting_delete_subtree(aKey, aIndex);
if (ret != 0) {
LOG_DBG("Entry not found aKey %u aIndex %d", aKey, aIndex);
return OT_ERROR_NOT_FOUND;
}
return OT_ERROR_NONE;
}
void otPlatSettingsWipe(otInstance *aInstance)
{
int ret;
ARG_UNUSED(aInstance);
ret = ot_setting_delete_subtree(-1, -1);
if (ret != 0) {
LOG_ERR("Failed to delete OT subtree");
__ASSERT_NO_MSG(false);
}
}
void otPlatSettingsDeinit(otInstance *aInstance)
{
ARG_UNUSED(aInstance);
}