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, &current_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