1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/sys/byteorder.h>
9 #include <zephyr/net_buf.h>
10 #include <zephyr/net/net_ip.h>
11 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
12 #include <zephyr/mgmt/mcumgr/transport/smp_dummy.h>
13 #include <zephyr/mgmt/mcumgr/grp/fs_mgmt/fs_mgmt.h>
14 #include <zcbor_common.h>
15 #include <zcbor_decode.h>
16 #include <mgmt/mcumgr/transport/smp_internal.h>
17
18 #define SMP_RESPONSE_WAIT_TIME 3
19
20 /* Test fs_mgmt supported hash/checksum query command */
21 static const uint8_t command[] = {
22 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x01, 0x03,
23 0xbf, 0xff,
24 };
25
26 struct hash_checksum_type {
27 uint8_t name[32];
28 uint32_t format;
29 uint32_t size;
30 bool found;
31 bool entries_matched;
32 };
33
ZTEST(fs_mgmt_hash_supported,test_supported)34 ZTEST(fs_mgmt_hash_supported, test_supported)
35 {
36 struct net_buf *nb;
37 struct hash_checksum_type expected_types[] = {
38 #ifdef CONFIG_MCUMGR_GRP_FS_HASH_SHA256
39
40 {
41 .name = "sha256",
42 .format = 1,
43 .size = 32,
44 .found = false,
45 .entries_matched = false,
46 },
47 #endif
48 #ifdef CONFIG_MCUMGR_GRP_FS_CHECKSUM_IEEE_CRC32
49 {
50 .name = "crc32",
51 .format = 0,
52 .size = 4,
53 .found = false,
54 .entries_matched = false,
55 },
56 #endif
57 };
58
59 /* Enable dummy SMP backend and ready for usage */
60 smp_dummy_enable();
61 smp_dummy_clear_state();
62
63 /* Send test echo command to dummy SMP backend */
64 (void)smp_dummy_tx_pkt(command, sizeof(command));
65 smp_dummy_add_data();
66
67 /* For a short duration to see if response has been received */
68 bool received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
69
70 zassert_true(received, "Expected to receive data but timed out\n");
71
72 /* Retrieve response buffer and ensure validity */
73 nb = smp_dummy_get_outgoing();
74 smp_dummy_disable();
75
76 /* Check that the headers seem valid */
77 struct smp_hdr *response_hdr = (struct smp_hdr *)nb->data;
78 uint16_t len = ntohs(response_hdr->nh_len);
79 uint16_t group = ntohs(response_hdr->nh_group);
80
81 zassert_equal(response_hdr->nh_op, MGMT_OP_READ_RSP,
82 "Expected response to have rease response type");
83 zassert_true((len > 20), "Expected response to be at least 20 bytes in length");
84 zassert_equal(group, MGMT_GROUP_ID_FS, "Expected response to be FS group");
85 zassert_equal(response_hdr->nh_id, FS_MGMT_ID_SUPPORTED_HASH_CHECKSUM,
86 "Expected response to be supported hash/checksum ID");
87
88 /* Process the payload with zcbor and check expected types are present */
89 zcbor_state_t state[10];
90 struct zcbor_string key;
91 uint32_t format_value;
92 bool format_found;
93 uint32_t size_value;
94 bool size_found;
95 int8_t entry = 0;
96 bool ok = true;
97
98 /* Search expected type array for this type and update details */
99 zcbor_new_decode_state(state, 10, &nb->data[sizeof(struct smp_hdr)],
100 (nb->len - sizeof(struct smp_hdr)), 1, NULL, 0);
101
102 ok = zcbor_map_start_decode(state);
103
104 ok = zcbor_tstr_decode(state, &key);
105
106 zassert_equal(key.len, strlen("types"),
107 "Expected CBOR response 'types' value length to match");
108 zassert_mem_equal(key.value, "types", strlen("types"),
109 "Expected CBOR response 'types' value to match");
110
111 ok = zcbor_map_start_decode(state);
112
113 while (ok == true) {
114 ok = zcbor_tstr_decode(state, &key);
115 if (!ok) {
116 break;
117 }
118
119 entry = 0;
120 while (entry < ARRAY_SIZE(expected_types)) {
121 if (memcmp(key.value, expected_types[entry].name, MIN(key.len,
122 strlen(expected_types[entry].name))) == 0) {
123 zassert_equal(expected_types[entry].found, false,
124 "Found entry multiple times");
125 expected_types[entry].found = true;
126 break;
127 }
128
129 ++entry;
130 }
131
132 zassert_equal(entry < ARRAY_SIZE(expected_types), true,
133 "Did not find entry for type");
134
135 ok = zcbor_map_start_decode(state);
136 format_found = false;
137 size_found = false;
138
139 while (ok == true) {
140 ok = zcbor_tstr_decode(state, &key);
141
142 if (!ok) {
143 break;
144 }
145
146 if (memcmp(key.value, "format", strlen("format")) == 0) {
147 zassert_false(format_found,
148 "Expected format to only be found once");
149 ok &= zcbor_uint32_decode(state, &format_value);
150 format_found = true;
151 } else if (memcmp(key.value, "size", strlen("size")) == 0) {
152 zassert_false(size_found, "Expected size to be only found once");
153 ok &= zcbor_uint32_decode(state, &size_value);
154 size_found = true;
155 } else {
156 zassert_true(false, "Unexpected field in CBOR response");
157 }
158
159 if (format_found == true && size_found == true) {
160 zassert_equal(expected_types[entry].format, format_value,
161 "Format value mismatch with expected value");
162 zassert_equal(expected_types[entry].size, size_value,
163 "Size value mismatch with expected value");
164 expected_types[entry].entries_matched = true;
165 }
166 }
167
168 ok = zcbor_map_end_decode(state);
169 }
170
171 ok = zcbor_map_end_decode(state);
172 }
173
174 ZTEST_SUITE(fs_mgmt_hash_supported, NULL, NULL, NULL, NULL, NULL);
175