1 /*
2 * Copyright (c) 2018-2021 mcumgr authors
3 * Copyright (c) 2021-2024 Nordic Semiconductor ASA
4 * Copyright (c) 2022 Laird Connectivity
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/sys/util.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/debug/object_tracing.h>
12 #include <zephyr/kernel_structs.h>
13 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
14 #include <zephyr/mgmt/mcumgr/smp/smp.h>
15 #include <zephyr/mgmt/mcumgr/mgmt/handlers.h>
16 #include <zephyr/mgmt/mcumgr/grp/os_mgmt/os_mgmt.h>
17 #include <zephyr/logging/log.h>
18 #include <assert.h>
19 #include <string.h>
20 #include <stdio.h>
21
22 #include <zcbor_common.h>
23 #include <zcbor_encode.h>
24 #include <zcbor_decode.h>
25
26 #include <mgmt/mcumgr/util/zcbor_bulk.h>
27
28 #ifdef CONFIG_REBOOT
29 #include <zephyr/sys/reboot.h>
30 #endif
31
32 #ifdef CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS
33 #include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
34 #endif
35
36 #ifdef CONFIG_MCUMGR_GRP_OS_DATETIME
37 #include <stdlib.h>
38 #include <zephyr/drivers/rtc.h>
39 #endif
40
41 #if defined(CONFIG_MCUMGR_GRP_OS_INFO) || defined(CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO)
42 #include <stdio.h>
43 #include <zephyr/version.h>
44 #if defined(CONFIG_MCUMGR_GRP_OS_INFO)
45 #include <os_mgmt_processor.h>
46 #endif
47 #if defined(CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO)
48 #include <bootutil/boot_status.h>
49 #endif
50 #include <mgmt/mcumgr/util/zcbor_bulk.h>
51 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
52 #include <zephyr/net/hostname.h>
53 #elif defined(CONFIG_BT)
54 #include <zephyr/bluetooth/bluetooth.h>
55 #endif
56 #endif
57
58 #ifdef CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE
59 #include <zephyr/retention/bootmode.h>
60 #include <limits.h>
61 #endif
62
63 LOG_MODULE_REGISTER(mcumgr_os_grp, CONFIG_MCUMGR_GRP_OS_LOG_LEVEL);
64
65 #if defined(CONFIG_REBOOT) && defined(CONFIG_MULTITHREADING)
66 static void os_mgmt_reset_work_handler(struct k_work *work);
67
68 static K_WORK_DELAYABLE_DEFINE(os_mgmt_reset_work, os_mgmt_reset_work_handler);
69 #endif
70
71 /* This is passed to zcbor_map_start/end_endcode as a number of
72 * expected "columns" (tid, priority, and so on)
73 * The value here does not affect memory allocation is used
74 * to predict how big the map may be. If you increase number
75 * of "columns" the taskstat sends you may need to increase the
76 * value otherwise zcbor_map_end_encode may return with error.
77 */
78 #define TASKSTAT_COLUMNS_MAX 20
79
80 #ifdef CONFIG_MCUMGR_GRP_OS_TASKSTAT
81 /* Thread iterator information passing structure */
82 struct thread_iterator_info {
83 zcbor_state_t *zse;
84 int thread_idx;
85 bool ok;
86 };
87 #endif
88
89 #ifdef CONFIG_MCUMGR_GRP_OS_DATETIME
90 /* Iterator for extracting values from the provided datetime string, min and max values are
91 * checked against the provided value, then the offset is added after. If the value is not
92 * within the min and max values, the set operation will be aborted.
93 */
94 struct datetime_parser {
95 int *value;
96 int min_value;
97 int max_value;
98 int offset;
99 };
100
101 /* RTC device alias to use for datetime functions, "rtc" */
102 #define RTC_DEVICE DEVICE_DT_GET(DT_ALIAS(rtc))
103
104 #define RTC_DATETIME_YEAR_OFFSET 1900
105 #define RTC_DATETIME_MONTH_OFFSET 1
106 #define RTC_DATETIME_NUMERIC_BASE 10
107 #define RTC_DATETIME_MS_TO_NS 1000000
108 #define RTC_DATETIME_YEAR_MIN 1900
109 #define RTC_DATETIME_YEAR_MAX 11899
110 #define RTC_DATETIME_MONTH_MIN 1
111 #define RTC_DATETIME_MONTH_MAX 12
112 #define RTC_DATETIME_DAY_MIN 1
113 #define RTC_DATETIME_DAY_MAX 31
114 #define RTC_DATETIME_HOUR_MIN 0
115 #define RTC_DATETIME_HOUR_MAX 23
116 #define RTC_DATETIME_MINUTE_MIN 0
117 #define RTC_DATETIME_MINUTE_MAX 59
118 #define RTC_DATETIME_SECOND_MIN 0
119 #define RTC_DATETIME_SECOND_MAX 59
120 #define RTC_DATETIME_MILLISECOND_MIN 0
121 #define RTC_DATETIME_MILLISECOND_MAX 999
122
123 /* Size used for datetime creation buffer */
124 #ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS
125 #define RTC_DATETIME_STRING_SIZE 32
126 #else
127 #define RTC_DATETIME_STRING_SIZE 26
128 #endif
129
130 /* Minimum/maximum size of a datetime string that a client can provide */
131 #define RTC_DATETIME_MIN_STRING_SIZE 19
132 #define RTC_DATETIME_MAX_STRING_SIZE 26
133 #endif
134
135 /* Specifies what the "all" ('a') of info parameter shows */
136 #define OS_MGMT_INFO_FORMAT_ALL \
137 OS_MGMT_INFO_FORMAT_KERNEL_NAME | OS_MGMT_INFO_FORMAT_NODE_NAME | \
138 OS_MGMT_INFO_FORMAT_KERNEL_RELEASE | OS_MGMT_INFO_FORMAT_KERNEL_VERSION | \
139 (IS_ENABLED(CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME) ? \
140 OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME : 0) | \
141 OS_MGMT_INFO_FORMAT_MACHINE | OS_MGMT_INFO_FORMAT_PROCESSOR | \
142 OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM | OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM
143
144 #ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
145 extern uint8_t *MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME;
146 #endif
147
148 /**
149 * Command handler: os echo
150 */
151 #ifdef CONFIG_MCUMGR_GRP_OS_ECHO
os_mgmt_echo(struct smp_streamer * ctxt)152 static int os_mgmt_echo(struct smp_streamer *ctxt)
153 {
154 bool ok;
155 zcbor_state_t *zsd = ctxt->reader->zs;
156 zcbor_state_t *zse = ctxt->writer->zs;
157 struct zcbor_string data = { 0 };
158 size_t decoded;
159
160 struct zcbor_map_decode_key_val echo_decode[] = {
161 ZCBOR_MAP_DECODE_KEY_DECODER("d", zcbor_tstr_decode, &data),
162 };
163
164 ok = zcbor_map_decode_bulk(zsd, echo_decode, ARRAY_SIZE(echo_decode), &decoded) == 0;
165
166 if (!ok) {
167 return MGMT_ERR_EINVAL;
168 }
169
170 ok = zcbor_tstr_put_lit(zse, "r") &&
171 zcbor_tstr_encode(zse, &data);
172
173 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
174 }
175 #endif
176
177 #ifdef CONFIG_MCUMGR_GRP_OS_TASKSTAT
178
179 #ifdef CONFIG_MCUMGR_GRP_OS_TASKSTAT_USE_THREAD_NAME_FOR_NAME
180 static inline bool
os_mgmt_taskstat_encode_thread_name(zcbor_state_t * zse,int idx,const struct k_thread * thread)181 os_mgmt_taskstat_encode_thread_name(zcbor_state_t *zse, int idx,
182 const struct k_thread *thread)
183 {
184 size_t name_len = strlen(thread->name);
185
186 ARG_UNUSED(idx);
187
188 if (name_len > CONFIG_MCUMGR_GRP_OS_TASKSTAT_THREAD_NAME_LEN) {
189 name_len = CONFIG_MCUMGR_GRP_OS_TASKSTAT_THREAD_NAME_LEN;
190 }
191
192 return zcbor_tstr_encode_ptr(zse, thread->name, name_len);
193 }
194
195 #else
196 static inline bool
os_mgmt_taskstat_encode_thread_name(zcbor_state_t * zse,int idx,const struct k_thread * thread)197 os_mgmt_taskstat_encode_thread_name(zcbor_state_t *zse, int idx,
198 const struct k_thread *thread)
199 {
200 char thread_name[CONFIG_MCUMGR_GRP_OS_TASKSTAT_THREAD_NAME_LEN + 1];
201
202 #if defined(CONFIG_MCUMGR_GRP_OS_TASKSTAT_USE_THREAD_PRIO_FOR_NAME)
203 idx = (int)thread->base.prio;
204 #elif defined(CONFIG_MCUMGR_GRP_OS_TASKSTAT_USE_THREAD_IDX_FOR_NAME)
205 ARG_UNUSED(thread);
206 #else
207 #error Unsupported option for taskstat thread name
208 #endif
209
210 snprintf(thread_name, sizeof(thread_name) - 1, "%d", idx);
211 thread_name[sizeof(thread_name) - 1] = 0;
212
213 return zcbor_tstr_put_term(zse, thread_name, sizeof(thread_name));
214 }
215
216 #endif
217
218 static inline bool
os_mgmt_taskstat_encode_stack_info(zcbor_state_t * zse,const struct k_thread * thread)219 os_mgmt_taskstat_encode_stack_info(zcbor_state_t *zse,
220 const struct k_thread *thread)
221 {
222 #ifdef CONFIG_MCUMGR_GRP_OS_TASKSTAT_STACK_INFO
223 size_t stack_size = 0;
224 size_t stack_used = 0;
225 bool ok = true;
226
227 #ifdef CONFIG_THREAD_STACK_INFO
228 stack_size = thread->stack_info.size / 4;
229
230 #ifdef CONFIG_INIT_STACKS
231 unsigned int stack_unused;
232
233 if (k_thread_stack_space_get(thread, &stack_unused) == 0) {
234 stack_used = (thread->stack_info.size - stack_unused) / 4;
235 }
236 #endif /* CONFIG_INIT_STACKS */
237 #endif /* CONFIG_THREAD_STACK_INFO */
238 ok = zcbor_tstr_put_lit(zse, "stksiz") &&
239 zcbor_uint64_put(zse, stack_size) &&
240 zcbor_tstr_put_lit(zse, "stkuse") &&
241 zcbor_uint64_put(zse, stack_used);
242
243 return ok;
244 #else
245 return true;
246 #endif /* CONFIG_MCUMGR_GRP_OS_TASKSTAT_STACK_INFO */
247 }
248
249 static inline bool
os_mgmt_taskstat_encode_runtime_info(zcbor_state_t * zse,const struct k_thread * thread)250 os_mgmt_taskstat_encode_runtime_info(zcbor_state_t *zse,
251 const struct k_thread *thread)
252 {
253 bool ok = true;
254
255 #if defined(CONFIG_SCHED_THREAD_USAGE)
256 k_thread_runtime_stats_t thread_stats;
257
258 k_thread_runtime_stats_get((struct k_thread *)thread, &thread_stats);
259
260 ok = zcbor_tstr_put_lit(zse, "runtime") &&
261 zcbor_uint64_put(zse, thread_stats.execution_cycles);
262 #elif !defined(CONFIG_MCUMGR_GRP_OS_TASKSTAT_ONLY_SUPPORTED_STATS)
263 ok = zcbor_tstr_put_lit(zse, "runtime") &&
264 zcbor_uint32_put(zse, 0);
265 #endif
266
267 return ok;
268 }
269
os_mgmt_taskstat_encode_unsupported(zcbor_state_t * zse)270 static inline bool os_mgmt_taskstat_encode_unsupported(zcbor_state_t *zse)
271 {
272 bool ok = true;
273
274 if (!IS_ENABLED(CONFIG_MCUMGR_GRP_OS_TASKSTAT_ONLY_SUPPORTED_STATS)) {
275 ok = zcbor_tstr_put_lit(zse, "cswcnt") &&
276 zcbor_uint32_put(zse, 0) &&
277 zcbor_tstr_put_lit(zse, "last_checkin") &&
278 zcbor_uint32_put(zse, 0) &&
279 zcbor_tstr_put_lit(zse, "next_checkin") &&
280 zcbor_uint32_put(zse, 0);
281 } else {
282 ARG_UNUSED(zse);
283 }
284
285 return ok;
286 }
287
288 static inline bool
os_mgmt_taskstat_encode_priority(zcbor_state_t * zse,const struct k_thread * thread)289 os_mgmt_taskstat_encode_priority(zcbor_state_t *zse, const struct k_thread *thread)
290 {
291 return (zcbor_tstr_put_lit(zse, "prio") &&
292 IS_ENABLED(CONFIG_MCUMGR_GRP_OS_TASKSTAT_SIGNED_PRIORITY) ?
293 zcbor_int32_put(zse, (int)thread->base.prio) :
294 zcbor_uint32_put(zse, (unsigned int)thread->base.prio) & 0xff);
295 }
296
297 /**
298 * Encodes a single taskstat entry.
299 */
os_mgmt_taskstat_encode_one(const struct k_thread * thread,void * user_data)300 static void os_mgmt_taskstat_encode_one(const struct k_thread *thread, void *user_data)
301 {
302 /*
303 * Threads are sent as map where thread name is key and value is map
304 * of thread parameters
305 */
306 struct thread_iterator_info *iterator_ctx = (struct thread_iterator_info *)user_data;
307
308 if (iterator_ctx->ok == true) {
309 iterator_ctx->ok =
310 os_mgmt_taskstat_encode_thread_name(iterator_ctx->zse,
311 iterator_ctx->thread_idx, thread) &&
312 zcbor_map_start_encode(iterator_ctx->zse, TASKSTAT_COLUMNS_MAX) &&
313 os_mgmt_taskstat_encode_priority(iterator_ctx->zse, thread) &&
314 zcbor_tstr_put_lit(iterator_ctx->zse, "tid") &&
315 zcbor_uint32_put(iterator_ctx->zse, iterator_ctx->thread_idx) &&
316 zcbor_tstr_put_lit(iterator_ctx->zse, "state") &&
317 zcbor_uint32_put(iterator_ctx->zse, thread->base.thread_state) &&
318 os_mgmt_taskstat_encode_stack_info(iterator_ctx->zse, thread) &&
319 os_mgmt_taskstat_encode_runtime_info(iterator_ctx->zse, thread) &&
320 os_mgmt_taskstat_encode_unsupported(iterator_ctx->zse) &&
321 zcbor_map_end_encode(iterator_ctx->zse, TASKSTAT_COLUMNS_MAX);
322
323 ++iterator_ctx->thread_idx;
324 }
325 }
326
327 /**
328 * Command handler: os taskstat
329 */
os_mgmt_taskstat_read(struct smp_streamer * ctxt)330 static int os_mgmt_taskstat_read(struct smp_streamer *ctxt)
331 {
332 zcbor_state_t *zse = ctxt->writer->zs;
333 struct thread_iterator_info iterator_ctx = {
334 .zse = zse,
335 .thread_idx = 0,
336 .ok = true,
337 };
338
339 zcbor_tstr_put_lit(zse, "tasks");
340 zcbor_map_start_encode(zse, CONFIG_MCUMGR_GRP_OS_TASKSTAT_MAX_NUM_THREADS);
341
342 /* Iterate the list of tasks, encoding each. */
343 k_thread_foreach(os_mgmt_taskstat_encode_one, (void *)&iterator_ctx);
344
345 if (!iterator_ctx.ok) {
346 LOG_ERR("Task iterator status is not OK");
347 }
348
349 if (!iterator_ctx.ok ||
350 !zcbor_map_end_encode(zse, CONFIG_MCUMGR_GRP_OS_TASKSTAT_MAX_NUM_THREADS)) {
351 return MGMT_ERR_EMSGSIZE;
352 }
353
354 return 0;
355 }
356 #endif /* CONFIG_MCUMGR_GRP_OS_TASKSTAT */
357
358 #ifdef CONFIG_REBOOT
359 /**
360 * Command handler: os reset
361 */
362 #ifdef CONFIG_MULTITHREADING
os_mgmt_reset_work_handler(struct k_work * work)363 static void os_mgmt_reset_work_handler(struct k_work *work)
364 {
365 ARG_UNUSED(work);
366
367 sys_reboot(SYS_REBOOT_WARM);
368 }
369 #endif
370
os_mgmt_reset(struct smp_streamer * ctxt)371 static int os_mgmt_reset(struct smp_streamer *ctxt)
372 {
373 #if defined(CONFIG_MCUMGR_GRP_OS_RESET_HOOK)
374 zcbor_state_t *zsd = ctxt->reader->zs;
375 zcbor_state_t *zse = ctxt->writer->zs;
376 size_t decoded;
377 enum mgmt_cb_return status;
378 int32_t err_rc;
379 uint16_t err_group;
380
381 #ifdef CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE
382 uint32_t boot_mode = BOOT_MODE_TYPE_NORMAL;
383 #endif
384
385 struct os_mgmt_reset_data reboot_data = {
386 .force = false
387 };
388
389 struct zcbor_map_decode_key_val reset_decode[] = {
390 ZCBOR_MAP_DECODE_KEY_DECODER("force", zcbor_bool_decode, &reboot_data.force),
391 #ifdef CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE
392 ZCBOR_MAP_DECODE_KEY_DECODER("boot_mode", zcbor_uint32_decode, &boot_mode),
393 #endif
394 };
395
396 /* Since this is a core command, if we fail to decode the data, ignore the error and
397 * continue with the default parameters.
398 */
399 (void)zcbor_map_decode_bulk(zsd, reset_decode, ARRAY_SIZE(reset_decode), &decoded);
400
401 #ifdef CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE
402 if (zcbor_map_decode_bulk_key_found(reset_decode, ARRAY_SIZE(reset_decode), "boot_mode")) {
403 if (boot_mode > UCHAR_MAX) {
404 return MGMT_ERR_EINVAL;
405 }
406
407 reboot_data.boot_mode = (uint8_t)boot_mode;
408 } else {
409 reboot_data.boot_mode = BOOT_MODE_TYPE_NORMAL;
410 }
411 #endif
412
413 status = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_RESET, &reboot_data,
414 sizeof(reboot_data), &err_rc, &err_group);
415
416 if (status != MGMT_CB_OK) {
417 bool ok;
418
419 if (status == MGMT_CB_ERROR_RC) {
420 return err_rc;
421 }
422
423 ok = smp_add_cmd_err(zse, err_group, (uint16_t)err_rc);
424 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
425 }
426 #elif defined(CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE)
427 zcbor_state_t *zsd = ctxt->reader->zs;
428 size_t decoded;
429 uint32_t boot_mode;
430
431 struct zcbor_map_decode_key_val reset_decode[] = {
432 ZCBOR_MAP_DECODE_KEY_DECODER("boot_mode", zcbor_uint32_decode, &boot_mode),
433 };
434
435 /* Since this is a core command, if we fail to decode the data, ignore the error and
436 * continue with the default parameters.
437 */
438 (void)zcbor_map_decode_bulk(zsd, reset_decode, ARRAY_SIZE(reset_decode), &decoded);
439
440 if (zcbor_map_decode_bulk_key_found(reset_decode, ARRAY_SIZE(reset_decode), "boot_mode")) {
441 if (boot_mode > UCHAR_MAX) {
442 return MGMT_ERR_EINVAL;
443 }
444 }
445 #endif
446
447 #if defined(CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE)
448 if (zcbor_map_decode_bulk_key_found(reset_decode, ARRAY_SIZE(reset_decode), "boot_mode")) {
449 (void)bootmode_set((uint8_t)boot_mode);
450 }
451 #endif
452
453 #ifdef CONFIG_MULTITHREADING
454 /* Reboot the system from the system workqueue thread. */
455 k_work_schedule(&os_mgmt_reset_work, K_MSEC(CONFIG_MCUMGR_GRP_OS_RESET_MS));
456 #else
457 sys_reboot(SYS_REBOOT_WARM);
458 #endif
459
460 return 0;
461 }
462 #endif
463
464 #ifdef CONFIG_MCUMGR_GRP_OS_MCUMGR_PARAMS
465 static int
os_mgmt_mcumgr_params(struct smp_streamer * ctxt)466 os_mgmt_mcumgr_params(struct smp_streamer *ctxt)
467 {
468 zcbor_state_t *zse = ctxt->writer->zs;
469 bool ok;
470
471 ok = zcbor_tstr_put_lit(zse, "buf_size") &&
472 zcbor_uint32_put(zse, CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE) &&
473 zcbor_tstr_put_lit(zse, "buf_count") &&
474 zcbor_uint32_put(zse, CONFIG_MCUMGR_TRANSPORT_NETBUF_COUNT);
475
476 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
477 }
478 #endif
479
480 #if defined(CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO)
481
482 #if defined(CONFIG_BOOTLOADER_MCUBOOT)
483 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SINGLE_APP)
484 #define BOOTLOADER_MODE MCUBOOT_MODE_SINGLE_SLOT
485 #elif defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH)
486 #define BOOTLOADER_MODE MCUBOOT_MODE_SWAP_USING_SCRATCH
487 #elif defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY)
488 #define BOOTLOADER_MODE MCUBOOT_MODE_UPGRADE_ONLY
489 #elif defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET)
490 #define BOOTLOADER_MODE MCUBOOT_MODE_SWAP_USING_OFFSET
491 #elif defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_MOVE) || \
492 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH)
493 #define BOOTLOADER_MODE MCUBOOT_MODE_SWAP_USING_MOVE
494 #elif defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP)
495 #define BOOTLOADER_MODE MCUBOOT_MODE_DIRECT_XIP
496 #elif defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)
497 #define BOOTLOADER_MODE MCUBOOT_MODE_DIRECT_XIP_WITH_REVERT
498 #elif defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_FIRMWARE_UPDATER)
499 #define BOOTLOADER_MODE MCUBOOT_MODE_FIRMWARE_LOADER
500 #else
501 #define BOOTLOADER_MODE -1
502 #endif
503 #endif
504
505 static int
os_mgmt_bootloader_info(struct smp_streamer * ctxt)506 os_mgmt_bootloader_info(struct smp_streamer *ctxt)
507 {
508 zcbor_state_t *zse = ctxt->writer->zs;
509 zcbor_state_t *zsd = ctxt->reader->zs;
510 struct zcbor_string query = { 0 };
511 size_t decoded;
512 bool ok = true;
513 bool has_output = false;
514
515 #if defined(CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO_HOOK)
516 enum mgmt_cb_return status;
517 int32_t err_rc;
518 uint16_t err_group;
519 struct os_mgmt_bootloader_info_data bootloader_info_data = {
520 .zse = zse,
521 .decoded = &decoded,
522 .query = &query,
523 .has_output = &has_output
524 };
525 #endif
526
527 struct zcbor_map_decode_key_val bootloader_info[] = {
528 ZCBOR_MAP_DECODE_KEY_DECODER("query", zcbor_tstr_decode, &query),
529 };
530
531 if (zcbor_map_decode_bulk(zsd, bootloader_info, ARRAY_SIZE(bootloader_info), &decoded)) {
532 return MGMT_ERR_EINVAL;
533 }
534
535 #if defined(CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO_HOOK)
536 status = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_BOOTLOADER_INFO, &bootloader_info_data,
537 sizeof(bootloader_info_data), &err_rc, &err_group);
538
539 if (status != MGMT_CB_OK) {
540 if (status == MGMT_CB_ERROR_RC) {
541 return err_rc;
542 }
543
544 ok = smp_add_cmd_err(zse, err_group, (uint16_t)err_rc);
545
546 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
547 }
548 #endif
549
550 /* If no parameter is recognized then just introduce the bootloader. */
551 if (!has_output) {
552 #if defined(CONFIG_BOOTLOADER_MCUBOOT)
553 if (decoded == 0) {
554 ok = zcbor_tstr_put_lit(zse, "bootloader") &&
555 zcbor_tstr_put_lit(zse, "MCUboot");
556 has_output = true;
557 } else if (zcbor_map_decode_bulk_key_found(bootloader_info,
558 ARRAY_SIZE(bootloader_info),
559 "query") && (sizeof("mode") - 1) == query.len &&
560 memcmp("mode", query.value, query.len) == 0) {
561
562 ok = zcbor_tstr_put_lit(zse, "mode") &&
563 zcbor_int32_put(zse, BOOTLOADER_MODE);
564 #ifdef CONFIG_MCUBOOT_BOOTLOADER_NO_DOWNGRADE
565 ok = ok && zcbor_tstr_put_lit(zse, "no-downgrade") &&
566 zcbor_bool_encode(zse, &(bool){true});
567 #endif
568 has_output = true;
569 }
570 #endif
571 }
572
573 if (!has_output) {
574 ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_OS, OS_MGMT_ERR_QUERY_YIELDS_NO_ANSWER);
575 }
576
577 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
578 }
579 #endif
580
581 #ifdef CONFIG_MCUMGR_GRP_OS_INFO
582 /**
583 * Command handler: os info
584 */
os_mgmt_info(struct smp_streamer * ctxt)585 static int os_mgmt_info(struct smp_streamer *ctxt)
586 {
587 struct zcbor_string format = { 0 };
588 uint8_t output[CONFIG_MCUMGR_GRP_OS_INFO_MAX_RESPONSE_SIZE] = { 0 };
589 zcbor_state_t *zse = ctxt->writer->zs;
590 zcbor_state_t *zsd = ctxt->reader->zs;
591 uint32_t format_bitmask = 0;
592 bool prior_output = false;
593 size_t i = 0;
594 size_t decoded;
595 bool custom_os_name = false;
596 int rc;
597 uint16_t output_length = 0;
598 uint16_t valid_formats = 0;
599
600 struct zcbor_map_decode_key_val fs_info_decode[] = {
601 ZCBOR_MAP_DECODE_KEY_DECODER("format", zcbor_tstr_decode, &format),
602 };
603
604 #ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
605 struct os_mgmt_info_check check_data = {
606 .format = &format,
607 .format_bitmask = &format_bitmask,
608 .valid_formats = &valid_formats,
609 .custom_os_name = &custom_os_name,
610 };
611
612 struct os_mgmt_info_append append_data = {
613 .format_bitmask = &format_bitmask,
614 .all_format_specified = false,
615 .output = output,
616 .output_length = &output_length,
617 .buffer_size = sizeof(output),
618 .prior_output = &prior_output,
619 };
620 #endif
621
622 #ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
623 enum mgmt_cb_return status;
624 int32_t err_rc;
625 uint16_t err_group;
626 #endif
627
628 if (zcbor_map_decode_bulk(zsd, fs_info_decode, ARRAY_SIZE(fs_info_decode), &decoded)) {
629 return MGMT_ERR_EINVAL;
630 }
631
632 /* Process all input characters in format value */
633 while (i < format.len) {
634 switch (format.value[i]) {
635 case 'a': {
636 #ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
637 append_data.all_format_specified = true;
638 #endif
639
640 format_bitmask = OS_MGMT_INFO_FORMAT_ALL;
641 ++valid_formats;
642 break;
643 }
644 case 's': {
645 format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_NAME;
646 ++valid_formats;
647 break;
648 }
649 case 'n': {
650 format_bitmask |= OS_MGMT_INFO_FORMAT_NODE_NAME;
651 ++valid_formats;
652 break;
653 }
654 case 'r': {
655 format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_RELEASE;
656 ++valid_formats;
657 break;
658 }
659 case 'v': {
660 format_bitmask |= OS_MGMT_INFO_FORMAT_KERNEL_VERSION;
661 ++valid_formats;
662 break;
663 }
664 #ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
665 case 'b': {
666 format_bitmask |= OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME;
667 ++valid_formats;
668 break;
669 }
670 #endif
671 case 'm': {
672 format_bitmask |= OS_MGMT_INFO_FORMAT_MACHINE;
673 ++valid_formats;
674 break;
675 }
676 case 'p': {
677 format_bitmask |= OS_MGMT_INFO_FORMAT_PROCESSOR;
678 ++valid_formats;
679 break;
680 }
681 case 'i': {
682 format_bitmask |= OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM;
683 ++valid_formats;
684 break;
685 }
686 case 'o': {
687 format_bitmask |= OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM;
688 ++valid_formats;
689 break;
690 }
691 default: {
692 break;
693 }
694 }
695
696 ++i;
697 }
698
699 #ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
700 /* Run callbacks to see if any additional handlers will add options */
701 (void)mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_INFO_CHECK, &check_data,
702 sizeof(check_data), &err_rc, &err_group);
703 #endif
704
705 if (valid_formats != format.len) {
706 /* A provided format specifier is not valid */
707 bool ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_OS, OS_MGMT_ERR_INVALID_FORMAT);
708
709 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
710 } else if (format_bitmask == 0) {
711 /* If no value is provided, use default of kernel name */
712 format_bitmask = OS_MGMT_INFO_FORMAT_KERNEL_NAME;
713 }
714
715 /* Process all options in order and append to output string */
716 if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_NAME) {
717 rc = snprintf(output, (sizeof(output) - output_length), "Zephyr");
718
719 if (rc < 0 || rc >= (sizeof(output) - output_length)) {
720 goto fail;
721 } else {
722 output_length += (uint16_t)rc;
723 }
724
725 prior_output = true;
726 }
727
728 if (format_bitmask & OS_MGMT_INFO_FORMAT_NODE_NAME) {
729 /* Get hostname, if enabled */
730 #if defined(CONFIG_NET_HOSTNAME_ENABLE)
731 /* From network */
732 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
733 (prior_output == true ? " %s" : "%s"), net_hostname_get());
734 #elif defined(CONFIG_BT)
735 /* From Bluetooth */
736 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
737 (prior_output == true ? " %s" : "%s"), bt_get_name());
738 #else
739 /* Not available */
740 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
741 "%sunknown", (prior_output == true ? " " : ""));
742 #endif
743
744 if (rc < 0 || rc >= (sizeof(output) - output_length)) {
745 goto fail;
746 } else {
747 output_length += (uint16_t)rc;
748 }
749
750 prior_output = true;
751 format_bitmask &= ~OS_MGMT_INFO_FORMAT_NODE_NAME;
752 }
753
754 if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_RELEASE) {
755 #ifdef BUILD_VERSION
756 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
757 (prior_output == true ? " %s" : "%s"), STRINGIFY(BUILD_VERSION));
758 #else
759 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
760 "%sunknown", (prior_output == true ? " " : ""));
761 #endif
762
763 if (rc < 0 || rc >= (sizeof(output) - output_length)) {
764 goto fail;
765 } else {
766 output_length += (uint16_t)rc;
767 }
768
769 prior_output = true;
770 format_bitmask &= ~OS_MGMT_INFO_FORMAT_KERNEL_RELEASE;
771 }
772
773 if (format_bitmask & OS_MGMT_INFO_FORMAT_KERNEL_VERSION) {
774 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
775 (prior_output == true ? " %s" : "%s"), KERNEL_VERSION_STRING);
776
777 if (rc < 0 || rc >= (sizeof(output) - output_length)) {
778 goto fail;
779 } else {
780 output_length += (uint16_t)rc;
781 }
782
783 prior_output = true;
784 format_bitmask &= ~OS_MGMT_INFO_FORMAT_KERNEL_VERSION;
785 }
786
787 #ifdef CONFIG_MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME
788 if (format_bitmask & OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME) {
789 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
790 (prior_output == true ? " %s" : "%s"),
791 MCUMGR_GRP_OS_INFO_BUILD_DATE_TIME);
792
793 if (rc < 0 || rc >= (sizeof(output) - output_length)) {
794 goto fail;
795 } else {
796 output_length += (uint16_t)rc;
797 }
798
799 prior_output = true;
800 format_bitmask &= ~OS_MGMT_INFO_FORMAT_BUILD_DATE_TIME;
801 }
802 #endif
803
804 if (format_bitmask & OS_MGMT_INFO_FORMAT_MACHINE) {
805 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
806 (prior_output == true ? " %s" : "%s"), CONFIG_ARCH);
807
808 if (rc < 0 || rc >= (sizeof(output) - output_length)) {
809 goto fail;
810 } else {
811 output_length += (uint16_t)rc;
812 }
813
814 prior_output = true;
815 format_bitmask &= ~OS_MGMT_INFO_FORMAT_MACHINE;
816 }
817
818 if (format_bitmask & OS_MGMT_INFO_FORMAT_PROCESSOR) {
819 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
820 (prior_output == true ? " %s" : "%s"), PROCESSOR_NAME);
821
822 if (rc < 0 || rc >= (sizeof(output) - output_length)) {
823 goto fail;
824 } else {
825 output_length += (uint16_t)rc;
826 }
827
828 prior_output = true;
829 format_bitmask &= ~OS_MGMT_INFO_FORMAT_PROCESSOR;
830 }
831
832 if (format_bitmask & OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM) {
833 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
834 (prior_output == true ? " %s%s%s" : "%s%s%s"), CONFIG_BOARD,
835 (sizeof(CONFIG_BOARD_REVISION) > 1 ? "@" : ""),
836 CONFIG_BOARD_REVISION);
837
838 if (rc < 0 || rc >= (sizeof(output) - output_length)) {
839 goto fail;
840 } else {
841 output_length += (uint16_t)rc;
842 }
843
844 prior_output = true;
845 format_bitmask &= ~OS_MGMT_INFO_FORMAT_HARDWARE_PLATFORM;
846 }
847
848 /* If custom_os_name is not set (by extension code) then return the default OS name of
849 * Zephyr
850 */
851 if (format_bitmask & OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM && custom_os_name == false) {
852 rc = snprintf(&output[output_length], (sizeof(output) - output_length),
853 "%sZephyr", (prior_output == true ? " " : ""));
854
855 if (rc < 0 || rc >= (sizeof(output) - output_length)) {
856 goto fail;
857 } else {
858 output_length += (uint16_t)rc;
859 }
860
861 prior_output = true;
862 format_bitmask &= ~OS_MGMT_INFO_FORMAT_OPERATING_SYSTEM;
863 }
864
865 #ifdef CONFIG_MCUMGR_GRP_OS_INFO_CUSTOM_HOOKS
866 /* Call custom handler command for additional output/processing */
867 status = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_INFO_APPEND, &append_data,
868 sizeof(append_data), &err_rc, &err_group);
869
870 if (status != MGMT_CB_OK) {
871 bool ok;
872
873 if (status == MGMT_CB_ERROR_RC) {
874 return err_rc;
875 }
876
877 ok = smp_add_cmd_err(zse, err_group, (uint16_t)err_rc);
878 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
879 }
880 #endif
881
882 if (zcbor_tstr_put_lit(zse, "output") &&
883 zcbor_tstr_encode_ptr(zse, output, output_length)) {
884 return MGMT_ERR_EOK;
885 }
886
887 fail:
888 return MGMT_ERR_EMSGSIZE;
889 }
890 #endif
891
892 #ifdef CONFIG_MCUMGR_GRP_OS_DATETIME
893 /**
894 * Command handler: os datetime get
895 */
os_mgmt_datetime_read(struct smp_streamer * ctxt)896 static int os_mgmt_datetime_read(struct smp_streamer *ctxt)
897 {
898 zcbor_state_t *zse = ctxt->writer->zs;
899 struct rtc_time current_time;
900 char date_string[RTC_DATETIME_STRING_SIZE];
901 int rc;
902 bool ok;
903
904 #if defined(CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK)
905 enum mgmt_cb_return status;
906 int32_t err_rc;
907 uint16_t err_group;
908
909 status = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_DATETIME_GET, NULL, 0, &err_rc,
910 &err_group);
911
912 if (status != MGMT_CB_OK) {
913 if (status == MGMT_CB_ERROR_RC) {
914 return err_rc;
915 }
916
917 ok = smp_add_cmd_err(zse, err_group, (uint16_t)err_rc);
918 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
919 }
920 #endif
921
922 rc = rtc_get_time(RTC_DEVICE, ¤t_time);
923
924 if (rc == -ENODATA) {
925 /* RTC not set */
926 ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_OS, OS_MGMT_ERR_RTC_NOT_SET);
927 goto finished;
928 } else if (rc != 0) {
929 /* Other RTC error */
930 ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_OS, OS_MGMT_ERR_RTC_COMMAND_FAILED);
931 goto finished;
932 }
933
934 sprintf(date_string, "%4d-%02d-%02dT%02d:%02d:%02d"
935 #ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS
936 ".%03d"
937 #endif
938 , (uint16_t)(current_time.tm_year + RTC_DATETIME_YEAR_OFFSET),
939 (uint8_t)(current_time.tm_mon + RTC_DATETIME_MONTH_OFFSET),
940 (uint8_t)current_time.tm_mday, (uint8_t)current_time.tm_hour,
941 (uint8_t)current_time.tm_min, (uint8_t)current_time.tm_sec
942 #ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS
943 , (uint16_t)(current_time.tm_nsec / RTC_DATETIME_MS_TO_NS)
944 #endif
945 );
946
947 ok = zcbor_tstr_put_lit(zse, "datetime") &&
948 zcbor_tstr_encode_ptr(zse, date_string, strlen(date_string));
949
950 finished:
951 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
952 }
953
954 /**
955 * Command handler: os datetime set
956 */
os_mgmt_datetime_write(struct smp_streamer * ctxt)957 static int os_mgmt_datetime_write(struct smp_streamer *ctxt)
958 {
959 zcbor_state_t *zsd = ctxt->reader->zs;
960 zcbor_state_t *zse = ctxt->writer->zs;
961 size_t decoded;
962 struct zcbor_string datetime = { 0 };
963 int rc;
964 uint8_t i = 0;
965 bool ok = true;
966 char *pos;
967 char *new_pos;
968 char date_string[RTC_DATETIME_MAX_STRING_SIZE];
969 struct rtc_time new_time = {
970 .tm_wday = -1,
971 .tm_yday = -1,
972 .tm_isdst = -1,
973 .tm_nsec = 0,
974 };
975 struct datetime_parser parser[] = {
976 {
977 .value = &new_time.tm_year,
978 .min_value = RTC_DATETIME_YEAR_MIN,
979 .max_value = RTC_DATETIME_YEAR_MAX,
980 .offset = -RTC_DATETIME_YEAR_OFFSET,
981 },
982 {
983 .value = &new_time.tm_mon,
984 .min_value = RTC_DATETIME_MONTH_MIN,
985 .max_value = RTC_DATETIME_MONTH_MAX,
986 .offset = -RTC_DATETIME_MONTH_OFFSET,
987 },
988 {
989 .value = &new_time.tm_mday,
990 .min_value = RTC_DATETIME_DAY_MIN,
991 .max_value = RTC_DATETIME_DAY_MAX,
992 },
993 {
994 .value = &new_time.tm_hour,
995 .min_value = RTC_DATETIME_HOUR_MIN,
996 .max_value = RTC_DATETIME_HOUR_MAX,
997 },
998 {
999 .value = &new_time.tm_min,
1000 .min_value = RTC_DATETIME_MINUTE_MIN,
1001 .max_value = RTC_DATETIME_MINUTE_MAX,
1002 },
1003 {
1004 .value = &new_time.tm_sec,
1005 .min_value = RTC_DATETIME_SECOND_MIN,
1006 .max_value = RTC_DATETIME_SECOND_MAX,
1007 },
1008 };
1009
1010 #if defined(CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK)
1011 enum mgmt_cb_return status;
1012 int32_t err_rc;
1013 uint16_t err_group;
1014 #endif
1015
1016 struct zcbor_map_decode_key_val datetime_decode[] = {
1017 ZCBOR_MAP_DECODE_KEY_DECODER("datetime", zcbor_tstr_decode, &datetime),
1018 };
1019
1020 if (zcbor_map_decode_bulk(zsd, datetime_decode, ARRAY_SIZE(datetime_decode), &decoded)) {
1021 return MGMT_ERR_EINVAL;
1022 } else if (datetime.len < RTC_DATETIME_MIN_STRING_SIZE ||
1023 datetime.len >= RTC_DATETIME_MAX_STRING_SIZE) {
1024 return MGMT_ERR_EINVAL;
1025 }
1026
1027 memcpy(date_string, datetime.value, datetime.len);
1028 date_string[datetime.len] = '\0';
1029
1030 pos = date_string;
1031
1032 while (i < ARRAY_SIZE(parser)) {
1033 if (pos == (date_string + datetime.len)) {
1034 /* Encountered end of string early, this is invalid */
1035 return MGMT_ERR_EINVAL;
1036 }
1037
1038 *parser[i].value = strtol(pos, &new_pos, RTC_DATETIME_NUMERIC_BASE);
1039
1040 if (pos == new_pos) {
1041 /* Missing or unable to convert field */
1042 return MGMT_ERR_EINVAL;
1043 }
1044
1045 if (*parser[i].value < parser[i].min_value ||
1046 *parser[i].value > parser[i].max_value) {
1047 /* Value is not within the allowed bounds of this field */
1048 return MGMT_ERR_EINVAL;
1049 }
1050
1051 *parser[i].value += parser[i].offset;
1052
1053 /* Skip a character as there is always a delimiter between the fields */
1054 ++i;
1055 pos = new_pos + 1;
1056 }
1057
1058 #ifdef CONFIG_MCUMGR_GRP_OS_DATETIME_MS
1059 if (*(pos - 1) == '.' && *pos != '\0') {
1060 /* Provided value has a ms value, extract it */
1061 new_time.tm_nsec = strtol(pos, &new_pos, RTC_DATETIME_NUMERIC_BASE);
1062
1063 if (new_time.tm_nsec < RTC_DATETIME_MILLISECOND_MIN ||
1064 new_time.tm_nsec > RTC_DATETIME_MILLISECOND_MAX) {
1065 return MGMT_ERR_EINVAL;
1066 }
1067
1068 new_time.tm_nsec *= RTC_DATETIME_MS_TO_NS;
1069 }
1070 #endif
1071
1072 #if defined(CONFIG_MCUMGR_GRP_OS_DATETIME_HOOK)
1073 status = mgmt_callback_notify(MGMT_EVT_OP_OS_MGMT_DATETIME_SET, &new_time,
1074 sizeof(new_time), &err_rc, &err_group);
1075
1076 if (status != MGMT_CB_OK) {
1077 if (status == MGMT_CB_ERROR_RC) {
1078 return err_rc;
1079 }
1080
1081 ok = smp_add_cmd_err(zse, err_group, (uint16_t)err_rc);
1082 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
1083 }
1084 #endif
1085
1086 rc = rtc_set_time(RTC_DEVICE, &new_time);
1087
1088 if (rc != 0) {
1089 ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_OS, OS_MGMT_ERR_RTC_COMMAND_FAILED);
1090 }
1091
1092 return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
1093 }
1094 #endif
1095
1096 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
1097 /*
1098 * @brief Translate OS mgmt group error code into MCUmgr error code
1099 *
1100 * @param ret #os_mgmt_err_code_t error code
1101 *
1102 * @return #mcumgr_err_t error code
1103 */
os_mgmt_translate_error_code(uint16_t err)1104 static int os_mgmt_translate_error_code(uint16_t err)
1105 {
1106 int rc;
1107
1108 switch (err) {
1109 case OS_MGMT_ERR_INVALID_FORMAT:
1110 rc = MGMT_ERR_EINVAL;
1111 break;
1112
1113 case OS_MGMT_ERR_QUERY_YIELDS_NO_ANSWER:
1114 case OS_MGMT_ERR_RTC_NOT_SET:
1115 case OS_MGMT_ERR_QUERY_RESPONSE_VALUE_NOT_VALID:
1116 rc = MGMT_ERR_ENOENT;
1117 break;
1118
1119 case OS_MGMT_ERR_UNKNOWN:
1120 case OS_MGMT_ERR_RTC_COMMAND_FAILED:
1121 default:
1122 rc = MGMT_ERR_EUNKNOWN;
1123 }
1124
1125 return rc;
1126 }
1127 #endif
1128
1129 static const struct mgmt_handler os_mgmt_group_handlers[] = {
1130 #ifdef CONFIG_MCUMGR_GRP_OS_ECHO
1131 [OS_MGMT_ID_ECHO] = {
1132 os_mgmt_echo, os_mgmt_echo
1133 },
1134 #endif
1135 #ifdef CONFIG_MCUMGR_GRP_OS_TASKSTAT
1136 [OS_MGMT_ID_TASKSTAT] = {
1137 os_mgmt_taskstat_read, NULL
1138 },
1139 #endif
1140
1141 #ifdef CONFIG_MCUMGR_GRP_OS_DATETIME
1142 [OS_MGMT_ID_DATETIME_STR] = {
1143 os_mgmt_datetime_read, os_mgmt_datetime_write
1144 },
1145 #endif
1146
1147 #ifdef CONFIG_REBOOT
1148 [OS_MGMT_ID_RESET] = {
1149 NULL, os_mgmt_reset
1150 },
1151 #endif
1152 #ifdef CONFIG_MCUMGR_GRP_OS_MCUMGR_PARAMS
1153 [OS_MGMT_ID_MCUMGR_PARAMS] = {
1154 os_mgmt_mcumgr_params, NULL
1155 },
1156 #endif
1157 #ifdef CONFIG_MCUMGR_GRP_OS_INFO
1158 [OS_MGMT_ID_INFO] = {
1159 os_mgmt_info, NULL
1160 },
1161 #endif
1162 #ifdef CONFIG_MCUMGR_GRP_OS_BOOTLOADER_INFO
1163 [OS_MGMT_ID_BOOTLOADER_INFO] = {
1164 os_mgmt_bootloader_info, NULL
1165 },
1166 #endif
1167 };
1168
1169 #define OS_MGMT_GROUP_SZ ARRAY_SIZE(os_mgmt_group_handlers)
1170
1171 static struct mgmt_group os_mgmt_group = {
1172 .mg_handlers = os_mgmt_group_handlers,
1173 .mg_handlers_count = OS_MGMT_GROUP_SZ,
1174 .mg_group_id = MGMT_GROUP_ID_OS,
1175 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
1176 .mg_translate_error = os_mgmt_translate_error_code,
1177 #endif
1178 #ifdef CONFIG_MCUMGR_GRP_ENUM_DETAILS_NAME
1179 .mg_group_name = "os mgmt",
1180 #endif
1181 };
1182
os_mgmt_register_group(void)1183 static void os_mgmt_register_group(void)
1184 {
1185 mgmt_register_group(&os_mgmt_group);
1186 }
1187
1188 MCUMGR_HANDLER_DEFINE(os_mgmt, os_mgmt_register_group);
1189