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 75d9dc75185..cd474b247bb 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 1cd6c94a46f..aeca99ef20c 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 82e7a3a6eeb..e0a5bce58c5 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 381ac6c42de..df47d9c1759 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 00000000000..a44b9ab269f --- /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 46de3369fb8..869f9e90f4d 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)