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