| /* |
| * Copyright (c) 2023 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <zcbor_common.h> |
| #include <zcbor_decode.h> |
| #include <zcbor_encode.h> |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/device.h> |
| #include <zephyr/sys/byteorder.h> |
| #include <zephyr/net/buf.h> |
| #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h> |
| #include <zephyr/mgmt/mcumgr/smp/smp.h> |
| #include <zephyr/mgmt/mcumgr/smp/smp_client.h> |
| #include <zephyr/mgmt/mcumgr/transport/smp.h> |
| #include <zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt.h> |
| #include <zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h> |
| |
| #include <mgmt/mcumgr/util/zcbor_bulk.h> |
| #include <mgmt/mcumgr/transport/smp_internal.h> |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(mcumgr_grp_img_client, CONFIG_MCUMGR_GRP_IMG_CLIENT_LOG_LEVEL); |
| |
| #define MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE 128 |
| |
| /* Pointer for active Client */ |
| static struct img_mgmt_client *active_client; |
| /* Image State read or set response pointer */ |
| static struct mcumgr_image_state *image_info; |
| /* Image upload response pointer */ |
| static struct mcumgr_image_upload *image_upload_buf; |
| |
| static K_SEM_DEFINE(mcumgr_img_client_grp_sem, 0, 1); |
| static K_MUTEX_DEFINE(mcumgr_img_client_grp_mutex); |
| |
| static const char smp_images_str[] = "images"; |
| #define IMAGES_STR_LEN (sizeof(smp_images_str) - 1) |
| |
| static int image_state_res_fn(struct net_buf *nb, void *user_data) |
| { |
| zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; |
| struct zcbor_string value = {0}; |
| int buf_len, rc; |
| uint32_t img_num, slot_num; |
| struct zcbor_string hash, version; |
| bool bootable, pending, confirmed, active, permanent, ok; |
| size_t decoded; |
| struct zcbor_map_decode_key_val list_res_decode[] = { |
| /* Mandatory */ |
| ZCBOR_MAP_DECODE_KEY_DECODER("version", zcbor_tstr_decode, &version), |
| ZCBOR_MAP_DECODE_KEY_DECODER("hash", zcbor_bstr_decode, &hash), |
| ZCBOR_MAP_DECODE_KEY_DECODER("slot", zcbor_uint32_decode, &slot_num), |
| /* Optional */ |
| ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &img_num), |
| ZCBOR_MAP_DECODE_KEY_DECODER("bootable", zcbor_bool_decode, &bootable), |
| ZCBOR_MAP_DECODE_KEY_DECODER("pending", zcbor_bool_decode, &pending), |
| ZCBOR_MAP_DECODE_KEY_DECODER("confirmed", zcbor_bool_decode, &confirmed), |
| ZCBOR_MAP_DECODE_KEY_DECODER("active", zcbor_bool_decode, &active), |
| ZCBOR_MAP_DECODE_KEY_DECODER("permanent", zcbor_bool_decode, &permanent) |
| }; |
| |
| buf_len = active_client->image_list_length; |
| |
| if (!nb) { |
| image_info->status = MGMT_ERR_ETIMEOUT; |
| goto out; |
| } |
| |
| zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0); |
| |
| ok = zcbor_map_start_decode(zsd); |
| if (!ok) { |
| image_info->status = MGMT_ERR_ECORRUPT; |
| goto out; |
| } |
| |
| ok = zcbor_tstr_decode(zsd, &value); |
| if (!ok) { |
| image_info->status = MGMT_ERR_ECORRUPT; |
| goto out; |
| } |
| if (value.len != IMAGES_STR_LEN || memcmp(value.value, smp_images_str, IMAGES_STR_LEN)) { |
| image_info->status = MGMT_ERR_EINVAL; |
| goto out; |
| } |
| |
| ok = zcbor_list_start_decode(zsd); |
| if (!ok) { |
| image_info->status = MGMT_ERR_ECORRUPT; |
| goto out; |
| } |
| |
| rc = 0; |
| /* Parse Image map info to configured buffer */ |
| while (rc == 0) { |
| decoded = 0; |
| zcbor_map_decode_bulk_reset(list_res_decode, ARRAY_SIZE(list_res_decode)); |
| /* Init buffer values */ |
| active = false; |
| bootable = false; |
| confirmed = false; |
| pending = false; |
| permanent = false; |
| img_num = 0; |
| slot_num = UINT32_MAX; |
| hash.len = 0; |
| version.len = 0; |
| |
| rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), |
| &decoded); |
| if (rc) { |
| if (image_info->image_list_length) { |
| /* No more map */ |
| break; |
| } |
| LOG_ERR("Corrupted Image data %d", rc); |
| image_info->status = MGMT_ERR_EINVAL; |
| goto out; |
| } |
| /* Check that mandatory parameters have decoded */ |
| if (hash.len != IMG_MGMT_DATA_SHA_LEN || !version.len || |
| !zcbor_map_decode_bulk_key_found(list_res_decode, ARRAY_SIZE(list_res_decode), |
| "slot")) { |
| LOG_ERR("Missing mandatory parametrs"); |
| image_info->status = MGMT_ERR_EINVAL; |
| goto out; |
| } |
| /* Store parsed values */ |
| if (buf_len) { |
| image_info->image_list[image_info->image_list_length].img_num = img_num; |
| image_info->image_list[image_info->image_list_length].slot_num = slot_num; |
| memcpy(image_info->image_list[image_info->image_list_length].hash, |
| hash.value, IMG_MGMT_DATA_SHA_LEN); |
| if (version.len > IMG_MGMT_VER_MAX_STR_LEN) { |
| LOG_WRN("Version truncated len %d -> %d", version.len, |
| IMG_MGMT_VER_MAX_STR_LEN); |
| version.len = IMG_MGMT_VER_MAX_STR_LEN; |
| } |
| memcpy(image_info->image_list[image_info->image_list_length].version, |
| version.value, version.len); |
| image_info->image_list[image_info->image_list_length].version[version.len] = |
| '\0'; |
| /* Set Image flags */ |
| image_info->image_list[image_info->image_list_length].flags.bootable = |
| bootable; |
| image_info->image_list[image_info->image_list_length].flags.pending = |
| pending; |
| image_info->image_list[image_info->image_list_length].flags.confirmed = |
| confirmed; |
| image_info->image_list[image_info->image_list_length].flags.active = active; |
| image_info->image_list[image_info->image_list_length].flags.permanent = |
| permanent; |
| /* Update valid image count */ |
| image_info->image_list_length++; |
| buf_len--; |
| } else { |
| LOG_INF("User configured image list buffer size %d can't store all info", |
| active_client->image_list_length); |
| } |
| } |
| |
| ok = zcbor_list_end_decode(zsd); |
| if (!ok) { |
| image_info->status = MGMT_ERR_ECORRUPT; |
| } else { |
| |
| image_info->status = MGMT_ERR_EOK; |
| } |
| |
| out: |
| if (image_info->status != MGMT_ERR_EOK) { |
| image_info->image_list_length = 0; |
| } |
| rc = image_info->status; |
| k_sem_give(user_data); |
| return rc; |
| } |
| |
| static int image_upload_res_fn(struct net_buf *nb, void *user_data) |
| { |
| zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; |
| size_t decoded; |
| int rc; |
| int32_t res_rc = MGMT_ERR_EOK; |
| |
| struct zcbor_map_decode_key_val upload_res_decode[] = { |
| ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode, |
| &image_upload_buf->image_upload_offset), |
| ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &res_rc)}; |
| |
| if (!nb) { |
| image_upload_buf->status = MGMT_ERR_ETIMEOUT; |
| goto end; |
| } |
| |
| zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0); |
| |
| rc = zcbor_map_decode_bulk(zsd, upload_res_decode, ARRAY_SIZE(upload_res_decode), &decoded); |
| if (rc || image_upload_buf->image_upload_offset == SIZE_MAX) { |
| image_upload_buf->status = MGMT_ERR_EINVAL; |
| goto end; |
| } |
| image_upload_buf->status = res_rc; |
| |
| active_client->upload.offset = image_upload_buf->image_upload_offset; |
| end: |
| /* Set status for Upload request handler */ |
| rc = image_upload_buf->status; |
| k_sem_give(user_data); |
| return rc; |
| } |
| |
| static int erase_res_fn(struct net_buf *nb, void *user_data) |
| { |
| zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; |
| size_t decoded; |
| int rc, status = MGMT_ERR_EOK; |
| |
| struct zcbor_map_decode_key_val upload_res_decode[] = { |
| ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &status) |
| }; |
| |
| if (!nb) { |
| active_client->status = MGMT_ERR_ETIMEOUT; |
| goto end; |
| } |
| |
| zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data, nb->len, 1, NULL, 0); |
| |
| rc = zcbor_map_decode_bulk(zsd, upload_res_decode, ARRAY_SIZE(upload_res_decode), &decoded); |
| if (rc) { |
| LOG_ERR("Erase fail %d", rc); |
| active_client->status = MGMT_ERR_EINVAL; |
| goto end; |
| } |
| active_client->status = status; |
| end: |
| rc = active_client->status; |
| k_sem_give(user_data); |
| return rc; |
| } |
| |
| static size_t upload_message_header_size(struct img_gr_upload *upload_state) |
| { |
| bool ok; |
| size_t cbor_length; |
| int map_count; |
| zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; |
| uint8_t temp_buf[MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE]; |
| uint8_t temp_data = 0U; |
| |
| /* Calculation of message header with data length of 1 */ |
| |
| zcbor_new_encode_state(zse, ARRAY_SIZE(zse), temp_buf, MCUMGR_UPLOAD_INIT_HEADER_BUF_SIZE, |
| 0); |
| if (upload_state->hash_initialized) { |
| map_count = 12; |
| } else { |
| map_count = 10; |
| } |
| |
| /* Init map start and write image info and data */ |
| ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "image") && |
| zcbor_uint32_put(zse, upload_state->image_num) && zcbor_tstr_put_lit(zse, "data") && |
| zcbor_bstr_encode_ptr(zse, &temp_data, 1) && zcbor_tstr_put_lit(zse, "len") && |
| zcbor_size_put(zse, upload_state->image_size) && zcbor_tstr_put_lit(zse, "off") && |
| zcbor_size_put(zse, upload_state->offset); |
| |
| /* Write hash when it defined and offset is 0 */ |
| if (ok && upload_state->hash_initialized) { |
| ok = zcbor_tstr_put_lit(zse, "sha") && |
| zcbor_bstr_encode_ptr(zse, upload_state->sha256, IMG_MGMT_DATA_SHA_LEN); |
| } |
| |
| if (ok) { |
| ok = zcbor_map_end_encode(zse, map_count); |
| } |
| |
| if (!ok) { |
| LOG_ERR("Failed to encode Image Upload packet"); |
| return 0; |
| } |
| cbor_length = zse->payload - temp_buf; |
| /* Return Message header length */ |
| return cbor_length + (CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE - 1); |
| } |
| |
| void 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) |
| { |
| client->smp_client = smp_client; |
| client->image_list_length = image_list_size; |
| client->image_list = image_list; |
| } |
| |
| int img_mgmt_client_upload_init(struct img_mgmt_client *client, size_t image_size, |
| uint32_t image_num, const char *image_hash) |
| { |
| int rc; |
| |
| k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); |
| client->upload.image_size = image_size; |
| client->upload.offset = 0; |
| client->upload.image_num = image_num; |
| if (image_hash) { |
| memcpy(client->upload.sha256, image_hash, IMG_MGMT_DATA_SHA_LEN); |
| client->upload.hash_initialized = true; |
| } else { |
| client->upload.hash_initialized = false; |
| } |
| |
| /* Calculate worst case header size for adapt payload length */ |
| client->upload.upload_header_size = upload_message_header_size(&client->upload); |
| if (client->upload.upload_header_size) { |
| rc = MGMT_ERR_EOK; |
| } else { |
| rc = MGMT_ERR_ENOMEM; |
| } |
| k_mutex_unlock(&mcumgr_img_client_grp_mutex); |
| return rc; |
| } |
| |
| int img_mgmt_client_upload(struct img_mgmt_client *client, const uint8_t *data, size_t length, |
| struct mcumgr_image_upload *res_buf) |
| { |
| struct net_buf *nb; |
| const uint8_t *write_ptr; |
| int rc; |
| uint32_t map_count; |
| bool ok; |
| size_t write_length, max_data_length, offset_before_send, request_length, wrote_length; |
| zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2]; |
| |
| k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); |
| active_client = client; |
| image_upload_buf = res_buf; |
| |
| request_length = length; |
| wrote_length = 0; |
| /* Calculate max data length based on |
| * net_buf size - (SMP header + CBOR message_len + 16-bit CRC + 16-bit length) |
| */ |
| max_data_length = CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE - |
| (active_client->upload.upload_header_size + MGMT_HDR_SIZE + 2U + 2U); |
| /* Trim length based on CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE */ |
| if (max_data_length % CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE) { |
| max_data_length -= |
| (max_data_length % CONFIG_MCUMGR_GRP_IMG_UPLOAD_DATA_ALIGNMENT_SIZE); |
| } |
| |
| while (request_length != wrote_length) { |
| write_ptr = data + wrote_length; |
| write_length = request_length - wrote_length; |
| if (write_length > max_data_length) { |
| write_length = max_data_length; |
| } |
| |
| nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, |
| IMG_MGMT_ID_UPLOAD, MGMT_OP_WRITE, |
| SMP_MCUMGR_VERSION_1); |
| if (!nb) { |
| image_upload_buf->status = MGMT_ERR_ENOMEM; |
| goto end; |
| } |
| |
| zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, |
| net_buf_tailroom(nb), 0); |
| if (active_client->upload.offset) { |
| map_count = 6; |
| } else if (active_client->upload.hash_initialized) { |
| map_count = 12; |
| } else { |
| map_count = 10; |
| } |
| |
| /* Init map start and write image info, data and offset */ |
| ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "image") && |
| zcbor_uint32_put(zse, active_client->upload.image_num) && |
| zcbor_tstr_put_lit(zse, "data") && |
| zcbor_bstr_encode_ptr(zse, write_ptr, write_length) && |
| zcbor_tstr_put_lit(zse, "off") && |
| zcbor_size_put(zse, active_client->upload.offset); |
| /* Write Len and configured hash when offset is zero */ |
| if (ok && !active_client->upload.offset) { |
| ok = zcbor_tstr_put_lit(zse, "len") && |
| zcbor_size_put(zse, active_client->upload.image_size); |
| if (ok && active_client->upload.hash_initialized) { |
| ok = zcbor_tstr_put_lit(zse, "sha") && |
| zcbor_bstr_encode_ptr(zse, active_client->upload.sha256, |
| IMG_MGMT_DATA_SHA_LEN); |
| } |
| } |
| |
| if (ok) { |
| ok = zcbor_map_end_encode(zse, map_count); |
| } |
| |
| if (!ok) { |
| LOG_ERR("Failed to encode Image Upload packet"); |
| smp_packet_free(nb); |
| image_upload_buf->status = MGMT_ERR_ENOMEM; |
| goto end; |
| } |
| |
| offset_before_send = active_client->upload.offset; |
| nb->len = zse->payload - nb->data; |
| k_sem_reset(&mcumgr_img_client_grp_sem); |
| |
| image_upload_buf->status = MGMT_ERR_EINVAL; |
| image_upload_buf->image_upload_offset = SIZE_MAX; |
| |
| rc = smp_client_send_cmd(active_client->smp_client, nb, image_upload_res_fn, |
| &mcumgr_img_client_grp_sem, |
| CONFIG_MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT); |
| if (rc) { |
| LOG_ERR("Failed to send SMP Upload init packet, err: %d", rc); |
| smp_packet_free(nb); |
| image_upload_buf->status = rc; |
| goto end; |
| |
| } |
| k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); |
| if (image_upload_buf->status) { |
| LOG_ERR("Upload Fail: %d", image_upload_buf->status); |
| goto end; |
| } |
| |
| if (offset_before_send + write_length < active_client->upload.offset) { |
| /* Offset further than expected which indicate upload session resume */ |
| goto end; |
| } |
| |
| wrote_length += write_length; |
| } |
| end: |
| rc = image_upload_buf->status; |
| active_client = NULL; |
| image_upload_buf = NULL; |
| k_mutex_unlock(&mcumgr_img_client_grp_mutex); |
| |
| return rc; |
| } |
| |
| int img_mgmt_client_state_write(struct img_mgmt_client *client, char *hash, bool confirm, |
| struct mcumgr_image_state *res_buf) |
| { |
| struct net_buf *nb; |
| int rc; |
| uint32_t map_count; |
| zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; |
| bool ok; |
| |
| k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); |
| active_client = client; |
| image_info = res_buf; |
| /* Init Response */ |
| res_buf->image_list_length = 0; |
| res_buf->image_list = active_client->image_list; |
| |
| nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, |
| IMG_MGMT_ID_STATE, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); |
| if (!nb) { |
| res_buf->status = MGMT_ERR_ENOMEM; |
| goto end; |
| } |
| |
| zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); |
| if (hash) { |
| map_count = 4; |
| } else { |
| map_count = 2; |
| } |
| |
| /* Write map start init and confirm params */ |
| ok = zcbor_map_start_encode(zse, map_count) && zcbor_tstr_put_lit(zse, "confirm") && |
| zcbor_bool_put(zse, confirm); |
| /* Write hash data */ |
| if (ok && hash) { |
| ok = zcbor_tstr_put_lit(zse, "hash") && |
| zcbor_bstr_encode_ptr(zse, hash, IMG_MGMT_DATA_SHA_LEN); |
| } |
| /* Close map */ |
| if (ok) { |
| ok = zcbor_map_end_encode(zse, map_count); |
| } |
| |
| if (!ok) { |
| smp_packet_free(nb); |
| res_buf->status = MGMT_ERR_ENOMEM; |
| goto end; |
| } |
| |
| nb->len = zse->payload - nb->data; |
| k_sem_reset(&mcumgr_img_client_grp_sem); |
| rc = smp_client_send_cmd(active_client->smp_client, nb, image_state_res_fn, |
| &mcumgr_img_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); |
| if (rc) { |
| res_buf->status = rc; |
| smp_packet_free(nb); |
| goto end; |
| } |
| k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); |
| end: |
| rc = res_buf->status; |
| active_client = NULL; |
| k_mutex_unlock(&mcumgr_img_client_grp_mutex); |
| return rc; |
| } |
| |
| int img_mgmt_client_state_read(struct img_mgmt_client *client, struct mcumgr_image_state *res_buf) |
| { |
| struct net_buf *nb; |
| int rc; |
| zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; |
| bool ok; |
| |
| k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); |
| active_client = client; |
| /* Init Response */ |
| res_buf->image_list_length = 0; |
| res_buf->image_list = active_client->image_list; |
| |
| image_info = res_buf; |
| |
| nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, |
| IMG_MGMT_ID_STATE, MGMT_OP_READ, SMP_MCUMGR_VERSION_1); |
| if (!nb) { |
| res_buf->status = MGMT_ERR_ENOMEM; |
| goto end; |
| } |
| |
| zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); |
| ok = zcbor_map_start_encode(zse, 1) && zcbor_map_end_encode(zse, 1); |
| if (!ok) { |
| smp_packet_free(nb); |
| res_buf->status = MGMT_ERR_ENOMEM; |
| goto end; |
| } |
| |
| nb->len = zse->payload - nb->data; |
| k_sem_reset(&mcumgr_img_client_grp_sem); |
| rc = smp_client_send_cmd(active_client->smp_client, nb, image_state_res_fn, |
| &mcumgr_img_client_grp_sem, CONFIG_SMP_CMD_DEFAULT_LIFE_TIME); |
| if (rc) { |
| smp_packet_free(nb); |
| res_buf->status = rc; |
| goto end; |
| } |
| k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); |
| end: |
| rc = res_buf->status; |
| image_info = NULL; |
| active_client = NULL; |
| k_mutex_unlock(&mcumgr_img_client_grp_mutex); |
| return rc; |
| } |
| |
| int img_mgmt_client_erase(struct img_mgmt_client *client, uint32_t slot) |
| { |
| struct net_buf *nb; |
| int rc; |
| zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS]; |
| bool ok; |
| |
| k_mutex_lock(&mcumgr_img_client_grp_mutex, K_FOREVER); |
| active_client = client; |
| |
| nb = smp_client_buf_allocation(active_client->smp_client, MGMT_GROUP_ID_IMAGE, |
| IMG_MGMT_ID_ERASE, MGMT_OP_WRITE, SMP_MCUMGR_VERSION_1); |
| if (!nb) { |
| active_client->status = MGMT_ERR_ENOMEM; |
| goto end; |
| } |
| |
| zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data + nb->len, net_buf_tailroom(nb), 0); |
| |
| ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "slot") && |
| zcbor_uint32_put(zse, slot) && zcbor_map_end_encode(zse, 2); |
| if (!ok) { |
| smp_packet_free(nb); |
| active_client->status = MGMT_ERR_ENOMEM; |
| goto end; |
| } |
| |
| nb->len = zse->payload - nb->data; |
| k_sem_reset(&mcumgr_img_client_grp_sem); |
| rc = smp_client_send_cmd(client->smp_client, nb, erase_res_fn, &mcumgr_img_client_grp_sem, |
| CONFIG_MCUMGR_GRP_IMG_FLASH_OPERATION_TIMEOUT); |
| if (rc) { |
| smp_packet_free(nb); |
| active_client->status = rc; |
| goto end; |
| } |
| k_sem_take(&mcumgr_img_client_grp_sem, K_FOREVER); |
| end: |
| rc = active_client->status; |
| active_client = NULL; |
| k_mutex_unlock(&mcumgr_img_client_grp_mutex); |
| return rc; |
| } |