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/mgmt/mcumgr/mgmt/mgmt.h>
11 #include <zephyr/mgmt/mcumgr/smp/smp.h>
12 #include <zephyr/mgmt/mcumgr/transport/smp.h>
13 #include "mgmt/mcumgr/transport/smp_reassembly.h"
14 #include "mgmt/mcumgr/transport/smp_internal.h"
15
16 #define TRANSPORT_NETBUF_SIZE CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE
17 static struct smp_transport smpt;
18 static uint8_t buff[TRANSPORT_NETBUF_SIZE];
19 #define TEST_FRAME_SIZE 256
20
21 static struct net_buf *backup;
22
23 /* The function is called by smp_reassembly_complete to pass a completed packet
24 * for further processing; since there is nothing to process, this stub will only backup
25 * buffer the pointer to allow a test case to free it with use of the mcumgr net_buf
26 * management.
27 */
smp_rx_req(struct smp_transport * transport,struct net_buf * nb)28 void smp_rx_req(struct smp_transport *transport, struct net_buf *nb)
29 {
30 backup = nb;
31 }
32
ZTEST(smp_reassembly,test_first)33 ZTEST(smp_reassembly, test_first)
34 {
35 smp_reassembly_init(&smpt);
36 struct smp_hdr *mh = (struct smp_hdr *)buff;
37 int frag_used;
38 int ret;
39 int expected;
40
41 /** First fragment errors **/
42 /* Len longer than netbuf error */
43 zassert_equal(-ENOSR, smp_reassembly_collect(&smpt, buff, TRANSPORT_NETBUF_SIZE + 1),
44 "Expected -ENOSR error");
45 /* Len not enough to read expected size from header */
46 zassert_equal(-ENODATA,
47 smp_reassembly_collect(&smpt, buff, sizeof(struct smp_hdr) - 1),
48 "Expected -ENODATA error");
49 /* Length extracted from header, plus size of header, is bigger than buffer */
50 mh->nh_len = sys_cpu_to_be16(TRANSPORT_NETBUF_SIZE - sizeof(struct smp_hdr) + 1);
51 zassert_equal(-ENOSR,
52 smp_reassembly_collect(&smpt, buff, sizeof(struct smp_hdr) + 1),
53 "Expected -ENOSR error");
54
55 /* Successfully alloc buffer */
56 mh->nh_len = sys_cpu_to_be16(TEST_FRAME_SIZE - sizeof(struct smp_hdr));
57 frag_used = 40;
58 expected = TEST_FRAME_SIZE - frag_used;
59 ret = smp_reassembly_collect(&smpt, buff, frag_used);
60 zassert_equal(expected, ret,
61 "Expected is %d should be %d\n", ret, expected);
62
63 /* Force complete it, expected returned number of bytes missing */
64 ret = smp_reassembly_complete(&smpt, true);
65 zassert_equal(expected, ret,
66 "Forced completion ret %d, but expected was %d\n", ret, expected);
67
68 /* Check fail due to lack of buffers: there is only one buffer and it already got passed
69 * for processing by complete
70 */
71 ret = smp_reassembly_collect(&smpt, buff, frag_used);
72 zassert_equal(-ENOMEM, ret,
73 "Expected -ENOMEM, got %d\n", ret);
74
75 /* This will normally be done by packet processing and should not be done by hand:
76 * release the buffer to the pool
77 */
78 smp_packet_free(backup);
79 }
80
ZTEST(smp_reassembly,test_drops)81 ZTEST(smp_reassembly, test_drops)
82 {
83 struct smp_hdr *mh = (struct smp_hdr *)buff;
84 int frag_used;
85 int ret;
86 int expected;
87
88 /* Collect one buffer and drop it */
89 mh->nh_len = sys_cpu_to_be16(TEST_FRAME_SIZE - sizeof(struct smp_hdr));
90 frag_used = 40;
91 expected = TEST_FRAME_SIZE - frag_used;
92 ret = smp_reassembly_collect(&smpt, buff, frag_used);
93 zassert_equal(expected, ret,
94 "Expected is %d should be %d\n", ret, expected);
95
96 ret = smp_reassembly_drop(&smpt);
97 zassert_equal(0, ret,
98 "Expected %d from drop, got %d", ret, expected);
99 }
100
ZTEST(smp_reassembly,test_collection)101 ZTEST(smp_reassembly, test_collection)
102 {
103 struct smp_hdr *mh = (struct smp_hdr *)buff;
104 int pkt_used;
105 int ret;
106 int expected;
107 int frag;
108 void *p;
109
110 for (int i = 0; i < ARRAY_SIZE(buff); i++) {
111 buff[i] = (i % 255) + 1;
112 }
113
114 /** Collect fragments **/
115 /* First fragment with header */
116 mh->nh_len = sys_cpu_to_be16(TEST_FRAME_SIZE - sizeof(struct smp_hdr));
117 frag = 40;
118 ret = smp_reassembly_collect(&smpt, buff, frag);
119 expected = TEST_FRAME_SIZE - frag;
120 zassert_equal(expected, ret,
121 "Expected is %d should be %d\n", ret, expected);
122 pkt_used = frag;
123
124 /* Next fragment */
125 frag = 40;
126 ret = smp_reassembly_collect(&smpt, &buff[pkt_used], frag);
127 pkt_used += frag;
128 expected = TEST_FRAME_SIZE - pkt_used;
129 zassert_equal(expected, ret,
130 "Expected is %d should be %d\n", ret, expected);
131
132 /* Try to complete incomplete, no force */
133 ret = smp_reassembly_complete(&smpt, false);
134 zassert_equal(-ENODATA, ret,
135 "Expected -ENODATA when completing incomplete buffer");
136
137 /* Last fragment */
138 ret = smp_reassembly_collect(&smpt, &buff[pkt_used], expected);
139 zassert_equal(0, ret,
140 "Expected 0, got %d\n", ret);
141
142 /* And overflow */
143 ret = smp_reassembly_collect(&smpt, buff, 1);
144 zassert_equal(-EOVERFLOW, ret,
145 "Expected -EOVERFLOW, got %d\n", ret);
146
147 /* Complete successfully complete buffer */
148 ret = smp_reassembly_complete(&smpt, false);
149 zassert_equal(0, ret,
150 "Expected 0 from complete, got %d\n", ret);
151
152 p = net_buf_pull_mem(backup, TEST_FRAME_SIZE);
153
154 ret = memcmp(p, buff, TEST_FRAME_SIZE);
155 zassert_equal(ret, 0, "Failed to assemble packet");
156
157 /* This will normally be done by packet processing and should not be done by hand:
158 * release the buffer to the pool
159 */
160 smp_packet_free(backup);
161 }
162
ZTEST(smp_reassembly,test_no_packet_started)163 ZTEST(smp_reassembly, test_no_packet_started)
164 {
165 int ret;
166
167 /** Complete on non-started packet **/
168 ret = smp_reassembly_complete(&smpt, false);
169 zassert_equal(-EINVAL, ret,
170 "Expected -EINVAL from complete, got %d", ret);
171 ret = smp_reassembly_complete(&smpt, true);
172 zassert_equal(-EINVAL, ret,
173 "Expected -EINVAL from complete, got %d", ret);
174
175 /* Try to drop packet when there is none yet */
176 ret = smp_reassembly_drop(&smpt);
177 zassert_equal(-EINVAL, ret,
178 "Expected -EINVAL, there is no packet started yet");
179 }
180
ZTEST(smp_reassembly,test_ud)181 ZTEST(smp_reassembly, test_ud)
182 {
183 struct smp_hdr *mh = (struct smp_hdr *)buff;
184 int frag_used;
185 int ret;
186 int expected;
187 void *p;
188
189 /* No packet started yet */
190 p = smp_reassembly_get_ud(&smpt);
191 zassert_equal(p, NULL, "Expect NULL ud poiner");
192
193 /* After collecting first fragment */
194 mh->nh_len = sys_cpu_to_be16(TEST_FRAME_SIZE);
195 frag_used = 40;
196 expected = TEST_FRAME_SIZE - frag_used + sizeof(struct smp_hdr);
197 ret = smp_reassembly_collect(&smpt, buff, frag_used);
198 zassert_equal(expected, ret,
199 "Expected is %d should be %d\n", ret, expected);
200
201 p = smp_reassembly_get_ud(&smpt);
202 zassert_not_equal(p, NULL, "Expect non-NULL ud poiner");
203 smp_reassembly_drop(&smpt);
204 }
205
206 ZTEST_SUITE(smp_reassembly, NULL, NULL, NULL, NULL, NULL);
207