zephyr/subsys/net/lib/openthread/platform/settings.c
Flavio Ceolin c4f7faea10 random: Include header where it is used
Unit tests were failing to build because random header was included by
kernel_includes.h. The problem is that rand32.h includes a generated
file that is either not generated or not included when building unit
tests. Also, it is better to limit the scope of this file to where it is
used.

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
2020-07-08 21:05:36 -04:00

313 lines
6.6 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)
{
ARG_UNUSED(aInstance);
(void)ot_setting_delete_subtree(-1, -1);
}