1 /*
2 * Copyright (c) 2023 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/os_mgmt/os_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 <zephyr/version.h>
18 #include <string.h>
19 #include <smp_internal.h>
20 #include "smp_test_util.h"
21
22 #define SMP_RESPONSE_WAIT_TIME 3
23 #define ZCBOR_BUFFER_SIZE 64
24 #define OUTPUT_BUFFER_SIZE 64
25 #define ZCBOR_HISTORY_ARRAY_SIZE 4
26
27 /* Test sets */
28 enum {
29 CB_NOTIFICATION_TEST_CALLBACK_DISABLED,
30 CB_NOTIFICATION_TEST_CALLBACK_ENABLED,
31 CB_NOTIFICATION_TEST_CALLBACK_DISABLED_VERIFY,
32
33 CB_NOTIFICATION_TEST_SET_COUNT
34 };
35
36 static struct net_buf *nb;
37
38 struct state {
39 uint8_t test_set;
40 };
41
42 static struct state test_state = {
43 .test_set = 0,
44 };
45
46 static bool cmd_recv_got;
47 static bool cmd_status_got;
48 static bool cmd_done_got;
49 static bool cmd_other_got;
50
51 /* Responses to commands */
52
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)53 static enum mgmt_cb_return mgmt_event_cmd_callback(uint32_t event, enum mgmt_cb_return prev_status,
54 int32_t *rc, uint16_t *group, bool *abort_more,
55 void *data, size_t data_size)
56 {
57 if (event == MGMT_EVT_OP_CMD_RECV) {
58 cmd_recv_got = true;
59 } else if (event == MGMT_EVT_OP_CMD_STATUS) {
60 cmd_status_got = true;
61 } else if (event == MGMT_EVT_OP_CMD_DONE) {
62 cmd_done_got = true;
63 } else {
64 cmd_other_got = true;
65 }
66
67 return MGMT_CB_OK;
68 }
69
70 static struct mgmt_callback mgmt_event_callback = {
71 .callback = mgmt_event_cmd_callback,
72 .event_id = (MGMT_EVT_OP_CMD_RECV | MGMT_EVT_OP_CMD_STATUS | MGMT_EVT_OP_CMD_DONE),
73 };
74
setup_callbacks(void)75 static void *setup_callbacks(void)
76 {
77 mgmt_callback_register(&mgmt_event_callback);
78 return NULL;
79 }
80
destroy_callbacks(void * p)81 static void destroy_callbacks(void *p)
82 {
83 mgmt_callback_unregister(&mgmt_event_callback);
84 }
85
wait_for_sync(void)86 static inline void wait_for_sync(void)
87 {
88 #ifdef CONFIG_SMP
89 /* For SMP systems, it is possible that a dummy response is fully received and processed
90 * prior to the callback code being executed, therefore implement a dummy wait to wait
91 * for callback synchronisation to take place.
92 */
93 k_sleep(K_MSEC(1));
94 #endif
95 }
96
ZTEST(callback_disabled,test_notifications_disabled)97 ZTEST(callback_disabled, test_notifications_disabled)
98 {
99 uint8_t buffer[ZCBOR_BUFFER_SIZE];
100 uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
101 bool ok;
102 uint16_t buffer_size;
103 zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
104 zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
105 bool received;
106
107 memset(buffer, 0, sizeof(buffer));
108 memset(buffer_out, 0, sizeof(buffer_out));
109 buffer_size = 0;
110 memset(zse, 0, sizeof(zse));
111 memset(zsd, 0, sizeof(zsd));
112
113 zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
114
115 ok = create_mcumgr_format_packet(zse, buffer, buffer_out, &buffer_size);
116 zassert_true(ok, "Expected packet creation to be successful\n");
117
118 /* Enable dummy SMP backend and ready for usage */
119 smp_dummy_enable();
120 smp_dummy_clear_state();
121
122 /* Send query command to dummy SMP backend */
123 (void)smp_dummy_tx_pkt(buffer_out, buffer_size);
124 smp_dummy_add_data();
125
126 /* For a short duration to see if response has been received */
127 received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
128
129 zassert_true(received, "Expected to receive data but timed out\n");
130
131 /* Retrieve response buffer */
132 nb = smp_dummy_get_outgoing();
133 smp_dummy_disable();
134
135 /* Check events */
136 wait_for_sync();
137 zassert_false(cmd_recv_got, "Did not expect received command callback\n");
138 zassert_false(cmd_status_got, "Did not expect IMG status callback\n");
139 zassert_false(cmd_done_got, "Did not expect done command callback\n");
140 zassert_false(cmd_other_got, "Did not expect other callback(s)\n");
141 }
142
ZTEST(callback_enabled,test_notifications_enabled)143 ZTEST(callback_enabled, test_notifications_enabled)
144 {
145 uint8_t buffer[ZCBOR_BUFFER_SIZE];
146 uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
147 bool ok;
148 uint16_t buffer_size;
149 zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
150 zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
151 bool received;
152
153 memset(buffer, 0, sizeof(buffer));
154 memset(buffer_out, 0, sizeof(buffer_out));
155 buffer_size = 0;
156 memset(zse, 0, sizeof(zse));
157 memset(zsd, 0, sizeof(zsd));
158
159 zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
160
161 ok = create_mcumgr_format_packet(zse, buffer, buffer_out, &buffer_size);
162 zassert_true(ok, "Expected packet creation to be successful\n");
163
164 /* Enable dummy SMP backend and ready for usage */
165 smp_dummy_enable();
166 smp_dummy_clear_state();
167
168 /* Send query command to dummy SMP backend */
169 (void)smp_dummy_tx_pkt(buffer_out, buffer_size);
170 smp_dummy_add_data();
171
172 /* For a short duration to see if response has been received */
173 received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
174
175 zassert_true(received, "Expected to receive data but timed out\n");
176
177 /* Retrieve response buffer */
178 nb = smp_dummy_get_outgoing();
179 smp_dummy_disable();
180
181 /* Check events */
182 wait_for_sync();
183 zassert_true(cmd_recv_got, "Expected received command callback\n");
184 zassert_false(cmd_status_got, "Did not expect IMG status callback\n");
185 zassert_true(cmd_done_got, "Expected done command callback\n");
186 zassert_false(cmd_other_got, "Did not expect other callback(s)\n");
187 }
188
ZTEST(callback_disabled_verify,test_notifications_disabled_verify)189 ZTEST(callback_disabled_verify, test_notifications_disabled_verify)
190 {
191 uint8_t buffer[ZCBOR_BUFFER_SIZE];
192 uint8_t buffer_out[OUTPUT_BUFFER_SIZE];
193 bool ok;
194 uint16_t buffer_size;
195 zcbor_state_t zse[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
196 zcbor_state_t zsd[ZCBOR_HISTORY_ARRAY_SIZE] = { 0 };
197 bool received;
198
199 memset(buffer, 0, sizeof(buffer));
200 memset(buffer_out, 0, sizeof(buffer_out));
201 buffer_size = 0;
202 memset(zse, 0, sizeof(zse));
203 memset(zsd, 0, sizeof(zsd));
204
205 zcbor_new_encode_state(zse, 2, buffer, ARRAY_SIZE(buffer), 0);
206
207 ok = create_mcumgr_format_packet(zse, buffer, buffer_out, &buffer_size);
208 zassert_true(ok, "Expected packet creation to be successful\n");
209
210 /* Enable dummy SMP backend and ready for usage */
211 smp_dummy_enable();
212 smp_dummy_clear_state();
213
214 /* Send query command to dummy SMP backend */
215 (void)smp_dummy_tx_pkt(buffer_out, buffer_size);
216 smp_dummy_add_data();
217
218 /* For a short duration to see if response has been received */
219 received = smp_dummy_wait_for_data(SMP_RESPONSE_WAIT_TIME);
220
221 zassert_true(received, "Expected to receive data but timed out\n");
222
223 /* Retrieve response buffer */
224 nb = smp_dummy_get_outgoing();
225 smp_dummy_disable();
226
227 /* Check events */
228 wait_for_sync();
229 zassert_false(cmd_recv_got, "Did not expect received command callback\n");
230 zassert_false(cmd_status_got, "Did not expect IMG status callback\n");
231 zassert_false(cmd_done_got, "Did not expect done command callback\n");
232 zassert_false(cmd_other_got, "Did not expect other callback(s)\n");
233 }
234
cleanup_test(void * p)235 static void cleanup_test(void *p)
236 {
237 if (nb != NULL) {
238 net_buf_unref(nb);
239 nb = NULL;
240 }
241
242 cmd_recv_got = false;
243 cmd_status_got = false;
244 cmd_done_got = false;
245 cmd_other_got = false;
246 }
247
test_main(void)248 void test_main(void)
249 {
250 while (test_state.test_set < CB_NOTIFICATION_TEST_SET_COUNT) {
251 ztest_run_all(&test_state, false, 1, 1);
252 ++test_state.test_set;
253 }
254
255 ztest_verify_all_test_suites_ran();
256 }
257
callback_disabled_predicate(const void * state)258 static bool callback_disabled_predicate(const void *state)
259 {
260 return ((struct state *)state)->test_set == CB_NOTIFICATION_TEST_CALLBACK_DISABLED;
261 }
262
callback_enabled_predicate(const void * state)263 static bool callback_enabled_predicate(const void *state)
264 {
265 return ((struct state *)state)->test_set == CB_NOTIFICATION_TEST_CALLBACK_ENABLED;
266 }
267
callback_disabled_verify_predicate(const void * state)268 static bool callback_disabled_verify_predicate(const void *state)
269 {
270 return ((struct state *)state)->test_set == CB_NOTIFICATION_TEST_CALLBACK_DISABLED_VERIFY;
271 }
272
273 ZTEST_SUITE(callback_disabled, callback_disabled_predicate, NULL, NULL, cleanup_test, NULL);
274 ZTEST_SUITE(callback_enabled, callback_enabled_predicate, setup_callbacks, NULL, cleanup_test,
275 destroy_callbacks);
276 ZTEST_SUITE(callback_disabled_verify, callback_disabled_verify_predicate, NULL, NULL,
277 cleanup_test, NULL);
278