1 /*
2  * Copyright (c) 2018-2021 mcumgr authors
3  * Copyright (c) 2022-2024 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/sys/util.h>
9 #include <limits.h>
10 #include <assert.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <zephyr/toolchain.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/storage/flash_map.h>
16 #include <zephyr/dfu/mcuboot.h>
17 
18 #include <zcbor_common.h>
19 #include <zcbor_decode.h>
20 #include <zcbor_encode.h>
21 
22 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
23 #include <zephyr/mgmt/mcumgr/smp/smp.h>
24 #include <zephyr/mgmt/mcumgr/mgmt/handlers.h>
25 #include <zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h>
26 
27 #include <mgmt/mcumgr/util/zcbor_bulk.h>
28 #include <mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h>
29 
30 #ifdef CONFIG_IMG_ENABLE_IMAGE_CHECK
31 #include <zephyr/dfu/flash_img.h>
32 #endif
33 
34 #ifdef CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS
35 #include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
36 #include <mgmt/mcumgr/transport/smp_internal.h>
37 #endif
38 
39 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD)
40 #include <bootutil/boot_status.h>
41 #include <zephyr/retention/blinfo.h>
42 #endif
43 
44 #if !defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD)
45 
46 #ifndef CONFIG_FLASH_LOAD_OFFSET
47 #error MCUmgr requires application to be built with CONFIG_FLASH_LOAD_OFFSET set \
48 	to be able to figure out application running slot.
49 #endif
50 
51 #define FIXED_PARTITION_IS_RUNNING_APP_PARTITION(label)	\
52 	 (FIXED_PARTITION_OFFSET(label) == CONFIG_FLASH_LOAD_OFFSET)
53 
54 BUILD_ASSERT(sizeof(struct image_header) == IMAGE_HEADER_SIZE,
55 	     "struct image_header not required size");
56 
57 #if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER >= 2
58 #if FIXED_PARTITION_EXISTS(slot0_ns_partition) &&			\
59 	FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_ns_partition)
60 #define ACTIVE_IMAGE_IS 0
61 #elif FIXED_PARTITION_EXISTS(slot0_partition) &&			\
62 	FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot0_partition)
63 #define ACTIVE_IMAGE_IS 0
64 #elif FIXED_PARTITION_EXISTS(slot1_partition) &&			\
65 	FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot1_partition)
66 #define ACTIVE_IMAGE_IS 0
67 #elif FIXED_PARTITION_EXISTS(slot2_partition) &&			\
68 	FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot2_partition)
69 #define ACTIVE_IMAGE_IS 1
70 #elif FIXED_PARTITION_EXISTS(slot3_partition) &&			\
71 	FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot3_partition)
72 #define ACTIVE_IMAGE_IS 1
73 #elif FIXED_PARTITION_EXISTS(slot4_partition) &&			\
74 	FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot4_partition)
75 #define ACTIVE_IMAGE_IS 2
76 #elif FIXED_PARTITION_EXISTS(slot5_partition) &&			\
77 	FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot5_partition)
78 #define ACTIVE_IMAGE_IS 2
79 #else
80 #define ACTIVE_IMAGE_IS 0
81 #endif
82 #else
83 #define ACTIVE_IMAGE_IS 0
84 #endif
85 
86 #else
87 #define ACTIVE_IMAGE_IS 0
88 #endif
89 
90 #define SLOTS_PER_IMAGE 2
91 
92 LOG_MODULE_REGISTER(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL);
93 
94 struct img_mgmt_state g_img_mgmt_state;
95 
96 #ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX
97 static K_MUTEX_DEFINE(img_mgmt_mutex);
98 #endif
99 
100 #ifdef CONFIG_MCUMGR_GRP_IMG_VERBOSE_ERR
101 const char *img_mgmt_err_str_app_reject = "app reject";
102 const char *img_mgmt_err_str_hdr_malformed = "header malformed";
103 const char *img_mgmt_err_str_magic_mismatch = "magic mismatch";
104 const char *img_mgmt_err_str_no_slot = "no slot";
105 const char *img_mgmt_err_str_flash_open_failed = "fa open fail";
106 const char *img_mgmt_err_str_flash_erase_failed = "fa erase fail";
107 const char *img_mgmt_err_str_flash_write_failed = "fa write fail";
108 const char *img_mgmt_err_str_downgrade = "downgrade";
109 const char *img_mgmt_err_str_image_bad_flash_addr = "img addr mismatch";
110 const char *img_mgmt_err_str_image_too_large = "img too large";
111 const char *img_mgmt_err_str_data_overrun = "data overrun";
112 #endif
113 
img_mgmt_take_lock(void)114 void img_mgmt_take_lock(void)
115 {
116 #ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX
117 	k_mutex_lock(&img_mgmt_mutex, K_FOREVER);
118 #endif
119 }
120 
img_mgmt_release_lock(void)121 void img_mgmt_release_lock(void)
122 {
123 #ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX
124 	k_mutex_unlock(&img_mgmt_mutex);
125 #endif
126 }
127 
128 #if defined(CONFIG_MCUMGR_GRP_IMG_SLOT_INFO_HOOKS)
img_mgmt_reset_zse(struct smp_streamer * ctxt)129 static bool img_mgmt_reset_zse(struct smp_streamer *ctxt)
130 {
131 	zcbor_state_t *zse = ctxt->writer->zs;
132 
133 	/* Because there is already data in the buffer, it must be cleared first */
134 	net_buf_reset(ctxt->writer->nb);
135 	ctxt->writer->nb->len = sizeof(struct smp_hdr);
136 	zcbor_new_encode_state(zse, ARRAY_SIZE(ctxt->writer->zs),
137 			       ctxt->writer->nb->data + sizeof(struct smp_hdr),
138 			       net_buf_tailroom(ctxt->writer->nb), 0);
139 
140 	return zcbor_map_start_encode(zse, CONFIG_MCUMGR_SMP_CBOR_MAX_MAIN_MAP_ENTRIES);
141 }
142 #endif
143 
144 #if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD)
img_mgmt_slot_max_size(size_t * area_sizes,zcbor_state_t * zse)145 static bool img_mgmt_slot_max_size(size_t *area_sizes, zcbor_state_t *zse)
146 {
147 	bool ok = true;
148 
149 	if (area_sizes[0] > 0 && area_sizes[1] > 0) {
150 		/* Calculate maximum image size */
151 		size_t area_size_difference = (size_t)abs((ssize_t)area_sizes[1] -
152 							  (ssize_t)area_sizes[0]);
153 
154 		if (CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE >= area_size_difference) {
155 			ok = zcbor_tstr_put_lit(zse, "max_image_size") &&
156 			     zcbor_uint32_put(zse, (uint32_t)(area_sizes[0] -
157 					      CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE));		}
158 	}
159 
160 	return ok;
161 }
162 #elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
img_mgmt_slot_max_size(size_t * area_sizes,zcbor_state_t * zse)163 static bool img_mgmt_slot_max_size(size_t *area_sizes, zcbor_state_t *zse)
164 {
165 	bool ok = true;
166 	int rc;
167 	int max_app_size;
168 
169 	ARG_UNUSED(area_sizes);
170 
171 	rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, &max_app_size, sizeof(max_app_size))
172 
173 	if (rc < 0) {
174 		LOG_ERR("Failed to lookup max application size: %d", rc);
175 	} else if (rc > 0) {
176 		ok = zcbor_tstr_put_lit(zse, "max_image_size") &&
177 		     zcbor_uint32_put(zse, (uint32_t)max_app_size);
178 	}
179 
180 	return ok;
181 }
182 #endif
183 
184 /**
185  * Finds the TLVs in the specified image slot, if any.
186  */
img_mgmt_find_tlvs(int slot,size_t * start_off,size_t * end_off,uint16_t magic)187 static int img_mgmt_find_tlvs(int slot, size_t *start_off, size_t *end_off, uint16_t magic)
188 {
189 	struct image_tlv_info tlv_info;
190 	int rc;
191 
192 	rc = img_mgmt_read(slot, *start_off, &tlv_info, sizeof(tlv_info));
193 	if (rc != 0) {
194 		/* Read error. */
195 		return rc;
196 	}
197 
198 	if (tlv_info.it_magic != magic) {
199 		/* No TLVs. */
200 		return IMG_MGMT_ERR_NO_TLVS;
201 	}
202 
203 	*start_off += sizeof(tlv_info);
204 	*end_off = *start_off + tlv_info.it_tlv_tot;
205 
206 	return IMG_MGMT_ERR_OK;
207 }
208 
img_mgmt_active_slot(int image)209 int img_mgmt_active_slot(int image)
210 {
211 	int slot = 0;
212 
213 	/* Multi image does not support DirectXIP or RAM load currently */
214 #if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER > 1
215 	slot = (image << 1);
216 #elif defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD)
217 	/* RAM load requires querying bootloader */
218 	int rc;
219 	uint8_t temp_slot;
220 
221 	rc = blinfo_lookup(BLINFO_RUNNING_SLOT, &temp_slot, sizeof(temp_slot));
222 
223 	if (rc <= 0) {
224 		LOG_ERR("Failed to fetch active slot: %d", rc);
225 
226 		return 255;
227 	}
228 
229 	slot = (int)temp_slot;
230 #else
231 	/* This covers single image, including DirectXiP */
232 	if (FIXED_PARTITION_IS_RUNNING_APP_PARTITION(slot1_partition)) {
233 		slot = 1;
234 	}
235 #endif
236 	LOG_DBG("(%d) => %d", image, slot);
237 
238 	return slot;
239 }
240 
img_mgmt_active_image(void)241 int img_mgmt_active_image(void)
242 {
243 	return ACTIVE_IMAGE_IS;
244 }
245 
246 /*
247  * Reads the version and build hash from the specified image slot.
248  */
img_mgmt_read_info(int image_slot,struct image_version * ver,uint8_t * hash,uint32_t * flags)249 int img_mgmt_read_info(int image_slot, struct image_version *ver, uint8_t *hash,
250 				   uint32_t *flags)
251 {
252 	struct image_header hdr;
253 	struct image_tlv tlv;
254 	size_t data_off;
255 	size_t data_end;
256 	bool hash_found;
257 	uint8_t erased_val;
258 	uint32_t erased_val_32;
259 	int rc;
260 
261 	rc = img_mgmt_erased_val(image_slot, &erased_val);
262 	if (rc != 0) {
263 		return IMG_MGMT_ERR_FLASH_CONFIG_QUERY_FAIL;
264 	}
265 
266 	rc = img_mgmt_read(image_slot,
267 			   boot_get_image_start_offset(img_mgmt_flash_area_id(image_slot)),
268 			   &hdr, sizeof(hdr));
269 
270 	if (rc != 0) {
271 		return rc;
272 	}
273 
274 	if (ver != NULL) {
275 		memset(ver, erased_val, sizeof(*ver));
276 	}
277 	erased_val_32 = ERASED_VAL_32(erased_val);
278 	if (hdr.ih_magic == IMAGE_MAGIC) {
279 		if (ver != NULL) {
280 			memcpy(ver, &hdr.ih_ver, sizeof(*ver));
281 		}
282 	} else if (hdr.ih_magic == erased_val_32) {
283 		return IMG_MGMT_ERR_NO_IMAGE;
284 	} else {
285 		return IMG_MGMT_ERR_INVALID_IMAGE_HEADER_MAGIC;
286 	}
287 
288 	if (flags != NULL) {
289 		*flags = hdr.ih_flags;
290 	}
291 
292 	/* Read the image's TLVs. We first try to find the protected TLVs, if the protected
293 	 * TLV does not exist, we try to find non-protected TLV which also contains the hash
294 	 * TLV. All images are required to have a hash TLV.  If the hash is missing, the image
295 	 * is considered invalid.
296 	 */
297 	data_off = hdr.ih_hdr_size + hdr.ih_img_size +
298 		   boot_get_image_start_offset(img_mgmt_flash_area_id(image_slot));
299 
300 	rc = img_mgmt_find_tlvs(image_slot, &data_off, &data_end, IMAGE_TLV_PROT_INFO_MAGIC);
301 	if (!rc) {
302 		/* The data offset should start after the header bytes after the end of
303 		 * the protected TLV, if one exists.
304 		 */
305 		data_off = data_end - sizeof(struct image_tlv_info);
306 	}
307 
308 	rc = img_mgmt_find_tlvs(image_slot, &data_off, &data_end, IMAGE_TLV_INFO_MAGIC);
309 	if (rc != 0) {
310 		return IMG_MGMT_ERR_NO_TLVS;
311 	}
312 
313 	hash_found = false;
314 	while (data_off + sizeof(tlv) <= data_end) {
315 		rc = img_mgmt_read(image_slot, data_off, &tlv, sizeof(tlv));
316 		if (rc != 0) {
317 			return rc;
318 		}
319 		if (tlv.it_type == 0xff && tlv.it_len == 0xffff) {
320 			return IMG_MGMT_ERR_INVALID_TLV;
321 		}
322 		if (tlv.it_type != IMAGE_TLV_SHA256 || tlv.it_len != IMAGE_HASH_LEN) {
323 			/* Non-hash TLV.  Skip it. */
324 			data_off += sizeof(tlv) + tlv.it_len;
325 			continue;
326 		}
327 
328 		if (hash_found) {
329 			/* More than one hash. */
330 			return IMG_MGMT_ERR_TLV_MULTIPLE_HASHES_FOUND;
331 		}
332 		hash_found = true;
333 
334 		data_off += sizeof(tlv);
335 		if (hash != NULL) {
336 			if (data_off + IMAGE_HASH_LEN > data_end) {
337 				return IMG_MGMT_ERR_TLV_INVALID_SIZE;
338 			}
339 			rc = img_mgmt_read(image_slot, data_off, hash, IMAGE_HASH_LEN);
340 			if (rc != 0) {
341 				return rc;
342 			}
343 		}
344 	}
345 
346 	if (!hash_found) {
347 		return IMG_MGMT_ERR_HASH_NOT_FOUND;
348 	}
349 
350 	return 0;
351 }
352 
353 /*
354  * Finds image given version number. Returns the slot number image is in,
355  * or -1 if not found.
356  */
357 int
img_mgmt_find_by_ver(struct image_version * find,uint8_t * hash)358 img_mgmt_find_by_ver(struct image_version *find, uint8_t *hash)
359 {
360 	int i;
361 	struct image_version ver;
362 
363 	for (i = 0; i < 2 * CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER; i++) {
364 		if (img_mgmt_read_info(i, &ver, hash, NULL) != 0) {
365 			continue;
366 		}
367 		if (!memcmp(find, &ver, sizeof(ver))) {
368 			return i;
369 		}
370 	}
371 	return -1;
372 }
373 
374 /*
375  * Finds image given hash of the image. Returns the slot number image is in,
376  * or -1 if not found.
377  */
378 int
img_mgmt_find_by_hash(uint8_t * find,struct image_version * ver)379 img_mgmt_find_by_hash(uint8_t *find, struct image_version *ver)
380 {
381 	int i;
382 	uint8_t hash[IMAGE_HASH_LEN];
383 
384 	for (i = 0; i < 2 * CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER; i++) {
385 		if (img_mgmt_read_info(i, ver, hash, NULL) != 0) {
386 			continue;
387 		}
388 		if (!memcmp(hash, find, IMAGE_HASH_LEN)) {
389 			return i;
390 		}
391 	}
392 	return -1;
393 }
394 
395 /*
396  * Resets upload status to defaults (no upload in progress)
397  */
398 #ifdef CONFIG_MCUMGR_GRP_IMG_MUTEX
img_mgmt_reset_upload(void)399 void img_mgmt_reset_upload(void)
400 #else
401 static void img_mgmt_reset_upload(void)
402 #endif
403 {
404 	img_mgmt_take_lock();
405 	memset(&g_img_mgmt_state, 0, sizeof(g_img_mgmt_state));
406 	g_img_mgmt_state.area_id = -1;
407 	img_mgmt_release_lock();
408 }
409 
410 /**
411  * Command handler: image erase
412  */
413 static int
img_mgmt_erase(struct smp_streamer * ctxt)414 img_mgmt_erase(struct smp_streamer *ctxt)
415 {
416 	struct image_version ver;
417 	int rc;
418 	zcbor_state_t *zse = ctxt->writer->zs;
419 	zcbor_state_t *zsd = ctxt->reader->zs;
420 	bool ok;
421 	uint32_t slot = img_mgmt_get_opposite_slot(img_mgmt_active_slot(img_mgmt_active_image()));
422 	size_t decoded = 0;
423 
424 	struct zcbor_map_decode_key_val image_erase_decode[] = {
425 		ZCBOR_MAP_DECODE_KEY_DECODER("slot", zcbor_uint32_decode, &slot),
426 	};
427 
428 	ok = zcbor_map_decode_bulk(zsd, image_erase_decode,
429 		ARRAY_SIZE(image_erase_decode), &decoded) == 0;
430 
431 	if (!ok) {
432 		return MGMT_ERR_EINVAL;
433 	}
434 
435 	img_mgmt_take_lock();
436 
437 	/*
438 	 * First check if image info is valid.
439 	 * This check is done incase the flash area has a corrupted image.
440 	 */
441 	rc = img_mgmt_read_info(slot, &ver, NULL, NULL);
442 
443 	if (rc == 0) {
444 		/* Image info is valid. */
445 		if (img_mgmt_slot_in_use(slot)) {
446 			/* No free slot. */
447 			ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_IMAGE,
448 					     IMG_MGMT_ERR_NO_FREE_SLOT);
449 			goto end;
450 		}
451 	}
452 
453 	rc = img_mgmt_erase_slot(slot);
454 	img_mgmt_reset_upload();
455 
456 	if (rc != 0) {
457 #if defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS)
458 		int32_t err_rc;
459 		uint16_t err_group;
460 
461 		(void)mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_DFU_STOPPED, NULL, 0, &err_rc,
462 					   &err_group);
463 #endif
464 		ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_IMAGE, rc);
465 		goto end;
466 	}
467 
468 	if (IS_ENABLED(CONFIG_MCUMGR_SMP_LEGACY_RC_BEHAVIOUR)) {
469 		if (!zcbor_tstr_put_lit(zse, "rc") || !zcbor_int32_put(zse, 0)) {
470 			img_mgmt_release_lock();
471 			return MGMT_ERR_EMSGSIZE;
472 		}
473 	}
474 
475 end:
476 	img_mgmt_release_lock();
477 
478 	return MGMT_ERR_EOK;
479 }
480 
481 #if defined(CONFIG_MCUMGR_GRP_IMG_SLOT_INFO)
482 /**
483  * Command handler: image slot info
484  */
img_mgmt_slot_info(struct smp_streamer * ctxt)485 static int img_mgmt_slot_info(struct smp_streamer *ctxt)
486 {
487 	int rc;
488 	zcbor_state_t *zse = ctxt->writer->zs;
489 	bool ok;
490 	uint8_t i = 0;
491 	size_t area_sizes[SLOTS_PER_IMAGE];
492 
493 #if defined(CONFIG_MCUMGR_GRP_IMG_SLOT_INFO_HOOKS)
494 	int32_t err_rc;
495 	uint16_t err_group;
496 	enum mgmt_cb_return status;
497 #endif
498 
499 	img_mgmt_take_lock();
500 
501 	ok = zcbor_tstr_put_lit(zse, "images") &&
502 	     zcbor_list_start_encode(zse, 10);
503 
504 	while (i < CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER * SLOTS_PER_IMAGE) {
505 		const struct flash_area *fa;
506 		int area_id = img_mgmt_flash_area_id(i);
507 
508 		if ((i % SLOTS_PER_IMAGE) == 0) {
509 			memset(area_sizes, 0, sizeof(area_sizes));
510 
511 			ok = zcbor_map_start_encode(zse, 4) &&
512 			     zcbor_tstr_put_lit(zse, "image") &&
513 			     zcbor_uint32_put(zse, (uint32_t)(i / SLOTS_PER_IMAGE)) &&
514 			     zcbor_tstr_put_lit(zse, "slots") &&
515 			     zcbor_list_start_encode(zse, 4);
516 
517 			if (!ok) {
518 				goto finish;
519 			}
520 		}
521 
522 		ok = zcbor_map_start_encode(zse, 4) &&
523 		     zcbor_tstr_put_lit(zse, "slot") &&
524 		     zcbor_uint32_put(zse, (uint32_t)(i % SLOTS_PER_IMAGE));
525 
526 		if (!ok) {
527 			goto finish;
528 		}
529 
530 		rc = flash_area_open(area_id, &fa);
531 
532 		if (rc) {
533 			/* Failed opening slot, mark as error */
534 			ok = zcbor_tstr_put_lit(zse, "rc") &&
535 			     zcbor_int32_put(zse, rc);
536 
537 			LOG_ERR("Failed to open slot %d for information fetching: %d", area_id, rc);
538 		} else {
539 #if defined(CONFIG_MCUMGR_GRP_IMG_SLOT_INFO_HOOKS)
540 			struct img_mgmt_slot_info_slot slot_info_data = {
541 				.image = (i / SLOTS_PER_IMAGE),
542 				.slot = (i % SLOTS_PER_IMAGE),
543 				.fa = fa,
544 				.zse = zse,
545 			};
546 #endif
547 
548 			if (sizeof(fa->fa_size) == sizeof(uint64_t)) {
549 				ok = zcbor_tstr_put_lit(zse, "size") &&
550 				     zcbor_uint64_put(zse, fa->fa_size);
551 			} else {
552 				ok = zcbor_tstr_put_lit(zse, "size") &&
553 				     zcbor_uint32_put(zse, fa->fa_size);
554 			}
555 
556 			area_sizes[(i % SLOTS_PER_IMAGE)] = fa->fa_size;
557 
558 			if (!ok) {
559 				goto finish;
560 			}
561 
562 			/*
563 			 * Check if we support uploading to this slot and if so, return the
564 			 * image ID
565 			 */
566 #if defined(CONFIG_MCUMGR_GRP_IMG_DIRECT_UPLOAD)
567 			ok = zcbor_tstr_put_lit(zse, "upload_image_id") &&
568 			     zcbor_uint32_put(zse, (i + 1));
569 #else
570 			if (img_mgmt_active_slot((i / SLOTS_PER_IMAGE)) != i) {
571 				ok = zcbor_tstr_put_lit(zse, "upload_image_id") &&
572 				     zcbor_uint32_put(zse, (i / SLOTS_PER_IMAGE));
573 			}
574 #endif
575 
576 			if (!ok) {
577 				goto finish;
578 			}
579 
580 #if defined(CONFIG_MCUMGR_GRP_IMG_SLOT_INFO_HOOKS)
581 			status = mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_SLOT_INFO_SLOT,
582 						      &slot_info_data, sizeof(slot_info_data),
583 						      &err_rc, &err_group);
584 #endif
585 
586 			flash_area_close(fa);
587 
588 #if defined(CONFIG_MCUMGR_GRP_IMG_SLOT_INFO_HOOKS)
589 			if (status != MGMT_CB_OK) {
590 				if (status == MGMT_CB_ERROR_RC) {
591 					img_mgmt_release_lock();
592 					return err_rc;
593 				}
594 
595 				ok = img_mgmt_reset_zse(ctxt) &&
596 				     smp_add_cmd_err(zse, err_group, (uint16_t)err_rc);
597 
598 				goto finish;
599 			}
600 #endif
601 		}
602 
603 		ok &= zcbor_map_end_encode(zse, 4);
604 
605 		if (!ok) {
606 			goto finish;
607 		}
608 
609 		if ((i % SLOTS_PER_IMAGE) == (SLOTS_PER_IMAGE - 1)) {
610 #if defined(CONFIG_MCUMGR_GRP_IMG_SLOT_INFO_HOOKS)
611 			struct img_mgmt_slot_info_image image_info_data = {
612 				.image = (i / SLOTS_PER_IMAGE),
613 				.zse = zse,
614 			};
615 #endif
616 
617 			ok = zcbor_list_end_encode(zse, 4);
618 
619 			if (!ok) {
620 				goto finish;
621 			}
622 
623 #if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) || \
624 	defined(MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
625 			ok = img_mgmt_slot_max_size(area_sizes, zse);
626 
627 			if (!ok) {
628 				goto finish;
629 			}
630 #endif
631 
632 #if defined(CONFIG_MCUMGR_GRP_IMG_SLOT_INFO_HOOKS)
633 			status = mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_SLOT_INFO_IMAGE,
634 						      &image_info_data, sizeof(image_info_data),
635 						      &err_rc, &err_group);
636 
637 			if (status != MGMT_CB_OK) {
638 				if (status == MGMT_CB_ERROR_RC) {
639 					img_mgmt_release_lock();
640 					return err_rc;
641 				}
642 
643 				ok = img_mgmt_reset_zse(ctxt) &&
644 				     smp_add_cmd_err(zse, err_group, (uint16_t)err_rc);
645 
646 				goto finish;
647 			}
648 #endif
649 
650 			ok = zcbor_map_end_encode(zse, 4);
651 
652 			if (!ok) {
653 				goto finish;
654 			}
655 		}
656 
657 		++i;
658 	}
659 
660 	ok = zcbor_list_end_encode(zse, 10);
661 
662 finish:
663 	img_mgmt_release_lock();
664 
665 	return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
666 }
667 #endif
668 
669 static int
img_mgmt_upload_good_rsp(struct smp_streamer * ctxt)670 img_mgmt_upload_good_rsp(struct smp_streamer *ctxt)
671 {
672 	zcbor_state_t *zse = ctxt->writer->zs;
673 	bool ok = true;
674 
675 	if (IS_ENABLED(CONFIG_MCUMGR_SMP_LEGACY_RC_BEHAVIOUR)) {
676 		ok = zcbor_tstr_put_lit(zse, "rc")		&&
677 		     zcbor_int32_put(zse, MGMT_ERR_EOK);
678 	}
679 
680 	ok = ok && zcbor_tstr_put_lit(zse, "off")		&&
681 		   zcbor_size_put(zse, g_img_mgmt_state.off);
682 
683 	return ok ? MGMT_ERR_EOK : MGMT_ERR_EMSGSIZE;
684 }
685 
686 /**
687  * Logs an upload request if necessary.
688  *
689  * @param is_first	Whether the request includes the first chunk of the image.
690  * @param is_last	Whether the request includes the last chunk of the image.
691  * @param status	The result of processing the upload request (MGMT_ERR code).
692  *
693  * @return 0 on success; nonzero on failure.
694  */
695 static int
img_mgmt_upload_log(bool is_first,bool is_last,int status)696 img_mgmt_upload_log(bool is_first, bool is_last, int status)
697 {
698 	uint8_t hash[IMAGE_HASH_LEN];
699 	const uint8_t *hashp;
700 	int rc;
701 
702 	if (is_last || status != 0) {
703 		/* Log the image hash if we know it. */
704 		rc = img_mgmt_read_info(1, NULL, hash, NULL);
705 		if (rc != 0) {
706 			hashp = NULL;
707 		} else {
708 			hashp = hash;
709 		}
710 	}
711 
712 	return 0;
713 }
714 
715 /**
716  * Command handler: image upload
717  */
718 static int
img_mgmt_upload(struct smp_streamer * ctxt)719 img_mgmt_upload(struct smp_streamer *ctxt)
720 {
721 	zcbor_state_t *zse = ctxt->writer->zs;
722 	zcbor_state_t *zsd = ctxt->reader->zs;
723 	bool ok;
724 	size_t decoded = 0;
725 	struct img_mgmt_upload_req req = {
726 		.off = SIZE_MAX,
727 		.size = SIZE_MAX,
728 		.img_data = { 0 },
729 		.data_sha = { 0 },
730 		.upgrade = false,
731 		.image = 0,
732 	};
733 	int rc;
734 	struct img_mgmt_upload_action action;
735 	bool last = false;
736 	bool reset = false;
737 
738 #ifdef CONFIG_IMG_ENABLE_IMAGE_CHECK
739 	bool data_match = false;
740 #endif
741 
742 #if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK)
743 	enum mgmt_cb_return status;
744 #endif
745 
746 #if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK) ||	\
747 defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS) ||		\
748 defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS)
749 	int32_t err_rc;
750 	uint16_t err_group;
751 #endif
752 
753 	struct zcbor_map_decode_key_val image_upload_decode[] = {
754 		ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &req.image),
755 		ZCBOR_MAP_DECODE_KEY_DECODER("data", zcbor_bstr_decode, &req.img_data),
756 		ZCBOR_MAP_DECODE_KEY_DECODER("len", zcbor_size_decode, &req.size),
757 		ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode, &req.off),
758 		ZCBOR_MAP_DECODE_KEY_DECODER("sha", zcbor_bstr_decode, &req.data_sha),
759 		ZCBOR_MAP_DECODE_KEY_DECODER("upgrade", zcbor_bool_decode, &req.upgrade)
760 	};
761 
762 #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS)
763 	struct mgmt_evt_op_cmd_arg cmd_status_arg = {
764 		.group = MGMT_GROUP_ID_IMAGE,
765 		.id = IMG_MGMT_ID_UPLOAD,
766 	};
767 #endif
768 
769 #if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK)
770 	struct img_mgmt_upload_check upload_check_data = {
771 		.action = &action,
772 		.req = &req,
773 	};
774 #endif
775 
776 	ok = zcbor_map_decode_bulk(zsd, image_upload_decode,
777 		ARRAY_SIZE(image_upload_decode), &decoded) == 0;
778 
779 	IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(&action, NULL);
780 
781 	if (!ok) {
782 		return MGMT_ERR_EINVAL;
783 	}
784 
785 	img_mgmt_take_lock();
786 
787 	/* Determine what actions to take as a result of this request. */
788 	rc = img_mgmt_upload_inspect(&req, &action);
789 	if (rc != 0) {
790 #if defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS)
791 		(void)mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_DFU_STOPPED, NULL, 0, &err_rc,
792 					   &err_group);
793 #endif
794 
795 		MGMT_CTXT_SET_RC_RSN(ctxt, IMG_MGMT_UPLOAD_ACTION_RC_RSN(&action));
796 		LOG_ERR("Image upload inspect failed: %d", rc);
797 		ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_IMAGE, rc);
798 		goto end;
799 	}
800 
801 	if (!action.proceed) {
802 		/* Request specifies incorrect offset.  Respond with a success code and
803 		 * the correct offset.
804 		 */
805 		rc = img_mgmt_upload_good_rsp(ctxt);
806 		img_mgmt_release_lock();
807 		return rc;
808 	}
809 
810 #if defined(CONFIG_MCUMGR_GRP_IMG_UPLOAD_CHECK_HOOK)
811 	/* Request is valid.  Give the application a chance to reject this upload
812 	 * request.
813 	 */
814 	status = mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK, &upload_check_data,
815 				      sizeof(upload_check_data), &err_rc, &err_group);
816 
817 	if (status != MGMT_CB_OK) {
818 		IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(&action, img_mgmt_err_str_app_reject);
819 
820 		if (status == MGMT_CB_ERROR_RC) {
821 			rc = err_rc;
822 			ok = zcbor_tstr_put_lit(zse, "rc")	&&
823 			     zcbor_int32_put(zse, rc);
824 		} else {
825 			ok = smp_add_cmd_err(zse, err_group, (uint16_t)err_rc);
826 		}
827 
828 		goto end;
829 	}
830 #endif
831 
832 	/* Remember flash area ID and image size for subsequent upload requests. */
833 	g_img_mgmt_state.area_id = action.area_id;
834 	g_img_mgmt_state.size = action.size;
835 
836 	if (req.off == 0) {
837 		/*
838 		 * New upload.
839 		 */
840 #ifdef CONFIG_IMG_ENABLE_IMAGE_CHECK
841 		struct flash_img_context ctx;
842 		struct flash_img_check fic;
843 #endif
844 
845 		g_img_mgmt_state.off = 0;
846 
847 #if defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS)
848 		(void)mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_DFU_STARTED, NULL, 0, &err_rc,
849 					   &err_group);
850 #endif
851 
852 #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS)
853 		cmd_status_arg.status = IMG_MGMT_ID_UPLOAD_STATUS_START;
854 #endif
855 
856 		/*
857 		 * We accept SHA trimmed to any length by client since it's up to client
858 		 * to make sure provided data are good enough to avoid collisions when
859 		 * resuming upload.
860 		 */
861 		g_img_mgmt_state.data_sha_len = req.data_sha.len;
862 		memcpy(g_img_mgmt_state.data_sha, req.data_sha.value, req.data_sha.len);
863 		memset(&g_img_mgmt_state.data_sha[req.data_sha.len], 0,
864 			   IMG_MGMT_DATA_SHA_LEN - req.data_sha.len);
865 
866 #ifdef CONFIG_IMG_ENABLE_IMAGE_CHECK
867 		/* Check if the existing image hash matches the hash of the underlying data,
868 		 * this check can only be performed if the provided hash is a full SHA256 hash
869 		 * of the file that is being uploaded, do not attempt the check if the length
870 		 * of the provided hash is less.
871 		 */
872 		if (g_img_mgmt_state.data_sha_len == IMG_MGMT_DATA_SHA_LEN) {
873 			fic.match = g_img_mgmt_state.data_sha;
874 			fic.clen = g_img_mgmt_state.size;
875 
876 			if (flash_img_check(&ctx, &fic, g_img_mgmt_state.area_id) == 0) {
877 				/* Underlying data already matches, no need to upload any more,
878 				 * set offset to image size so client knows upload has finished.
879 				 */
880 				g_img_mgmt_state.off = g_img_mgmt_state.size;
881 				reset = true;
882 				last = true;
883 				data_match = true;
884 
885 #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS)
886 				cmd_status_arg.status = IMG_MGMT_ID_UPLOAD_STATUS_COMPLETE;
887 #endif
888 
889 				goto end;
890 			}
891 		}
892 #endif
893 
894 #ifndef CONFIG_IMG_ERASE_PROGRESSIVELY
895 		/* erase the entire req.size all at once */
896 		if (action.erase) {
897 			rc = img_mgmt_erase_image_data(0, req.size);
898 			if (rc != 0) {
899 				IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(&action,
900 					img_mgmt_err_str_flash_erase_failed);
901 				ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_IMAGE, rc);
902 				goto end;
903 			}
904 		}
905 #endif
906 	} else {
907 #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS)
908 		cmd_status_arg.status = IMG_MGMT_ID_UPLOAD_STATUS_ONGOING;
909 #endif
910 	}
911 
912 	/* Write the image data to flash. */
913 	if (req.img_data.len != 0) {
914 		/* If this is the last chunk */
915 		if (g_img_mgmt_state.off + req.img_data.len == g_img_mgmt_state.size) {
916 			last = true;
917 		}
918 
919 		rc = img_mgmt_write_image_data(req.off, req.img_data.value, action.write_bytes,
920 						    last);
921 		if (rc == 0) {
922 			g_img_mgmt_state.off += action.write_bytes;
923 		} else {
924 			/* Write failed, currently not able to recover from this */
925 #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS)
926 			cmd_status_arg.status = IMG_MGMT_ID_UPLOAD_STATUS_COMPLETE;
927 #endif
928 
929 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(&action,
930 				img_mgmt_err_str_flash_write_failed);
931 			reset = true;
932 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(&action,
933 				img_mgmt_err_str_flash_write_failed);
934 
935 			LOG_ERR("Irrecoverable error: flash write failed: %d", rc);
936 
937 			ok = smp_add_cmd_err(zse, MGMT_GROUP_ID_IMAGE, rc);
938 			goto end;
939 		}
940 
941 		if (g_img_mgmt_state.off == g_img_mgmt_state.size) {
942 			/* Done */
943 			reset = true;
944 
945 #ifdef CONFIG_IMG_ENABLE_IMAGE_CHECK
946 			static struct flash_img_context ctx;
947 
948 			if (flash_img_init_id(&ctx, g_img_mgmt_state.area_id) == 0) {
949 				struct flash_img_check fic = {
950 					.match = g_img_mgmt_state.data_sha,
951 					.clen = g_img_mgmt_state.size,
952 				};
953 
954 				if (flash_img_check(&ctx, &fic, g_img_mgmt_state.area_id) == 0) {
955 					data_match = true;
956 				} else {
957 					LOG_ERR("Uploaded image sha256 hash verification failed");
958 				}
959 			} else {
960 				LOG_ERR("Uploaded image sha256 could not be checked");
961 			}
962 #endif
963 
964 #if defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS)
965 			(void)mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_DFU_PENDING, NULL, 0,
966 						   &err_rc, &err_group);
967 		} else {
968 			/* Notify that the write has completed */
969 			(void)mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK_WRITE_COMPLETE,
970 						   NULL, 0, &err_rc, &err_group);
971 #endif
972 		}
973 	}
974 end:
975 
976 	img_mgmt_upload_log(req.off == 0, g_img_mgmt_state.off == g_img_mgmt_state.size, rc);
977 
978 #if defined(CONFIG_MCUMGR_SMP_COMMAND_STATUS_HOOKS)
979 	(void)mgmt_callback_notify(MGMT_EVT_OP_CMD_STATUS, &cmd_status_arg,
980 				   sizeof(cmd_status_arg), &err_rc, &err_group);
981 #endif
982 
983 	if (rc != 0) {
984 #if defined(CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS)
985 		(void)mgmt_callback_notify(MGMT_EVT_OP_IMG_MGMT_DFU_STOPPED, NULL, 0, &err_rc,
986 					   &err_group);
987 #endif
988 
989 		img_mgmt_reset_upload();
990 	} else {
991 		rc = img_mgmt_upload_good_rsp(ctxt);
992 
993 #ifdef CONFIG_IMG_ENABLE_IMAGE_CHECK
994 		if (last && rc == MGMT_ERR_EOK) {
995 			/* Append status to last packet */
996 			ok = zcbor_tstr_put_lit(zse, "match")	&&
997 			     zcbor_bool_put(zse, data_match);
998 		}
999 #endif
1000 
1001 		if (reset) {
1002 			/* Reset the upload state struct back to default */
1003 			img_mgmt_reset_upload();
1004 		}
1005 	}
1006 
1007 	img_mgmt_release_lock();
1008 
1009 	if (!ok) {
1010 		return MGMT_ERR_EMSGSIZE;
1011 	}
1012 
1013 	return MGMT_ERR_EOK;
1014 }
1015 
img_mgmt_my_version(struct image_version * ver)1016 int img_mgmt_my_version(struct image_version *ver)
1017 {
1018 	return img_mgmt_read_info(img_mgmt_active_slot(img_mgmt_active_image()),
1019 				  ver, NULL, NULL);
1020 }
1021 
1022 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
1023 /*
1024  * @brief	Translate IMG mgmt group error code into MCUmgr error code
1025  *
1026  * @param ret	#img_mgmt_err_code_t error code
1027  *
1028  * @return	#mcumgr_err_t error code
1029  */
img_mgmt_translate_error_code(uint16_t err)1030 static int img_mgmt_translate_error_code(uint16_t err)
1031 {
1032 	int rc;
1033 
1034 	switch (err) {
1035 	case IMG_MGMT_ERR_NO_IMAGE:
1036 	case IMG_MGMT_ERR_NO_TLVS:
1037 		rc = MGMT_ERR_ENOENT;
1038 		break;
1039 
1040 	case IMG_MGMT_ERR_NO_FREE_SLOT:
1041 	case IMG_MGMT_ERR_CURRENT_VERSION_IS_NEWER:
1042 	case IMG_MGMT_ERR_IMAGE_ALREADY_PENDING:
1043 		rc = MGMT_ERR_EBADSTATE;
1044 		break;
1045 
1046 	case IMG_MGMT_ERR_NO_FREE_MEMORY:
1047 		rc = MGMT_ERR_ENOMEM;
1048 		break;
1049 
1050 	case IMG_MGMT_ERR_INVALID_SLOT:
1051 	case IMG_MGMT_ERR_INVALID_PAGE_OFFSET:
1052 	case IMG_MGMT_ERR_INVALID_OFFSET:
1053 	case IMG_MGMT_ERR_INVALID_LENGTH:
1054 	case IMG_MGMT_ERR_INVALID_IMAGE_HEADER:
1055 	case IMG_MGMT_ERR_INVALID_HASH:
1056 	case IMG_MGMT_ERR_INVALID_FLASH_ADDRESS:
1057 		rc = MGMT_ERR_EINVAL;
1058 		break;
1059 
1060 	case IMG_MGMT_ERR_FLASH_CONFIG_QUERY_FAIL:
1061 	case IMG_MGMT_ERR_VERSION_GET_FAILED:
1062 	case IMG_MGMT_ERR_TLV_MULTIPLE_HASHES_FOUND:
1063 	case IMG_MGMT_ERR_TLV_INVALID_SIZE:
1064 	case IMG_MGMT_ERR_HASH_NOT_FOUND:
1065 	case IMG_MGMT_ERR_INVALID_TLV:
1066 	case IMG_MGMT_ERR_FLASH_OPEN_FAILED:
1067 	case IMG_MGMT_ERR_FLASH_READ_FAILED:
1068 	case IMG_MGMT_ERR_FLASH_WRITE_FAILED:
1069 	case IMG_MGMT_ERR_FLASH_ERASE_FAILED:
1070 	case IMG_MGMT_ERR_FLASH_CONTEXT_ALREADY_SET:
1071 	case IMG_MGMT_ERR_FLASH_CONTEXT_NOT_SET:
1072 	case IMG_MGMT_ERR_FLASH_AREA_DEVICE_NULL:
1073 	case IMG_MGMT_ERR_INVALID_IMAGE_HEADER_MAGIC:
1074 	case IMG_MGMT_ERR_INVALID_IMAGE_VECTOR_TABLE:
1075 	case IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE:
1076 	case IMG_MGMT_ERR_INVALID_IMAGE_DATA_OVERRUN:
1077 	case IMG_MGMT_ERR_UNKNOWN:
1078 	default:
1079 		rc = MGMT_ERR_EUNKNOWN;
1080 	}
1081 
1082 	return rc;
1083 }
1084 #endif
1085 
1086 static const struct mgmt_handler img_mgmt_handlers[] = {
1087 	[IMG_MGMT_ID_STATE] = {
1088 		.mh_read = img_mgmt_state_read,
1089 #if defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) || \
1090 	defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD)
1091 		.mh_write = NULL
1092 #else
1093 		.mh_write = img_mgmt_state_write,
1094 #endif
1095 	},
1096 	[IMG_MGMT_ID_UPLOAD] = {
1097 		.mh_read = NULL,
1098 		.mh_write = img_mgmt_upload
1099 	},
1100 	[IMG_MGMT_ID_ERASE] = {
1101 		.mh_read = NULL,
1102 		.mh_write = img_mgmt_erase
1103 	},
1104 #if defined(CONFIG_MCUMGR_GRP_IMG_SLOT_INFO)
1105 	[IMG_MGMT_ID_SLOT_INFO] = {
1106 		.mh_read = img_mgmt_slot_info,
1107 		.mh_write = NULL
1108 	},
1109 #endif
1110 };
1111 
1112 static const struct mgmt_handler img_mgmt_handlers[];
1113 
1114 #define IMG_MGMT_HANDLER_CNT ARRAY_SIZE(img_mgmt_handlers)
1115 
1116 static struct mgmt_group img_mgmt_group = {
1117 	.mg_handlers = (struct mgmt_handler *)img_mgmt_handlers,
1118 	.mg_handlers_count = IMG_MGMT_HANDLER_CNT,
1119 	.mg_group_id = MGMT_GROUP_ID_IMAGE,
1120 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
1121 	.mg_translate_error = img_mgmt_translate_error_code,
1122 #endif
1123 #ifdef CONFIG_MCUMGR_GRP_ENUM_DETAILS_NAME
1124 	.mg_group_name = "img mgmt",
1125 #endif
1126 };
1127 
img_mgmt_register_group(void)1128 static void img_mgmt_register_group(void)
1129 {
1130 	mgmt_register_group(&img_mgmt_group);
1131 }
1132 
1133 MCUMGR_HANDLER_DEFINE(img_mgmt, img_mgmt_register_group);
1134