From 17a565dd880b8854b98d95e75e7fe5b185e60f6d Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 17 Oct 2022 10:27:08 +0100 Subject: [PATCH 1/5] mgmt: mcumgr: lib: cmd: os: Add device information handler The device information handler can be used to retrieve information about the configuration of the configured device such as board name, board revision, firmware version and build date. Signed-off-by: Jamie McCrae --- .../zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h | 60 ++++ include/zephyr/mgmt/mcumgr/mgmt/callbacks.h | 6 + subsys/mgmt/mcumgr/grp/os_mgmt/CMakeLists.txt | 7 + subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig | 35 ++ .../grp/os_mgmt/include/os_mgmt_processor.h | 137 ++++++++ subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c | 326 ++++++++++++++++++ 6 files changed, 571 insertions(+) create mode 100644 subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h diff --git a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h index 75d9dc7518564..cd474b247bbe2 100644 --- a/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h +++ b/include/zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h @@ -22,6 +22,66 @@ extern "C" { #define OS_MGMT_ID_DATETIME_STR 4 #define OS_MGMT_ID_RESET 5 #define OS_MGMT_ID_MCUMGR_PARAMS 6 +#define OS_MGMT_ID_INFO 7 + +/* Bitmask values used by the os info command handler. Note that the width of this variable is + * 32-bits, allowing 32 flags, custom user-level implementations should start at + * OS_MGMT_INFO_FORMAT_USER_CUSTOM_START and reference that directly as additional format + * specifiers might be added to this list in the future. + */ +enum os_mgmt_info_formats { + OS_MGMT_INFO_FORMAT_KERNEL_NAME = BIT(0), + OS_MGMT_INFO_FORMAT_NODE_NAME = BIT(1), + OS_MGMT_INFO_FORMAT_KERNEL_RELEASE = BIT(2), + OS_MGMT_INFO_FORMAT_KERNEL_VERSION = BIT(3), + OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME = BIT(4), + OS_MGMT_INFO_FORMAT_MACHINE = BIT(5), + OS_MGMT_INFO_FORMAT_PROCESSOR = BIT(6), + OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM = BIT(7), + OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM = BIT(8), + + OS_MGMT_INFO_FORMAT_USER_CUSTOM_START = BIT(9), +}; + +/* Structure provided in the MGMT_EVT_OP_OS_MGMT_INFO_CHECK notification callback */ +struct os_mgmt_info_check { + /* Input format string from the mcumgr client */ + struct zcbor_string *format; + /* Bitmask of values specifying which outputs should be present */ + uint32_t *format_bitmask; + /* Number of valid format characters parsed, must be incremented by 1 for each valid + * character + */ + uint16_t *valid_formats; + /* Needs to be set to true if the OS name is being provided by external code */ + bool *custom_os_name; +}; + +/* Structure provided in the MGMT_EVT_OP_OS_MGMT_INFO_APPEND notification callback */ +struct os_mgmt_info_append { + /* The format bitmask from the processed commands, the bits should be cleared once + * processed, note that if all_format_specified is specified, the corrisponding bits here + * will not be set + */ + uint32_t *format_bitmask; + /* Will be true if the all 'a' specifier was provided */ + bool all_format_specified; + /* The output buffer which the responses should be appended to. If prior_output is true, a + * space must be added prior to the output response + */ + uint8_t *output; + /* The current size of the output response in the output buffer, must be updated to be the + * size of the output response after appending data + */ + uint16_t *output_length; + /* The size of the output buffer, including null terminator character, if the output + * response would exceed this size, the function must abort and return false to return a + * memory error to the client + */ + uint16_t buffer_size; + /* If there has been prior output, must be set to true if a response has been output */ + bool *prior_output; +}; /** * @brief Registers the OS management command handler group. diff --git a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h index 1cd6c94a46f77..aeca99ef20cfd 100644 --- a/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h +++ b/include/zephyr/mgmt/mcumgr/mgmt/callbacks.h @@ -146,6 +146,12 @@ enum os_mgmt_group_events { /** Callback when a reset command has been received. */ MGMT_EVT_OP_OS_MGMT_RESET = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 0), + /** Callback when an info command is processed, data is os_mgmt_info_check. */ + MGMT_EVT_OP_OS_MGMT_INFO_CHECK = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 1), + + /** Callback when an info command needs to output data, data is os_mgmt_info_append. */ + MGMT_EVT_OP_OS_MGMT_INFO_APPEND = MGMT_DEF_EVT_OP_ID(MGMT_EVT_GRP_OS, 2), + /** Used to enable all os_mgmt_group events. */ MGMT_EVT_OP_OS_MGMT_ALL = MGMT_DEF_EVT_OP_ALL(MGMT_EVT_GRP_OS), }; diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/CMakeLists.txt b/subsys/mgmt/mcumgr/grp/os_mgmt/CMakeLists.txt index 82e7a3a6eeb7f..e0a5bce58c530 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/CMakeLists.txt +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/CMakeLists.txt @@ -20,3 +20,10 @@ if (CONFIG_REBOOT) endif() target_link_libraries(mgmt_mcumgr INTERFACE mgmt_mcumgr_grp_os) + +if(DEFINED CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME) + set(MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR ${PROJECT_BINARY_DIR}/os_mgmt_auto) + file(MAKE_DIRECTORY ${MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR}) + file(WRITE ${MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR}/os_mgmt_build_date.c "/* Auto generated file, do not edit */\n#include \nuint8_t *MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME = __TIMESTAMP__;") + zephyr_library_sources(${MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME_DIR}/os_mgmt_build_date.c) +endif() diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig b/subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig index 381ac6c42dedc..df47d9c175954 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/Kconfig @@ -123,4 +123,39 @@ config OS_MGMT_ECHO config OS_MGMT_MCUMGR_PARAMS bool "MCUMGR Parameters retrieval command" +config MCUMGR_GRP_OS_INFO + bool "Support for info command" + help + Can be used similarly to the unix/linux uname command for retrieving system information + including kernel version, processor architecture and board name. + +if MCUMGR_GRP_OS_INFO + +config MCUMGR_GRP_OS_INFO_MAX_RESPONSE_SIZE + int "Maximum response size for info command" + default 256 + range 32 512 + help + The maximum size of the response to the info command, will use a stack buffer of this + size to store the data in. If the output response is too big then the output will not be + present in the response, which will just contain the result code (rc) of memory error. + +config MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS + bool "Custom info hooks" + depends on MCUMGR_MGMT_NOTIFICATION_HOOKS + help + Supports adding custom command/character processing to the info command by using + registered callbacks. Data can be appended to the struct provided in the callback. + +config MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME + bool "Show build date and time" + help + Will allow returning the build date and time of the firmware by using the info with + format option 'b' (will also be returned with all responses by using 'a'). + + Note: This will invalidate reproducible builds of the firmware as it will embed the + build date/time in the output firmware image. + +endif + endif diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h new file mode 100644 index 0000000000000..a44b9ab269f7c --- /dev/null +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/include/os_mgmt_processor.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2022 Zephyr authors + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_OS_MGMT_PROCESSOR_ +#define H_OS_MGMT_PROCESSOR_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Processor name (used in uname output command) + * Will be unknown if processor type is not listed + * (List extracted from /cmake/gcc-m-cpu.cmake) + */ +#if defined(CONFIG_ARM) +#if defined(CONFIG_CPU_CORTEX_M0) +#define PROCESSOR_NAME "cortex-m0" +#elif defined(CONFIG_CPU_CORTEX_M0PLUS) +#define PROCESSOR_NAME "cortex-m0plus" +#elif defined(CONFIG_CPU_CORTEX_M1) +#define PROCESSOR_NAME "cortex-m1" +#elif defined(CONFIG_CPU_CORTEX_M3) +#define PROCESSOR_NAME "cortex-m3" +#elif defined(CONFIG_CPU_CORTEX_M4) +#define PROCESSOR_NAME "cortex-m4" +#elif defined(CONFIG_CPU_CORTEX_M7) +#define PROCESSOR_NAME "cortex-m7" +#elif defined(CONFIG_CPU_CORTEX_M23) +#define PROCESSOR_NAME "cortex-m23" +#elif defined(CONFIG_CPU_CORTEX_M33) +#if defined(CONFIG_ARMV8_M_DSP) +#define PROCESSOR_NAME "cortex-m33" +#else +#define PROCESSOR_NAME "cortex-m33+nodsp" +#endif +#elif defined(CONFIG_CPU_CORTEX_M55) +#if defined(CONFIG_ARMV8_1_M_MVEF) +#define PROCESSOR_NAME "cortex-m55" +#elif defined(CONFIG_ARMV8_1_M_MVEI) +#define PROCESSOR_NAME "cortex-m55+nomve.fp" +#elif defined(CONFIG_ARMV8_M_DSP) +#define PROCESSOR_NAME "cortex-m55+nomve" +#else +#define PROCESSOR_NAME "cortex-m55+nodsp" +#endif +#elif defined(CONFIG_CPU_CORTEX_R4) +#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP) +#define PROCESSOR_NAME "cortex-r4f" +#else +#define PROCESSOR_NAME "cortex-r4" +#endif +#elif defined(CONFIG_CPU_CORTEX_R5) +#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP) +#if !defined(CONFIG_VFP_FEATURE_DOUBLE_PRECISION) +#define PROCESSOR_NAME "cortex-r5+nofp.dp" +#else +#define PROCESSOR_NAME "cortex-r5" +#endif +#else +#define PROCESSOR_NAME "cortex-r5+nofp" +#endif +#elif defined(CONFIG_CPU_CORTEX_R7) +#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP) +#if !defined(CONFIG_VFP_FEATURE_DOUBLE_PRECISION) +#define PROCESSOR_NAME "cortex-r7+nofp.dp" +#else +#define PROCESSOR_NAME "cortex-r7" +#endif +#else +#define PROCESSOR_NAME "cortex-r7+nofp" +#endif +#elif defined(CONFIG_CPU_CORTEX_R52) +#if defined(CONFIG_FPU) && defined(CONFIG_CPU_HAS_VFP) +#if !defined(CONFIG_VFP_FEATURE_DOUBLE_PRECISION) +#define PROCESSOR_NAME "cortex-r52+nofp.dp" +#else +#define PROCESSOR_NAME "cortex-r52" +#endif +#else +#define PROCESSOR_NAME "cortex-r52" +#endif +#elif defined(CONFIG_CPU_CORTEX_A9) +#define PROCESSOR_NAME "cortex-a9" +#endif +#elif defined(CONFIG_ARM64) +#if defined(CONFIG_CPU_CORTEX_A53) +#define PROCESSOR_NAME "cortex-a53" +#if defined(CONFIG_CPU_CORTEX_A55) +#define PROCESSOR_NAME "cortex-a55" +#elif defined(CONFIG_CPU_CORTEX_A72) +#define PROCESSOR_NAME "cortex-a72" +#elif defined(CONFIG_CPU_CORTEX_R82) +#define PROCESSOR_NAME "armv8.4-a+nolse" +#endif +#endif +#elif defined(CONFIG_ARC) +#if defined(CONFIG_CPU_EM4_FPUS) +#define PROCESSOR_NAME "em4_fpus" +#elif defined(CONFIG_CPU_EM4_DMIPS) +#define PROCESSOR_NAME "em4_dmips" +#elif defined(CONFIG_CPU_EM4_FPUDA) +#define PROCESSOR_NAME "em4_fpuda" +#elif defined(CONFIG_CPU_HS3X) +#define PROCESSOR_NAME "archs" +#elif defined(CONFIG_CPU_HS5X) +#define PROCESSOR_NAME "hs5x" +#elif defined(CONFIG_CPU_HS6X) +#define PROCESSOR_NAME "hs6x" +#elif defined(CONFIG_CPU_EM4) +#define PROCESSOR_NAME "arcem" +#elif defined(CONFIG_CPU_EM6) +#define PROCESSOR_NAME "arcem" +#endif +#elif defined(CONFIG_X86) +#if defined(CONFIG_X86_64) +#define PROCESSOR_NAME "x86_64" +#else +#define PROCESSOR_NAME "x86" +#endif +#elif defined(CONFIG_RISCV) +#define PROCESSOR_NAME "riscv" +#endif + +#ifndef PROCESSOR_NAME +#warning "Processor type could not be determined" +#define PROCESSOR_NAME "unknown" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_OS_MGMT_PROCESSOR_ */ diff --git a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c index 46de3369fb85e..869f9e90f4dd3 100644 --- a/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c +++ b/subsys/mgmt/mcumgr/grp/os_mgmt/src/os_mgmt.c @@ -28,6 +28,18 @@ #include #endif +#ifdef CONFIG_MCUMGR_GRP_OS_INFO +#include +#include +#include +#include +#if defined(CONFIG_NET_HOSTNAME_ENABLE) +#include +#elif defined(CONFIG_BT) +#include +#endif +#endif + #ifdef CONFIG_REBOOT static void os_mgmt_reset_work_handler(struct k_work *work); static void os_mgmt_reset_cb(struct k_timer *timer); @@ -54,6 +66,19 @@ struct thread_iterator_info { }; #endif +/* Specifies what the "all" ('a') of info parameter shows */ +#define OS_MGMT_INFO_FORMAT_ALL \ + OS_MGMT_INFO_FORMAT_KERNEL_NAME | OS_MGMT_INFO_FORMAT_NODE_NAME | \ + OS_MGMT_INFO_FORMAT_KERNEL_RELEASE | OS_MGMT_INFO_FORMAT_KERNEL_VERSION | \ + (IS_ENABLED(CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME) ? \ + OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME : 0) | \ + OS_MGMT_INFO_FORMAT_MACHINE | OS_MGMT_INFO_FORMAT_PROCESSOR | \ + OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM | OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME +extern uint8_t *MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME; +#endif + /** * Command handler: os echo */ @@ -318,6 +343,302 @@ os_mgmt_mcumgr_params(struct smp_streamer *ctxt) } #endif +#ifdef CONFIG_MCUMGR_GRP_OS_INFO +/** + * Command handler: os info + */ +static int os_mgmt_info(struct smp_streamer *ctxt) +{ + struct zcbor_string format = { 0 }; + uint8_t output[CONFIG_MCUMGR_GRP_OS_INFO_MAX_RESPONSE_SIZE] = { 0 }; + zcbor_state_t *zse = ctxt->writer->zs; + zcbor_state_t *zsd = ctxt->reader->zs; + uint32_t format_bitmask = 0; + bool prior_output = false; + size_t i = 0; + size_t decoded; + bool custom_os_name = false; + int rc; + uint16_t output_length = 0; + uint16_t valid_formats = 0; + + struct zcbor_map_decode_key_val fs_info_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(format, zcbor_tstr_decode, &format), + }; + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS + struct os_mgmt_info_check check_data = { + .format = &format, + .format_bitmask = &format_bitmask, + .valid_formats = &valid_formats, + .custom_os_name = &custom_os_name, + }; + + struct os_mgmt_info_append append_data = { + .format_bitmask = &format_bitmask, + .all_format_specified = false, + .output = output, + .output_length = &output_length, + .buffer_size = sizeof(output), + .prior_output = &prior_output, + }; +#endif + + if (zcbor_map_decode_bulk(zsd, fs_info_decode, ARRAY_SIZE(fs_info_decode), &decoded)) { + return MGMT_ERR_EINVAL; + } + + /* Process all input characters in format value */ + while (i < format.len) { + switch (format.value[i]) { + case 'a': { +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS + append_data.all_format_specified = true; +#endif + + format_bitmask = OS_MGMT_INFO_FORMAT_ALL; + ++valid_formats; + break; + } + case 's': { + format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_NAME; + ++valid_formats; + break; + } + case 'n': { + format_bitmask |= OS_MGMT_INFO_FORMAT_NODE_NAME; + ++valid_formats; + break; + } + case 'r': { + format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_RELEASE; + ++valid_formats; + break; + } + case 'v': { + format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_VERSION; + ++valid_formats; + break; + } +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME + case 'b': { + format_bitmask |= OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME; + ++valid_formats; + break; + } +#endif + case 'm': { + format_bitmask |= OS_MGMT_INFO_FORMAT_MACHINE; + ++valid_formats; + break; + } + case 'p': { + format_bitmask |= OS_MGMT_INFO_FORMAT_PROCESSOR; + ++valid_formats; + break; + } + case 'i': { + format_bitmask |= OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM; + ++valid_formats; + break; + } + case 'o': { + format_bitmask |= OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM; + ++valid_formats; + break; + } + default: { + break; + } + } + + ++i; + } + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS + /* Run callbacks to see if any additional handlers will add options */ + (void)mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_INFO_CHECK, &check_data, + sizeof(check_data)); +#endif + + if (valid_formats != format.len) { + /* A provided format specifier is not valid */ + return MGMT_ERR_EINVAL; + } else if (format_bitmask == 0) { + /* If no value is provided, use default of kernel name */ + format_bitmask = OS_MGMT_INFO_FORMAT_KERNEL_NAME; + } + + /* Process all options in order and append to output string */ + if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_NAME) { + rc = snprintf(output, (sizeof(output) - output_length), "Zephyr"); + + if (rc < 0 || rc >= (sizeof(output) - output_length)) { + goto fail; + } else { + output_length += (uint16_t)rc; + } + + prior_output = true; + } + + if (format_bitmask & OS_MGMT_INFO_FORMAT_NODE_NAME) { + /* Get hostname, if enabled */ +#if defined(CONFIG_NET_HOSTNAME_ENABLE) + /* From network */ + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + (prior_output == true ? " %s" : "%s"), net_hostname_get()); +#elif defined(CONFIG_BT) + /* From Bluetooth */ + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + (prior_output == true ? " %s" : "%s"), bt_get_name()); +#else + /* Not available */ + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + "%sunknown", (prior_output == true ? " " : "")); +#endif + + if (rc < 0 || rc >= (sizeof(output) - output_length)) { + goto fail; + } else { + output_length += (uint16_t)rc; + } + + prior_output = true; + format_bitmask &= ~OS_MGMT_INFO_FORMAT_NODE_NAME; + } + + if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_RELEASE) { +#ifdef BUILD_VERSION + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + (prior_output == true ? " %s" : "%s"), STRINGIFY(BUILD_VERSION)); +#else + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + "%sunknown", (prior_output == true ? " " : "")); +#endif + + if (rc < 0 || rc >= (sizeof(output) - output_length)) { + goto fail; + } else { + output_length += (uint16_t)rc; + } + + prior_output = true; + format_bitmask &= ~OS_MGMT_INFO_FORMAT_KERNEL_RELEASE; + } + + if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_VERSION) { + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + (prior_output == true ? " %s" : "%s"), KERNEL_VERSION_STRING); + + if (rc < 0 || rc >= (sizeof(output) - output_length)) { + goto fail; + } else { + output_length += (uint16_t)rc; + } + + prior_output = true; + format_bitmask &= ~OS_MGMT_INFO_FORMAT_KERNEL_VERSION; + } + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME + if (format_bitmask & OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME) { + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + (prior_output == true ? " %s" : "%s"), + MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME); + + if (rc < 0 || rc >= (sizeof(output) - output_length)) { + goto fail; + } else { + output_length += (uint16_t)rc; + } + + prior_output = true; + format_bitmask &= ~OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME; + } +#endif + + if (format_bitmask & OS_MGMT_INFO_FORMAT_MACHINE) { + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + (prior_output == true ? " %s" : "%s"), CONFIG_ARCH); + + if (rc < 0 || rc >= (sizeof(output) - output_length)) { + goto fail; + } else { + output_length += (uint16_t)rc; + } + + prior_output = true; + format_bitmask &= ~OS_MGMT_INFO_FORMAT_MACHINE; + } + + if (format_bitmask & OS_MGMT_INFO_FORMAT_PROCESSOR) { + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + (prior_output == true ? " %s" : "%s"), PROCESSOR_NAME); + + if (rc < 0 || rc >= (sizeof(output) - output_length)) { + goto fail; + } else { + output_length += (uint16_t)rc; + } + + prior_output = true; + format_bitmask &= ~OS_MGMT_INFO_FORMAT_PROCESSOR; + } + + if (format_bitmask & OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM) { + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + (prior_output == true ? " %s%s%s" : "%s%s%s"), CONFIG_BOARD, + (sizeof(CONFIG_BOARD_REVISION) > 1 ? "@" : ""), + CONFIG_BOARD_REVISION); + + if (rc < 0 || rc >= (sizeof(output) - output_length)) { + goto fail; + } else { + output_length += (uint16_t)rc; + } + + prior_output = true; + format_bitmask &= ~OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM; + } + + /* If custom_os_name is not set (by extension code) then return the default OS name of + * Zephyr + */ + if (format_bitmask & OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM && custom_os_name == false) { + rc = snprintf(&output[output_length], (sizeof(output) - output_length), + "%sZephyr", (prior_output == true ? " " : "")); + + if (rc < 0 || rc >= (sizeof(output) - output_length)) { + goto fail; + } else { + output_length += (uint16_t)rc; + } + + prior_output = true; + format_bitmask &= ~OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM; + } + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS + /* Call custom handler command for additional output/processing */ + rc = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_INFO_APPEND, &append_data, + sizeof(append_data)); + + if (rc != MGMT_ERR_EOK) { + return rc; + } +#endif + + if (zcbor_tstr_put_lit(zse, "output") && + zcbor_tstr_encode_ptr(zse, output, output_length)) { + return MGMT_ERR_EOK; + } + +fail: + return MGMT_ERR_EMSGSIZE; +} +#endif + static const struct mgmt_handler os_mgmt_group_handlers[] = { #ifdef CONFIG_OS_MGMT_ECHO [OS_MGMT_ID_ECHO] = { @@ -339,6 +660,11 @@ static const struct mgmt_handler os_mgmt_group_handlers[] = { os_mgmt_mcumgr_params, NULL }, #endif +#ifdef CONFIG_MCUMGR_GRP_OS_INFO + [OS_MGMT_ID_INFO] = { + os_mgmt_info, NULL + }, +#endif }; #define OS_MGMT_GROUP_SZ ARRAY_SIZE(os_mgmt_group_handlers) From 1227f8e2ed290d1dd7f7eaa93119dbcf272c676d Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 17 Oct 2022 10:01:45 +0100 Subject: [PATCH 2/5] doc: mgmt: smp group 0: Add OS info details Adds details on the OS information mcumgr command. Signed-off-by: Jamie McCrae --- .../device_mgmt/smp_groups/smp_group_0.rst | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/doc/services/device_mgmt/smp_groups/smp_group_0.rst b/doc/services/device_mgmt/smp_groups/smp_group_0.rst index db32642bc01bc..1ffc985ed906e 100644 --- a/doc/services/device_mgmt/smp_groups/smp_group_0.rst +++ b/doc/services/device_mgmt/smp_groups/smp_group_0.rst @@ -26,6 +26,8 @@ OS management group defines following commands: +-------------------+-----------------------------------------------+ | ``6`` | MCUMGR parameters | +-------------------+-----------------------------------------------+ + | ``7`` | OS/Application info | + +-------------------+-----------------------------------------------+ Echo command ************ @@ -542,3 +544,95 @@ where: | "rc" | :ref:`mcumgr_smp_protocol_status_codes`; | | | may not appear if 0 | +-----------------------+---------------------------------------------------+ + +.. _mcumgr_os_application_info: + +OS/Application Info +******************* + +Used to obtain information on running image, similar functionality to the linux +uname command, allowing details such as kernel name, kernel version, build +date/time, processor type and application-defined details to be returned. This +functionality can be enabled with :kconfig:option:`CONFIG_MCUMGR_GRP_OS_INFO`. + +OS/Application Info Request +=========================== + +OS/Application info request header fields: + +.. table:: + :align: center + + +--------+--------------+----------------+ + | ``OP`` | ``Group ID`` | ``Command ID`` | + +========+==============+================+ + | ``0`` | ``0`` | ``7`` | + +--------+--------------+----------------+ + +CBOR data of request: + +.. code-block:: none + + { + (str,opt)"format" : (str) + } + +where: + +.. table:: + :align: center + + +----------+-------------------------------------------------------------------+ + | "format" | Format specifier of returned response, fields are appended in | + | | their natural ascending index order, not the order of | + | | characters that are received by the command. Format | + | | specifiers: |br| | + | | * ``s`` Kernel name |br| | + | | * ``n`` Node name |br| | + | | * ``r`` Kernel release |br| | + | | * ``v`` Kernel version |br| | + | | * ``b`` Build date and time (requires | + | | :kconfig:option:`CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME`) |br| | + | | * ``m`` Machine |br| | + | | * ``p`` Processor |br| | + | | * ``i`` Hardware platform |br| | + | | * ``o`` Operating system |br| | + | | * ``a`` All fields (shorthand for all above options) |br| | + | | If this option is not provided, the ``s`` Kernel name option | + | | will be used. | + +----------+-------------------------------------------------------------------+ + +OS/Application Info Response +============================ + +OS/Application info response header fields + +.. table:: + :align: center + + +--------+--------------+----------------+ + | ``OP`` | ``Group ID`` | ``Command ID`` | + +========+==============+================+ + | ``2`` | ``0`` | ``7`` | + +--------+--------------+----------------+ + +CBOR data of response: + +.. code-block:: none + + { + (str)"output" : (str) + (opt,str)"rc" : (int) + } + +where: + +.. table:: + :align: center + + +--------------+------------------------------------------------------------+ + | "output" | Text response including requested parameters | + +--------------+------------------------------------------------------------+ + | "rc" | :ref:`mcumgr_smp_protocol_status_codes`; will not appear | + | | if 0 | + +--------------+------------------------------------------------------------+ From 1e57b66ecc1cf56ea7ff686d660f0d46afc6bf41 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 17 Oct 2022 10:06:09 +0100 Subject: [PATCH 3/5] doc: release: 3.3: Add os_mgmt info command Adds details of a new os_mgmt command for getting OS/application information. Signed-off-by: Jamie McCrae --- doc/releases/release-notes-3.3.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/releases/release-notes-3.3.rst b/doc/releases/release-notes-3.3.rst index 4df81c9c759b9..d3de4e2a4e503 100644 --- a/doc/releases/release-notes-3.3.rst +++ b/doc/releases/release-notes-3.3.rst @@ -400,6 +400,9 @@ Libraries / Subsystems Private headers for above areas can be accessed, when required, using paths: ``mgmt/mcumgr/mgmt//``. + * MCUmgr os_mgmt info command has been added that allows querying details on + the kernel and application, allowing application-level extensibility + see :ref:`mcumgr_os_application_info` for details. * LwM2M From f2ccd71af69bf4a1982831fdb206ffcf4de3a7cb Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Mon, 17 Oct 2022 13:04:06 +0100 Subject: [PATCH 4/5] tests: mgmt: mcumgr: os_mgmt_info: Add tests Adds tests for the os_mgmt info command. Signed-off-by: Jamie McCrae --- .../mgmt/mcumgr/os_mgmt_info/CMakeLists.txt | 24 + tests/subsys/mgmt/mcumgr/os_mgmt_info/Kconfig | 15 + .../os_mgmt_info/boards/qemu_riscv32_smp.conf | 1 + .../os_mgmt_info/boards/qemu_riscv64.conf | 1 + .../os_mgmt_info/boards/qemu_riscv64_smp.conf | 1 + .../subsys/mgmt/mcumgr/os_mgmt_info/prj.conf | 15 + .../mgmt/mcumgr/os_mgmt_info/src/build_date.c | 268 +++ .../mgmt/mcumgr/os_mgmt_info/src/limited.c | 187 ++ .../mgmt/mcumgr/os_mgmt_info/src/main.c | 1562 +++++++++++++++++ .../mcumgr/os_mgmt_info/src/smp_test_util.c | 43 + .../mcumgr/os_mgmt_info/src/smp_test_util.h | 23 + .../mgmt/mcumgr/os_mgmt_info/testcase.yaml | 57 + 12 files changed, 2197 insertions(+) create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/CMakeLists.txt create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/Kconfig create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv32_smp.conf create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64.conf create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64_smp.conf create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/prj.conf create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.h create mode 100644 tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/CMakeLists.txt b/tests/subsys/mgmt/mcumgr/os_mgmt_info/CMakeLists.txt new file mode 100644 index 0000000000000..552c82052be7e --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/CMakeLists.txt @@ -0,0 +1,24 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(os_mgmt_info) + +FILE(GLOB app_sources + src/*.c +) + +target_sources(app PRIVATE ${app_sources}) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/transport/include/mgmt/mcumgr/transport/) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/mgmt/mcumgr/grp/os_mgmt/include/) + +if(DEFINED CONFIG_BUILD_DATE_TIME_TEST) + set(TEST_DATE_TIME_DIR ${PROJECT_BINARY_DIR}/test) + file(MAKE_DIRECTORY ${TEST_DATE_TIME_DIR}) + file(WRITE ${TEST_DATE_TIME_DIR}/test_date.c "/* Auto generated file, do not edit */\n#include \nuint8_t *test_date_time = __TIMESTAMP__;") + target_sources(app PRIVATE ${TEST_DATE_TIME_DIR}/test_date.c) +endif() diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/Kconfig b/tests/subsys/mgmt/mcumgr/os_mgmt_info/Kconfig new file mode 100644 index 0000000000000..e63a141658419 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2022 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config CUSTOM_OS_NAME_VALUE + string "Custom OS name" + default "Fake OS Name" + +config BUILD_DATE_TIME_TEST + bool "Build date time test" + select MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME + +config LIMITED_TEST + bool "Limited buffer size test" + +source "Kconfig.zephyr" diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv32_smp.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv32_smp.conf new file mode 100644 index 0000000000000..1ede042960b60 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv32_smp.conf @@ -0,0 +1 @@ +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64.conf new file mode 100644 index 0000000000000..1ede042960b60 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64.conf @@ -0,0 +1 @@ +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64_smp.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64_smp.conf new file mode 100644 index 0000000000000..1ede042960b60 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/boards/qemu_riscv64_smp.conf @@ -0,0 +1 @@ +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/prj.conf b/tests/subsys/mgmt/mcumgr/os_mgmt_info/prj.conf new file mode 100644 index 0000000000000..2166e715625fe --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/prj.conf @@ -0,0 +1,15 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +CONFIG_ZTEST=y +CONFIG_MCUMGR=y +CONFIG_MCUMGR_SMP_DUMMY=y +CONFIG_MCUMGR_SMP_DUMMY_RX_BUF_SIZE=256 +CONFIG_MCUMGR_CMD_OS_MGMT=y +CONFIG_MCUMGR_GRP_OS_INFO=y +CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS=y +CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=y +CONFIG_ZTEST_NEW_API=y +CONFIG_ZTEST_STACK_SIZE=2048 diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c new file mode 100644 index 0000000000000..98b92677a09aa --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/build_date.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_BUILD_DATE_TIME_TEST) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_test_util.h" + +#define SMP_RESPONSE_WAIT_TIME 3 +#define ZCBOR_BUFFER_SIZE 256 +#define OUTPUT_BUFFER_SIZE 256 +#define ZCBOR_HISTORY_ARRAY_SIZE 4 + +static struct net_buf *nb; + +/* Responses to commands */ +extern uint8_t *test_date_time; +const uint8_t response_all_board_revision_left[] = "Zephyr unknown " STRINGIFY(BUILD_VERSION) " " + KERNEL_VERSION_STRING " "; +const uint8_t response_all_board_revision_right[] = " " CONFIG_ARCH " " PROCESSOR_NAME " " + CONFIG_BOARD "@" CONFIG_BOARD_REVISION + " Zephyr"; +const uint8_t response_all_left[] = "Zephyr unknown " STRINGIFY(BUILD_VERSION) " " + KERNEL_VERSION_STRING " "; +const uint8_t response_all_right[] = " " CONFIG_ARCH " " PROCESSOR_NAME " " CONFIG_BOARD " Zephyr"; + +const uint8_t query_build_date[] = "b"; +const uint8_t query_all[] = "a"; + +#define DATE_CHECK_LEFT_CHARS 11 +#define DATE_CHECK_RIGHT_CHARS 5 +#define TIME_CHECK_HH_START_CHAR 11 + +#define TIME_HH_OFFSET 0 +#define TIME_MM_OFFSET 3 +#define TIME_SS_OFFSET 6 + +#define SECONDS_PER_HOUR 3600 +#define SECONDS_PER_MINUTE 60 + +#define TIME_DIFFERENCE_ALLOWANCE 60 + +static int32_t time_string_to_seconds(const uint8_t *time_string) +{ + uint8_t time_hh; + uint8_t time_mm; + uint8_t time_ss; + + /* Convert times to separate fields and then to timestamps which can be compared */ + time_hh = ((time_string[TIME_HH_OFFSET] - '0') * 10) + + (time_string[TIME_HH_OFFSET + 1] - '0'); + time_mm = ((time_string[TIME_MM_OFFSET] - '0') * 10) + + (time_string[TIME_MM_OFFSET + 1] - '0'); + time_ss = ((time_string[TIME_SS_OFFSET] - '0') * 10) + + (time_string[TIME_SS_OFFSET + 1] - '0'); + + return (time_hh * SECONDS_PER_HOUR) + (time_mm * SECONDS_PER_MINUTE) + time_ss; +} + +ZTEST(os_mgmt_info_build_date, test_info_build_date_1_build_date) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t expected_time_seconds; + int32_t received_time_seconds; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_build_date, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send test echo command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal(strlen(test_date_time), output.len, + "Expected to receive %d bytes but got %d\n", + strlen(test_date_time), output.len); + + /* Check left and right sides of date which should match */ + zassert_mem_equal(test_date_time, output.value, DATE_CHECK_LEFT_CHARS, + "Expected received data mismatch"); + zassert_mem_equal(&test_date_time[(strlen(test_date_time) - DATE_CHECK_RIGHT_CHARS)], + &output.value[(strlen(test_date_time) - DATE_CHECK_RIGHT_CHARS)], + DATE_CHECK_RIGHT_CHARS, "Expected received data mismatch"); + + /* Extract time strings into timestamps */ + expected_time_seconds = time_string_to_seconds(&test_date_time[TIME_CHECK_HH_START_CHAR]); + received_time_seconds = time_string_to_seconds(&output.value[TIME_CHECK_HH_START_CHAR]); + + zassert_within(expected_time_seconds, received_time_seconds, TIME_DIFFERENCE_ALLOWANCE, + "Expected times to be within %d seconds but got %d", + TIME_DIFFERENCE_ALLOWANCE, + abs(expected_time_seconds - received_time_seconds)); +} + +ZTEST(os_mgmt_info_build_date, test_info_build_date_2_all) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t expected_time_seconds; + int32_t received_time_seconds; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_all, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send test echo command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + if (sizeof(CONFIG_BOARD_REVISION) > 1) { + /* Check with board revision */ + zassert_equal((strlen(test_date_time) + strlen(response_all_board_revision_left) + + strlen(response_all_board_revision_right)), output.len, + "Expected to receive %d bytes but got %d\n", + (strlen(test_date_time) + strlen(response_all_board_revision_left) + + strlen(response_all_board_revision_right)), output.len); + + zassert_mem_equal(response_all_board_revision_left, output.value, + strlen(response_all_board_revision_left), + "Expected received data mismatch"); + zassert_mem_equal(response_all_board_revision_right, + &output.value[strlen(response_all_board_revision_left) + + strlen(test_date_time)], + strlen(response_all_board_revision_right), + "Expected received data mismatch"); + } else { + /* Check without board revision */ + zassert_equal((strlen(test_date_time) + strlen(response_all_left) + + strlen(response_all_right)), output.len, + "Expected to receive %d bytes but got %d\n", + (strlen(test_date_time) + strlen(response_all_left) + + strlen(response_all_right)), output.len); + + zassert_mem_equal(response_all_left, output.value, strlen(response_all_left), + "Expected received data mismatch"); + zassert_mem_equal(response_all_right, &output.value[strlen(response_all_left) + + strlen(test_date_time)], strlen(response_all_right), + "Expected received data mismatch"); + } + + /* Extract time strings into timestamps */ + expected_time_seconds = time_string_to_seconds(&test_date_time[TIME_CHECK_HH_START_CHAR]); + received_time_seconds = time_string_to_seconds(&output.value[(strlen(response_all_left) + + TIME_CHECK_HH_START_CHAR)]); + + zassert_within(expected_time_seconds, received_time_seconds, TIME_DIFFERENCE_ALLOWANCE, + "Expected times to be within %d seconds but got %d", + TIME_DIFFERENCE_ALLOWANCE, + abs(expected_time_seconds - received_time_seconds)); +} + +static void *setup_tests(void) +{ + /* Register os_mgmt mcumgr group */ + os_mgmt_register_group(); + + return NULL; +} + +static void cleanup_test(void *p) +{ + if (nb != NULL) { + net_buf_unref(nb); + nb = NULL; + } +} + +/* Build date/time test set */ +ZTEST_SUITE(os_mgmt_info_build_date, NULL, setup_tests, NULL, cleanup_test, NULL); + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c new file mode 100644 index 0000000000000..e06faee6c0847 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/limited.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if defined(CONFIG_LIMITED_TEST) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_test_util.h" + +#define SMP_RESPONSE_WAIT_TIME 3 +#define ZCBOR_BUFFER_SIZE 64 +#define OUTPUT_BUFFER_SIZE 64 +#define ZCBOR_HISTORY_ARRAY_SIZE 4 + +static struct net_buf *nb; + +/* Responses to commands */ +const uint8_t response_kernel_name[] = "Zephyr"; + +const uint8_t query_kernel_name[] = "s"; +const uint8_t query_all[] = "a"; + +ZTEST(os_mgmt_info_limited, test_info_1_kernel_name) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_kernel_name, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_kernel_name) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_kernel_name) - 1), output.len); + + zassert_mem_equal(response_kernel_name, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info_limited, test_info_2_all) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_all, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + /* Ensure only an error is received */ + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + zassert_equal(rc, MGMT_ERR_EMSGSIZE, "Expected to receive EMSGSIZE error but got %d\n", + rc); +} + +static void *setup_tests(void) +{ + /* Register os_mgmt mcumgr group */ + os_mgmt_register_group(); + + return NULL; +} + +static void cleanup_test(void *p) +{ + if (nb != NULL) { + net_buf_unref(nb); + nb = NULL; + } +} + +/* Limited size buffer test set */ +ZTEST_SUITE(os_mgmt_info_limited, NULL, setup_tests, NULL, cleanup_test, NULL); + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c new file mode 100644 index 0000000000000..0a9734467a215 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/main.c @@ -0,0 +1,1562 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#if !defined(CONFIG_BUILD_DATE_TIME_TEST) && !defined(CONFIG_LIMITED_TEST) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smp_test_util.h" + +#define SMP_RESPONSE_WAIT_TIME 3 +#define QUERY_BUFFER_SIZE 16 +#define ZCBOR_BUFFER_SIZE 256 +#define OUTPUT_BUFFER_SIZE 256 +#define ZCBOR_HISTORY_ARRAY_SIZE 4 +#define QUERY_TEST_CMD_BITMASK OS_MGMT_INFO_FORMAT_USER_CUSTOM_START + +/* Test sets */ +enum { + OS_MGMT_TEST_SET_MAIN = 0, +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS + OS_MGMT_TEST_SET_CUSTOM_OS, + OS_MGMT_TEST_SET_CUSTOM_OS_DISABLED, + OS_MGMT_TEST_SET_CUSTOM_CMD_DISABLED, + OS_MGMT_TEST_SET_CUSTOM_CMD, + OS_MGMT_TEST_SET_CUSTOM_CMD_DISABLED_VERIFY, +#endif + + OS_MGMT_TEST_SET_COUNT +}; + +/* Test os_mgmt info command requesting 's' (kernel name) */ +static const uint8_t command[] = { + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x01, 0x07, + 0xbf, 0x66, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x61, 0x73, 0xff +}; + +/* Expected response from mcumgr */ +static const uint8_t expected_response[] = { + 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x07, + 0xbf, 0x66, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x66, 0x5a, 0x65, 0x70, 0x68, 0x79, 0x72, 0xff +}; + +static struct net_buf *nb; + +struct state { + uint8_t test_set; +}; + +static struct state test_state = { + .test_set = 0, +}; + +/* Responses to commands */ +const uint8_t response_kernel_name[] = "Zephyr"; + +#if defined(CONFIG_BT) +const uint8_t response_node_name[] = CONFIG_BT_DEVICE_NAME; +#elif defined(CONFIG_NET_HOSTNAME_ENABLE) +const uint8_t response_node_name[] = CONFIG_NET_HOSTNAME; +#else +const uint8_t response_node_name[] = "unknown"; +#endif + +const uint8_t response_kernel_release[] = STRINGIFY(BUILD_VERSION); +const uint8_t response_kernel_version[] = KERNEL_VERSION_STRING; +const uint8_t response_machine[] = CONFIG_ARCH; +const uint8_t response_processor[] = PROCESSOR_NAME; +const uint8_t response_board_revision[] = CONFIG_BOARD "@" CONFIG_BOARD_REVISION; +const uint8_t response_board[] = CONFIG_BOARD; +const uint8_t response_os[] = "Zephyr"; +const uint8_t response_custom_cmd[] = "Magic Output for Test"; +const uint8_t response_os_custom[] = CONFIG_CUSTOM_OS_NAME_VALUE; + +const uint8_t response_all_board_revision[] = "Zephyr " +#if defined(CONFIG_BT) + CONFIG_BT_DEVICE_NAME +#elif defined(CONFIG_NET_HOSTNAME_ENABLE) + CONFIG_NET_HOSTNAME +#else + "unknown" +#endif + " " STRINGIFY(BUILD_VERSION) " " + KERNEL_VERSION_STRING " " CONFIG_ARCH " " + PROCESSOR_NAME " " CONFIG_BOARD "@" + CONFIG_BOARD_REVISION " Zephyr"; + +const uint8_t response_all[] = "Zephyr " +#if defined(CONFIG_BT) + CONFIG_BT_DEVICE_NAME +#elif defined(CONFIG_NET_HOSTNAME_ENABLE) + CONFIG_NET_HOSTNAME +#else + "unknown" +#endif + " " STRINGIFY(BUILD_VERSION) " " KERNEL_VERSION_STRING " " + CONFIG_ARCH " " PROCESSOR_NAME " " CONFIG_BOARD " Zephyr"; + +const uint8_t query_kernel_name[] = "s"; +const uint8_t query_node_name[] = "n"; +const uint8_t query_kernel_release[] = "r"; +const uint8_t query_kernel_version[] = "v"; +const uint8_t query_machine[] = "m"; +const uint8_t query_processor[] = "p"; +const uint8_t query_platform[] = "i"; +const uint8_t query_os[] = "o"; +const uint8_t query_all[] = "a"; +const uint8_t query_test_cmd[] = "k"; + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS +static int32_t os_mgmt_info_custom_os_callback(uint32_t event, int32_t rc, bool *abort_more, + void *data, size_t data_size) +{ + if (event == MGMT_EVT_OP_OS_MGMT_INFO_CHECK) { + struct os_mgmt_info_check *check_data = (struct os_mgmt_info_check *)data; + + *check_data->custom_os_name = true; + } else if (event == MGMT_EVT_OP_OS_MGMT_INFO_APPEND) { + int rc; + struct os_mgmt_info_append *append_data = (struct os_mgmt_info_append *)data; + + if (*append_data->format_bitmask & OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM) { + rc = snprintf(&append_data->output[*append_data->output_length], + (append_data->buffer_size - *append_data->output_length), + "%s%s", (*append_data->prior_output == true ? " " : ""), + CONFIG_CUSTOM_OS_NAME_VALUE); + + if (rc < 0 || + rc >= (append_data->buffer_size - *append_data->output_length)) { + *abort_more = true; + return -1; + } + + *append_data->output_length += (uint16_t)rc; + *append_data->prior_output = true; + *append_data->format_bitmask &= ~OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM; + } + } + + return MGMT_ERR_EOK; +} + +static struct mgmt_callback custom_os_check_callback = { + .callback = os_mgmt_info_custom_os_callback, + .event_id = MGMT_EVT_OP_OS_MGMT_INFO_CHECK, +}; + +static struct mgmt_callback custom_os_append_callback = { + .callback = os_mgmt_info_custom_os_callback, + .event_id = MGMT_EVT_OP_OS_MGMT_INFO_APPEND, +}; + +static int32_t os_mgmt_info_custom_cmd_callback(uint32_t event, int32_t rc, bool *abort_more, + void *data, size_t data_size) +{ + if (event == MGMT_EVT_OP_OS_MGMT_INFO_CHECK) { + struct os_mgmt_info_check *check_data = (struct os_mgmt_info_check *)data; + size_t i = 0; + + while (i < check_data->format->len) { + if (check_data->format->value[i] == query_test_cmd[0]) { + *check_data->format_bitmask |= QUERY_TEST_CMD_BITMASK; + ++(*check_data->valid_formats); + } + + ++i; + } + } else if (event == MGMT_EVT_OP_OS_MGMT_INFO_APPEND) { + int rc; + struct os_mgmt_info_append *append_data = (struct os_mgmt_info_append *)data; + + if (append_data->all_format_specified || + (*append_data->format_bitmask & QUERY_TEST_CMD_BITMASK)) { + rc = snprintf(&append_data->output[*append_data->output_length], + (append_data->buffer_size - *append_data->output_length), + "%sMagic Output for Test", + (*append_data->prior_output == true ? " " : "")); + + if (rc < 0 || + rc >= (append_data->buffer_size - *append_data->output_length)) { + *abort_more = true; + return -1; + } + + *append_data->output_length += (uint16_t)rc; + *append_data->prior_output = true; + *append_data->format_bitmask &= ~QUERY_TEST_CMD_BITMASK; + } + } + + return MGMT_ERR_EOK; +} + +static struct mgmt_callback custom_cmd_check_callback = { + .callback = os_mgmt_info_custom_cmd_callback, + .event_id = MGMT_EVT_OP_OS_MGMT_INFO_CHECK, +}; + +static struct mgmt_callback custom_cmd_append_callback = { + .callback = os_mgmt_info_custom_cmd_callback, + .event_id = MGMT_EVT_OP_OS_MGMT_INFO_APPEND, +}; +#endif + +ZTEST(os_mgmt_info, test_info_1) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(command, sizeof(command)); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + bool received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + zassert_equal(sizeof(expected_response), nb->len, + "Expected to receive %d bytes but got %d\n", sizeof(expected_response), + nb->len); + + zassert_mem_equal(expected_response, nb->data, nb->len, + "Expected received data mismatch"); + + net_buf_unref(nb); + + /* Generate the same command dynamically */ + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, "s", buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Ensure the dynamically-generated size and payload matches the expected payload */ + zassert_equal(sizeof(command), buffer_size, + "Expected received data mismatch"); + zassert_mem_equal(command, buffer_out, sizeof(command), + "Expected received data mismatch"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + zassert_equal(sizeof(expected_response), nb->len, + "Expected to receive %d bytes but got %d\n", sizeof(expected_response), + nb->len); + + zassert_mem_equal(expected_response, nb->data, nb->len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_2_kernel_name) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_kernel_name, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_kernel_name) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_kernel_name) - 1), output.len); + + zassert_mem_equal(response_kernel_name, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_3_node_name) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_node_name, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_node_name) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_node_name) - 1), output.len); + + zassert_mem_equal(response_node_name, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_4_kernel_release) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_kernel_release, buffer, buffer_out, + &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_kernel_release) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_kernel_release) - 1), output.len); + + zassert_mem_equal(response_kernel_release, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_5_kernel_version) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_kernel_version, buffer, buffer_out, + &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_kernel_version) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_kernel_version) - 1), output.len); + + zassert_mem_equal(response_kernel_version, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_6_machine) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_machine, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_machine) - 1), output.len, + "Expected to receive %d bytes but got %d\n", (sizeof(response_machine) - 1), + output.len); + + zassert_mem_equal(response_machine, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_7_processor) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_processor, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_processor) - 1), output.len, + "Expected to receive %d bytes but got %d\n", (sizeof(response_processor) - 1), + output.len); + + zassert_mem_equal(response_processor, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_8_platform) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_platform, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + if (sizeof(CONFIG_BOARD_REVISION) > 1) { + /* Check with board revision */ + zassert_equal((sizeof(response_board_revision) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_board_revision) - 1), output.len); + + zassert_mem_equal(response_board_revision, output.value, output.len, + "Expected received data mismatch"); + } else { + /* Check without board revision */ + zassert_equal((sizeof(response_board) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_board) - 1), output.len); + + zassert_mem_equal(response_board, output.value, output.len, + "Expected received data mismatch"); + } +} + +ZTEST(os_mgmt_info, test_info_9_os) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_os, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_os) - 1), output.len, + "Expected to receive %d bytes but got %d\n", (sizeof(response_os) - 1), + output.len); + + zassert_mem_equal(response_os, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_10_all) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_all, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + if (sizeof(CONFIG_BOARD_REVISION) > 1) { + /* Check with board revision */ + zassert_equal((sizeof(response_all_board_revision) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_all_board_revision) - 1), output.len); + + zassert_mem_equal(response_all_board_revision, output.value, output.len, + "Expected received data mismatch"); + } else { + /* Check without board revision */ + zassert_equal((sizeof(response_all) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_all) - 1), output.len); + + zassert_mem_equal(response_all, output.value, output.len, + "Expected received data mismatch"); + } +} + +ZTEST(os_mgmt_info, test_info_11_multi_1) +{ + uint8_t query[QUERY_BUFFER_SIZE]; + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + /* Construct query for processor, kernel release and OS name */ + sprintf(query, "%s%s%s", query_processor, query_kernel_release, query_os); + ok = create_mcumgr_format_packet(zse, query, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + /* Construct expected response to be compared against */ + sprintf(buffer, "%s %s %s", response_kernel_release, response_processor, response_os); + + zassert_equal(strlen(buffer), output.len, "Expected to receive %d bytes but got %d\n", + strlen(buffer), output.len); + + zassert_mem_equal(buffer, output.value, output.len, "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_12_multi_2) +{ + uint8_t query[QUERY_BUFFER_SIZE]; + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + /* Construct query for node name and kernel version (twice) */ + sprintf(query, "%s%s%s", query_kernel_version, query_node_name, query_kernel_version); + ok = create_mcumgr_format_packet(zse, query, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + /* Construct expected response to be compared against, only 2 responses will be returned + * despite 3 being sent, because 2 were duplicates + */ + sprintf(buffer, "%s %s", response_node_name, response_kernel_version); + + zassert_equal(strlen(buffer), output.len, "Expected to receive %d bytes but got %d\n", + strlen(buffer), output.len); + + zassert_mem_equal(buffer, output.value, output.len, "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info, test_info_13_invalid_1) +{ + uint8_t query[QUERY_BUFFER_SIZE]; + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + /* Construct query for node name with invalid specifier */ + sprintf(query, "%sM", query_kernel_version); + ok = create_mcumgr_format_packet(zse, query, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + /* Ensure only an error is received */ + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to receive EINVAL error but got %d\n", rc); +} + +ZTEST(os_mgmt_info, test_info_14_invalid_2) +{ + uint8_t query[QUERY_BUFFER_SIZE]; + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + /* Construct query for processor with invalid specifier */ + sprintf(query, "2%s", query_processor); + ok = create_mcumgr_format_packet(zse, query, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + /* Ensure only an error is received */ + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to receive EINVAL error but got %d\n", rc); +} + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS +static void *setup_custom_os(void) +{ + mgmt_callback_register(&custom_os_check_callback); + mgmt_callback_register(&custom_os_append_callback); + return NULL; +} + +static void destroy_custom_os(void *p) +{ + mgmt_callback_unregister(&custom_os_check_callback); + mgmt_callback_unregister(&custom_os_append_callback); +} + +ZTEST(os_mgmt_info_custom_os, test_info_os_custom) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_os, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_os_custom) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_os_custom) - 1), output.len); + + zassert_mem_equal(response_os_custom, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info_custom_os_disabled, test_info_os_custom_disabled) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_os, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_os) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_os) - 1), output.len); + + zassert_mem_equal(response_os, output.value, output.len, + "Expected received data mismatch"); +} + +static void *setup_custom_cmd(void) +{ + mgmt_callback_register(&custom_cmd_check_callback); + mgmt_callback_register(&custom_cmd_append_callback); + + return NULL; +} + +static void destroy_custom_cmd(void *p) +{ + mgmt_callback_unregister(&custom_cmd_check_callback); + mgmt_callback_unregister(&custom_cmd_append_callback); +} + +ZTEST(os_mgmt_info_custom_cmd, test_info_cmd_custom) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_test_cmd, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal((sizeof(response_custom_cmd) - 1), output.len, + "Expected to receive %d bytes but got %d\n", + (sizeof(response_custom_cmd) - 1), output.len); + + zassert_mem_equal(response_custom_cmd, output.value, output.len, + "Expected received data mismatch"); +} + +ZTEST(os_mgmt_info_custom_cmd_disabled, test_info_cmd_custom_disabled) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_test_cmd, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to receive EINVAL error but got %d\n", rc); +} + +ZTEST(os_mgmt_info_custom_cmd_disabled_verify, test_info_cmd_custom_disabled) +{ + uint8_t buffer[ZCBOR_BUFFER_SIZE]; + uint8_t buffer_out[OUTPUT_BUFFER_SIZE]; + bool ok; + uint16_t buffer_size; + zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 }; + bool received; + struct zcbor_string output = { 0 }; + size_t decoded = 0; + int32_t rc; + + struct zcbor_map_decode_key_val output_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(output, zcbor_tstr_decode, &output), + }; + + struct zcbor_map_decode_key_val error_decode[] = { + ZCBOR_MAP_DECODE_KEY_VAL(rc, zcbor_int32_decode, &rc), + }; + + memset(buffer, 0, sizeof(buffer)); + memset(buffer_out, 0, sizeof(buffer_out)); + buffer_size = 0; + memset(zse, 0, sizeof(zse)); + memset(zsd, 0, sizeof(zsd)); + + zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0); + + ok = create_mcumgr_format_packet(zse, query_test_cmd, buffer, buffer_out, &buffer_size); + zassert_true(ok, "Expected packet creation to be successful\n"); + + /* Enable dummy SMP backend and ready for usage */ + smp_dummy_enable(); + smp_dummy_clear_state(); + + /* Send query command to dummy SMP backend */ + (void)smp_dummy_tx_pkt(buffer_out, buffer_size); + smp_dummy_add_data(); + + /* For a short duration to see if response has been received */ + received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME); + + zassert_true(received, "Expected to receive data but timed out\n"); + + /* Retrieve response buffer and ensure validity */ + nb = smp_dummy_get_outgoing(); + smp_dummy_disable(); + + /* Process received data by removing header */ + (void)net_buf_pull(nb, sizeof(struct smp_hdr)); + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + + ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 0, "Expected to receive 0 decoded zcbor element\n"); + + zcbor_new_decode_state(zsd, 3, nb->data, nb->len, 1); + ok = zcbor_map_decode_bulk(zsd, error_decode, ARRAY_SIZE(error_decode), &decoded) == 0; + + zassert_true(ok, "Expected decode to be successful\n"); + zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element\n"); + + zassert_equal(output.len, 0, "Expected to receive 0 bytes but got %d\n", output.len); + + zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to receive EINVAL error but got %d\n", rc); + +} +#endif + +static void cleanup_test(void *p) +{ + if (nb != NULL) { + net_buf_unref(nb); + nb = NULL; + } +} + +void test_main(void) +{ + /* Register os_mgmt mcumgr group */ + os_mgmt_register_group(); + + while (test_state.test_set < OS_MGMT_TEST_SET_COUNT) { + ztest_run_all(&test_state); + ++test_state.test_set; + } + + ztest_verify_all_test_suites_ran(); +} + +static bool main_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_MAIN; +} + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS +static bool custom_os_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_OS; +} + +static bool custom_os_disabled_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_OS_DISABLED; +} + +static bool custom_cmd_disabled_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_CMD_DISABLED; +} + +static bool custom_cmd_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_CMD; +} + +static bool custom_cmd_disabled_verify_predicate(const void *state) +{ + return ((struct state *)state)->test_set == OS_MGMT_TEST_SET_CUSTOM_CMD_DISABLED_VERIFY; +} +#endif + +/* Main test set */ +ZTEST_SUITE(os_mgmt_info, main_predicate, NULL, NULL, cleanup_test, NULL); + +#ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS +/* Custom OS test set */ +ZTEST_SUITE(os_mgmt_info_custom_os, custom_os_predicate, setup_custom_os, NULL, cleanup_test, + destroy_custom_os); +ZTEST_SUITE(os_mgmt_info_custom_os_disabled, custom_os_disabled_predicate, NULL, NULL, + cleanup_test, NULL); + +/* Custom cmd test set */ +ZTEST_SUITE(os_mgmt_info_custom_cmd_disabled, custom_cmd_disabled_predicate, NULL, NULL, + cleanup_test, NULL); +ZTEST_SUITE(os_mgmt_info_custom_cmd, custom_cmd_predicate, setup_custom_cmd, NULL, cleanup_test, + destroy_custom_cmd); +ZTEST_SUITE(os_mgmt_info_custom_cmd_disabled_verify, custom_cmd_disabled_verify_predicate, NULL, + NULL, cleanup_test, NULL); +#endif + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c new file mode 100644 index 0000000000000..c1dcded0ff68b --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "smp_test_util.h" +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt info command header with sequence number set to 1 */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len) +{ + *rsp_hdr = (struct smp_hdr) { + .nh_len = sys_cpu_to_be16(len), + .nh_flags = 0, + .nh_op = 0, + .nh_group = sys_cpu_to_be16(MGMT_GROUP_ID_OS), + .nh_seq = 1, + .nh_id = OS_MGMT_ID_INFO, + }; +} + +/* Function for creating an os_mgmt info command */ +bool create_mcumgr_format_packet(zcbor_state_t *zse, const uint8_t *format, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size) +{ + bool ok; + + ok = zcbor_map_start_encode(zse, 2) && + zcbor_tstr_put_lit(zse, "format") && + zcbor_tstr_put_term(zse, format) && + zcbor_map_end_encode(zse, 2); + + *buffer_size = (zse->payload_mut - buffer); + smp_make_hdr((struct smp_hdr *)output_buffer, *buffer_size); + memcpy(&output_buffer[sizeof(struct smp_hdr)], buffer, *buffer_size); + *buffer_size += sizeof(struct smp_hdr); + + return ok; +} diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.h b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.h new file mode 100644 index 0000000000000..1b28b850781ba --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/src/smp_test_util.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef H_SMP_TEST_UTIL_ +#define H_SMP_TEST_UTIL_ + +#include +#include +#include +#include + +/* SMP header function for generating os_mgmt info command header with sequence number set to 1 */ +void smp_make_hdr(struct smp_hdr *rsp_hdr, size_t len); + +/* Function for creating an os_mgmt info command */ +bool create_mcumgr_format_packet(zcbor_state_t *zse, const uint8_t *format, uint8_t *buffer, + uint8_t *output_buffer, uint16_t *buffer_size); + + +#endif diff --git a/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml b/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml new file mode 100644 index 0000000000000..4ff0292b6da94 --- /dev/null +++ b/tests/subsys/mgmt/mcumgr/os_mgmt_info/testcase.yaml @@ -0,0 +1,57 @@ +# +# Copyright (c) 2022 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +tests: + os.mgmt.info: + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + os.mgmt.info_no_hooks: + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + extra_configs: + - CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS=n + - CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=n + os.mgmt.info_bt: + depends_on: ble + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + extra_configs: + - CONFIG_BT=y + - CONFIG_BT_DEVICE_NAME="a_bt_name" + os.mgmt.info_net: + depends_on: netif + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + platform_exclude: qemu_cortex_a9 qemu_x86 qemu_riscv64_smp qemu_riscv64 qemu_riscv32e + qemu_riscv32 qemu_riscv32_smp qemu_cortex_m3 mps2_an385 + tags: os_mgmt_info + extra_configs: + - CONFIG_NETWORKING=y + - CONFIG_NET_HOSTNAME_ENABLE=y + - CONFIG_NET_HOSTNAME="test_net_name" + - CONFIG_TEST_RANDOM_GENERATOR=y + os.mgmt.info_build_date: + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + extra_configs: + - CONFIG_BUILD_DATE_TIME_TEST=y + os.mgmt.info_limited_size: + # FIXME: Exclude architectures that lack a reboot handler function + # FIXME: Exclude systems whereby the processor type is not known and emits a warning + arch_exclude: arm64 nios2 sparc arc xtensa mips posix + tags: os_mgmt_info + extra_configs: + - CONFIG_LIMITED_TEST=y + - CONFIG_MCUMGR_SMP_DUMMY_RX_BUF_SIZE=64 + - CONFIG_MCUMGR_GRP_OS_INFO_MAX_RESPONSE_SIZE=32 From 8f4730b74ccebeabbc98c669c8bfee39638a6138 Mon Sep 17 00:00:00 2001 From: Jamie McCrae Date: Tue, 18 Oct 2022 13:26:50 +0100 Subject: [PATCH 5/5] mgmt: mcumgr: transport: dummy: Fix issue with large packets Fixes an issue with large packets being received, these packets are chunked into 127-byte frames for the serial transport but this system is not needed for the dummy transport as it has a fixed size buffer. Signed-off-by: Jamie McCrae --- subsys/mgmt/mcumgr/transport/src/smp_dummy.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/mgmt/mcumgr/transport/src/smp_dummy.c b/subsys/mgmt/mcumgr/transport/src/smp_dummy.c index 4df3fcb4dc82b..a74c1c5a35189 100644 --- a/subsys/mgmt/mcumgr/transport/src/smp_dummy.c +++ b/subsys/mgmt/mcumgr/transport/src/smp_dummy.c @@ -11,6 +11,7 @@ /* Define required for uart_mcumgr.h functionality reuse */ #define CONFIG_UART_MCUMGR_RX_BUF_SIZE CONFIG_MCUMGR_SMP_DUMMY_RX_BUF_SIZE +#define MCUMGR_DUMMY_MAX_FRAME CONFIG_MCUMGR_SMP_DUMMY_RX_BUF_SIZE #include #include @@ -581,7 +582,7 @@ int mcumgr_dummy_tx_frame(const uint8_t *data, bool first, int len, } while (1) { - if (dst_off >= MCUMGR_SERIAL_MAX_FRAME - 4) { + if (dst_off >= MCUMGR_DUMMY_MAX_FRAME - 4) { /* Can't fit any more data in this frame. */ break; }