1 #include "test_pbuf.h"
2 
3 #include "lwip/pbuf.h"
4 #include "lwip/stats.h"
5 
6 #if !LWIP_STATS || !MEM_STATS ||!MEMP_STATS
7 #error "This tests needs MEM- and MEMP-statistics enabled"
8 #endif
9 #if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !LWIP_WND_SCALE
10 #error "This test needs TCP OOSEQ queueing and window scaling enabled"
11 #endif
12 
13 /* Setups/teardown functions */
14 
15 static void
pbuf_setup(void)16 pbuf_setup(void)
17 {
18   lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
19 }
20 
21 static void
pbuf_teardown(void)22 pbuf_teardown(void)
23 {
24   lwip_check_ensure_no_alloc(SKIP_POOL(MEMP_SYS_TIMEOUT));
25 }
26 
27 
28 #define TESTBUFSIZE_1 65535
29 #define TESTBUFSIZE_2 65530
30 #define TESTBUFSIZE_3 50050
31 static u8_t testbuf_1[TESTBUFSIZE_1];
32 static u8_t testbuf_1a[TESTBUFSIZE_1];
33 static u8_t testbuf_2[TESTBUFSIZE_2];
34 static u8_t testbuf_2a[TESTBUFSIZE_2];
35 static u8_t testbuf_3[TESTBUFSIZE_3];
36 static u8_t testbuf_3a[TESTBUFSIZE_3];
37 
38 /* Test functions */
START_TEST(test_pbuf_alloc_zero_pbufs)39 START_TEST(test_pbuf_alloc_zero_pbufs)
40 {
41   struct pbuf *p;
42   LWIP_UNUSED_ARG(_i);
43 
44   p = pbuf_alloc(PBUF_RAW, 0, PBUF_ROM);
45   fail_unless(p != NULL);
46   if (p != NULL) {
47     pbuf_free(p);
48   }
49 
50   p = pbuf_alloc(PBUF_RAW, 0, PBUF_RAM);
51   fail_unless(p != NULL);
52   if (p != NULL) {
53     pbuf_free(p);
54   }
55 
56   p = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);
57   fail_unless(p != NULL);
58   if (p != NULL) {
59     pbuf_free(p);
60   }
61 
62   p = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);
63   fail_unless(p != NULL);
64   if (p != NULL) {
65     pbuf_free(p);
66   }
67 }
68 END_TEST
69 
70 /** Call pbuf_copy on a pbuf with zero length */
START_TEST(test_pbuf_copy_zero_pbuf)71 START_TEST(test_pbuf_copy_zero_pbuf)
72 {
73   struct pbuf *p1, *p2, *p3;
74   err_t err;
75   LWIP_UNUSED_ARG(_i);
76 
77   p1 = pbuf_alloc(PBUF_RAW, 1024, PBUF_RAM);
78   fail_unless(p1 != NULL);
79   fail_unless(p1->ref == 1);
80 
81   p2 = pbuf_alloc(PBUF_RAW, 2, PBUF_POOL);
82   fail_unless(p2 != NULL);
83   fail_unless(p2->ref == 1);
84   p2->len = p2->tot_len = 0;
85 
86   pbuf_cat(p1, p2);
87   fail_unless(p1->ref == 1);
88   fail_unless(p2->ref == 1);
89 
90   p3 = pbuf_alloc(PBUF_RAW, p1->tot_len, PBUF_POOL);
91   err = pbuf_copy(p3, p1);
92   fail_unless(err == ERR_VAL);
93 
94   pbuf_free(p1);
95   pbuf_free(p3);
96 }
97 END_TEST
98 
99 /** Call pbuf_copy on pbufs with chains of different sizes */
START_TEST(test_pbuf_copy_unmatched_chains)100 START_TEST(test_pbuf_copy_unmatched_chains)
101 {
102   uint16_t i, j;
103   err_t err;
104   struct pbuf *source, *dest, *p;
105   LWIP_UNUSED_ARG(_i);
106 
107   source = NULL;
108   /* Build source pbuf from linked 16 byte parts,
109    * with payload bytes containing their offset */
110   for (i = 0; i < 8; i++) {
111     p = pbuf_alloc(PBUF_RAW, 16, PBUF_RAM);
112     fail_unless(p != NULL);
113     for (j = 0; j < p->len; j++) {
114         ((u8_t*)p->payload)[j] = (u8_t)((i << 4) | j);
115     }
116     if (source) {
117         pbuf_cat(source, p);
118     } else {
119         source = p;
120     }
121   }
122   for (i = 0; i < source->tot_len; i++) {
123     fail_unless(pbuf_get_at(source, i) == i);
124   }
125 
126   /* Build dest pbuf from other lengths */
127   dest = pbuf_alloc(PBUF_RAW, 35, PBUF_RAM);
128   fail_unless(dest != NULL);
129   p = pbuf_alloc(PBUF_RAW, 81, PBUF_RAM);
130   fail_unless(p != NULL);
131   pbuf_cat(dest, p);
132   p = pbuf_alloc(PBUF_RAW, 27, PBUF_RAM);
133   fail_unless(p != NULL);
134   pbuf_cat(dest, p);
135 
136   /* Copy contents and verify data */
137   err = pbuf_copy(dest, source);
138   fail_unless(err == ERR_OK);
139   for (i = 0; i < source->tot_len; i++) {
140     fail_unless(pbuf_get_at(dest, i) == i);
141   }
142 
143   pbuf_free(source);
144   pbuf_free(dest);
145 }
146 END_TEST
147 
START_TEST(test_pbuf_copy_partial_pbuf)148 START_TEST(test_pbuf_copy_partial_pbuf)
149 {
150   struct pbuf *a, *b, *dest;
151   char lwip[] = "lwip ";
152   char packet[] = "packet";
153   err_t err;
154   LWIP_UNUSED_ARG(_i);
155 
156   a = pbuf_alloc(PBUF_RAW, 5, PBUF_REF);
157   fail_unless(a != NULL);
158   a->payload = lwip;
159   b = pbuf_alloc(PBUF_RAW, 7, PBUF_REF);
160   fail_unless(b != NULL);
161   b->payload = packet;
162   pbuf_cat(a, b);
163   dest = pbuf_alloc(PBUF_RAW, 14, PBUF_RAM);
164   memset(dest->payload, 0, dest->len);
165   fail_unless(dest != NULL);
166 
167   /* Don't copy if data will not fit */
168   err = pbuf_copy_partial_pbuf(dest, a, a->tot_len, 4);
169   fail_unless(err == ERR_ARG);
170   /* Don't copy if length is longer than source */
171   err = pbuf_copy_partial_pbuf(dest, a, a->tot_len + 1, 0);
172   fail_unless(err == ERR_ARG);
173   /* Normal copy */
174   err = pbuf_copy_partial_pbuf(dest, a, a->tot_len, 0);
175   fail_unless(err == ERR_OK);
176   fail_unless(strcmp("lwip packet", (char*)dest->payload) == 0);
177   /* Copy at offset */
178   err = pbuf_copy_partial_pbuf(dest, a, a->tot_len, 1);
179   fail_unless(err == ERR_OK);
180   fail_unless(strcmp("llwip packet", (char*)dest->payload) == 0);
181   /* Copy at offset with shorter length */
182   err = pbuf_copy_partial_pbuf(dest, a, 6, 6);
183   fail_unless(err == ERR_OK);
184   fail_unless(strcmp("llwip lwip p", (char*)dest->payload) == 0);
185   /* Copy with shorter length */
186   err = pbuf_copy_partial_pbuf(dest, a, 5, 0);
187   fail_unless(err == ERR_OK);
188   fail_unless(strcmp("lwip  lwip p", (char*)dest->payload) == 0);
189 
190   pbuf_free(dest);
191   pbuf_free(a);
192 }
193 END_TEST
194 
START_TEST(test_pbuf_split_64k_on_small_pbufs)195 START_TEST(test_pbuf_split_64k_on_small_pbufs)
196 {
197   struct pbuf *p, *rest=NULL;
198   LWIP_UNUSED_ARG(_i);
199 
200   p = pbuf_alloc(PBUF_RAW, 1, PBUF_POOL);
201   pbuf_split_64k(p, &rest);
202   fail_unless(p->tot_len == 1);
203   pbuf_free(p);
204 }
205 END_TEST
206 
START_TEST(test_pbuf_queueing_bigger_than_64k)207 START_TEST(test_pbuf_queueing_bigger_than_64k)
208 {
209   int i;
210   err_t err;
211   struct pbuf *p1, *p2, *p3, *rest2=NULL, *rest3=NULL;
212   LWIP_UNUSED_ARG(_i);
213 
214   for(i = 0; i < TESTBUFSIZE_1; i++) {
215     testbuf_1[i] = (u8_t)rand();
216   }
217   for(i = 0; i < TESTBUFSIZE_2; i++) {
218     testbuf_2[i] = (u8_t)rand();
219   }
220   for(i = 0; i < TESTBUFSIZE_3; i++) {
221     testbuf_3[i] = (u8_t)rand();
222   }
223 
224   p1 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_1, PBUF_POOL);
225   fail_unless(p1 != NULL);
226   p2 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_2, PBUF_POOL);
227   fail_unless(p2 != NULL);
228   p3 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_3, PBUF_POOL);
229   fail_unless(p3 != NULL);
230   err = pbuf_take(p1, testbuf_1, TESTBUFSIZE_1);
231   fail_unless(err == ERR_OK);
232   err = pbuf_take(p2, testbuf_2, TESTBUFSIZE_2);
233   fail_unless(err == ERR_OK);
234   err = pbuf_take(p3, testbuf_3, TESTBUFSIZE_3);
235   fail_unless(err == ERR_OK);
236 
237   pbuf_cat(p1, p2);
238   pbuf_cat(p1, p3);
239 
240   pbuf_split_64k(p1, &rest2);
241   fail_unless(p1->tot_len == TESTBUFSIZE_1);
242   fail_unless(rest2->tot_len == (u16_t)((TESTBUFSIZE_2+TESTBUFSIZE_3) & 0xFFFF));
243   pbuf_split_64k(rest2, &rest3);
244   fail_unless(rest2->tot_len == TESTBUFSIZE_2);
245   fail_unless(rest3->tot_len == TESTBUFSIZE_3);
246 
247   pbuf_copy_partial(p1, testbuf_1a, TESTBUFSIZE_1, 0);
248   pbuf_copy_partial(rest2, testbuf_2a, TESTBUFSIZE_2, 0);
249   pbuf_copy_partial(rest3, testbuf_3a, TESTBUFSIZE_3, 0);
250   fail_if(memcmp(testbuf_1, testbuf_1a, TESTBUFSIZE_1));
251   fail_if(memcmp(testbuf_2, testbuf_2a, TESTBUFSIZE_2));
252   fail_if(memcmp(testbuf_3, testbuf_3a, TESTBUFSIZE_3));
253 
254   pbuf_free(p1);
255   pbuf_free(rest2);
256   pbuf_free(rest3);
257 }
258 END_TEST
259 
260 /* Test for bug that writing with pbuf_take_at() did nothing
261  * and returned ERR_OK when writing at beginning of a pbuf
262  * in the chain.
263  */
START_TEST(test_pbuf_take_at_edge)264 START_TEST(test_pbuf_take_at_edge)
265 {
266   err_t res;
267   u8_t *out;
268   int i;
269   u8_t testdata[] = { 0x01, 0x08, 0x82, 0x02 };
270   struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL);
271   struct pbuf *q = p->next;
272   LWIP_UNUSED_ARG(_i);
273   /* alloc big enough to get a chain of pbufs */
274   fail_if(p->tot_len == p->len);
275   memset(p->payload, 0, p->len);
276   memset(q->payload, 0, q->len);
277 
278   /* copy data to the beginning of first pbuf */
279   res = pbuf_take_at(p, &testdata, sizeof(testdata), 0);
280   fail_unless(res == ERR_OK);
281 
282   out = (u8_t*)p->payload;
283   for (i = 0; i < (int)sizeof(testdata); i++) {
284     fail_unless(out[i] == testdata[i],
285       "Bad data at pos %d, was %02X, expected %02X", i, out[i], testdata[i]);
286   }
287 
288   /* copy data to the just before end of first pbuf */
289   res = pbuf_take_at(p, &testdata, sizeof(testdata), p->len - 1);
290   fail_unless(res == ERR_OK);
291 
292   out = (u8_t*)p->payload;
293   fail_unless(out[p->len - 1] == testdata[0],
294     "Bad data at pos %d, was %02X, expected %02X", p->len - 1, out[p->len - 1], testdata[0]);
295   out = (u8_t*)q->payload;
296   for (i = 1; i < (int)sizeof(testdata); i++) {
297     fail_unless(out[i-1] == testdata[i],
298       "Bad data at pos %d, was %02X, expected %02X", p->len - 1 + i, out[i-1], testdata[i]);
299   }
300 
301   /* copy data to the beginning of second pbuf */
302   res = pbuf_take_at(p, &testdata, sizeof(testdata), p->len);
303   fail_unless(res == ERR_OK);
304 
305   out = (u8_t*)p->payload;
306   for (i = 0; i < (int)sizeof(testdata); i++) {
307     fail_unless(out[i] == testdata[i],
308       "Bad data at pos %d, was %02X, expected %02X", p->len+i, out[i], testdata[i]);
309   }
310   pbuf_free(p);
311 }
312 END_TEST
313 
314 /* Verify pbuf_put_at()/pbuf_get_at() when using
315  * offsets equal to beginning of new pbuf in chain
316  */
START_TEST(test_pbuf_get_put_at_edge)317 START_TEST(test_pbuf_get_put_at_edge)
318 {
319   u8_t *out;
320   u8_t testdata = 0x01;
321   u8_t getdata;
322   struct pbuf *p = pbuf_alloc(PBUF_RAW, 1024, PBUF_POOL);
323   struct pbuf *q = p->next;
324   LWIP_UNUSED_ARG(_i);
325   /* alloc big enough to get a chain of pbufs */
326   fail_if(p->tot_len == p->len);
327   memset(p->payload, 0, p->len);
328   memset(q->payload, 0, q->len);
329 
330   /* put byte at the beginning of second pbuf */
331   pbuf_put_at(p, p->len, testdata);
332 
333   out = (u8_t*)q->payload;
334   fail_unless(*out == testdata,
335     "Bad data at pos %d, was %02X, expected %02X", p->len, *out, testdata);
336 
337   getdata = pbuf_get_at(p, p->len);
338   fail_unless(*out == getdata,
339     "pbuf_get_at() returned bad data at pos %d, was %02X, expected %02X", p->len, getdata, *out);
340   pbuf_free(p);
341 }
342 END_TEST
343 
344 /** Create the suite including all tests for this module */
345 Suite *
pbuf_suite(void)346 pbuf_suite(void)
347 {
348   testfunc tests[] = {
349     TESTFUNC(test_pbuf_alloc_zero_pbufs),
350     TESTFUNC(test_pbuf_copy_zero_pbuf),
351     TESTFUNC(test_pbuf_copy_unmatched_chains),
352     TESTFUNC(test_pbuf_copy_partial_pbuf),
353     TESTFUNC(test_pbuf_split_64k_on_small_pbufs),
354     TESTFUNC(test_pbuf_queueing_bigger_than_64k),
355     TESTFUNC(test_pbuf_take_at_edge),
356     TESTFUNC(test_pbuf_get_put_at_edge)
357   };
358   return create_suite("PBUF", tests, sizeof(tests)/sizeof(testfunc), pbuf_setup, pbuf_teardown);
359 }
360