mgmt: mcumgr: Add settings management
Adds a settings management group to MCUmgr which allows for manipulation of the zephyr settings from a remote device. Includes callback hooks to secure access from an application. Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
This commit is contained in:
parent
6728af6458
commit
55527d8733
46
include/zephyr/mgmt/mcumgr/grp/settings_mgmt/settings_mgmt.h
Normal file
46
include/zephyr/mgmt/mcumgr/grp/settings_mgmt/settings_mgmt.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef H_SETTINGS_MGMT_
|
||||
#define H_SETTINGS_MGMT_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Command IDs for settings management group.
|
||||
*/
|
||||
#define SETTINGS_MGMT_ID_READ_WRITE 0
|
||||
#define SETTINGS_MGMT_ID_DELETE 1
|
||||
#define SETTINGS_MGMT_ID_COMMIT 2
|
||||
#define SETTINGS_MGMT_ID_LOAD_SAVE 3
|
||||
|
||||
/**
|
||||
* Command result codes for settings management group.
|
||||
*/
|
||||
enum settings_mgmt_ret_code_t {
|
||||
/** No error, this is implied if there is no ret value in the response. */
|
||||
SETTINGS_MGMT_ERR_OK = 0,
|
||||
|
||||
/** Unknown error occurred. */
|
||||
SETTINGS_MGMT_ERR_UNKNOWN,
|
||||
|
||||
/** The provided key name is too long to be used. */
|
||||
SETTINGS_MGMT_ERR_KEY_TOO_LONG,
|
||||
|
||||
/** The provided key name does not exist. */
|
||||
SETTINGS_MGMT_ERR_KEY_NOT_FOUND,
|
||||
|
||||
/** The provided key name does not support being read. */
|
||||
SETTINGS_MGMT_ERR_READ_NOT_SUPPORTED,
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef H_MCUMGR_SETTINGS_MGMT_CALLBACKS_
|
||||
#define H_MCUMGR_SETTINGS_MGMT_CALLBACKS_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief MCUmgr settings_mgmt callback API
|
||||
* @defgroup mcumgr_callback_api_settings_mgmt MCUmgr settings_mgmt callback API
|
||||
* @ingroup mcumgr_callback_api
|
||||
* @{
|
||||
*/
|
||||
|
||||
enum settings_mgmt_access_types {
|
||||
SETTINGS_ACCESS_READ,
|
||||
SETTINGS_ACCESS_WRITE,
|
||||
SETTINGS_ACCESS_DELETE,
|
||||
SETTINGS_ACCESS_COMMIT,
|
||||
SETTINGS_ACCESS_LOAD,
|
||||
SETTINGS_ACCESS_SAVE,
|
||||
};
|
||||
|
||||
/**
|
||||
* Structure provided in the #MGMT_EVT_OP_SETTINGS_MGMT_ACCESS notification callback: This
|
||||
* callback function is used to notify the application about a pending setting
|
||||
* read/write/delete/load/save/commit request and to authorise or deny it. Access will be allowed
|
||||
* so long as no handlers return an error, if one returns an error then access will be denied.
|
||||
*/
|
||||
struct settings_mgmt_access {
|
||||
/** Type of access */
|
||||
enum settings_mgmt_access_types access;
|
||||
|
||||
/**
|
||||
* Key name for accesses (only set for SETTINGS_ACCESS_READ, SETTINGS_ACCESS_WRITE and
|
||||
* SETTINGS_ACCESS_DELETE). Note that this can be changed by handlers to redirect settings
|
||||
* access if needed (as long as it does not exceed the maximum setting string size) if
|
||||
* CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_STACK is selected, of maximum size
|
||||
* CONFIG_MCUMGR_GRP_SETTINGS_NAME_LEN.
|
||||
*
|
||||
* Note: This string *must* be NULL terminated.
|
||||
*/
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
|
||||
/** Data provided by the user (only set for SETTINGS_ACCESS_WRITE) */
|
||||
const uint8_t *val;
|
||||
|
||||
/** Length of data provided by the user (only set for SETTINGS_ACCESS_WRITE) */
|
||||
const size_t *val_length;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
* Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
@ -23,6 +23,10 @@
|
|||
#include <zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt_callbacks.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS
|
||||
#include <zephyr/mgmt/mcumgr/grp/settings_mgmt/settings_mgmt_callbacks.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -113,6 +117,7 @@ enum mgmt_cb_groups {
|
|||
MGMT_EVT_GRP_OS,
|
||||
MGMT_EVT_GRP_IMG,
|
||||
MGMT_EVT_GRP_FS,
|
||||
MGMT_EVT_GRP_SETTINGS,
|
||||
|
||||
MGMT_EVT_GRP_USER_CUSTOM_START = MGMT_GROUP_ID_PERUSER,
|
||||
};
|
||||
|
@ -196,6 +201,17 @@ enum os_mgmt_group_events {
|
|||
MGMT_EVT_OP_OS_MGMT_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_OS),
|
||||
};
|
||||
|
||||
/**
|
||||
* MGMT event opcodes for settings management group.
|
||||
*/
|
||||
enum settings_mgmt_group_events {
|
||||
/** Callback when a setting is read/written/deleted. */
|
||||
MGMT_EVT_OP_SETTINGS_MGMT_ACCESS = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_SETTINGS, 0),
|
||||
|
||||
/** Used to enable all settings_mgmt_group events. */
|
||||
MGMT_EVT_OP_SETTINGS_MGMT_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_SETTINGS),
|
||||
};
|
||||
|
||||
/**
|
||||
* MGMT callback struct
|
||||
*/
|
||||
|
|
|
@ -23,6 +23,12 @@ extern "C" {
|
|||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Used at end of MCUmgr handlers to return an error if the message size limit was reached,
|
||||
* or OK if it was not
|
||||
*/
|
||||
#define MGMT_RETURN_CHECK(ok) ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE
|
||||
|
||||
/** Opcodes; encoded in first byte of header. */
|
||||
enum mcumgr_op_t {
|
||||
/** Read op-code */
|
||||
|
@ -52,8 +58,8 @@ enum mcumgr_group_t {
|
|||
/** Statistic management group, used for retieving statistics */
|
||||
MGMT_GROUP_ID_STAT,
|
||||
|
||||
/** System configuration group (unused) */
|
||||
MGMT_GROUP_ID_CONFIG,
|
||||
/** Settings management (config) group, used for reading/writing settings */
|
||||
MGMT_GROUP_ID_SETTINGS,
|
||||
|
||||
/** Log management group (unused) */
|
||||
MGMT_GROUP_ID_LOG,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#
|
||||
# Copyright (c) 2018-2021 mcumgr authors
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
# Copyright (c) 2022-2023 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
@ -13,3 +13,4 @@ add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_OS_CLIENT os_mgmt_client)
|
|||
add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_STAT stat_mgmt)
|
||||
add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_SHELL shell_mgmt)
|
||||
add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_ZBASIC zephyr_basic)
|
||||
add_subdirectory_ifdef(CONFIG_MCUMGR_GRP_SETTINGS settings_mgmt)
|
||||
|
|
|
@ -17,3 +17,5 @@ rsource "shell_mgmt/Kconfig"
|
|||
rsource "stat_mgmt/Kconfig"
|
||||
|
||||
rsource "zephyr_basic/Kconfig"
|
||||
|
||||
rsource "settings_mgmt/Kconfig"
|
||||
|
|
18
subsys/mgmt/mcumgr/grp/settings_mgmt/CMakeLists.txt
Normal file
18
subsys/mgmt/mcumgr/grp/settings_mgmt/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# Settings management group public API is exposed by MCUmgr API
|
||||
# interface, when settings management is enabled.
|
||||
zephyr_library(mgmt_mcumgr_grp_settings)
|
||||
zephyr_library_sources(src/settings_mgmt.c)
|
||||
|
||||
if(CONFIG_MCUMGR_GRP_SETTINGS AND NOT CONFIG_MCUMGR_GRP_SETTINGS_ACCESS_HOOK)
|
||||
message(WARNING "Note: MCUmgr settings management is enabled but settings access hooks are "
|
||||
"disabled, this is an insecure configuration and not recommended for production "
|
||||
"use, as all settings on the device can be manipulated by a remote device. See "
|
||||
"https://docs.zephyrproject.org/latest/services/device_mgmt/mcumgr_callbacks.html "
|
||||
"for details on enabling and using MCUmgr hooks.")
|
||||
endif()
|
68
subsys/mgmt/mcumgr/grp/settings_mgmt/Kconfig
Normal file
68
subsys/mgmt/mcumgr/grp/settings_mgmt/Kconfig
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Copyright Nordic Semiconductor ASA 2023. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
menuconfig MCUMGR_GRP_SETTINGS
|
||||
bool "MCUmgr handlers for settings management"
|
||||
depends on SETTINGS
|
||||
depends on SETTINGS_RUNTIME
|
||||
select MCUMGR_SMP_CBOR_MIN_DECODING_LEVEL_2
|
||||
select MCUMGR_SMP_CBOR_MIN_ENCODING_LEVEL_2 if ZCBOR_CANONICAL
|
||||
select MCUMGR_SMP_CBOR_MIN_ENCODING_LEVEL_1
|
||||
help
|
||||
Enables MCUmgr handlers for settings manipulation.
|
||||
|
||||
if MCUMGR_GRP_SETTINGS
|
||||
|
||||
choice MCUMGR_GRP_SETTINGS_BUFFER_TYPE
|
||||
prompt "Buffer type"
|
||||
default MCUMGR_GRP_SETTINGS_BUFFER_TYPE_STACK
|
||||
help
|
||||
Selects if the stack or heap will be used for variables that are
|
||||
needed when processing requests.
|
||||
|
||||
config MCUMGR_GRP_SETTINGS_BUFFER_TYPE_STACK
|
||||
bool "Stack (fixed size)"
|
||||
help
|
||||
Use a fixed size stack buffer, any user-supplied values longer than
|
||||
this will be rejected.
|
||||
|
||||
Note that stack usage for parameter storage alone will be
|
||||
MCUMGR_GRP_SETTINGS_NAME_LEN + MCUMGR_GRP_SETTINGS_VALUE_LEN,
|
||||
therefore the MCUmgr stack should be appropriately sized.
|
||||
|
||||
config MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
bool "Heap (dynamic size)"
|
||||
depends on COMMON_LIBC_MALLOC_ARENA_SIZE > 0
|
||||
help
|
||||
Use dynamic heap memory allocation through malloc, if there is
|
||||
insufficient heap memory for the allocation then the request will be
|
||||
rejected.
|
||||
|
||||
endchoice
|
||||
|
||||
config MCUMGR_GRP_SETTINGS_NAME_LEN
|
||||
int "Maximum setting name length"
|
||||
default 32
|
||||
help
|
||||
Maximum length of a key to lookup, this will be the size of the
|
||||
variable if placed on the stack or the maximum allocated size of the
|
||||
variable if placed on the heap.
|
||||
|
||||
config MCUMGR_GRP_SETTINGS_VALUE_LEN
|
||||
int "Maximum setting value length"
|
||||
default 32
|
||||
help
|
||||
Maximum length of a value to read, this will be the size of the
|
||||
variable if placed on the stack or the allocated size of the
|
||||
variable if placed on the heap (settings does not support getting
|
||||
the size of a value prior to looking it up).
|
||||
|
||||
config MCUMGR_GRP_SETTINGS_ACCESS_HOOK
|
||||
bool "Settings access hook"
|
||||
depends on MCUMGR_MGMT_NOTIFICATION_HOOKS
|
||||
help
|
||||
Allows applications to control settings management access by
|
||||
registering for a callback which is then triggered whenever a
|
||||
settings read or write attempt is made.
|
||||
|
||||
endif
|
528
subsys/mgmt/mcumgr/grp/settings_mgmt/src/settings_mgmt.c
Normal file
528
subsys/mgmt/mcumgr/grp/settings_mgmt/src/settings_mgmt.c
Normal file
|
@ -0,0 +1,528 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/settings/settings.h>
|
||||
#include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
|
||||
#include <zephyr/mgmt/mcumgr/smp/smp.h>
|
||||
#include <zephyr/mgmt/mcumgr/mgmt/handlers.h>
|
||||
#include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
|
||||
#include <zephyr/mgmt/mcumgr/grp/settings_mgmt/settings_mgmt.h>
|
||||
#include <mgmt/mcumgr/util/zcbor_bulk.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zcbor_common.h>
|
||||
#include <zcbor_decode.h>
|
||||
#include <zcbor_encode.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_MCUMGR_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(settings_mgmt);
|
||||
|
||||
/**
|
||||
* Command handler: settings read
|
||||
*/
|
||||
static int settings_mgmt_read(struct smp_streamer *ctxt)
|
||||
{
|
||||
int rc;
|
||||
zcbor_state_t *zse = ctxt->writer->zs;
|
||||
zcbor_state_t *zsd = ctxt->reader->zs;
|
||||
bool ok;
|
||||
size_t decoded;
|
||||
struct zcbor_string key = { 0 };
|
||||
uint32_t max_size = CONFIG_MCUMGR_GRP_SETTINGS_VALUE_LEN;
|
||||
bool limited_size = false;
|
||||
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
char *key_name = NULL;
|
||||
uint8_t *data = NULL;
|
||||
#else
|
||||
char key_name[CONFIG_MCUMGR_GRP_SETTINGS_NAME_LEN] = { 0 };
|
||||
uint8_t data[CONFIG_MCUMGR_GRP_SETTINGS_VALUE_LEN] = { 0 };
|
||||
#endif
|
||||
|
||||
struct zcbor_map_decode_key_val settings_read_decode[] = {
|
||||
ZCBOR_MAP_DECODE_KEY_DECODER("name", zcbor_tstr_decode, &key),
|
||||
ZCBOR_MAP_DECODE_KEY_DECODER("max_size", zcbor_uint32_decode, &max_size),
|
||||
};
|
||||
|
||||
ok = zcbor_map_decode_bulk(zsd, settings_read_decode, ARRAY_SIZE(settings_read_decode),
|
||||
&decoded) == 0;
|
||||
|
||||
if (!ok || key.len == 0) {
|
||||
return MGMT_ERR_EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the length of the user supplied key is too large for the configuration
|
||||
* to allow and return an error if so
|
||||
*/
|
||||
if (key.len >= CONFIG_MCUMGR_GRP_SETTINGS_NAME_LEN) {
|
||||
ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_SETTINGS,
|
||||
SETTINGS_MGMT_ERR_KEY_TOO_LONG);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (max_size > CONFIG_MCUMGR_GRP_SETTINGS_VALUE_LEN) {
|
||||
max_size = CONFIG_MCUMGR_GRP_SETTINGS_VALUE_LEN;
|
||||
limited_size = true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
key_name = (char *)malloc(key.len + 1);
|
||||
data = (uint8_t *)malloc(max_size);
|
||||
|
||||
if (data == NULL || key_name == NULL) {
|
||||
if (key_name != NULL) {
|
||||
free(key_name);
|
||||
}
|
||||
|
||||
return MGMT_ERR_ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(key_name, key.value, key.len);
|
||||
key_name[key.len] = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MCUMGR_GRP_SETTINGS_ACCESS_HOOK)) {
|
||||
/* Send request to application to check if access should be allowed or not */
|
||||
struct settings_mgmt_access settings_access_data = {
|
||||
.access = SETTINGS_ACCESS_READ,
|
||||
.name = key_name,
|
||||
};
|
||||
|
||||
enum mgmt_cb_return status;
|
||||
int32_t ret_rc;
|
||||
uint16_t ret_group;
|
||||
|
||||
status = mgmt_callback_notify(MGMT_EVT_OP_SETTINGS_MGMT_ACCESS,
|
||||
&settings_access_data, sizeof(settings_access_data),
|
||||
&ret_rc, &ret_group);
|
||||
|
||||
if (status != MGMT_CB_OK) {
|
||||
bool ok;
|
||||
|
||||
if (status == MGMT_CB_ERROR_RC) {
|
||||
return ret_rc;
|
||||
}
|
||||
|
||||
ok = smp_add_cmd_err(zse, ret_group, (uint16_t)ret_rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the settings key */
|
||||
rc = settings_runtime_get(key_name, data, max_size);
|
||||
|
||||
if (rc < 0) {
|
||||
if (rc == -EINVAL) {
|
||||
rc = SETTINGS_MGMT_ERR_KEY_NOT_FOUND;
|
||||
} else if (rc == -ENOTSUP) {
|
||||
rc = SETTINGS_MGMT_ERR_READ_NOT_SUPPORTED;
|
||||
} else {
|
||||
rc = SETTINGS_MGMT_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_SETTINGS, (uint16_t)rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ok = zcbor_tstr_put_lit(zse, "val") &&
|
||||
zcbor_bstr_encode_ptr(zse, data, rc);
|
||||
|
||||
if (ok && limited_size) {
|
||||
ok = zcbor_tstr_put_lit(zse, "max_size") &&
|
||||
zcbor_uint32_put(zse, CONFIG_MCUMGR_GRP_SETTINGS_VALUE_LEN);
|
||||
}
|
||||
|
||||
end:
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
free(key_name);
|
||||
free(data);
|
||||
#endif
|
||||
|
||||
return MGMT_RETURN_CHECK(ok);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command handler: settings write
|
||||
*/
|
||||
static int settings_mgmt_write(struct smp_streamer *ctxt)
|
||||
{
|
||||
int rc;
|
||||
zcbor_state_t *zse = ctxt->writer->zs;
|
||||
zcbor_state_t *zsd = ctxt->reader->zs;
|
||||
bool ok;
|
||||
struct zcbor_string data = { 0 };
|
||||
size_t decoded;
|
||||
struct zcbor_string key = { 0 };
|
||||
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
char *key_name = NULL;
|
||||
#else
|
||||
char key_name[CONFIG_MCUMGR_GRP_SETTINGS_NAME_LEN];
|
||||
#endif
|
||||
|
||||
struct zcbor_map_decode_key_val settings_write_decode[] = {
|
||||
ZCBOR_MAP_DECODE_KEY_DECODER("name", zcbor_tstr_decode, &key),
|
||||
ZCBOR_MAP_DECODE_KEY_DECODER("val", zcbor_bstr_decode, &data),
|
||||
};
|
||||
|
||||
ok = zcbor_map_decode_bulk(zsd, settings_write_decode, ARRAY_SIZE(settings_write_decode),
|
||||
&decoded) == 0;
|
||||
|
||||
if (!ok || key.len == 0) {
|
||||
return MGMT_ERR_EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the length of the user supplied key is too large for the configuration
|
||||
* to allow and return an error if so
|
||||
*/
|
||||
if (key.len >= CONFIG_MCUMGR_GRP_SETTINGS_NAME_LEN) {
|
||||
ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_SETTINGS,
|
||||
SETTINGS_MGMT_ERR_KEY_TOO_LONG);
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
key_name = (char *)malloc(key.len + 1);
|
||||
|
||||
if (key_name == NULL) {
|
||||
return MGMT_ERR_ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(key_name, key.value, key.len);
|
||||
key_name[key.len] = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MCUMGR_GRP_SETTINGS_ACCESS_HOOK)) {
|
||||
/* Send request to application to check if access should be allowed or not */
|
||||
struct settings_mgmt_access settings_access_data = {
|
||||
.access = SETTINGS_ACCESS_WRITE,
|
||||
.name = key_name,
|
||||
.val = data.value,
|
||||
.val_length = &data.len,
|
||||
};
|
||||
|
||||
enum mgmt_cb_return status;
|
||||
int32_t ret_rc;
|
||||
uint16_t ret_group;
|
||||
|
||||
status = mgmt_callback_notify(MGMT_EVT_OP_SETTINGS_MGMT_ACCESS,
|
||||
&settings_access_data, sizeof(settings_access_data),
|
||||
&ret_rc, &ret_group);
|
||||
|
||||
if (status != MGMT_CB_OK) {
|
||||
bool ok;
|
||||
|
||||
if (status == MGMT_CB_ERROR_RC) {
|
||||
return ret_rc;
|
||||
}
|
||||
|
||||
ok = smp_add_cmd_err(zse, ret_group, (uint16_t)ret_rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the settings data */
|
||||
rc = settings_runtime_set(key_name, data.value, data.len);
|
||||
|
||||
if (rc < 0) {
|
||||
if (rc == -EINVAL) {
|
||||
rc = SETTINGS_MGMT_ERR_KEY_NOT_FOUND;
|
||||
} else {
|
||||
rc = SETTINGS_MGMT_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_SETTINGS, (uint16_t)rc);
|
||||
}
|
||||
|
||||
end:
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
free(key_name);
|
||||
#endif
|
||||
|
||||
return MGMT_RETURN_CHECK(ok);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command handler: settings delete
|
||||
*/
|
||||
static int settings_mgmt_delete(struct smp_streamer *ctxt)
|
||||
{
|
||||
zcbor_state_t *zse = ctxt->writer->zs;
|
||||
zcbor_state_t *zsd = ctxt->reader->zs;
|
||||
int rc;
|
||||
bool ok;
|
||||
size_t decoded;
|
||||
struct zcbor_string key = { 0 };
|
||||
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
char *key_name = NULL;
|
||||
#else
|
||||
char key_name[CONFIG_MCUMGR_GRP_SETTINGS_NAME_LEN];
|
||||
#endif
|
||||
|
||||
struct zcbor_map_decode_key_val settings_delete_decode[] = {
|
||||
ZCBOR_MAP_DECODE_KEY_DECODER("name", zcbor_tstr_decode, &key),
|
||||
};
|
||||
|
||||
ok = zcbor_map_decode_bulk(zsd, settings_delete_decode, ARRAY_SIZE(settings_delete_decode),
|
||||
&decoded) == 0;
|
||||
|
||||
if (!ok || key.len == 0) {
|
||||
return MGMT_ERR_EINVAL;
|
||||
}
|
||||
|
||||
/* Check if the length of the user supplied key is too large for the configuration
|
||||
* to allow and return an error if so
|
||||
*/
|
||||
if (key.len >= CONFIG_MCUMGR_GRP_SETTINGS_NAME_LEN) {
|
||||
ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_SETTINGS,
|
||||
SETTINGS_MGMT_ERR_KEY_TOO_LONG);
|
||||
goto end;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
key_name = (char *)malloc(key.len + 1);
|
||||
|
||||
if (key_name == NULL) {
|
||||
return MGMT_ERR_ENOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(key_name, key.value, key.len);
|
||||
key_name[key.len] = 0;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MCUMGR_GRP_SETTINGS_ACCESS_HOOK)) {
|
||||
/* Send request to application to check if access should be allowed or not */
|
||||
struct settings_mgmt_access settings_access_data = {
|
||||
.access = SETTINGS_ACCESS_DELETE,
|
||||
.name = key_name,
|
||||
};
|
||||
|
||||
enum mgmt_cb_return status;
|
||||
int32_t ret_rc;
|
||||
uint16_t ret_group;
|
||||
|
||||
status = mgmt_callback_notify(MGMT_EVT_OP_SETTINGS_MGMT_ACCESS,
|
||||
&settings_access_data, sizeof(settings_access_data),
|
||||
&ret_rc, &ret_group);
|
||||
|
||||
if (status != MGMT_CB_OK) {
|
||||
bool ok;
|
||||
|
||||
if (status == MGMT_CB_ERROR_RC) {
|
||||
return ret_rc;
|
||||
}
|
||||
|
||||
ok = smp_add_cmd_err(zse, ret_group, (uint16_t)ret_rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete requested key from settings */
|
||||
rc = settings_delete(key_name);
|
||||
|
||||
#ifdef CONFIG_MCUMGR_GRP_SETTINGS_BUFFER_TYPE_HEAP
|
||||
free(key_name);
|
||||
#endif
|
||||
|
||||
if (rc < 0) {
|
||||
if (rc == -ENOENT) {
|
||||
rc = SETTINGS_MGMT_ERR_KEY_NOT_FOUND;
|
||||
} else {
|
||||
rc = SETTINGS_MGMT_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_SETTINGS, (uint16_t)rc);
|
||||
}
|
||||
|
||||
end:
|
||||
return MGMT_RETURN_CHECK(ok);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command handler: settings commit
|
||||
*/
|
||||
static int settings_mgmt_commit(struct smp_streamer *ctxt)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MCUMGR_GRP_SETTINGS_ACCESS_HOOK)) {
|
||||
/* Send request to application to check if access should be allowed or not */
|
||||
struct settings_mgmt_access settings_access_data = {
|
||||
.access = SETTINGS_ACCESS_COMMIT,
|
||||
};
|
||||
|
||||
zcbor_state_t *zse = ctxt->writer->zs;
|
||||
enum mgmt_cb_return status;
|
||||
int32_t ret_rc;
|
||||
uint16_t ret_group;
|
||||
|
||||
status = mgmt_callback_notify(MGMT_EVT_OP_SETTINGS_MGMT_ACCESS,
|
||||
&settings_access_data, sizeof(settings_access_data),
|
||||
&ret_rc, &ret_group);
|
||||
|
||||
if (status != MGMT_CB_OK) {
|
||||
bool ok;
|
||||
|
||||
if (status == MGMT_CB_ERROR_RC) {
|
||||
return ret_rc;
|
||||
}
|
||||
|
||||
ok = smp_add_cmd_err(zse, ret_group, (uint16_t)ret_rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
settings_commit();
|
||||
|
||||
end:
|
||||
return MGMT_RETURN_CHECK(ok);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command handler: settings load
|
||||
*/
|
||||
static int settings_mgmt_load(struct smp_streamer *ctxt)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MCUMGR_GRP_SETTINGS_ACCESS_HOOK)) {
|
||||
/* Send request to application to check if access should be allowed or not */
|
||||
struct settings_mgmt_access settings_access_data = {
|
||||
.access = SETTINGS_ACCESS_LOAD,
|
||||
};
|
||||
|
||||
zcbor_state_t *zse = ctxt->writer->zs;
|
||||
enum mgmt_cb_return status;
|
||||
int32_t ret_rc;
|
||||
uint16_t ret_group;
|
||||
|
||||
status = mgmt_callback_notify(MGMT_EVT_OP_SETTINGS_MGMT_ACCESS,
|
||||
&settings_access_data, sizeof(settings_access_data),
|
||||
&ret_rc, &ret_group);
|
||||
|
||||
if (status != MGMT_CB_OK) {
|
||||
bool ok;
|
||||
|
||||
if (status == MGMT_CB_ERROR_RC) {
|
||||
return ret_rc;
|
||||
}
|
||||
|
||||
ok = smp_add_cmd_err(zse, ret_group, (uint16_t)ret_rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
settings_load();
|
||||
|
||||
end:
|
||||
return MGMT_RETURN_CHECK(ok);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command handler: settings save
|
||||
*/
|
||||
static int settings_mgmt_save(struct smp_streamer *ctxt)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MCUMGR_GRP_SETTINGS_ACCESS_HOOK)) {
|
||||
/* Send request to application to check if access should be allowed or not */
|
||||
struct settings_mgmt_access settings_access_data = {
|
||||
.access = SETTINGS_ACCESS_SAVE,
|
||||
};
|
||||
|
||||
zcbor_state_t *zse = ctxt->writer->zs;
|
||||
enum mgmt_cb_return status;
|
||||
int32_t ret_rc;
|
||||
uint16_t ret_group;
|
||||
|
||||
status = mgmt_callback_notify(MGMT_EVT_OP_SETTINGS_MGMT_ACCESS,
|
||||
&settings_access_data, sizeof(settings_access_data),
|
||||
&ret_rc, &ret_group);
|
||||
|
||||
if (status != MGMT_CB_OK) {
|
||||
bool ok;
|
||||
|
||||
if (status == MGMT_CB_ERROR_RC) {
|
||||
return ret_rc;
|
||||
}
|
||||
|
||||
ok = smp_add_cmd_err(zse, ret_group, (uint16_t)ret_rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
settings_save();
|
||||
|
||||
end:
|
||||
return MGMT_RETURN_CHECK(ok);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
|
||||
static int settings_mgmt_translate_error_code(uint16_t ret)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (ret) {
|
||||
case SETTINGS_MGMT_ERR_KEY_TOO_LONG:
|
||||
rc = MGMT_ERR_EINVAL;
|
||||
break;
|
||||
|
||||
case SETTINGS_MGMT_ERR_KEY_NOT_FOUND:
|
||||
case SETTINGS_MGMT_ERR_READ_NOT_SUPPORTED:
|
||||
rc = MGMT_ERR_ENOENT;
|
||||
break;
|
||||
|
||||
case SETTINGS_MGMT_ERR_UNKNOWN:
|
||||
default:
|
||||
rc = MGMT_ERR_EUNKNOWN;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct mgmt_handler settings_mgmt_handlers[] = {
|
||||
[SETTINGS_MGMT_ID_READ_WRITE] = {
|
||||
.mh_read = settings_mgmt_read,
|
||||
.mh_write = settings_mgmt_write,
|
||||
},
|
||||
[SETTINGS_MGMT_ID_DELETE] = {
|
||||
.mh_read = NULL,
|
||||
.mh_write = settings_mgmt_delete,
|
||||
},
|
||||
[SETTINGS_MGMT_ID_COMMIT] = {
|
||||
.mh_read = NULL,
|
||||
.mh_write = settings_mgmt_commit,
|
||||
},
|
||||
[SETTINGS_MGMT_ID_LOAD_SAVE] = {
|
||||
.mh_read = settings_mgmt_load,
|
||||
.mh_write = settings_mgmt_save,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mgmt_group settings_mgmt_group = {
|
||||
.mg_handlers = settings_mgmt_handlers,
|
||||
.mg_handlers_count = ARRAY_SIZE(settings_mgmt_handlers),
|
||||
.mg_group_id = MGMT_GROUP_ID_SETTINGS,
|
||||
#ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
|
||||
.mg_translate_error = settings_mgmt_translate_error_code,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void settings_mgmt_register_group(void)
|
||||
{
|
||||
mgmt_register_group(&settings_mgmt_group);
|
||||
}
|
||||
|
||||
MCUMGR_HANDLER_DEFINE(settings_mgmt, settings_mgmt_register_group);
|
Loading…
Reference in a new issue