1 /*
2  * Copyright (c) 2018-2021 mcumgr authors
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/init.h>
9 #include <zephyr/drivers/flash.h>
10 #include <zephyr/storage/flash_map.h>
11 #include <zephyr/dfu/mcuboot.h>
12 #include <zephyr/dfu/flash_img.h>
13 #include <zephyr/logging/log.h>
14 #include <bootutil/bootutil_public.h>
15 #include <assert.h>
16 
17 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
18 #include <zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h>
19 
20 #include <mgmt/mcumgr/grp/img_mgmt/img_mgmt_priv.h>
21 
22 #if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
23 #include <zephyr/retention/retention.h>
24 #include <zephyr/retention/blinfo.h>
25 #endif
26 
27 LOG_MODULE_DECLARE(mcumgr_img_grp, CONFIG_MCUMGR_GRP_IMG_LOG_LEVEL);
28 
29 #define SLOT0_PARTITION		slot0_partition
30 #define SLOT1_PARTITION		slot1_partition
31 #define SLOT2_PARTITION		slot2_partition
32 #define SLOT3_PARTITION		slot3_partition
33 #define SLOT4_PARTITION		slot4_partition
34 #define SLOT5_PARTITION		slot5_partition
35 
36 /* SLOT0_PARTITION and SLOT1_PARTITION are not checked because
37  * there is not conditional code that depends on them. If they do
38  * not exist compilation will fail, but in case if some of other
39  * partitions do not exist, code will compile and will not work
40  * properly.
41  */
42 #if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER >= 2
43 BUILD_ASSERT(FIXED_PARTITION_EXISTS(SLOT2_PARTITION) &&
44 	     FIXED_PARTITION_EXISTS(SLOT3_PARTITION),
45 	     "Missing partitions?");
46 #endif
47 
48 #if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER == 3
49 BUILD_ASSERT(FIXED_PARTITION_EXISTS(SLOT4_PARTITION) &&
50 	     FIXED_PARTITION_EXISTS(SLOT5_PARTITION),
51 	     "Missing partitions?");
52 #endif
53 
54 /**
55  * Determines if the specified area of flash is completely unwritten.
56  *
57  * @param	fa	pointer to flash area to scan
58  *
59  * @return	0 when not empty, 1 when empty, negative errno code on error.
60  */
img_mgmt_flash_check_empty_inner(const struct flash_area * fa)61 static int img_mgmt_flash_check_empty_inner(const struct flash_area *fa)
62 {
63 	uint32_t data[16];
64 	off_t addr;
65 	off_t end;
66 	int bytes_to_read;
67 	int rc;
68 	int i;
69 	uint8_t erased_val;
70 	uint32_t erased_val_32;
71 
72 	assert(fa->fa_size % 4 == 0);
73 
74 	erased_val = flash_area_erased_val(fa);
75 	erased_val_32 = ERASED_VAL_32(erased_val);
76 
77 	end = fa->fa_size;
78 	for (addr = 0; addr < end; addr += sizeof(data)) {
79 		if (end - addr < sizeof(data)) {
80 			bytes_to_read = end - addr;
81 		} else {
82 			bytes_to_read = sizeof(data);
83 		}
84 
85 		rc = flash_area_read(fa, addr, data, bytes_to_read);
86 		if (rc < 0) {
87 			LOG_ERR("Failed to read data from flash area: %d", rc);
88 			return IMG_MGMT_ERR_FLASH_READ_FAILED;
89 		}
90 
91 		for (i = 0; i < bytes_to_read / 4; i++) {
92 			if (data[i] != erased_val_32) {
93 				return 0;
94 			}
95 		}
96 	}
97 
98 	return 1;
99 }
100 
101 #ifndef CONFIG_IMG_ERASE_PROGRESSIVELY
102 /* Check if area is empty
103  *
104  * @param	fa_id	ID of flash area to scan.
105  *
106  * @return	0 when not empty, 1 when empty, negative errno code on error.
107  */
img_mgmt_flash_check_empty(uint8_t fa_id)108 static int img_mgmt_flash_check_empty(uint8_t fa_id)
109 {
110 	const struct flash_area *fa;
111 	int rc;
112 
113 	rc = flash_area_open(fa_id, &fa);
114 	if (rc == 0) {
115 		rc = img_mgmt_flash_check_empty_inner(fa);
116 
117 		flash_area_close(fa);
118 	} else {
119 		LOG_ERR("Failed to open flash area ID %u: %d", fa_id, rc);
120 		rc = IMG_MGMT_ERR_FLASH_OPEN_FAILED;
121 	}
122 
123 	return rc;
124 }
125 #endif
126 
127 /**
128  * Get flash_area ID for a image number; actually the slots are images
129  * for Zephyr, as slot 0 of image 0 is image_0, slot 0 of image 1 is
130  * image_2 and so on. The function treats slot numbers as absolute
131  * slot number starting at 0.
132  */
133 int
img_mgmt_flash_area_id(int slot)134 img_mgmt_flash_area_id(int slot)
135 {
136 	uint8_t fa_id;
137 
138 	switch (slot) {
139 	case 0:
140 		fa_id = FIXED_PARTITION_ID(SLOT0_PARTITION);
141 		break;
142 
143 	case 1:
144 		fa_id = FIXED_PARTITION_ID(SLOT1_PARTITION);
145 		break;
146 
147 #if FIXED_PARTITION_EXISTS(SLOT2_PARTITION)
148 	case 2:
149 		fa_id = FIXED_PARTITION_ID(SLOT2_PARTITION);
150 		break;
151 #endif
152 
153 #if FIXED_PARTITION_EXISTS(SLOT3_PARTITION)
154 	case 3:
155 		fa_id = FIXED_PARTITION_ID(SLOT3_PARTITION);
156 		break;
157 #endif
158 
159 #if FIXED_PARTITION_EXISTS(SLOT4_PARTITION)
160 	case 4:
161 		fa_id = FIXED_PARTITION_ID(SLOT4_PARTITION);
162 		break;
163 #endif
164 
165 #if FIXED_PARTITION_EXISTS(SLOT5_PARTITION)
166 	case 5:
167 		fa_id = FIXED_PARTITION_ID(SLOT5_PARTITION);
168 		break;
169 #endif
170 
171 	default:
172 		fa_id = -1;
173 		break;
174 	}
175 
176 	return fa_id;
177 }
178 
179 #if CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER == 1
180 /**
181  * In normal operation this function will select between first two slot
182  * (in reality it just checks whether second slot can be used), ignoring the
183  * slot parameter.
184  * When CONFIG_MCUMGR_GRP_IMG_DIRECT_UPLOAD is defined it will check if given
185  * slot is available, and allowed, for DFU; providing 0 as a parameter means
186  * find any unused and non-active available (auto-select); any other positive
187  * value is direct (slot + 1) to be used; if checks are positive, then area
188  * ID is returned, -1 is returned otherwise.
189  * Note that auto-selection is performed only between the two first slots.
190  */
img_mgmt_get_unused_slot_area_id(int slot)191 static int img_mgmt_get_unused_slot_area_id(int slot)
192 {
193 #if defined(CONFIG_MCUMGR_GRP_IMG_DIRECT_UPLOAD)
194 	slot--;
195 	if (slot < -1) {
196 		return -1;
197 	} else if (slot == -1) {
198 #endif
199 		/*
200 		 * Auto select slot; note that this is performed only between two first
201 		 * slots, at this point, which will require fix when Direct-XIP, which
202 		 * may support more slots, gets support within Zephyr.
203 		 */
204 		for (slot = 0; slot < 2; slot++) {
205 			if (img_mgmt_slot_in_use(slot) == 0) {
206 				int area_id = img_mgmt_flash_area_id(slot);
207 
208 				if (area_id >= 0) {
209 					return area_id;
210 				}
211 			}
212 		}
213 		return -1;
214 #if defined(CONFIG_MCUMGR_GRP_IMG_DIRECT_UPLOAD)
215 	}
216 	/*
217 	 * Direct selection; the first two slots are checked for being available
218 	 * and unused; the all other slots are just checked for availability.
219 	 */
220 	if (slot < 2) {
221 		slot = img_mgmt_slot_in_use(slot) == 0 ? slot : -1;
222 	}
223 
224 	/* Return area ID for the slot or -1 */
225 	return slot != -1  ? img_mgmt_flash_area_id(slot) : -1;
226 #endif
227 }
228 #elif CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER >= 2
img_mgmt_get_unused_slot_area_id(unsigned int image)229 static int img_mgmt_get_unused_slot_area_id(unsigned int image)
230 {
231 	int area_id = -1;
232 	int slot = 0;
233 
234 	slot = img_mgmt_get_opposite_slot(img_mgmt_active_slot(image));
235 
236 	if (!img_mgmt_slot_in_use(slot)) {
237 		area_id = img_mgmt_flash_area_id(slot);
238 	}
239 
240 	return area_id;
241 }
242 #else
243 #error "Unsupported number of images"
244 #endif
245 
img_mgmt_vercmp(const struct image_version * a,const struct image_version * b)246 int img_mgmt_vercmp(const struct image_version *a, const struct image_version *b)
247 {
248 	if (a->iv_major < b->iv_major) {
249 		return -1;
250 	} else if (a->iv_major > b->iv_major) {
251 		return 1;
252 	}
253 
254 	if (a->iv_minor < b->iv_minor) {
255 		return -1;
256 	} else if (a->iv_minor > b->iv_minor) {
257 		return 1;
258 	}
259 
260 	if (a->iv_revision < b->iv_revision) {
261 		return -1;
262 	} else if (a->iv_revision > b->iv_revision) {
263 		return 1;
264 	}
265 
266 #if defined(CONFIG_MCUMGR_GRP_IMG_VERSION_CMP_USE_BUILD_NUMBER)
267 	if (a->iv_build_num < b->iv_build_num) {
268 		return -1;
269 	} else if (a->iv_build_num > b->iv_build_num) {
270 		return 1;
271 	}
272 #endif
273 
274 	return 0;
275 }
276 
img_mgmt_erase_slot(int slot)277 int img_mgmt_erase_slot(int slot)
278 {
279 	const struct flash_area *fa;
280 	int rc;
281 	int area_id = img_mgmt_flash_area_id(slot);
282 
283 	if (area_id < 0) {
284 		return IMG_MGMT_ERR_INVALID_SLOT;
285 	}
286 
287 	rc = flash_area_open(area_id, &fa);
288 
289 	if (rc < 0) {
290 		LOG_ERR("Failed to open flash area ID %u: %d", area_id, rc);
291 		return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
292 	}
293 
294 	rc = img_mgmt_flash_check_empty_inner(fa);
295 
296 	if (rc == 0) {
297 		rc = flash_area_flatten(fa, 0, fa->fa_size);
298 
299 		if (rc != 0) {
300 			LOG_ERR("Failed to erase flash area: %d", rc);
301 			rc = IMG_MGMT_ERR_FLASH_ERASE_FAILED;
302 		}
303 	} else if (rc == 1) {
304 		/* A return value of 1 indicates that the slot is already erased, thus
305 		 * return a success code to the client
306 		 */
307 		rc = 0;
308 	}
309 
310 	flash_area_close(fa);
311 
312 	return rc;
313 }
314 
img_mgmt_write_pending(int slot,bool permanent)315 int img_mgmt_write_pending(int slot, bool permanent)
316 {
317 	int rc;
318 
319 	if (slot != 1 && !(CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER == 2 && slot == 3)) {
320 		return IMG_MGMT_ERR_INVALID_SLOT;
321 	}
322 
323 	rc = boot_request_upgrade_multi(img_mgmt_slot_to_image(slot), permanent);
324 	if (rc != 0) {
325 		LOG_ERR("Failed to write pending flag for slot %d: %d", slot, rc);
326 		return IMG_MGMT_ERR_FLASH_WRITE_FAILED;
327 	}
328 
329 	return IMG_MGMT_ERR_OK;
330 }
331 
img_mgmt_write_confirmed(void)332 int img_mgmt_write_confirmed(void)
333 {
334 	int rc;
335 
336 	rc = boot_write_img_confirmed();
337 	if (rc != 0) {
338 		LOG_ERR("Failed to write confirmed flag: %d", rc);
339 		return IMG_MGMT_ERR_FLASH_WRITE_FAILED;
340 	}
341 
342 	return IMG_MGMT_ERR_OK;
343 }
344 
img_mgmt_read(int slot,unsigned int offset,void * dst,unsigned int num_bytes)345 int img_mgmt_read(int slot, unsigned int offset, void *dst, unsigned int num_bytes)
346 {
347 	const struct flash_area *fa;
348 	int rc;
349 	int area_id = img_mgmt_flash_area_id(slot);
350 
351 	if (area_id < 0) {
352 		return IMG_MGMT_ERR_INVALID_SLOT;
353 	}
354 
355 	rc = flash_area_open(area_id, &fa);
356 	if (rc != 0) {
357 		LOG_ERR("Failed to open flash area ID %u: %d", area_id, rc);
358 		return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
359 	}
360 
361 	rc = flash_area_read(fa, offset, dst, num_bytes);
362 	flash_area_close(fa);
363 
364 	if (rc != 0) {
365 		LOG_ERR("Failed to read data from flash: %d", rc);
366 		return IMG_MGMT_ERR_FLASH_READ_FAILED;
367 	}
368 
369 	return 0;
370 }
371 
372 #if defined(CONFIG_MCUMGR_GRP_IMG_USE_HEAP_FOR_FLASH_IMG_CONTEXT)
img_mgmt_write_image_data(unsigned int offset,const void * data,unsigned int num_bytes,bool last)373 int img_mgmt_write_image_data(unsigned int offset, const void *data, unsigned int num_bytes,
374 			      bool last)
375 {
376 	/* Even if K_HEAP_MEM_POOL_SIZE will be able to match size of the structure,
377 	 * keep in mind that when application will put the heap under pressure, obtaining
378 	 * of a flash image context may not be possible, so plan bigger heap size or
379 	 * make sure to limit application pressure on heap when DFU is expected.
380 	 */
381 	BUILD_ASSERT(K_HEAP_MEM_POOL_SIZE >= (sizeof(struct flash_img_context)),
382 		     "Not enough heap mem for flash_img_context.");
383 
384 	int rc = IMG_MGMT_ERR_OK;
385 	static struct flash_img_context *ctx;
386 
387 	if (offset != 0 && ctx == NULL) {
388 		return IMG_MGMT_ERR_FLASH_CONTEXT_NOT_SET;
389 	}
390 
391 	if (offset == 0) {
392 		if (ctx != NULL) {
393 			return IMG_MGMT_ERR_FLASH_CONTEXT_ALREADY_SET;
394 		}
395 		ctx = k_malloc(sizeof(struct flash_img_context));
396 
397 		if (ctx == NULL) {
398 			return IMG_MGMT_ERR_NO_FREE_MEMORY;
399 		}
400 
401 		if (flash_img_init_id(ctx, g_img_mgmt_state.area_id) != 0) {
402 			rc = IMG_MGMT_ERR_FLASH_OPEN_FAILED;
403 			goto out;
404 		}
405 	}
406 
407 	if (flash_img_buffered_write(ctx, data, num_bytes, last) != 0) {
408 		rc = IMG_MGMT_ERR_FLASH_WRITE_FAILED;
409 		goto out;
410 	}
411 
412 out:
413 	if (last || rc != MGMT_ERR_EOK) {
414 		k_free(ctx);
415 		ctx = NULL;
416 	}
417 
418 	return rc;
419 }
420 #else
img_mgmt_write_image_data(unsigned int offset,const void * data,unsigned int num_bytes,bool last)421 int img_mgmt_write_image_data(unsigned int offset, const void *data, unsigned int num_bytes,
422 			      bool last)
423 {
424 	static struct flash_img_context ctx;
425 
426 	if (offset == 0) {
427 		if (flash_img_init_id(&ctx, g_img_mgmt_state.area_id) != 0) {
428 			return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
429 		}
430 	}
431 
432 	if (flash_img_buffered_write(&ctx, data, num_bytes, last) != 0) {
433 		return IMG_MGMT_ERR_FLASH_WRITE_FAILED;
434 	}
435 
436 	return IMG_MGMT_ERR_OK;
437 }
438 #endif
439 
img_mgmt_erase_image_data(unsigned int off,unsigned int num_bytes)440 int img_mgmt_erase_image_data(unsigned int off, unsigned int num_bytes)
441 {
442 	const struct flash_area *fa;
443 	int rc;
444 	const struct device *dev;
445 	struct flash_pages_info page;
446 	off_t page_offset;
447 	size_t erase_size;
448 
449 	if (off != 0) {
450 		rc = IMG_MGMT_ERR_INVALID_OFFSET;
451 		goto end;
452 	}
453 
454 	rc = flash_area_open(g_img_mgmt_state.area_id, &fa);
455 	if (rc != 0) {
456 		LOG_ERR("Can't bind to the flash area (err %d)", rc);
457 		rc = IMG_MGMT_ERR_FLASH_OPEN_FAILED;
458 		goto end;
459 	}
460 
461 	/* Align requested erase size to the erase-block-size */
462 	dev = flash_area_get_device(fa);
463 
464 	if (dev == NULL) {
465 		rc = IMG_MGMT_ERR_FLASH_AREA_DEVICE_NULL;
466 		goto end_fa;
467 	}
468 
469 	page_offset = fa->fa_off + num_bytes - 1;
470 	rc = flash_get_page_info_by_offs(dev, page_offset, &page);
471 	if (rc != 0) {
472 		LOG_ERR("bad offset (0x%lx)", (long)page_offset);
473 		rc = IMG_MGMT_ERR_INVALID_PAGE_OFFSET;
474 		goto end_fa;
475 	}
476 
477 	erase_size = page.start_offset + page.size - fa->fa_off;
478 	rc = flash_area_flatten(fa, boot_get_image_start_offset(g_img_mgmt_state.area_id),
479 				erase_size);
480 
481 	if (rc != 0) {
482 		LOG_ERR("image slot erase of 0x%zx bytes failed (err %d)", erase_size,
483 				rc);
484 		rc = IMG_MGMT_ERR_FLASH_ERASE_FAILED;
485 		goto end_fa;
486 	}
487 
488 	LOG_INF("Erased 0x%zx bytes of image slot", erase_size);
489 
490 #ifdef CONFIG_MCUBOOT_IMG_MANAGER
491 	/* Right now MCUmgr supports only mcuboot images.
492 	 * Above compilation swich might help to recognize mcuboot related
493 	 * code when supports for anothe bootloader will be introduced.
494 	 */
495 
496 	/* erase the image trailer area if it was not erased */
497 	off = boot_get_trailer_status_offset(fa->fa_size);
498 	if (off >= erase_size) {
499 		rc = flash_get_page_info_by_offs(dev, fa->fa_off + off, &page);
500 
501 		off = page.start_offset - fa->fa_off;
502 		erase_size = fa->fa_size - off;
503 
504 		rc = flash_area_flatten(fa, off, erase_size);
505 		if (rc != 0) {
506 			LOG_ERR("image slot trailer erase of 0x%zx bytes failed (err %d)",
507 					erase_size, rc);
508 			rc = IMG_MGMT_ERR_FLASH_ERASE_FAILED;
509 			goto end_fa;
510 		}
511 
512 		LOG_INF("Erased 0x%zx bytes of image slot trailer", erase_size);
513 	}
514 #endif
515 	rc = IMG_MGMT_ERR_OK;
516 
517 end_fa:
518 	flash_area_close(fa);
519 end:
520 	return rc;
521 }
522 
img_mgmt_swap_type(int slot)523 int img_mgmt_swap_type(int slot)
524 {
525 	int image = img_mgmt_slot_to_image(slot);
526 
527 	switch (mcuboot_swap_type_multi(image)) {
528 	case BOOT_SWAP_TYPE_NONE:
529 		return IMG_MGMT_SWAP_TYPE_NONE;
530 	case BOOT_SWAP_TYPE_TEST:
531 		return IMG_MGMT_SWAP_TYPE_TEST;
532 	case BOOT_SWAP_TYPE_PERM:
533 		return IMG_MGMT_SWAP_TYPE_PERM;
534 	case BOOT_SWAP_TYPE_REVERT:
535 		return IMG_MGMT_SWAP_TYPE_REVERT;
536 	default:
537 		return IMG_MGMT_SWAP_TYPE_UNKNOWN;
538 	}
539 }
540 
541 /**
542  * Verifies an upload request and indicates the actions that should be taken
543  * during processing of the request.  This is a "read only" function in the
544  * sense that it doesn't write anything to flash and doesn't modify any global
545  * variables.
546  *
547  * @param req		The upload request to inspect.
548  * @param action	On success, gets populated with information about how to process
549  *			the request.
550  *
551  * @return 0 if processing should occur; A MGMT_ERR code if an error response should be sent
552  *	   instead.
553  */
img_mgmt_upload_inspect(const struct img_mgmt_upload_req * req,struct img_mgmt_upload_action * action)554 int img_mgmt_upload_inspect(const struct img_mgmt_upload_req *req,
555 			    struct img_mgmt_upload_action *action)
556 {
557 	const struct image_header *hdr;
558 	struct image_version cur_ver;
559 	int rc;
560 
561 	memset(action, 0, sizeof(*action));
562 
563 	if (req->off == SIZE_MAX) {
564 		/* Request did not include an `off` field. */
565 		IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed);
566 		LOG_DBG("Request did not include an `off` field");
567 		return IMG_MGMT_ERR_INVALID_OFFSET;
568 	}
569 
570 	if (req->off == 0) {
571 		/* First upload chunk. */
572 		const struct flash_area *fa;
573 #if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) &&			\
574 	(defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) ||	\
575 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET) ||		\
576 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_MOVE) ||		\
577 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) ||		\
578 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) ||		\
579 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) ||			\
580 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) ||			\
581 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) &&	\
582 	CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0
583 		const struct flash_area *fa_current;
584 		int current_img_area;
585 #elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
586 		int max_image_size;
587 #endif
588 
589 		if (req->img_data.len < sizeof(struct image_header)) {
590 			/*  Image header is the first thing in the image */
591 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed);
592 			LOG_DBG("Image data too short: %u < %u", req->img_data.len,
593 				sizeof(struct image_header));
594 			return IMG_MGMT_ERR_INVALID_IMAGE_HEADER;
595 		}
596 
597 		if (req->size == SIZE_MAX) {
598 			/* Request did not include a `len` field. */
599 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_hdr_malformed);
600 			LOG_DBG("Request did not include a `len` field");
601 			return IMG_MGMT_ERR_INVALID_LENGTH;
602 		}
603 
604 		action->size = req->size;
605 
606 		hdr = (struct image_header *)req->img_data.value;
607 		if (hdr->ih_magic != IMAGE_MAGIC) {
608 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_magic_mismatch);
609 			LOG_DBG("Magic mismatch: %08X != %08X", hdr->ih_magic, IMAGE_MAGIC);
610 			return IMG_MGMT_ERR_INVALID_IMAGE_HEADER_MAGIC;
611 		}
612 
613 		if (req->data_sha.len > IMG_MGMT_DATA_SHA_LEN) {
614 			LOG_DBG("Invalid hash length: %u", req->data_sha.len);
615 			return IMG_MGMT_ERR_INVALID_HASH;
616 		}
617 
618 		/*
619 		 * If request includes proper data hash we can check whether there is
620 		 * upload in progress (interrupted due to e.g. link disconnection) with
621 		 * the same data hash so we can just resume it by simply including
622 		 * current upload offset in response.
623 		 */
624 		if ((req->data_sha.len > 0) && (g_img_mgmt_state.area_id != -1)) {
625 			if ((g_img_mgmt_state.data_sha_len == req->data_sha.len) &&
626 			    !memcmp(g_img_mgmt_state.data_sha, req->data_sha.value,
627 				    req->data_sha.len)) {
628 				return IMG_MGMT_ERR_OK;
629 			}
630 		}
631 
632 		action->area_id = img_mgmt_get_unused_slot_area_id(req->image);
633 		if (action->area_id < 0) {
634 			/* No slot available to upload to */
635 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_no_slot);
636 			LOG_DBG("No slot available to upload to");
637 			return IMG_MGMT_ERR_NO_FREE_SLOT;
638 		}
639 
640 		rc = flash_area_open(action->area_id, &fa);
641 		if (rc) {
642 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
643 				img_mgmt_err_str_flash_open_failed);
644 			LOG_ERR("Failed to open flash area ID %u: %d", action->area_id, rc);
645 			return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
646 		}
647 
648 		/* Check that the area is of sufficient size to store the new image */
649 		if (req->size > fa->fa_size) {
650 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
651 				img_mgmt_err_str_image_too_large);
652 			flash_area_close(fa);
653 			LOG_DBG("Upload too large for slot: %u > %u", req->size,
654 				fa->fa_size);
655 			return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE;
656 		}
657 
658 #if defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD) &&			\
659 	(defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_WITHOUT_SCRATCH) ||	\
660 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_OFFSET) ||		\
661 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_USING_MOVE) ||		\
662 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_SWAP_SCRATCH) ||		\
663 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_OVERWRITE_ONLY) ||		\
664 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_RAM_LOAD) ||			\
665 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP) ||			\
666 	 defined(CONFIG_MCUBOOT_BOOTLOADER_MODE_DIRECT_XIP_WITH_REVERT)) &&	\
667 	CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE > 0
668 		/* Check if slot1 is larger than slot0 by the update size, if so then the size
669 		 * check can be skipped because the devicetree partitions are okay
670 		 */
671 		current_img_area = img_mgmt_flash_area_id(req->image);
672 
673 		if (current_img_area < 0) {
674 			/* Current slot cannot be determined */
675 			LOG_ERR("Failed to determine active slot for image %d: %d", req->image,
676 				current_img_area);
677 			return IMG_MGMT_ERR_ACTIVE_SLOT_NOT_KNOWN;
678 		}
679 
680 		rc = flash_area_open(current_img_area, &fa_current);
681 		if (rc) {
682 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
683 				img_mgmt_err_str_flash_open_failed);
684 			LOG_ERR("Failed to open flash area ID %u: %d", current_img_area, rc);
685 			flash_area_close(fa);
686 			return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
687 		}
688 
689 		flash_area_close(fa_current);
690 
691 		LOG_DBG("Primary size: %d, secondary size: %d, overhead: %d, max update size: %d",
692 			fa_current->fa_size, fa->fa_size, CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE,
693 			(fa->fa_size + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE));
694 
695 		if (fa_current->fa_size >= (fa->fa_size + CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)) {
696 			/* Upgrade slot is of sufficient size, nothing to check */
697 			LOG_INF("Upgrade slots already sized appropriately, "
698 				"CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_SYSBUILD is not needed");
699 			goto skip_size_check;
700 		}
701 
702 		if (req->size > (fa->fa_size - CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE)) {
703 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
704 				img_mgmt_err_str_image_too_large);
705 			flash_area_close(fa);
706 			LOG_DBG("Upload too large for slot (with end offset): %u > %u", req->size,
707 				(fa->fa_size - CONFIG_MCUBOOT_UPDATE_FOOTER_SIZE));
708 			return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE;
709 		}
710 
711 skip_size_check:
712 #elif defined(CONFIG_MCUMGR_GRP_IMG_TOO_LARGE_BOOTLOADER_INFO)
713 		rc = blinfo_lookup(BLINFO_MAX_APPLICATION_SIZE, (char *)&max_image_size,
714 				   sizeof(max_image_size));
715 
716 		if (rc == sizeof(max_image_size) && max_image_size > 0 &&
717 		    req->size > max_image_size) {
718 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
719 				img_mgmt_err_str_image_too_large);
720 			flash_area_close(fa);
721 			LOG_DBG("Upload too large for slot (with max image size): %u > %u",
722 				req->size, max_image_size);
723 			return IMG_MGMT_ERR_INVALID_IMAGE_TOO_LARGE;
724 		}
725 #endif
726 
727 #if defined(CONFIG_MCUMGR_GRP_IMG_REJECT_DIRECT_XIP_MISMATCHED_SLOT)
728 		if (hdr->ih_flags & IMAGE_F_ROM_FIXED) {
729 			if (fa->fa_off != hdr->ih_load_addr) {
730 				IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
731 					img_mgmt_err_str_image_bad_flash_addr);
732 				flash_area_close(fa);
733 				LOG_DBG("Invalid flash address: %08X, expected: %08X",
734 					hdr->ih_load_addr, (int)fa->fa_off);
735 				return IMG_MGMT_ERR_INVALID_FLASH_ADDRESS;
736 			}
737 		}
738 #endif
739 
740 		flash_area_close(fa);
741 
742 		if (req->upgrade) {
743 			/* User specified upgrade-only. Make sure new image version is
744 			 * greater than that of the currently running image.
745 			 */
746 			rc = img_mgmt_my_version(&cur_ver);
747 			if (rc != 0) {
748 				LOG_DBG("Version get failed: %d", rc);
749 				return IMG_MGMT_ERR_VERSION_GET_FAILED;
750 			}
751 
752 			if (img_mgmt_vercmp(&cur_ver, &hdr->ih_ver) >= 0) {
753 				IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action,
754 					img_mgmt_err_str_downgrade);
755 				LOG_DBG("Downgrade: %d.%d.%d.%d, expected: %d.%d.%d.%d",
756 					cur_ver.iv_major, cur_ver.iv_minor, cur_ver.iv_revision,
757 					cur_ver.iv_build_num, hdr->ih_ver.iv_major,
758 					hdr->ih_ver.iv_minor, hdr->ih_ver.iv_revision,
759 					hdr->ih_ver.iv_build_num);
760 				return IMG_MGMT_ERR_CURRENT_VERSION_IS_NEWER;
761 			}
762 		}
763 
764 #ifndef CONFIG_IMG_ERASE_PROGRESSIVELY
765 		rc = img_mgmt_flash_check_empty(action->area_id);
766 		if (rc < 0) {
767 			LOG_DBG("Flash check empty failed: %d", rc);
768 			return rc;
769 		}
770 
771 		action->erase = (rc == 0);
772 #endif
773 	} else {
774 		/* Continuation of upload. */
775 		action->area_id = g_img_mgmt_state.area_id;
776 		action->size = g_img_mgmt_state.size;
777 
778 		if (req->off != g_img_mgmt_state.off) {
779 			/*
780 			 * Invalid offset. Drop the data, and respond with the offset we're
781 			 * expecting data for.
782 			 */
783 			LOG_DBG("Invalid offset: %08x, expected: %08x", req->off,
784 				g_img_mgmt_state.off);
785 			return IMG_MGMT_ERR_OK;
786 		}
787 
788 		if ((req->off + req->img_data.len) > action->size) {
789 			/* Data overrun, the amount of data written would be more than the size
790 			 * of the image that the client originally sent
791 			 */
792 			IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, img_mgmt_err_str_data_overrun);
793 			LOG_DBG("Data overrun: %u + %u > %llu", req->off, req->img_data.len,
794 				action->size);
795 			return IMG_MGMT_ERR_INVALID_IMAGE_DATA_OVERRUN;
796 		}
797 	}
798 
799 	action->write_bytes = req->img_data.len;
800 	action->proceed = true;
801 	IMG_MGMT_UPLOAD_ACTION_SET_RC_RSN(action, NULL);
802 
803 	return IMG_MGMT_ERR_OK;
804 }
805 
img_mgmt_erased_val(int slot,uint8_t * erased_val)806 int img_mgmt_erased_val(int slot, uint8_t *erased_val)
807 {
808 	const struct flash_area *fa;
809 	int rc;
810 	int area_id = img_mgmt_flash_area_id(slot);
811 
812 	if (area_id < 0) {
813 		LOG_DBG("Invalid slot: %d", area_id);
814 		return IMG_MGMT_ERR_INVALID_SLOT;
815 	}
816 
817 	rc = flash_area_open(area_id, &fa);
818 	if (rc != 0) {
819 		LOG_ERR("Failed to open flash area ID %u: %d", area_id, rc);
820 		return IMG_MGMT_ERR_FLASH_OPEN_FAILED;
821 	}
822 
823 	*erased_val = flash_area_erased_val(fa);
824 	flash_area_close(fa);
825 
826 	return 0;
827 }
828