1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/net_buf.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <zephyr/mgmt/mcumgr/smp/smp_client.h>
11 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
12 #include <zephyr/mgmt/mcumgr/grp/img_mgmt/img_mgmt_client.h>
13 #include <zephyr/sys/byteorder.h>
14 
15 #include <zcbor_common.h>
16 #include <zcbor_encode.h>
17 #include <zcbor_decode.h>
18 #include <mgmt/mcumgr/util/zcbor_bulk.h>
19 #include <mgmt/mcumgr/transport/smp_internal.h>
20 #include "smp_stub.h"
21 #include "img_gr_stub.h"
22 
23 static struct mcumgr_image_data image_dummy_info[2];
24 static size_t test_offset;
25 static uint8_t *image_hash_ptr;
26 
27 #ifdef CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER
28 #define IMG_UPDATABLE_IMAGE_COUNT CONFIG_MCUMGR_GRP_IMG_UPDATABLE_IMAGE_NUMBER
29 #else
30 #define IMG_UPDATABLE_IMAGE_COUNT 1
31 #endif
32 
33 #define ZCBOR_ENCODE_FLAG(zse, label, value)                                                       \
34 	(zcbor_tstr_put_lit(zse, label) && zcbor_bool_put(zse, value))
35 
img_upload_stub_init(void)36 void img_upload_stub_init(void)
37 {
38 	test_offset = 0;
39 }
40 
img_upload_response(size_t offset,int status)41 void img_upload_response(size_t offset, int status)
42 {
43 	struct net_buf *nb;
44 	zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
45 	bool ok;
46 
47 	nb = smp_response_buf_allocation();
48 
49 	if (!nb) {
50 		return;
51 	}
52 
53 	zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0);
54 
55 	/* Init map start and write image info and data */
56 	if (status) {
57 		ok = zcbor_map_start_encode(zse, 4) && zcbor_tstr_put_lit(zse, "rc") &&
58 	     zcbor_int32_put(zse, status) && zcbor_tstr_put_lit(zse, "off") &&
59 	     zcbor_size_put(zse, offset) && zcbor_map_end_encode(zse, 4);
60 	} else {
61 		/* Drop Status away from response */
62 		ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "off") &&
63 	     zcbor_size_put(zse, offset) && zcbor_map_end_encode(zse, 4);
64 	}
65 
66 
67 	if (!ok) {
68 		smp_client_response_buf_clean();
69 	} else {
70 		nb->len = zse->payload - nb->data;
71 	}
72 }
73 
img_fail_response(int status)74 void img_fail_response(int status)
75 {
76 	struct net_buf *nb;
77 	zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
78 	bool ok;
79 
80 	nb = smp_response_buf_allocation();
81 
82 	if (!nb) {
83 		return;
84 	}
85 
86 	zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0);
87 
88 	/* Init map start and write image info and data */
89 	ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "rc") &&
90 	     zcbor_int32_put(zse, status) && zcbor_map_end_encode(zse, 2);
91 	if (!ok) {
92 		smp_client_response_buf_clean();
93 	} else {
94 		nb->len = zse->payload - nb->data;
95 	}
96 }
97 
img_read_response(int count)98 void img_read_response(int count)
99 {
100 	struct net_buf *nb;
101 	zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
102 	bool ok;
103 
104 	nb = smp_response_buf_allocation();
105 
106 	if (!nb) {
107 		return;
108 	}
109 
110 	zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0);
111 
112 	ok = zcbor_map_start_encode(zse, 15) && zcbor_tstr_put_lit(zse, "images") &&
113 	     zcbor_list_start_encode(zse, 2);
114 
115 	for (int i = 0; ok && i < count; i++) {
116 
117 		ok = zcbor_map_start_encode(zse, 15) &&
118 		     ((zcbor_tstr_put_lit(zse, "image") &&
119 		       zcbor_uint32_put(zse, image_dummy_info[i].img_num))) &&
120 		     zcbor_tstr_put_lit(zse, "slot") &&
121 		     zcbor_uint32_put(zse, image_dummy_info[i].slot_num) &&
122 		     zcbor_tstr_put_lit(zse, "version") &&
123 		     zcbor_tstr_put_term(zse, image_dummy_info[i].version,
124 					sizeof(image_dummy_info[i].version)) &&
125 
126 		     zcbor_tstr_put_lit(zse, "hash") &&
127 		     zcbor_bstr_encode_ptr(zse, image_dummy_info[i].hash, IMG_MGMT_DATA_SHA_LEN) &&
128 		     ZCBOR_ENCODE_FLAG(zse, "bootable", image_dummy_info[i].flags.bootable) &&
129 		     ZCBOR_ENCODE_FLAG(zse, "pending", image_dummy_info[i].flags.pending) &&
130 		     ZCBOR_ENCODE_FLAG(zse, "confirmed", image_dummy_info[i].flags.confirmed) &&
131 		     ZCBOR_ENCODE_FLAG(zse, "active", image_dummy_info[i].flags.active) &&
132 		     ZCBOR_ENCODE_FLAG(zse, "permanent", image_dummy_info[i].flags.permanent) &&
133 		     zcbor_map_end_encode(zse, 15);
134 	}
135 
136 	ok = ok && zcbor_list_end_encode(zse, 2 * IMG_UPDATABLE_IMAGE_COUNT);
137 
138 	ok = ok && zcbor_map_end_encode(zse, 15);
139 
140 	if (!ok) {
141 		smp_client_response_buf_clean();
142 	} else {
143 		nb->len = zse->payload - nb->data;
144 	}
145 }
146 
img_erase_response(int status)147 void img_erase_response(int status)
148 {
149 	struct net_buf *nb;
150 	zcbor_state_t zse[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
151 	bool ok;
152 
153 	nb = smp_response_buf_allocation();
154 
155 	if (!nb) {
156 		return;
157 	}
158 
159 	zcbor_new_encode_state(zse, ARRAY_SIZE(zse), nb->data, net_buf_tailroom(nb), 0);
160 
161 	/* Init map start and write image info and data */
162 	ok = zcbor_map_start_encode(zse, 2) && zcbor_tstr_put_lit(zse, "rc") &&
163 	     zcbor_int32_put(zse, status) && zcbor_map_end_encode(zse, 2);
164 	if (!ok) {
165 		smp_client_response_buf_clean();
166 	} else {
167 		nb->len = zse->payload - nb->data;
168 	}
169 }
170 
img_state_write_verify(struct net_buf * nb)171 void img_state_write_verify(struct net_buf *nb)
172 {
173 	/* Parse CBOR data: hash and confirm */
174 	zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
175 	int rc;
176 	struct zcbor_string hash;
177 	bool confirm;
178 	size_t decoded;
179 	struct zcbor_map_decode_key_val list_res_decode[] = {
180 		ZCBOR_MAP_DECODE_KEY_DECODER("confirm", zcbor_bool_decode, &confirm),
181 		ZCBOR_MAP_DECODE_KEY_DECODER("hash", zcbor_bstr_decode, &hash)
182 		};
183 
184 	zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1,
185 				NULL, 0);
186 
187 	decoded = 0;
188 	/* Init buffer values */
189 	confirm = false;
190 	hash.len = 0;
191 
192 	rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), &decoded);
193 	if (rc) {
194 		printf("Corrupted data %d\r\n", rc);
195 		img_fail_response(MGMT_ERR_EINVAL);
196 		return;
197 	}
198 	if (hash.len) {
199 		printf("HASH %d", hash.len);
200 		if (memcmp(hash.value, image_dummy_info[1].hash, 32) == 0) {
201 			if (confirm) {
202 				/* Set Permanent bit */
203 				image_dummy_info[1].flags.permanent = true;
204 			} else {
205 				/* Set pending */
206 				image_dummy_info[1].flags.pending = true;
207 			}
208 			img_read_response(2);
209 		} else {
210 			img_fail_response(MGMT_ERR_EINVAL);
211 		}
212 	} else {
213 		if (confirm) {
214 			image_dummy_info[0].flags.confirmed = true;
215 		}
216 		img_read_response(2);
217 	}
218 }
219 
img_upload_init_verify(struct net_buf * nb)220 void img_upload_init_verify(struct net_buf *nb)
221 {
222 	/* Parse CBOR data: hash and confirm */
223 	zcbor_state_t zsd[CONFIG_MCUMGR_SMP_CBOR_MAX_DECODING_LEVELS + 2];
224 	int rc;
225 	uint32_t image;
226 	struct zcbor_string sha, data;
227 	size_t decoded, length, offset;
228 	struct zcbor_map_decode_key_val list_res_decode[] = {
229 		ZCBOR_MAP_DECODE_KEY_DECODER("image", zcbor_uint32_decode, &image),
230 		ZCBOR_MAP_DECODE_KEY_DECODER("data", zcbor_bstr_decode, &data),
231 		ZCBOR_MAP_DECODE_KEY_DECODER("len", zcbor_size_decode, &length),
232 		ZCBOR_MAP_DECODE_KEY_DECODER("off", zcbor_size_decode, &offset),
233 		ZCBOR_MAP_DECODE_KEY_DECODER("sha", zcbor_bstr_decode, &sha)
234 		};
235 
236 	zcbor_new_decode_state(zsd, ARRAY_SIZE(zsd), nb->data + sizeof(struct smp_hdr), nb->len, 1,
237 				NULL, 0);
238 
239 	decoded = 0;
240 	/* Init buffer values */
241 	sha.len = 0;
242 	data.len = 0;
243 	length = SIZE_MAX;
244 	offset = SIZE_MAX;
245 	image = UINT32_MAX;
246 
247 	rc = zcbor_map_decode_bulk(zsd, list_res_decode, ARRAY_SIZE(list_res_decode), &decoded);
248 	if (rc || data.len == 0 || offset == SIZE_MAX || image != TEST_IMAGE_NUM) {
249 		printf("Corrupted data %d or %d data len\r\n", rc, data.len);
250 		img_upload_response(0, MGMT_ERR_EINVAL);
251 		return;
252 	}
253 
254 	if (sha.len) {
255 		if (memcmp(sha.value, image_hash_ptr, 32)) {
256 			printf("Hash not same\r\n");
257 			img_upload_response(0, MGMT_ERR_EINVAL);
258 			return;
259 		}
260 	}
261 
262 	if (offset != test_offset) {
263 		printf("Offset not exepected %d vs received %d\r\n", test_offset, offset);
264 	}
265 
266 	if (offset == 0) {
267 		if (length != TEST_IMAGE_SIZE) {
268 			img_upload_response(0, MGMT_ERR_EINVAL);
269 		}
270 	}
271 
272 	test_offset += data.len;
273 	printf("Upload offset %d\r\n", test_offset);
274 	if (test_offset <= TEST_IMAGE_SIZE) {
275 		img_upload_response(test_offset, MGMT_ERR_EOK);
276 	} else {
277 		img_upload_response(0, MGMT_ERR_EINVAL);
278 	}
279 }
280 
img_gr_stub_data_init(uint8_t * hash_ptr)281 void img_gr_stub_data_init(uint8_t *hash_ptr)
282 {
283 	image_hash_ptr = hash_ptr;
284 	for (int i = 0; i < 32; i++) {
285 		image_hash_ptr[i] = i;
286 		image_dummy_info[0].hash[i] = i + 32;
287 		image_dummy_info[1].hash[i] = i + 64;
288 	}
289 	/* Set dummy image list data */
290 	for (int i = 0; i < 2; i++) {
291 		image_dummy_info[i].img_num = i;
292 		image_dummy_info[i].slot_num = i;
293 		/* Write version */
294 		snprintf(image_dummy_info[i].version, IMG_MGMT_VER_MAX_STR_LEN, "1.1.%u", i);
295 		image_dummy_info[i].version[sizeof(image_dummy_info[i].version) - 1] = '\0';
296 		image_dummy_info[i].flags.bootable = true;
297 		image_dummy_info[i].flags.pending = false;
298 		if (i) {
299 			image_dummy_info[i].flags.confirmed = false;
300 			image_dummy_info[i].flags.active = false;
301 		} else {
302 			image_dummy_info[i].flags.confirmed = true;
303 			image_dummy_info[i].flags.active = true;
304 		}
305 		image_dummy_info[i].flags.permanent = false;
306 	}
307 }
308