zephyr/modules/openthread/platform/settings.c
Robert Lubos 815ebc316e net: openthread: Move glue code into module directory
Move OpenThread's glue code along with the Kconfig files that configure
OpenThread stack itself into module directory.

Update the maintainers file to reflect this change.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
2022-07-11 11:00:12 +02:00

330 lines
7.1 KiB
C

/*
* Copyright (c) 2019 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h>
#include <zephyr/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;
/* Indicates if delete subtree root. */
bool delete_subtree_root;
};
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;
}
if (key == NULL && ctx->delete_subtree_root == false) {
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", path);
ret = settings_delete(path);
if (ret != 0) {
LOG_ERR("Failed to remove setting %s, ret %d", path,
ret);
__ASSERT_NO_MSG(false);
}
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, bool delete_subtree_root)
{
int ret;
char subtree[OT_SETTINGS_MAX_PATH_LEN];
struct ot_setting_delete_ctx delete_ctx = {
.subtree = subtree,
.status = -ENOENT,
.target_index = index,
.delete_subtree_root = delete_subtree_root,
};
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);
__ASSERT_NO_MSG(false);
}
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 instance 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, const uint16_t *aSensitiveKeys,
uint16_t aSensitiveKeysLength)
{
int ret;
ARG_UNUSED(aInstance);
ARG_UNUSED(aSensitiveKeys);
ARG_UNUSED(aSensitiveKeysLength);
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, false);
ret = snprintk(path, sizeof(path), "%s/%x", OT_SETTINGS_ROOT_KEY, aKey);
__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, true);
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, true);
}
void otPlatSettingsDeinit(otInstance *aInstance)
{
ARG_UNUSED(aInstance);
}