/* * Copyright (c) 2019 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include 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); }