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