1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/net_buf.h>
9 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
10 #include <zephyr/mgmt/mcumgr/transport/smp_dummy.h>
11 #include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
12 #include <zephyr/mgmt/mcumgr/grp/enum_mgmt/enum_mgmt.h>
13 #include <zcbor_common.h>
14 #include <zcbor_decode.h>
15 #include <zcbor_encode.h>
16 #include <mgmt/mcumgr/util/zcbor_bulk.h>
17 #include <string.h>
18 #include <zephyr/sys/byteorder.h>
19 #include <smp_internal.h>
20 #include "smp_test_util.h"
21 
22 #define LOG_LEVEL LOG_LEVEL_DBG
23 #include <zephyr/logging/log.h>
24 LOG_MODULE_REGISTER(smp_sample);
25 
26 #define SHELL_MGMT_HANDLERS 1
27 #define OS_MGMT_HANDLERS 6
28 #define ENUM_MGMT_HANDLERS 4
29 
30 #define OS_MGMT_NAME "os mgmt"
31 #define ENUM_MGMT_NAME "enum mgmt"
32 #define SHELL_MGMT_NAME "shell mgmt"
33 
34 #if defined(CONFIG_MCUMGR_GRP_SHELL) && defined(CONFIG_MCUMGR_GRP_OS)
35 #define TEST_GROUPS 3
36 #elif defined(CONFIG_MCUMGR_GRP_SHELL) || defined(CONFIG_MCUMGR_GRP_OS)
37 #define TEST_GROUPS 2
38 #else
39 #define TEST_GROUPS 1
40 #endif
41 
42 #if defined(CONFIG_MCUMGR_GRP_SHELL) && defined(CONFIG_MCUMGR_GRP_OS)
43 #define FOUND_INDEX_SHELL 2
44 #else
45 #define FOUND_INDEX_SHELL 1
46 #endif
47 #define FOUND_INDEX_OS 1
48 #define FOUND_INDEX_ENUM 0
49 
50 #define SMP_RESPONSE_WAIT_TIME 3
51 #define ZCBOR_BUFFER_SIZE 128
52 #define OUTPUT_BUFFER_SIZE 512
53 #define ZCBOR_HISTORY_ARRAY_SIZE 7
54 
55 static struct net_buf *nb;
56 static bool enum_valid_got;
57 static bool enum_field_added;
58 static bool event_invalid_got;
59 static bool block_access;
60 static bool add_field;
61 
62 struct list_entries {
63 	uint8_t entries;
64 	uint16_t groups[16];
65 };
66 
67 struct details_entries {
68 	char expected_name[32];
69 	uint8_t expected_handlers;
70 	bool expected_test;
71 
72 	bool matched_name;
73 	bool matched_handlers;
74 	bool matched_test;
75 };
76 
77 #if defined(CONFIG_MCUMGR_GRP_SHELL)
78 #define SINGLE_MATCHED_SHELL 0x1
79 #else
80 #define SINGLE_MATCHED_SHELL 0x0
81 #endif
82 #if defined(CONFIG_MCUMGR_GRP_OS)
83 #define SINGLE_MATCHED_OS 0x2
84 #else
85 #define SINGLE_MATCHED_OS 0x0
86 #endif
87 #define SINGLE_MATCHED_ENUM 0x4
88 
89 #define SINGLE_MATCHED_ALL (SINGLE_MATCHED_SHELL | SINGLE_MATCHED_OS | SINGLE_MATCHED_ENUM)
90 
cleanup_test(void * p)91 static void cleanup_test(void *p)
92 {
93 	if (nb != NULL) {
94 		net_buf_unref(nb);
95 		nb = NULL;
96 	}
97 
98 	enum_valid_got = false;
99 	enum_field_added = false;
100 	event_invalid_got = false;
101 	block_access = false;
102 	add_field = false;
103 }
104 
ZTEST(enum_mgmt,test_count)105 ZTEST(enum_mgmt, test_count)
106 {
107 	uint8_t buffer[ZCBOR_BUFFER_SIZE];
108 	uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
109 	bool ok;
110 	uint16_t buffer_size;
111 	zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
112 	zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
113 	bool received;
114 	struct smp_hdr *header;
115 	uint32_t count_response = 0;
116 	size_t decoded = 0;
117 
118 	struct zcbor_map_decode_key_val output_decode[] = {
119 		ZCBOR_MAP_DECODE_KEY_DECODER("count", zcbor_uint32_decode, &count_response),
120 	};
121 
122 	memset(buffer, 0, sizeof(buffer));
123 	memset(buffer_out, 0, sizeof(buffer_out));
124 	buffer_size = 0;
125 	memset(zse, 0, sizeof(zse));
126 	memset(zsd, 0, sizeof(zsd));
127 
128 	zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
129 
130 	ok = create_enum_mgmt_count_packet(zse, buffer, buffer_out, &buffer_size);
131 	zassert_true(ok, "Expected packet creation to be successful");
132 
133 	/* Enable dummy SMP backend and ready for usage */
134 	smp_dummy_enable();
135 	smp_dummy_clear_state();
136 
137 	/* Send query command to dummy SMP backend */
138 	(void)smp_dummy_tx_pkt(buffer_out, buffer_size);
139 	smp_dummy_add_data();
140 
141 	/* Wait for a short duration to see if response has been received */
142 	received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
143 	zassert_true(received, "Expected to receive data but timed out");
144 
145 	/* Retrieve response buffer */
146 	nb = smp_dummy_get_outgoing();
147 	smp_dummy_disable();
148 
149 	/* Check response is as expected */
150 	header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
151 
152 	zassert_equal(header->nh_flags, 0, "SMP header flags mismatch");
153 	zassert_equal(header->nh_op, MGMT_OP_READ_RSP, "SMP header operation mismatch");
154 	zassert_equal(header->nh_group, sys_cpu_to_be16(MGMT_GROUP_ID_ENUM),
155 		      "SMP header group mismatch");
156 	zassert_equal(header->nh_seq, 1, "SMP header sequence number mismatch");
157 	zassert_equal(header->nh_id, ENUM_MGMT_ID_COUNT, "SMP header command ID mismatch");
158 	zassert_equal(header->nh_version, 1, "SMP header version mismatch");
159 
160 	/* Get the response value to compare */
161 	zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0);
162 	ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
163 	zassert_true(ok, "Expected decode to be successful");
164 	zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
165 
166 	/* Ensure the right amount of data was read and that the value matches */
167 	zassert_equal(count_response, TEST_GROUPS, "Expected data mismatch");
168 
169 	/* Clean up test */
170 	cleanup_test(NULL);
171 }
172 
parse_list_entries(zcbor_state_t * state,void * user_data)173 static bool parse_list_entries(zcbor_state_t *state, void *user_data)
174 {
175 	uint32_t temp = 0;
176 	uint16_t i = 0;
177 	struct list_entries *entry_data = (struct list_entries *)user_data;
178 
179 	if (!zcbor_list_start_decode(state)) {
180 		return false;
181 	}
182 
183 	while (!zcbor_array_at_end(state)) {
184 		if (!zcbor_uint32_decode(state, &temp)) {
185 			return false;
186 		}
187 
188 		if (i > ARRAY_SIZE(entry_data->groups)) {
189 			return false;
190 		}
191 
192 		entry_data->groups[i] = (uint16_t)temp;
193 
194 		++i;
195 	}
196 
197 	(void)zcbor_list_end_decode(state);
198 
199 	entry_data->entries = i;
200 
201 	return true;
202 }
203 
ZTEST(enum_mgmt,test_list)204 ZTEST(enum_mgmt, test_list)
205 {
206 	uint8_t buffer[ZCBOR_BUFFER_SIZE];
207 	uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
208 	bool ok;
209 	uint16_t buffer_size;
210 	zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
211 	zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
212 	bool received;
213 	struct smp_hdr *header;
214 	size_t decoded = 0;
215 	struct list_entries list_response = { 0 };
216 	uint8_t i;
217 	bool found_groups[TEST_GROUPS] = { 0 };
218 
219 	struct zcbor_map_decode_key_val output_decode[] = {
220 		ZCBOR_MAP_DECODE_KEY_DECODER("groups", parse_list_entries, &list_response),
221 	};
222 
223 	memset(buffer, 0, sizeof(buffer));
224 	memset(buffer_out, 0, sizeof(buffer_out));
225 	buffer_size = 0;
226 	memset(zse, 0, sizeof(zse));
227 	memset(zsd, 0, sizeof(zsd));
228 
229 	zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
230 
231 	ok = create_enum_mgmt_list_packet(zse, buffer, buffer_out, &buffer_size);
232 	zassert_true(ok, "Expected packet creation to be successful");
233 
234 	/* Enable dummy SMP backend and ready for usage */
235 	smp_dummy_enable();
236 	smp_dummy_clear_state();
237 
238 	/* Send query command to dummy SMP backend */
239 	(void)smp_dummy_tx_pkt(buffer_out, buffer_size);
240 	smp_dummy_add_data();
241 
242 	/* Wait for a short duration to see if response has been received */
243 	received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
244 	zassert_true(received, "Expected to receive data but timed out");
245 
246 	/* Retrieve response buffer */
247 	nb = smp_dummy_get_outgoing();
248 	smp_dummy_disable();
249 
250 	/* Check response is as expected */
251 	header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
252 
253 	zassert_equal(header->nh_flags, 0, "SMP header flags mismatch");
254 	zassert_equal(header->nh_op, MGMT_OP_READ_RSP, "SMP header operation mismatch");
255 	zassert_equal(header->nh_group, sys_cpu_to_be16(MGMT_GROUP_ID_ENUM),
256 		      "SMP header group mismatch");
257 	zassert_equal(header->nh_seq, 1, "SMP header sequence number mismatch");
258 	zassert_equal(header->nh_id, ENUM_MGMT_ID_LIST, "SMP header command ID mismatch");
259 	zassert_equal(header->nh_version, 1, "SMP header version mismatch");
260 
261 	/* Get the response value to compare */
262 	zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0);
263 	ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
264 	zassert_true(ok, "Expected decode to be successful");
265 	zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
266 
267 	/* Ensure the right amount of data was read and that the values match */
268 	zassert_equal(list_response.entries, TEST_GROUPS, "Expected data mismatch");
269 
270 	i = 0;
271 
272 	while (i < list_response.entries) {
273 		uint8_t index = 0xff;
274 
275 		if (list_response.groups[i] == MGMT_GROUP_ID_ENUM) {
276 			index = FOUND_INDEX_ENUM;
277 		}
278 #if defined(CONFIG_MCUMGR_GRP_OS)
279 		if (list_response.groups[i] == MGMT_GROUP_ID_OS) {
280 			index = FOUND_INDEX_OS;
281 		}
282 #endif
283 #if defined(CONFIG_MCUMGR_GRP_SHELL)
284 		if (list_response.groups[i] == MGMT_GROUP_ID_SHELL) {
285 			index = FOUND_INDEX_SHELL;
286 		}
287 #endif
288 
289 		if (index != 0xff) {
290 			found_groups[index] = true;
291 		}
292 
293 		++i;
294 	}
295 
296 	i = 0;
297 
298 	while (i < TEST_GROUPS) {
299 		zassert_true(found_groups[i], "Expected group to be found in list");
300 		++i;
301 	}
302 
303 	/* Clean up test */
304 	cleanup_test(NULL);
305 }
306 
ZTEST(enum_mgmt,test_single)307 ZTEST(enum_mgmt, test_single)
308 {
309 	uint8_t buffer[ZCBOR_BUFFER_SIZE];
310 	uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
311 	bool ok;
312 	uint16_t buffer_size;
313 	zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
314 	zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
315 	bool received;
316 	struct smp_hdr *header;
317 	size_t decoded = 0;
318 	uint8_t i;
319 	uint8_t matched_entries = 0;
320 	uint32_t received_group = 0;
321 	bool received_end = false;
322 
323 	i = 0;
324 	while (received_end == false) {
325 		struct zcbor_map_decode_key_val output_decode[] = {
326 			ZCBOR_MAP_DECODE_KEY_DECODER("group", zcbor_uint32_decode, &received_group),
327 			ZCBOR_MAP_DECODE_KEY_DECODER("end", zcbor_bool_decode, &received_end),
328 		};
329 
330 		memset(buffer, 0, sizeof(buffer));
331 		memset(buffer_out, 0, sizeof(buffer_out));
332 		buffer_size = 0;
333 		memset(zse, 0, sizeof(zse));
334 		memset(zsd, 0, sizeof(zsd));
335 
336 		zcbor_new_encode_state(zse, 3, buffer, ARRAY_SIZE(buffer), 0);
337 		ok = create_enum_mgmt_single_packet(zse, buffer, buffer_out, &buffer_size, i);
338 		zassert_true(ok, "Expected packet creation to be successful");
339 
340 		/* Enable dummy SMP backend and ready for usage */
341 		smp_dummy_enable();
342 		smp_dummy_clear_state();
343 
344 		/* Send query command to dummy SMP backend */
345 		(void)smp_dummy_tx_pkt(buffer_out, buffer_size);
346 		smp_dummy_add_data();
347 
348 		/* Wait for a short duration to see if response has been received */
349 		received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
350 		zassert_true(received, "Expected to receive data but timed out");
351 
352 		/* Retrieve response buffer */
353 		nb = smp_dummy_get_outgoing();
354 		smp_dummy_disable();
355 
356 		/* Check response is as expected */
357 		header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
358 
359 		zassert_equal(header->nh_flags, 0, "SMP header flags mismatch");
360 		zassert_equal(header->nh_op, MGMT_OP_READ_RSP, "SMP header operation mismatch");
361 		zassert_equal(header->nh_group, sys_cpu_to_be16(MGMT_GROUP_ID_ENUM),
362 			      "SMP header group mismatch");
363 		zassert_equal(header->nh_seq, 1, "SMP header sequence number mismatch");
364 		zassert_equal(header->nh_id, ENUM_MGMT_ID_SINGLE,
365 			      "SMP header command ID mismatch");
366 		zassert_equal(header->nh_version, 1, "SMP header version mismatch");
367 
368 		/* Get the response value to compare */
369 		zcbor_new_decode_state(zsd, 7, nb->data, nb->len, 1, NULL, 0);
370 		ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode),
371 					   &decoded) == 0;
372 		zassert_true(ok, "Expected decode to be successful");
373 		zassert_not_equal(decoded, 0,
374 				  "Expected to receive at least 1 decoded zcbor element");
375 
376 		if (received_group == MGMT_GROUP_ID_SHELL) {
377 			matched_entries |= SINGLE_MATCHED_SHELL;
378 		} else if (received_group == MGMT_GROUP_ID_OS) {
379 			matched_entries |= SINGLE_MATCHED_OS;
380 		} else if (received_group == MGMT_GROUP_ID_ENUM) {
381 			matched_entries |= SINGLE_MATCHED_ENUM;
382 		} else {
383 			zassert_true(0, "Received unknown group");
384 		}
385 
386 		if (matched_entries == SINGLE_MATCHED_ALL) {
387 			zassert_true(received_end, "Expected to have received end");
388 			zassert_equal(decoded, 2, "Expected to receive 2 decoded zcbor elements");
389 		} else {
390 			zassert_false(received_end, "Did not expect to receive end");
391 			zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor elements");
392 		}
393 
394 		zassert_true((i <= TEST_GROUPS), "Loop ran too many times");
395 
396 		/* Clean up test */
397 		cleanup_test(NULL);
398 
399 		++i;
400 	}
401 
402 	zassert_equal(matched_entries, SINGLE_MATCHED_ALL, "Received entries mismatch");
403 }
404 
parse_details_entries(zcbor_state_t * state,void * user_data)405 static bool parse_details_entries(zcbor_state_t *state, void *user_data)
406 {
407 	uint32_t group = 0;
408 	struct zcbor_string name = { 0 };
409 	uint32_t handlers = 0;
410 	uint32_t test = 0;
411 	uint16_t i = 0;
412 	struct details_entries *entry_data = (struct details_entries *)user_data;
413 
414 	struct zcbor_map_decode_key_val output_decode[] = {
415 		ZCBOR_MAP_DECODE_KEY_DECODER("group", zcbor_uint32_decode, &group),
416 		ZCBOR_MAP_DECODE_KEY_DECODER("name", zcbor_tstr_decode, &name),
417 		ZCBOR_MAP_DECODE_KEY_DECODER("handlers", zcbor_uint32_decode, &handlers),
418 		ZCBOR_MAP_DECODE_KEY_DECODER("test", zcbor_uint32_decode, &test),
419 	};
420 
421 	if (!zcbor_list_start_decode(state)) {
422 		return false;
423 	}
424 
425 	while (!zcbor_array_at_end(state)) {
426 		uint8_t index = 0;
427 		bool ok;
428 		size_t decoded = 0;
429 
430 		/* Reset */
431 		group = 0;
432 		name.value = NULL;
433 		name.len = 0;
434 		handlers = 0;
435 		test = 0;
436 
437 		i = 0;
438 
439 		while (i < ARRAY_SIZE(output_decode)) {
440 			output_decode[i].found = false;
441 			++i;
442 		}
443 
444 		ok = zcbor_map_decode_bulk(state, output_decode, ARRAY_SIZE(output_decode),
445 					   &decoded) == 0;
446 		zassert_true(ok, "Expected decode to be successful");
447 
448 		if (group == MGMT_GROUP_ID_ENUM) {
449 			index = FOUND_INDEX_ENUM;
450 
451 			if (strcmp(name.value, ENUM_MGMT_NAME) == 0) {
452 				entry_data[index].matched_name = true;
453 			}
454 		}
455 #if defined(CONFIG_MCUMGR_GRP_OS)
456 		else if (group == MGMT_GROUP_ID_OS) {
457 			index = FOUND_INDEX_OS;
458 
459 			if (strcmp(name.value, OS_MGMT_NAME) == 0) {
460 				entry_data[index].matched_name = true;
461 			}
462 		}
463 #endif
464 #if defined(CONFIG_MCUMGR_GRP_SHELL)
465 		else if (group == MGMT_GROUP_ID_SHELL) {
466 			index = FOUND_INDEX_SHELL;
467 		}
468 #endif
469 		else {
470 			return false;
471 		}
472 
473 		if (entry_data[index].expected_test) {
474 			zassert_equal(decoded, 4, "Expected to receive 4 decoded zcbor element");
475 		} else {
476 			zassert_equal(decoded, 3, "Expected to receive 3 decoded zcbor element");
477 		}
478 
479 		if (memcmp(name.value, entry_data[index].expected_name, name.len) == 0) {
480 			entry_data[index].matched_name = true;
481 		}
482 
483 		if (handlers == entry_data[index].expected_handlers) {
484 			entry_data[index].matched_handlers = true;
485 		}
486 
487 		if (output_decode[3].found == entry_data[index].expected_test) {
488 			/* Check value is correct */
489 			if (entry_data[index].expected_test == false ||
490 			    (entry_data[index].expected_test == true && test == (group * 3 + 1))) {
491 				entry_data[index].matched_test = true;
492 			}
493 		}
494 	}
495 
496 	(void)zcbor_list_end_decode(state);
497 
498 	return true;
499 }
500 
ZTEST(enum_mgmt,test_details)501 ZTEST(enum_mgmt, test_details)
502 {
503 	uint8_t buffer[ZCBOR_BUFFER_SIZE];
504 	uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
505 	bool ok;
506 	uint16_t buffer_size;
507 	zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
508 	zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
509 	bool received;
510 	struct smp_hdr *header;
511 	size_t decoded = 0;
512 	struct details_entries details_response[TEST_GROUPS] = { 0 };
513 	uint8_t i;
514 
515 #if defined(CONFIG_MCUMGR_GRP_SHELL)
516 	strcpy(details_response[FOUND_INDEX_SHELL].expected_name, SHELL_MGMT_NAME);
517 	details_response[FOUND_INDEX_SHELL].expected_handlers = SHELL_MGMT_HANDLERS;
518 	details_response[FOUND_INDEX_SHELL].expected_test = false;
519 #endif
520 
521 #if defined(CONFIG_MCUMGR_GRP_OS)
522 	strcpy(details_response[FOUND_INDEX_OS].expected_name, OS_MGMT_NAME);
523 	details_response[FOUND_INDEX_OS].expected_handlers = OS_MGMT_HANDLERS;
524 	details_response[FOUND_INDEX_OS].expected_test = false;
525 #endif
526 
527 	strcpy(details_response[FOUND_INDEX_ENUM].expected_name, ENUM_MGMT_NAME);
528 	details_response[FOUND_INDEX_ENUM].expected_handlers = ENUM_MGMT_HANDLERS;
529 	details_response[FOUND_INDEX_ENUM].expected_test = false;
530 
531 	struct zcbor_map_decode_key_val output_decode[] = {
532 		ZCBOR_MAP_DECODE_KEY_DECODER("groups", parse_details_entries, &details_response),
533 	};
534 
535 	memset(buffer, 0, sizeof(buffer));
536 	memset(buffer_out, 0, sizeof(buffer_out));
537 	buffer_size = 0;
538 	memset(zse, 0, sizeof(zse));
539 	memset(zsd, 0, sizeof(zsd));
540 
541 	zcbor_new_encode_state(zse, 3, buffer, ARRAY_SIZE(buffer), 0);
542 
543 	ok = create_enum_mgmt_details_packet(zse, buffer, buffer_out, &buffer_size, NULL, 0);
544 	zassert_true(ok, "Expected packet creation to be successful");
545 
546 	/* Enable dummy SMP backend and ready for usage */
547 	smp_dummy_enable();
548 	smp_dummy_clear_state();
549 
550 	/* Send query command to dummy SMP backend */
551 	(void)smp_dummy_tx_pkt(buffer_out, buffer_size);
552 	smp_dummy_add_data();
553 
554 	/* Wait for a short duration to see if response has been received */
555 	received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
556 	zassert_true(received, "Expected to receive data but timed out");
557 
558 	/* Retrieve response buffer */
559 	nb = smp_dummy_get_outgoing();
560 	smp_dummy_disable();
561 
562 	/* Check response is as expected */
563 	header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
564 
565 	zassert_equal(header->nh_flags, 0, "SMP header flags mismatch");
566 	zassert_equal(header->nh_op, MGMT_OP_READ_RSP, "SMP header operation mismatch");
567 	zassert_equal(header->nh_group, sys_cpu_to_be16(MGMT_GROUP_ID_ENUM),
568 		      "SMP header group mismatch");
569 	zassert_equal(header->nh_seq, 1, "SMP header sequence number mismatch");
570 	zassert_equal(header->nh_id, ENUM_MGMT_ID_DETAILS, "SMP header command ID mismatch");
571 	zassert_equal(header->nh_version, 1, "SMP header version mismatch");
572 
573 	/* Get the response value to compare */
574 	zcbor_new_decode_state(zsd, 7, nb->data, nb->len, 1, NULL, 0);
575 	ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
576 	zassert_true(ok, "Expected decode to be successful");
577 	zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
578 
579 	i = 0;
580 
581 	while (i < TEST_GROUPS) {
582 		zassert_true(details_response[i].matched_name,
583 			     "Expected group name to be found in details");
584 		zassert_true(details_response[i].matched_handlers,
585 			     "Expected group handler to be found in details");
586 		zassert_true(details_response[i].matched_test,
587 			     "Did not expect group test to be found in details");
588 		++i;
589 	}
590 
591 	zassert_true(enum_valid_got, "Expected callback to have ran");
592 	zassert_false(enum_field_added, "Did not expect field to be added");
593 	zassert_false(event_invalid_got, "Did not expect invalid callback to have ran");
594 
595 	/* Clean up test */
596 	cleanup_test(NULL);
597 }
598 
ZTEST(enum_mgmt,test_details_blocked)599 ZTEST(enum_mgmt, test_details_blocked)
600 {
601 	uint8_t buffer[ZCBOR_BUFFER_SIZE];
602 	uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
603 	bool ok;
604 	uint16_t buffer_size;
605 	zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
606 	zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
607 	bool received;
608 	struct smp_hdr *header;
609 	size_t decoded = 0;
610 	uint32_t rc = 0;
611 
612 	struct zcbor_map_decode_key_val output_decode[] = {
613 		ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_uint32_decode, &rc),
614 	};
615 
616 	memset(buffer, 0, sizeof(buffer));
617 	memset(buffer_out, 0, sizeof(buffer_out));
618 	buffer_size = 0;
619 	memset(zse, 0, sizeof(zse));
620 	memset(zsd, 0, sizeof(zsd));
621 
622 	zcbor_new_encode_state(zse, 3, buffer, ARRAY_SIZE(buffer), 0);
623 
624 	ok = create_enum_mgmt_details_packet(zse, buffer, buffer_out, &buffer_size, NULL, 0);
625 	zassert_true(ok, "Expected packet creation to be successful");
626 
627 	/* Enable dummy SMP backend and ready for usage */
628 	smp_dummy_enable();
629 	smp_dummy_clear_state();
630 
631 	/* Force notification callback to return an error */
632 	block_access = true;
633 
634 	/* Send query command to dummy SMP backend */
635 	(void)smp_dummy_tx_pkt(buffer_out, buffer_size);
636 	smp_dummy_add_data();
637 
638 	/* Wait for a short duration to see if response has been received */
639 	received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
640 	zassert_true(received, "Expected to receive data but timed out");
641 
642 	/* Retrieve response buffer */
643 	nb = smp_dummy_get_outgoing();
644 	smp_dummy_disable();
645 
646 	/* Check response is as expected */
647 	header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
648 
649 	zassert_equal(header->nh_flags, 0, "SMP header flags mismatch");
650 	zassert_equal(header->nh_op, MGMT_OP_READ_RSP, "SMP header operation mismatch");
651 	zassert_equal(header->nh_group, sys_cpu_to_be16(MGMT_GROUP_ID_ENUM),
652 		      "SMP header group mismatch");
653 	zassert_equal(header->nh_seq, 1, "SMP header sequence number mismatch");
654 	zassert_equal(header->nh_id, ENUM_MGMT_ID_DETAILS, "SMP header command ID mismatch");
655 	zassert_equal(header->nh_version, 1, "SMP header version mismatch");
656 
657 	/* Get the response value to compare */
658 	zcbor_new_decode_state(zsd, 5, nb->data, nb->len, 1, NULL, 0);
659 	ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
660 	zassert_true(ok, "Expected decode to be successful");
661 	zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
662 
663 	zassert_true(enum_valid_got, "Expected callback to have ran");
664 	zassert_false(enum_field_added, "Did not expect field to be added");
665 	zassert_false(event_invalid_got, "Did not expect invalid callback to have ran");
666 
667 	/* Clean up test */
668 	cleanup_test(NULL);
669 }
670 
ZTEST(enum_mgmt,test_details_extra)671 ZTEST(enum_mgmt, test_details_extra)
672 {
673 	uint8_t buffer[ZCBOR_BUFFER_SIZE];
674 	uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
675 	bool ok;
676 	uint16_t buffer_size;
677 	zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
678 	zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
679 	bool received;
680 	struct smp_hdr *header;
681 	size_t decoded = 0;
682 	struct details_entries details_response[TEST_GROUPS] = { 0 };
683 	uint8_t i;
684 
685 #if defined(CONFIG_MCUMGR_GRP_SHELL)
686 	strcpy(details_response[FOUND_INDEX_SHELL].expected_name, SHELL_MGMT_NAME);
687 	details_response[FOUND_INDEX_SHELL].expected_handlers = SHELL_MGMT_HANDLERS;
688 	details_response[FOUND_INDEX_SHELL].expected_test = true;
689 #endif
690 
691 #if defined(CONFIG_MCUMGR_GRP_OS)
692 	strcpy(details_response[FOUND_INDEX_OS].expected_name, OS_MGMT_NAME);
693 	details_response[FOUND_INDEX_OS].expected_handlers = OS_MGMT_HANDLERS;
694 	details_response[FOUND_INDEX_OS].expected_test = true;
695 #endif
696 
697 	strcpy(details_response[FOUND_INDEX_ENUM].expected_name, ENUM_MGMT_NAME);
698 	details_response[FOUND_INDEX_ENUM].expected_handlers = ENUM_MGMT_HANDLERS;
699 	details_response[FOUND_INDEX_ENUM].expected_test = true;
700 
701 	struct zcbor_map_decode_key_val output_decode[] = {
702 		ZCBOR_MAP_DECODE_KEY_DECODER("groups", parse_details_entries, &details_response),
703 	};
704 
705 	memset(buffer, 0, sizeof(buffer));
706 	memset(buffer_out, 0, sizeof(buffer_out));
707 	buffer_size = 0;
708 	memset(zse, 0, sizeof(zse));
709 	memset(zsd, 0, sizeof(zsd));
710 
711 	zcbor_new_encode_state(zse, 3, buffer, ARRAY_SIZE(buffer), 0);
712 
713 	ok = create_enum_mgmt_details_packet(zse, buffer, buffer_out, &buffer_size, NULL, 0);
714 	zassert_true(ok, "Expected packet creation to be successful");
715 
716 	add_field = true;
717 
718 	/* Enable dummy SMP backend and ready for usage */
719 	smp_dummy_enable();
720 	smp_dummy_clear_state();
721 
722 	/* Send query command to dummy SMP backend */
723 	(void)smp_dummy_tx_pkt(buffer_out, buffer_size);
724 	smp_dummy_add_data();
725 
726 	/* Wait for a short duration to see if response has been received */
727 	received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
728 	zassert_true(received, "Expected to receive data but timed out");
729 
730 	/* Retrieve response buffer */
731 	nb = smp_dummy_get_outgoing();
732 	smp_dummy_disable();
733 
734 	/* Check response is as expected */
735 	header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
736 
737 	zassert_equal(header->nh_flags, 0, "SMP header flags mismatch");
738 	zassert_equal(header->nh_op, MGMT_OP_READ_RSP, "SMP header operation mismatch");
739 	zassert_equal(header->nh_group, sys_cpu_to_be16(MGMT_GROUP_ID_ENUM),
740 		      "SMP header group mismatch");
741 	zassert_equal(header->nh_seq, 1, "SMP header sequence number mismatch");
742 	zassert_equal(header->nh_id, ENUM_MGMT_ID_DETAILS, "SMP header command ID mismatch");
743 	zassert_equal(header->nh_version, 1, "SMP header version mismatch");
744 
745 	/* Get the response value to compare */
746 	zcbor_new_decode_state(zsd, 5, nb->data, nb->len, 1, NULL, 0);
747 	ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
748 	zassert_true(ok, "Expected decode to be successful");
749 	zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
750 
751 	i = 0;
752 
753 	while (i < TEST_GROUPS) {
754 		zassert_true(details_response[i].matched_name,
755 			     "Expected group name to be found in details");
756 		zassert_true(details_response[i].matched_handlers,
757 			     "Expected group handler to be found in details");
758 		zassert_true(details_response[i].matched_test,
759 			     "Expected group test to be found in details");
760 		++i;
761 	}
762 
763 	zassert_true(enum_valid_got, "Expected callback to have ran");
764 	zassert_true(enum_field_added, "Expected field to be added");
765 	zassert_false(event_invalid_got, "Did not expect invalid callback to have ran");
766 
767 	/* Clean up test */
768 	cleanup_test(NULL);
769 }
770 
mgmt_event_cmd_callback(uint32_t event,enum mgmt_cb_return prev_status,int32_t * rc,uint16_t * group,bool * abort_more,void * data,size_t data_size)771 static enum mgmt_cb_return mgmt_event_cmd_callback(uint32_t event, enum mgmt_cb_return prev_status,
772 						   int32_t *rc, uint16_t *group, bool *abort_more,
773 						   void *data, size_t data_size)
774 {
775 	if (event == MGMT_EVT_OP_ENUM_MGMT_DETAILS) {
776 		struct enum_mgmt_detail_output *enum_data = (struct enum_mgmt_detail_output *)data;
777 
778 		enum_valid_got = true;
779 
780 		if (add_field == true) {
781 			uint32_t temp = enum_data->group->mg_group_id * 3 + 1;
782 			bool ok;
783 
784 			ok = zcbor_tstr_put_lit(enum_data->zse, "test") &&
785 			     zcbor_uint32_encode(enum_data->zse, &temp);
786 
787 			if (!ok) {
788 				*rc = MGMT_ERR_EUNKNOWN;
789 				return MGMT_CB_ERROR_RC;
790 			}
791 
792 			enum_field_added = true;
793 		}
794 
795 		if (block_access == true) {
796 			*rc = MGMT_ERR_EPERUSER;
797 			return MGMT_CB_ERROR_RC;
798 		}
799 	} else {
800 		event_invalid_got = true;
801 	}
802 
803 	return MGMT_CB_OK;
804 }
805 
806 static struct mgmt_callback mgmt_event_callback = {
807 	.callback = mgmt_event_cmd_callback,
808 	.event_id = MGMT_EVT_OP_ENUM_MGMT_DETAILS,
809 };
810 
setup_test(void)811 static void *setup_test(void)
812 {
813 	mgmt_callback_register(&mgmt_event_callback);
814 
815 	return NULL;
816 }
817 
818 ZTEST_SUITE(enum_mgmt, NULL, setup_test, NULL, cleanup_test, NULL);
819