1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <zcbor_common.h>
12 #include <zcbor_decode.h>
13 #include <zcbor_encode.h>
14 
15 #include <zephyr/kernel.h>
16 #include <zephyr/device.h>
17 #include <zephyr/sys/byteorder.h>
18 #include <zephyr/net_buf.h>
19 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
20 #include <zephyr/mgmt/mcumgr/smp/smp.h>
21 #include <zephyr/mgmt/mcumgr/smp/smp_client.h>
22 #include <zephyr/mgmt/mcumgr/transport/smp.h>
23 #include <zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h>
24 #include <zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h>
25 
26 #include <mgmt/mcumgr/util/zcbor_bulk.h>
27 #include <mgmt/mcumgr/transport/smp_internal.h>
28 
29 #include <zephyr/logging/log.h>
30 LOG_MODULE_REGISTER(mcumgr_grp_img_client, CONFIG_MCUMGR_GRP_IMG_CLIENT_LOG_LEVEL);
31 
32 #define MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE 128
33 
34 /* Pointer for active Client */
35 static struct img_mgmt_client *active_client;
36 /* Image State read or set response pointer */
37 static struct mcumgr_image_state *image_info;
38 /* Image upload response pointer */
39 static struct mcumgr_image_upload *image_upload_buf;
40 
41 static K_SEM_DEFINE(mcumgr_img_client_grp_sem, 0, 1);
42 static K_MUTEX_DEFINE(mcumgr_img_client_grp_mutex);
43 
44 static const char smp_images_str[] = "images";
45 #define IMAGES_STR_LEN (sizeof(smp_images_str) - 1)
46 
image_state_res_fn(struct net_buf * nb,void * user_data)47 static int image_state_res_fn(struct net_buf *nb, void *user_data)
48 {
49 	zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
50 	struct zcbor_string value = {0};
51 	int buf_len, rc;
52 	uint32_t img_num, slot_num;
53 	struct zcbor_string hash, version;
54 	bool bootable, pending, confirmed, active, permanent, ok;
55 	size_t decoded;
56 	struct zcbor_map_decode_key_val list_res_decode[] = {
57 		/* Mandatory */
58 		ZCBOR_MAP_DECODE_KEY_DECODER("version", zcbor_tstr_decode, &version),
59 		ZCBOR_MAP_DECODE_KEY_DECODER("hash", zcbor_bstr_decode, &hash),
60 		ZCBOR_MAP_DECODE_KEY_DECODER("slot", zcbor_uint32_decode, &slot_num),
61 		/* Optional */
62 		ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &img_num),
63 		ZCBOR_MAP_DECODE_KEY_DECODER("bootable", zcbor_bool_decode, &bootable),
64 		ZCBOR_MAP_DECODE_KEY_DECODER("pending", zcbor_bool_decode, &pending),
65 		ZCBOR_MAP_DECODE_KEY_DECODER("confirmed", zcbor_bool_decode, &confirmed),
66 		ZCBOR_MAP_DECODE_KEY_DECODER("active", zcbor_bool_decode, &active),
67 		ZCBOR_MAP_DECODE_KEY_DECODER("permanent", zcbor_bool_decode, &permanent)
68 		};
69 
70 	buf_len = active_client->image_list_length;
71 
72 	if (!nb) {
73 		image_info->status = MGMT_ERR_ETIMEOUT;
74 		goto out;
75 	}
76 
77 	zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0);
78 
79 	ok = zcbor_map_start_decode(zsd);
80 	if (!ok) {
81 		image_info->status = MGMT_ERR_ECORRUPT;
82 		goto out;
83 	}
84 
85 	ok = zcbor_tstr_decode(zsd, &value);
86 	if (!ok) {
87 		image_info->status = MGMT_ERR_ECORRUPT;
88 		goto out;
89 	}
90 	if (value.len != IMAGES_STR_LEN || memcmp(value.value, smp_images_str, IMAGES_STR_LEN)) {
91 		image_info->status = MGMT_ERR_EINVAL;
92 		goto out;
93 	}
94 
95 	ok = zcbor_list_start_decode(zsd);
96 	if (!ok) {
97 		image_info->status = MGMT_ERR_ECORRUPT;
98 		goto out;
99 	}
100 
101 	rc = 0;
102 	/* Parse Image map info to configured buffer */
103 	while (rc == 0) {
104 		decoded = 0;
105 		zcbor_map_decode_bulk_reset(list_res_decode, ARRAY_SIZE(list_res_decode));
106 		/* Init buffer values */
107 		active = false;
108 		bootable = false;
109 		confirmed = false;
110 		pending = false;
111 		permanent = false;
112 		img_num = 0;
113 		slot_num = UINT32_MAX;
114 		hash.len = 0;
115 		version.len = 0;
116 
117 		rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode),
118 					   &decoded);
119 		if (rc) {
120 			if (image_info->image_list_length) {
121 				/* No more map */
122 				break;
123 			}
124 			LOG_ERR("Corrupted Image data %d", rc);
125 			image_info->status = MGMT_ERR_EINVAL;
126 			goto out;
127 		}
128 		/* Check that mandatory parameters have decoded */
129 		if (hash.len != IMG_MGMT_DATA_SHA_LEN || !version.len ||
130 		    !zcbor_map_decode_bulk_key_found(list_res_decode, ARRAY_SIZE(list_res_decode),
131 						     "slot")) {
132 			LOG_ERR("Missing mandatory parametrs");
133 			image_info->status = MGMT_ERR_EINVAL;
134 			goto out;
135 		}
136 		/* Store parsed values */
137 		if (buf_len) {
138 			image_info->image_list[image_info->image_list_length].img_num = img_num;
139 			image_info->image_list[image_info->image_list_length].slot_num = slot_num;
140 			memcpy(image_info->image_list[image_info->image_list_length].hash,
141 			       hash.value, IMG_MGMT_DATA_SHA_LEN);
142 			if (version.len > IMG_MGMT_VER_MAX_STR_LEN) {
143 				LOG_WRN("Version truncated len %d -> %d", version.len,
144 					IMG_MGMT_VER_MAX_STR_LEN);
145 				version.len = IMG_MGMT_VER_MAX_STR_LEN;
146 			}
147 			memcpy(image_info->image_list[image_info->image_list_length].version,
148 			       version.value, version.len);
149 			image_info->image_list[image_info->image_list_length].version[version.len] =
150 				'\0';
151 			/* Set Image flags */
152 			image_info->image_list[image_info->image_list_length].flags.bootable =
153 				bootable;
154 			image_info->image_list[image_info->image_list_length].flags.pending =
155 				pending;
156 			image_info->image_list[image_info->image_list_length].flags.confirmed =
157 				confirmed;
158 			image_info->image_list[image_info->image_list_length].flags.active = active;
159 			image_info->image_list[image_info->image_list_length].flags.permanent =
160 				permanent;
161 			/* Update valid image count */
162 			image_info->image_list_length++;
163 			buf_len--;
164 		} else {
165 			LOG_INF("User configured image list buffer size %d can't store all info",
166 				active_client->image_list_length);
167 		}
168 	}
169 
170 	ok = zcbor_list_end_decode(zsd);
171 	if (!ok) {
172 		image_info->status = MGMT_ERR_ECORRUPT;
173 	} else {
174 
175 		image_info->status = MGMT_ERR_EOK;
176 	}
177 
178 out:
179 	if (image_info->status != MGMT_ERR_EOK) {
180 		image_info->image_list_length = 0;
181 	}
182 	rc = image_info->status;
183 	k_sem_give(user_data);
184 	return rc;
185 }
186 
image_upload_res_fn(struct net_buf * nb,void * user_data)187 static int image_upload_res_fn(struct net_buf *nb, void *user_data)
188 {
189 	zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
190 	size_t decoded;
191 	int rc;
192 	int32_t res_rc = MGMT_ERR_EOK;
193 
194 	struct zcbor_map_decode_key_val upload_res_decode[] = {
195 		ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode,
196 					     &image_upload_buf->image_upload_offset),
197 		ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &res_rc)};
198 
199 	if (!nb) {
200 		image_upload_buf->status = MGMT_ERR_ETIMEOUT;
201 		goto end;
202 	}
203 
204 	zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0);
205 
206 	rc = zcbor_map_decode_bulk(zsd, upload_res_decode, ARRAY_SIZE(upload_res_decode), &decoded);
207 	if (rc || image_upload_buf->image_upload_offset == SIZE_MAX) {
208 		image_upload_buf->status = MGMT_ERR_EINVAL;
209 		goto end;
210 	}
211 	image_upload_buf->status = res_rc;
212 
213 	active_client->upload.offset = image_upload_buf->image_upload_offset;
214 end:
215 	/* Set status for Upload request handler */
216 	rc = image_upload_buf->status;
217 	k_sem_give(user_data);
218 	return rc;
219 }
220 
erase_res_fn(struct net_buf * nb,void * user_data)221 static int erase_res_fn(struct net_buf *nb, void *user_data)
222 {
223 	zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
224 	size_t decoded;
225 	int rc, status = MGMT_ERR_EOK;
226 
227 	struct zcbor_map_decode_key_val upload_res_decode[] = {
228 		ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &status)
229 		};
230 
231 	if (!nb) {
232 		active_client->status = MGMT_ERR_ETIMEOUT;
233 		goto end;
234 	}
235 
236 	zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0);
237 
238 	rc = zcbor_map_decode_bulk(zsd, upload_res_decode, ARRAY_SIZE(upload_res_decode), &decoded);
239 	if (rc) {
240 		LOG_ERR("Erase fail %d", rc);
241 		active_client->status = MGMT_ERR_EINVAL;
242 		goto end;
243 	}
244 	active_client->status = status;
245 end:
246 	rc = active_client->status;
247 	k_sem_give(user_data);
248 	return rc;
249 }
250 
upload_message_header_size(struct img_gr_upload * upload_state)251 static size_t upload_message_header_size(struct img_gr_upload *upload_state)
252 {
253 	bool ok;
254 	size_t cbor_length;
255 	int map_count;
256 	zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
257 	uint8_t temp_buf[MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE];
258 	uint8_t temp_data = 0U;
259 
260 	/* Calculation of message header with data length of 1 */
261 
262 	zcbor_new_encode_state(zse, ARRAY_SIZE(zse), temp_buf, MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE,
263 			       0);
264 	if (upload_state->hash_initialized) {
265 		map_count = 12;
266 	} else {
267 		map_count = 10;
268 	}
269 
270 	/* Init map start and write image info and data */
271 	ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "image") &&
272 	     zcbor_uint32_put(zse, upload_state->image_num) && zcbor_tstr_put_lit(zse, "data") &&
273 	     zcbor_bstr_encode_ptr(zse, &temp_data, 1) && zcbor_tstr_put_lit(zse, "len") &&
274 	     zcbor_size_put(zse, upload_state->image_size) && zcbor_tstr_put_lit(zse, "off") &&
275 	     zcbor_size_put(zse, upload_state->offset);
276 
277 	/* Write hash when it defined and offset is 0 */
278 	if (ok && upload_state->hash_initialized) {
279 		ok = zcbor_tstr_put_lit(zse, "sha") &&
280 		     zcbor_bstr_encode_ptr(zse, upload_state->sha256, IMG_MGMT_DATA_SHA_LEN);
281 	}
282 
283 	if (ok) {
284 		ok = zcbor_map_end_encode(zse, map_count);
285 	}
286 
287 	if (!ok) {
288 		LOG_ERR("Failed to encode Image Upload packet");
289 		return 0;
290 	}
291 	cbor_length = zse->payload - temp_buf;
292 	/* Return Message header length */
293 	return cbor_length + (CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE - 1);
294 }
295 
img_mgmt_client_init(struct img_mgmt_client * client,struct smp_client_object * smp_client,int image_list_size,struct mcumgr_image_data * image_list)296 void img_mgmt_client_init(struct img_mgmt_client *client, struct smp_client_object *smp_client,
297 			  int image_list_size, struct mcumgr_image_data *image_list)
298 {
299 	client->smp_client = smp_client;
300 	client->image_list_length = image_list_size;
301 	client->image_list = image_list;
302 }
303 
img_mgmt_client_upload_init(struct img_mgmt_client * client,size_t image_size,uint32_t image_num,const char * image_hash)304 int img_mgmt_client_upload_init(struct img_mgmt_client *client, size_t image_size,
305 				uint32_t image_num, const char *image_hash)
306 {
307 	int rc;
308 
309 	k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER);
310 	client->upload.image_size = image_size;
311 	client->upload.offset = 0;
312 	client->upload.image_num = image_num;
313 	if (image_hash) {
314 		memcpy(client->upload.sha256, image_hash, IMG_MGMT_DATA_SHA_LEN);
315 		client->upload.hash_initialized = true;
316 	} else {
317 		client->upload.hash_initialized = false;
318 	}
319 
320 	/* Calculate worst case header size for adapt payload length */
321 	client->upload.upload_header_size = upload_message_header_size(&client->upload);
322 	if (client->upload.upload_header_size) {
323 		rc = MGMT_ERR_EOK;
324 	} else {
325 		rc = MGMT_ERR_ENOMEM;
326 	}
327 	k_mutex_unlock(&mcumgr_img_client_grp_mutex);
328 	return rc;
329 }
330 
img_mgmt_client_upload(struct img_mgmt_client * client,const uint8_t * data,size_t length,struct mcumgr_image_upload * res_buf)331 int img_mgmt_client_upload(struct img_mgmt_client *client, const uint8_t *data, size_t length,
332 			   struct mcumgr_image_upload *res_buf)
333 {
334 	struct net_buf *nb;
335 	const uint8_t *write_ptr;
336 	int rc;
337 	uint32_t map_count;
338 	bool ok;
339 	size_t write_length, max_data_length, offset_before_send, request_length, wrote_length;
340 	zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
341 
342 	k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER);
343 	active_client = client;
344 	image_upload_buf = res_buf;
345 
346 	request_length = length;
347 	wrote_length = 0;
348 	/* Calculate max data length based on
349 	 * net_buf size - (SMP header + CBOR message_len + 16-bit CRC + 16-bit length)
350 	 */
351 	max_data_length = CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE -
352 			  (active_client->upload.upload_header_size + MGMT_HDR_SIZE + 2U + 2U);
353 	/* Trim length based on CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE */
354 	if (max_data_length % CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE) {
355 		max_data_length -=
356 			(max_data_length % CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE);
357 	}
358 
359 	while (request_length != wrote_length) {
360 		write_ptr = data + wrote_length;
361 		write_length = request_length - wrote_length;
362 		if (write_length > max_data_length) {
363 			write_length = max_data_length;
364 		}
365 
366 		nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE,
367 					       IMG_MGMT_ID_UPLOAD, MGMT_OP_WRITE,
368 					       SMP_MCUMGR_VERSION_1);
369 		if (!nb) {
370 			image_upload_buf->status = MGMT_ERR_ENOMEM;
371 			goto end;
372 		}
373 
374 		zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len,
375 				       net_buf_tailroom(nb), 0);
376 		if (active_client->upload.offset) {
377 			map_count = 6;
378 		} else if (active_client->upload.hash_initialized) {
379 			map_count = 12;
380 		} else {
381 			map_count = 10;
382 		}
383 
384 		/* Init map start and write image info, data and offset */
385 		ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "image") &&
386 		     zcbor_uint32_put(zse, active_client->upload.image_num) &&
387 		     zcbor_tstr_put_lit(zse, "data") &&
388 		     zcbor_bstr_encode_ptr(zse, write_ptr, write_length) &&
389 		     zcbor_tstr_put_lit(zse, "off") &&
390 		     zcbor_size_put(zse, active_client->upload.offset);
391 		/* Write Len and configured hash when offset is zero */
392 		if (ok && !active_client->upload.offset) {
393 			ok = zcbor_tstr_put_lit(zse, "len") &&
394 			     zcbor_size_put(zse, active_client->upload.image_size);
395 			if (ok && active_client->upload.hash_initialized) {
396 				ok = zcbor_tstr_put_lit(zse, "sha") &&
397 				     zcbor_bstr_encode_ptr(zse, active_client->upload.sha256,
398 							   IMG_MGMT_DATA_SHA_LEN);
399 			}
400 		}
401 
402 		if (ok) {
403 			ok = zcbor_map_end_encode(zse, map_count);
404 		}
405 
406 		if (!ok) {
407 			LOG_ERR("Failed to encode Image Upload packet");
408 			smp_packet_free(nb);
409 			image_upload_buf->status = MGMT_ERR_ENOMEM;
410 			goto end;
411 		}
412 
413 		offset_before_send = active_client->upload.offset;
414 		nb->len = zse->payload - nb->data;
415 		k_sem_reset(&mcumgr_img_client_grp_sem);
416 
417 		image_upload_buf->status = MGMT_ERR_EINVAL;
418 		image_upload_buf->image_upload_offset = SIZE_MAX;
419 
420 		rc = smp_client_send_cmd(active_client->smp_client, nb, image_upload_res_fn,
421 					 &mcumgr_img_client_grp_sem,
422 					 CONFIG_MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT);
423 		if (rc) {
424 			LOG_ERR("Failed to send SMP Upload init packet, err: %d", rc);
425 			smp_packet_free(nb);
426 			image_upload_buf->status = rc;
427 			goto end;
428 
429 		}
430 		k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER);
431 		if (image_upload_buf->status) {
432 			LOG_ERR("Upload Fail: %d", image_upload_buf->status);
433 			goto end;
434 		}
435 
436 		if (offset_before_send + write_length < active_client->upload.offset) {
437 			/* Offset further than expected which indicate upload session resume */
438 			goto end;
439 		}
440 
441 		wrote_length += write_length;
442 	}
443 end:
444 	rc = image_upload_buf->status;
445 	active_client = NULL;
446 	image_upload_buf = NULL;
447 	k_mutex_unlock(&mcumgr_img_client_grp_mutex);
448 
449 	return rc;
450 }
451 
img_mgmt_client_state_write(struct img_mgmt_client * client,char * hash,bool confirm,struct mcumgr_image_state * res_buf)452 int img_mgmt_client_state_write(struct img_mgmt_client *client, char *hash, bool confirm,
453 				struct mcumgr_image_state *res_buf)
454 {
455 	struct net_buf *nb;
456 	int rc;
457 	uint32_t map_count;
458 	zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS];
459 	bool ok;
460 
461 	k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER);
462 	active_client = client;
463 	image_info = res_buf;
464 	/* Init Response */
465 	res_buf->image_list_length = 0;
466 	res_buf->image_list = active_client->image_list;
467 
468 	nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE,
469 				       IMG_MGMT_ID_STATE, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1);
470 	if (!nb) {
471 		res_buf->status = MGMT_ERR_ENOMEM;
472 		goto end;
473 	}
474 
475 	zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0);
476 	if (hash) {
477 		map_count = 4;
478 	} else {
479 		map_count = 2;
480 	}
481 
482 	/* Write map start init and confirm params */
483 	ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "confirm") &&
484 	     zcbor_bool_put(zse, confirm);
485 	/* Write hash data */
486 	if (ok && hash) {
487 		ok = zcbor_tstr_put_lit(zse, "hash") &&
488 		     zcbor_bstr_encode_ptr(zse, hash, IMG_MGMT_DATA_SHA_LEN);
489 	}
490 	/* Close map */
491 	if (ok) {
492 		ok = zcbor_map_end_encode(zse, map_count);
493 	}
494 
495 	if (!ok) {
496 		smp_packet_free(nb);
497 		res_buf->status = MGMT_ERR_ENOMEM;
498 		goto end;
499 	}
500 
501 	nb->len = zse->payload - nb->data;
502 	k_sem_reset(&mcumgr_img_client_grp_sem);
503 	rc = smp_client_send_cmd(active_client->smp_client, nb, image_state_res_fn,
504 				 &mcumgr_img_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME);
505 	if (rc) {
506 		res_buf->status = rc;
507 		smp_packet_free(nb);
508 		goto end;
509 	}
510 	k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER);
511 end:
512 	rc = res_buf->status;
513 	active_client = NULL;
514 	k_mutex_unlock(&mcumgr_img_client_grp_mutex);
515 	return rc;
516 }
517 
img_mgmt_client_state_read(struct img_mgmt_client * client,struct mcumgr_image_state * res_buf)518 int img_mgmt_client_state_read(struct img_mgmt_client *client, struct mcumgr_image_state *res_buf)
519 {
520 	struct net_buf *nb;
521 	int rc;
522 	zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS];
523 	bool ok;
524 
525 	k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER);
526 	active_client = client;
527 	/* Init Response */
528 	res_buf->image_list_length = 0;
529 	res_buf->image_list = active_client->image_list;
530 
531 	image_info = res_buf;
532 
533 	nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE,
534 				       IMG_MGMT_ID_STATE, MGMT_OP_READ, SMP_MCUMGR_VERSION_1);
535 	if (!nb) {
536 		res_buf->status = MGMT_ERR_ENOMEM;
537 		goto end;
538 	}
539 
540 	zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0);
541 	ok = zcbor_map_start_encode(zse, 1) && zcbor_map_end_encode(zse, 1);
542 	if (!ok) {
543 		smp_packet_free(nb);
544 		res_buf->status = MGMT_ERR_ENOMEM;
545 		goto end;
546 	}
547 
548 	nb->len = zse->payload - nb->data;
549 	k_sem_reset(&mcumgr_img_client_grp_sem);
550 	rc = smp_client_send_cmd(active_client->smp_client, nb, image_state_res_fn,
551 				 &mcumgr_img_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME);
552 	if (rc) {
553 		smp_packet_free(nb);
554 		res_buf->status = rc;
555 		goto end;
556 	}
557 	k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER);
558 end:
559 	rc = res_buf->status;
560 	image_info = NULL;
561 	active_client = NULL;
562 	k_mutex_unlock(&mcumgr_img_client_grp_mutex);
563 	return rc;
564 }
565 
img_mgmt_client_erase(struct img_mgmt_client * client,uint32_t slot)566 int img_mgmt_client_erase(struct img_mgmt_client *client, uint32_t slot)
567 {
568 	struct net_buf *nb;
569 	int rc;
570 	zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS];
571 	bool ok;
572 
573 	k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER);
574 	active_client = client;
575 
576 	nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE,
577 				       IMG_MGMT_ID_ERASE, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1);
578 	if (!nb) {
579 		active_client->status = MGMT_ERR_ENOMEM;
580 		goto end;
581 	}
582 
583 	zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0);
584 
585 	ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "slot") &&
586 	     zcbor_uint32_put(zse, slot) && zcbor_map_end_encode(zse, 2);
587 	if (!ok) {
588 		smp_packet_free(nb);
589 		active_client->status = MGMT_ERR_ENOMEM;
590 		goto end;
591 	}
592 
593 	nb->len = zse->payload - nb->data;
594 	k_sem_reset(&mcumgr_img_client_grp_sem);
595 	rc = smp_client_send_cmd(client->smp_client, nb, erase_res_fn, &mcumgr_img_client_grp_sem,
596 				 CONFIG_MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT);
597 	if (rc) {
598 		smp_packet_free(nb);
599 		active_client->status = rc;
600 		goto end;
601 	}
602 	k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER);
603 end:
604 	rc = active_client->status;
605 	active_client = NULL;
606 	k_mutex_unlock(&mcumgr_img_client_grp_mutex);
607 	return rc;
608 }
609