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/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/grp/os_mgmt/os_mgmt.h>
12 #include <zcbor_common.h>
13 #include <zcbor_decode.h>
14 #include <zcbor_encode.h>
15 #include <mgmt/mcumgr/util/zcbor_bulk.h>
16 #include <string.h>
17 #include <smp_internal.h>
18 #include "smp_test_util.h"
19
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(mcumgr_fs_grp, 4);
22
23 enum {
24 LEGACY_VERSION = 0,
25 CURRENT_VERSION,
26 FUTURE_VERSION,
27 };
28
29 #define SMP_RESPONSE_WAIT_TIME 3
30 #define QUERY_BUFFER_SIZE 16
31 #define ZCBOR_BUFFER_SIZE 256
32 #define OUTPUT_BUFFER_SIZE 256
33 #define ZCBOR_HISTORY_ARRAY_SIZE 4
34
35 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
36 /* Response to legacy packet */
37 static const uint8_t response_old[] = {
38 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x07,
39 0xbf, 0x62, 0x72, 0x63, 0x03, 0xff
40 };
41 #else
42 /* Response if a legacy packet is sent and server does not support it */
43 static const uint8_t response_old[] = {
44 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x07,
45 0xbf, 0x62, 0x72, 0x63, 0x0c, 0xff
46 };
47 #endif
48
49 /* Response to current packet */
50 static const uint8_t response_current[] = {
51 0x09, 0x00, 0x00, 0x13, 0x00, 0x00, 0x01, 0x07,
52 0xbf, 0x63, 0x65, 0x72, 0x72, 0xbf, 0x65, 0x67,
53 0x72, 0x6f, 0x75, 0x70, 0x00, 0x62, 0x72, 0x63,
54 0x02, 0xff, 0xff
55 };
56
57 /* Response if an invalid (too high) version packet is sent and server does not support it */
58 static const uint8_t response_new[] = {
59 0x09, 0x00, 0x00, 0x06, 0x00, 0x00, 0x01, 0x07,
60 0xbf, 0x62, 0x72, 0x63, 0x0d, 0xff
61 };
62
63 static struct net_buf *nb;
64
65 const uint8_t query_fake[] = "8";
66
67 struct group_error {
68 uint16_t group;
69 uint16_t rc;
70 bool found;
71 };
72
mcumgr_ret_decode(zcbor_state_t * state,struct group_error * result)73 static bool mcumgr_ret_decode(zcbor_state_t *state, struct group_error *result)
74 {
75 bool ok;
76 size_t decoded;
77 uint32_t tmp_group;
78 uint32_t tmp_rc;
79
80 struct zcbor_map_decode_key_val output_decode[] = {
81 ZCBOR_MAP_DECODE_KEY_DECODER("group", zcbor_uint32_decode, &tmp_group),
82 ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_uint32_decode, &tmp_rc),
83 };
84
85 result->found = false;
86
87 ok = zcbor_map_decode_bulk(state, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
88
89 if (ok &&
90 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "group") &&
91 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode), "rc")) {
92 result->group = (uint16_t)tmp_group;
93 result->rc = (uint16_t)tmp_rc;
94 result->found = true;
95 }
96
97 return ok;
98 }
99
ZTEST(smp_version,test_legacy_command)100 ZTEST(smp_version, test_legacy_command)
101 {
102 uint8_t buffer[ZCBOR_BUFFER_SIZE];
103 uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
104 bool ok;
105 uint16_t buffer_size;
106 zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
107 zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
108 bool received;
109 struct zcbor_string output = { 0 };
110 size_t decoded = 0;
111 struct smp_hdr *smp_header;
112 int32_t rc;
113 struct group_error group_error;
114
115 struct zcbor_map_decode_key_val output_decode[] = {
116 ZCBOR_MAP_DECODE_KEY_DECODER("output", zcbor_tstr_decode, &output),
117 ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc),
118 ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error),
119 };
120
121 memset(buffer, 0, sizeof(buffer));
122 memset(buffer_out, 0, sizeof(buffer_out));
123 buffer_size = 0;
124 memset(zse, 0, sizeof(zse));
125 memset(zsd, 0, sizeof(zsd));
126
127 zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
128
129 ok = create_mcumgr_format_packet(zse, query_fake, buffer, buffer_out, &buffer_size,
130 LEGACY_VERSION);
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 /* 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 and ensure validity */
146 nb = smp_dummy_get_outgoing();
147 smp_dummy_disable();
148
149 /* Check that the received response matches the expected response */
150 zassert_equal(sizeof(response_old), nb->len, "Expected received data length mismatch");
151 zassert_mem_equal(response_old, nb->data, nb->len, "Expected received data mismatch");
152
153 /* Process received data by removing header */
154 smp_header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
155 zassert_equal(smp_header->nh_version, LEGACY_VERSION,
156 "Expected response header version mismatch");
157
158 zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0);
159 ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
160
161 zassert_true(ok, "Expected decode to be successful");
162 zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
163
164 zassert_equal(
165 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
166 "output"), 0,
167 "Did not expect to get output in response");
168
169 zassert_equal(
170 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
171 "rc"), 1,
172 "Expected to get rc in response");
173
174 zassert_equal(
175 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
176 "err"), 0,
177 "Did not expect to get ret in response");
178
179 #ifdef CONFIG_MCUMGR_SMP_SUPPORT_ORIGINAL_PROTOCOL
180 zassert_equal(rc, MGMT_ERR_EINVAL, "Expected to get MGMT_ERR_EINVAL error");
181 #else
182 zassert_equal(rc, MGMT_ERR_UNSUPPORTED_TOO_OLD,
183 "Expected to get MGMT_ERR_UNSUPPORTED_TOO_OLD error");
184 #endif
185 }
186
ZTEST(smp_version,test_current_command)187 ZTEST(smp_version, test_current_command)
188 {
189 uint8_t buffer[ZCBOR_BUFFER_SIZE];
190 uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
191 bool ok;
192 uint16_t buffer_size;
193 zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
194 zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
195 bool received;
196 struct zcbor_string output = { 0 };
197 size_t decoded = 0;
198 struct smp_hdr *smp_header;
199 int32_t rc;
200 struct group_error group_error;
201
202 struct zcbor_map_decode_key_val output_decode[] = {
203 ZCBOR_MAP_DECODE_KEY_DECODER("output", zcbor_tstr_decode, &output),
204 ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc),
205 ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error),
206 };
207
208 memset(buffer, 0, sizeof(buffer));
209 memset(buffer_out, 0, sizeof(buffer_out));
210 buffer_size = 0;
211 memset(zse, 0, sizeof(zse));
212 memset(zsd, 0, sizeof(zsd));
213
214 zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
215
216 ok = create_mcumgr_format_packet(zse, query_fake, buffer, buffer_out, &buffer_size,
217 CURRENT_VERSION);
218 zassert_true(ok, "Expected packet creation to be successful");
219
220 /* Enable dummy SMP backend and ready for usage */
221 smp_dummy_enable();
222 smp_dummy_clear_state();
223
224 /* Send query command to dummy SMP backend */
225 (void)smp_dummy_tx_pkt(buffer_out, buffer_size);
226 smp_dummy_add_data();
227
228 /* For a short duration to see if response has been received */
229 received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
230 zassert_true(received, "Expected to receive data but timed out");
231
232 /* Retrieve response buffer and ensure validity */
233 nb = smp_dummy_get_outgoing();
234 smp_dummy_disable();
235
236 /* Check that the received response matches the expected response */
237 zassert_equal(sizeof(response_current), nb->len, "Expected received data length mismatch");
238 zassert_mem_equal(response_current, nb->data, nb->len, "Expected received data mismatch");
239
240 /* Process received data by removing header */
241 smp_header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
242 zassert_equal(smp_header->nh_version, CURRENT_VERSION,
243 "Expected response header version mismatch");
244
245 zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0);
246 ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
247
248 zassert_true(ok, "Expected decode to be successful");
249 zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
250
251 zassert_equal(
252 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
253 "output"), 0,
254 "Did not expect to get output in response");
255
256 zassert_equal(
257 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
258 "rc"), 0,
259 "Did not expect to get rc in response");
260
261 zassert_equal(
262 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
263 "err"), 1,
264 "Expected to get ret in response");
265
266 zassert_true(group_error.found, "Expected both group and rc in ret to be found");
267 zassert_equal(group_error.group, MGMT_GROUP_ID_OS,
268 "Expected to get MGMT_GROUP_ID_OS for ret group");
269 zassert_equal(group_error.rc, OS_MGMT_ERR_INVALID_FORMAT,
270 "Expected to get OS_MGMT_ERR_INVALID_FORMAT for ret rc");
271 }
272
ZTEST(smp_version,test_new_command)273 ZTEST(smp_version, test_new_command)
274 {
275 uint8_t buffer[ZCBOR_BUFFER_SIZE];
276 uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
277 bool ok;
278 uint16_t buffer_size;
279 zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
280 zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
281 bool received;
282 struct zcbor_string output = { 0 };
283 size_t decoded = 0;
284 struct smp_hdr *smp_header;
285 int32_t rc;
286 struct group_error group_error;
287
288 struct zcbor_map_decode_key_val output_decode[] = {
289 ZCBOR_MAP_DECODE_KEY_DECODER("output", zcbor_tstr_decode, &output),
290 ZCBOR_MAP_DECODE_KEY_DECODER("rc", zcbor_int32_decode, &rc),
291 ZCBOR_MAP_DECODE_KEY_DECODER("err", mcumgr_ret_decode, &group_error),
292 };
293
294 memset(buffer, 0, sizeof(buffer));
295 memset(buffer_out, 0, sizeof(buffer_out));
296 buffer_size = 0;
297 memset(zse, 0, sizeof(zse));
298 memset(zsd, 0, sizeof(zsd));
299
300 zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
301
302 ok = create_mcumgr_format_packet(zse, query_fake, buffer, buffer_out, &buffer_size,
303 FUTURE_VERSION);
304 zassert_true(ok, "Expected packet creation to be successful");
305
306 /* Enable dummy SMP backend and ready for usage */
307 smp_dummy_enable();
308 smp_dummy_clear_state();
309
310 /* Send query command to dummy SMP backend */
311 (void)smp_dummy_tx_pkt(buffer_out, buffer_size);
312 smp_dummy_add_data();
313
314 /* For a short duration to see if response has been received */
315 received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
316 zassert_true(received, "Expected to receive data but timed out");
317
318 /* Retrieve response buffer and ensure validity */
319 nb = smp_dummy_get_outgoing();
320 smp_dummy_disable();
321
322 /* Check that the received response matches the expected response */
323 zassert_equal(sizeof(response_new), nb->len, "Expected received data length mismatch");
324 zassert_mem_equal(response_new, nb->data, nb->len, "Expected received data mismatch");
325
326 /* Process received data by removing header */
327 smp_header = net_buf_pull_mem(nb, sizeof(struct smp_hdr));
328 zassert_equal(smp_header->nh_version, CURRENT_VERSION,
329 "Expected response header version mismatch");
330
331 zcbor_new_decode_state(zsd, 4, nb->data, nb->len, 1, NULL, 0);
332 ok = zcbor_map_decode_bulk(zsd, output_decode, ARRAY_SIZE(output_decode), &decoded) == 0;
333
334 zassert_true(ok, "Expected decode to be successful");
335 zassert_equal(decoded, 1, "Expected to receive 1 decoded zcbor element");
336
337 zassert_equal(
338 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
339 "output"), 0,
340 "Did not expect to get output in response");
341
342 zassert_equal(
343 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
344 "rc"), 1,
345 "Expected to get rc in response");
346
347 zassert_equal(
348 zcbor_map_decode_bulk_key_found(output_decode, ARRAY_SIZE(output_decode),
349 "err"), 0,
350 "Did not expect to get ret in response");
351
352 zassert_equal(rc, MGMT_ERR_UNSUPPORTED_TOO_NEW,
353 "Expected to get MGMT_ERR_UNSUPPORTED_TOO_NEW error");
354 }
355
cleanup_test(void * p)356 static void cleanup_test(void *p)
357 {
358 if (nb != NULL) {
359 net_buf_unref(nb);
360 nb = NULL;
361 }
362 }
363
364 /* Main test set */
365 ZTEST_SUITE(smp_version, NULL, NULL, NULL, cleanup_test, NULL);
366