]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/xen/netback/netback_unit_tests.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / xen / netback / netback_unit_tests.c
1 /*-
2  * Copyright (c) 2009-2011 Spectra Logic Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions, and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    substantially similar to the "NO WARRANTY" disclaimer below
13  *    ("Disclaimer") and any redistribution must be conditioned upon
14  *    including a substantially similar Disclaimer requirement for further
15  *    binary redistribution.
16  *
17  * NO WARRANTY
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGES.
29  *
30  * Authors: Justin T. Gibbs     (Spectra Logic Corporation)
31  *          Alan Somers         (Spectra Logic Corporation)
32  *          John Suykerbuyk     (Spectra Logic Corporation)
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 /**
39  * \file netback_unit_tests.c
40  *
41  * \brief Unit tests for the Xen netback driver.
42  *
43  * Due to the driver's use of static functions, these tests cannot be compiled
44  * standalone; they must be #include'd from the driver's .c file.
45  */
46
47
48 /** Helper macro used to snprintf to a buffer and update the buffer pointer */
49 #define SNCATF(buffer, buflen, ...) do {                                \
50         size_t new_chars = snprintf(buffer, buflen, __VA_ARGS__);       \
51         buffer += new_chars;                                            \
52         /* be careful; snprintf's return value can be  > buflen */      \
53         buflen -= MIN(buflen, new_chars);                               \
54 } while (0)
55
56 /* STRINGIFY and TOSTRING are used only to help turn __LINE__ into a string */
57 #define STRINGIFY(x) #x
58 #define TOSTRING(x) STRINGIFY(x)
59
60 /**
61  * Writes an error message to buffer if cond is false
62  * Note the implied parameters buffer and
63  * buflen
64  */
65 #define XNB_ASSERT(cond) ({                                             \
66         int passed = (cond);                                            \
67         char *_buffer = (buffer);                                       \
68         size_t _buflen = (buflen);                                      \
69         if (! passed) {                                                 \
70                 strlcat(_buffer, __func__, _buflen);                    \
71                 strlcat(_buffer, ":" TOSTRING(__LINE__)                 \
72                   " Assertion Error: " #cond "\n", _buflen);            \
73         }                                                               \
74         })
75
76
77 /**
78  * The signature used by all testcases.  If the test writes anything
79  * to buffer, then it will be considered a failure
80  * \param buffer        Return storage for error messages
81  * \param buflen        The space available in the buffer
82  */
83 typedef void testcase_t(char *buffer, size_t buflen);
84
85 /**
86  * Signature used by setup functions
87  * \return nonzero on error
88  */
89 typedef int setup_t(void);
90
91 typedef void teardown_t(void);
92
93 /** A simple test fixture comprising setup, teardown, and test */
94 struct test_fixture {
95         /** Will be run before the test to allocate and initialize variables */
96         setup_t *setup;
97
98         /** Will be run if setup succeeds */
99         testcase_t *test;
100
101         /** Cleans up test data whether or not the setup suceeded*/
102         teardown_t *teardown;
103 };
104
105 typedef struct test_fixture test_fixture_t;
106
107 static void     xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len,
108                                    uint16_t ip_id, uint16_t ip_p,
109                                    uint16_t ip_off, uint16_t ip_sum);
110 static void     xnb_fill_tcp(struct mbuf *m);
111 static int      xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags);
112 static int      xnb_unit_test_runner(test_fixture_t const tests[], int ntests,
113                                      char *buffer, size_t buflen);
114
115 static int __unused
116 null_setup(void) { return 0; }
117
118 static void __unused
119 null_teardown(void) { }
120
121 static setup_t setup_pvt_data;
122 static teardown_t teardown_pvt_data;
123 static testcase_t xnb_ring2pkt_emptyring;
124 static testcase_t xnb_ring2pkt_1req;
125 static testcase_t xnb_ring2pkt_2req;
126 static testcase_t xnb_ring2pkt_3req;
127 static testcase_t xnb_ring2pkt_extra;
128 static testcase_t xnb_ring2pkt_partial;
129 static testcase_t xnb_ring2pkt_wraps;
130 static testcase_t xnb_txpkt2rsp_emptypkt;
131 static testcase_t xnb_txpkt2rsp_1req;
132 static testcase_t xnb_txpkt2rsp_extra;
133 static testcase_t xnb_txpkt2rsp_long;
134 static testcase_t xnb_txpkt2rsp_invalid;
135 static testcase_t xnb_txpkt2rsp_error;
136 static testcase_t xnb_txpkt2rsp_wraps;
137 static testcase_t xnb_pkt2mbufc_empty;
138 static testcase_t xnb_pkt2mbufc_short;
139 static testcase_t xnb_pkt2mbufc_csum;
140 static testcase_t xnb_pkt2mbufc_1cluster;
141 static testcase_t xnb_pkt2mbufc_largecluster;
142 static testcase_t xnb_pkt2mbufc_2cluster;
143 static testcase_t xnb_txpkt2gnttab_empty;
144 static testcase_t xnb_txpkt2gnttab_short;
145 static testcase_t xnb_txpkt2gnttab_2req;
146 static testcase_t xnb_txpkt2gnttab_2cluster;
147 static testcase_t xnb_update_mbufc_short;
148 static testcase_t xnb_update_mbufc_2req;
149 static testcase_t xnb_update_mbufc_2cluster;
150 static testcase_t xnb_mbufc2pkt_empty;
151 static testcase_t xnb_mbufc2pkt_short;
152 static testcase_t xnb_mbufc2pkt_1cluster;
153 static testcase_t xnb_mbufc2pkt_2short;
154 static testcase_t xnb_mbufc2pkt_long;
155 static testcase_t xnb_mbufc2pkt_extra;
156 static testcase_t xnb_mbufc2pkt_nospace;
157 static testcase_t xnb_rxpkt2gnttab_empty;
158 static testcase_t xnb_rxpkt2gnttab_short;
159 static testcase_t xnb_rxpkt2gnttab_2req;
160 static testcase_t xnb_rxpkt2rsp_empty;
161 static testcase_t xnb_rxpkt2rsp_short;
162 static testcase_t xnb_rxpkt2rsp_extra;
163 static testcase_t xnb_rxpkt2rsp_2short;
164 static testcase_t xnb_rxpkt2rsp_2slots;
165 static testcase_t xnb_rxpkt2rsp_copyerror;
166 /* TODO: add test cases for xnb_add_mbuf_cksum for IPV6 tcp and udp */
167 static testcase_t xnb_add_mbuf_cksum_arp;
168 static testcase_t xnb_add_mbuf_cksum_tcp;
169 static testcase_t xnb_add_mbuf_cksum_udp;
170 static testcase_t xnb_add_mbuf_cksum_icmp;
171 static testcase_t xnb_add_mbuf_cksum_tcp_swcksum;
172 static testcase_t xnb_sscanf_llu;
173 static testcase_t xnb_sscanf_lld;
174 static testcase_t xnb_sscanf_hhu;
175 static testcase_t xnb_sscanf_hhd;
176 static testcase_t xnb_sscanf_hhn;
177
178 /** Private data used by unit tests */
179 static struct {
180         gnttab_copy_table       gnttab;
181         netif_rx_back_ring_t    rxb;
182         netif_rx_front_ring_t   rxf;
183         netif_tx_back_ring_t    txb;
184         netif_tx_front_ring_t   txf;
185         struct ifnet*           ifp;
186         netif_rx_sring_t*       rxs;
187         netif_tx_sring_t*       txs;
188 } xnb_unit_pvt;
189
190 static inline void safe_m_freem(struct mbuf **ppMbuf) {
191         if (*ppMbuf != NULL) {
192                 m_freem(*ppMbuf);
193                 *ppMbuf = NULL;
194         }
195 }
196
197 /**
198  * The unit test runner.  It will run every supplied test and return an
199  * output message as a string
200  * \param tests         An array of tests.  Every test will be attempted.
201  * \param ntests        The length of tests
202  * \param buffer        Return storage for the result string
203  * \param buflen        The length of buffer
204  * \return              The number of tests that failed
205  */
206 static int
207 xnb_unit_test_runner(test_fixture_t const tests[], int ntests, char *buffer,
208                      size_t buflen)
209 {
210         int i;
211         int n_passes;
212         int n_failures = 0;
213
214         for (i = 0; i < ntests; i++) {
215                 int error = tests[i].setup();
216                 if (error != 0) {
217                         SNCATF(buffer, buflen,
218                             "Setup failed for test idx %d\n", i);
219                         n_failures++;
220                 } else {
221                         size_t new_chars;
222
223                         tests[i].test(buffer, buflen);
224                         new_chars = strnlen(buffer, buflen);
225                         buffer += new_chars;
226                         buflen -= new_chars;
227
228                         if (new_chars > 0) {
229                                 n_failures++;
230                         }
231                 }
232                 tests[i].teardown();
233         }
234
235         n_passes = ntests - n_failures;
236         if (n_passes > 0) {
237                 SNCATF(buffer, buflen, "%d Tests Passed\n", n_passes);
238         }
239         if (n_failures > 0) {
240                 SNCATF(buffer, buflen, "%d Tests FAILED\n", n_failures);
241         }
242
243         return n_failures;
244 }
245
246 /** Number of unit tests.  Must match the length of the tests array below */
247 #define TOTAL_TESTS     (53)
248 /**
249  * Max memory available for returning results.  400 chars/test should give
250  * enough space for a five line error message for every test
251  */
252 #define TOTAL_BUFLEN    (400 * TOTAL_TESTS + 2)
253
254 /**
255  * Called from userspace by a sysctl.  Runs all internal unit tests, and
256  * returns the results to userspace as a string
257  * \param oidp  unused
258  * \param arg1  pointer to an xnb_softc for a specific xnb device
259  * \param arg2  unused
260  * \param req   sysctl access structure
261  * \return a string via the special SYSCTL_OUT macro.
262  */
263
264 static int
265 xnb_unit_test_main(SYSCTL_HANDLER_ARGS) {
266         test_fixture_t const tests[TOTAL_TESTS] = {
267                 {setup_pvt_data, xnb_ring2pkt_emptyring, teardown_pvt_data},
268                 {setup_pvt_data, xnb_ring2pkt_1req, teardown_pvt_data},
269                 {setup_pvt_data, xnb_ring2pkt_2req, teardown_pvt_data},
270                 {setup_pvt_data, xnb_ring2pkt_3req, teardown_pvt_data},
271                 {setup_pvt_data, xnb_ring2pkt_extra, teardown_pvt_data},
272                 {setup_pvt_data, xnb_ring2pkt_partial, teardown_pvt_data},
273                 {setup_pvt_data, xnb_ring2pkt_wraps, teardown_pvt_data},
274                 {setup_pvt_data, xnb_txpkt2rsp_emptypkt, teardown_pvt_data},
275                 {setup_pvt_data, xnb_txpkt2rsp_1req, teardown_pvt_data},
276                 {setup_pvt_data, xnb_txpkt2rsp_extra, teardown_pvt_data},
277                 {setup_pvt_data, xnb_txpkt2rsp_long, teardown_pvt_data},
278                 {setup_pvt_data, xnb_txpkt2rsp_invalid, teardown_pvt_data},
279                 {setup_pvt_data, xnb_txpkt2rsp_error, teardown_pvt_data},
280                 {setup_pvt_data, xnb_txpkt2rsp_wraps, teardown_pvt_data},
281                 {setup_pvt_data, xnb_pkt2mbufc_empty, teardown_pvt_data},
282                 {setup_pvt_data, xnb_pkt2mbufc_short, teardown_pvt_data},
283                 {setup_pvt_data, xnb_pkt2mbufc_csum, teardown_pvt_data},
284                 {setup_pvt_data, xnb_pkt2mbufc_1cluster, teardown_pvt_data},
285                 {setup_pvt_data, xnb_pkt2mbufc_largecluster, teardown_pvt_data},
286                 {setup_pvt_data, xnb_pkt2mbufc_2cluster, teardown_pvt_data},
287                 {setup_pvt_data, xnb_txpkt2gnttab_empty, teardown_pvt_data},
288                 {setup_pvt_data, xnb_txpkt2gnttab_short, teardown_pvt_data},
289                 {setup_pvt_data, xnb_txpkt2gnttab_2req, teardown_pvt_data},
290                 {setup_pvt_data, xnb_txpkt2gnttab_2cluster, teardown_pvt_data},
291                 {setup_pvt_data, xnb_update_mbufc_short, teardown_pvt_data},
292                 {setup_pvt_data, xnb_update_mbufc_2req, teardown_pvt_data},
293                 {setup_pvt_data, xnb_update_mbufc_2cluster, teardown_pvt_data},
294                 {setup_pvt_data, xnb_mbufc2pkt_empty, teardown_pvt_data},
295                 {setup_pvt_data, xnb_mbufc2pkt_short, teardown_pvt_data},
296                 {setup_pvt_data, xnb_mbufc2pkt_1cluster, teardown_pvt_data},
297                 {setup_pvt_data, xnb_mbufc2pkt_2short, teardown_pvt_data},
298                 {setup_pvt_data, xnb_mbufc2pkt_long, teardown_pvt_data},
299                 {setup_pvt_data, xnb_mbufc2pkt_extra, teardown_pvt_data},
300                 {setup_pvt_data, xnb_mbufc2pkt_nospace, teardown_pvt_data},
301                 {setup_pvt_data, xnb_rxpkt2gnttab_empty, teardown_pvt_data},
302                 {setup_pvt_data, xnb_rxpkt2gnttab_short, teardown_pvt_data},
303                 {setup_pvt_data, xnb_rxpkt2gnttab_2req, teardown_pvt_data},
304                 {setup_pvt_data, xnb_rxpkt2rsp_empty, teardown_pvt_data},
305                 {setup_pvt_data, xnb_rxpkt2rsp_short, teardown_pvt_data},
306                 {setup_pvt_data, xnb_rxpkt2rsp_extra, teardown_pvt_data},
307                 {setup_pvt_data, xnb_rxpkt2rsp_2short, teardown_pvt_data},
308                 {setup_pvt_data, xnb_rxpkt2rsp_2slots, teardown_pvt_data},
309                 {setup_pvt_data, xnb_rxpkt2rsp_copyerror, teardown_pvt_data},
310                 {null_setup, xnb_add_mbuf_cksum_arp, null_teardown},
311                 {null_setup, xnb_add_mbuf_cksum_icmp, null_teardown},
312                 {null_setup, xnb_add_mbuf_cksum_tcp, null_teardown},
313                 {null_setup, xnb_add_mbuf_cksum_tcp_swcksum, null_teardown},
314                 {null_setup, xnb_add_mbuf_cksum_udp, null_teardown},
315                 {null_setup, xnb_sscanf_hhd, null_teardown},
316                 {null_setup, xnb_sscanf_hhu, null_teardown},
317                 {null_setup, xnb_sscanf_lld, null_teardown},
318                 {null_setup, xnb_sscanf_llu, null_teardown},
319                 {null_setup, xnb_sscanf_hhn, null_teardown},
320         };
321         /**
322          * results is static so that the data will persist after this function
323          * returns.  The sysctl code expects us to return a constant string.
324          * \todo: the static variable is not thread safe.  Put a mutex around
325          * it.
326          */
327         static char results[TOTAL_BUFLEN];
328
329         /* empty the result strings */
330         results[0] = 0;
331         xnb_unit_test_runner(tests, TOTAL_TESTS, results, TOTAL_BUFLEN);
332
333         return (SYSCTL_OUT(req, results, strnlen(results, TOTAL_BUFLEN)));
334 }
335
336 static int
337 setup_pvt_data(void)
338 {
339         int error = 0;
340
341         bzero(xnb_unit_pvt.gnttab, sizeof(xnb_unit_pvt.gnttab));
342
343         xnb_unit_pvt.txs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
344         if (xnb_unit_pvt.txs != NULL) {
345                 SHARED_RING_INIT(xnb_unit_pvt.txs);
346                 BACK_RING_INIT(&xnb_unit_pvt.txb, xnb_unit_pvt.txs, PAGE_SIZE);
347                 FRONT_RING_INIT(&xnb_unit_pvt.txf, xnb_unit_pvt.txs, PAGE_SIZE);
348         } else {
349                 error = 1;
350         }
351
352         xnb_unit_pvt.ifp = if_alloc(IFT_ETHER);
353         if (xnb_unit_pvt.ifp == NULL) {
354                 error = 1;
355         }
356
357         xnb_unit_pvt.rxs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
358         if (xnb_unit_pvt.rxs != NULL) {
359                 SHARED_RING_INIT(xnb_unit_pvt.rxs);
360                 BACK_RING_INIT(&xnb_unit_pvt.rxb, xnb_unit_pvt.rxs, PAGE_SIZE);
361                 FRONT_RING_INIT(&xnb_unit_pvt.rxf, xnb_unit_pvt.rxs, PAGE_SIZE);
362         } else {
363                 error = 1;
364         }
365
366         return error;
367 }
368
369 static void
370 teardown_pvt_data(void)
371 {
372         if (xnb_unit_pvt.txs != NULL) {
373                 free(xnb_unit_pvt.txs, M_XENNETBACK);
374         }
375         if (xnb_unit_pvt.rxs != NULL) {
376                 free(xnb_unit_pvt.rxs, M_XENNETBACK);
377         }
378         if (xnb_unit_pvt.ifp != NULL) {
379                 if_free(xnb_unit_pvt.ifp);
380         }
381 }
382
383 /**
384  * Verify that xnb_ring2pkt will not consume any requests from an empty ring
385  */
386 static void
387 xnb_ring2pkt_emptyring(char *buffer, size_t buflen)
388 {
389         struct xnb_pkt pkt;
390         int num_consumed;
391
392         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
393                                     xnb_unit_pvt.txb.req_cons);
394         XNB_ASSERT(num_consumed == 0);
395 }
396
397 /**
398  * Verify that xnb_ring2pkt can convert a single request packet correctly
399  */
400 static void
401 xnb_ring2pkt_1req(char *buffer, size_t buflen)
402 {
403         struct xnb_pkt pkt;
404         int num_consumed;
405         struct netif_tx_request *req;
406
407         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
408             xnb_unit_pvt.txf.req_prod_pvt);
409
410         req->flags = 0;
411         req->size = 69; /* arbitrary number for test */
412         xnb_unit_pvt.txf.req_prod_pvt++;
413
414         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
415
416         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
417                                     xnb_unit_pvt.txb.req_cons);
418         XNB_ASSERT(num_consumed == 1);
419         XNB_ASSERT(pkt.size == 69);
420         XNB_ASSERT(pkt.car_size == 69);
421         XNB_ASSERT(pkt.flags == 0);
422         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
423         XNB_ASSERT(pkt.list_len == 1);
424         XNB_ASSERT(pkt.car == 0);
425 }
426
427 /**
428  * Verify that xnb_ring2pkt can convert a two request packet correctly.
429  * This tests handling of the MORE_DATA flag and cdr
430  */
431 static void
432 xnb_ring2pkt_2req(char *buffer, size_t buflen)
433 {
434         struct xnb_pkt pkt;
435         int num_consumed;
436         struct netif_tx_request *req;
437         RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
438
439         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
440             xnb_unit_pvt.txf.req_prod_pvt);
441         req->flags = NETTXF_more_data;
442         req->size = 100;
443         xnb_unit_pvt.txf.req_prod_pvt++;
444
445         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
446             xnb_unit_pvt.txf.req_prod_pvt);
447         req->flags = 0;
448         req->size = 40;
449         xnb_unit_pvt.txf.req_prod_pvt++;
450
451         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
452
453         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
454                                     xnb_unit_pvt.txb.req_cons);
455         XNB_ASSERT(num_consumed == 2);
456         XNB_ASSERT(pkt.size == 100);
457         XNB_ASSERT(pkt.car_size == 60);
458         XNB_ASSERT(pkt.flags == 0);
459         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
460         XNB_ASSERT(pkt.list_len == 2);
461         XNB_ASSERT(pkt.car == start_idx);
462         XNB_ASSERT(pkt.cdr == start_idx + 1);
463 }
464
465 /**
466  * Verify that xnb_ring2pkt can convert a three request packet correctly
467  */
468 static void
469 xnb_ring2pkt_3req(char *buffer, size_t buflen)
470 {
471         struct xnb_pkt pkt;
472         int num_consumed;
473         struct netif_tx_request *req;
474         RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
475
476         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
477             xnb_unit_pvt.txf.req_prod_pvt);
478         req->flags = NETTXF_more_data;
479         req->size = 200;
480         xnb_unit_pvt.txf.req_prod_pvt++;
481
482         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
483             xnb_unit_pvt.txf.req_prod_pvt);
484         req->flags = NETTXF_more_data;
485         req->size = 40;
486         xnb_unit_pvt.txf.req_prod_pvt++;
487
488         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
489             xnb_unit_pvt.txf.req_prod_pvt);
490         req->flags = 0;
491         req->size = 50;
492         xnb_unit_pvt.txf.req_prod_pvt++;
493
494         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
495
496         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
497                                     xnb_unit_pvt.txb.req_cons);
498         XNB_ASSERT(num_consumed == 3);
499         XNB_ASSERT(pkt.size == 200);
500         XNB_ASSERT(pkt.car_size == 110);
501         XNB_ASSERT(pkt.flags == 0);
502         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
503         XNB_ASSERT(pkt.list_len == 3);
504         XNB_ASSERT(pkt.car == start_idx);
505         XNB_ASSERT(pkt.cdr == start_idx + 1);
506         XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
507 }
508
509 /**
510  * Verify that xnb_ring2pkt can read extra inf
511  */
512 static void
513 xnb_ring2pkt_extra(char *buffer, size_t buflen)
514 {
515         struct xnb_pkt pkt;
516         int num_consumed;
517         struct netif_tx_request *req;
518         struct netif_extra_info *ext;
519         RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
520
521         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
522             xnb_unit_pvt.txf.req_prod_pvt);
523         req->flags = NETTXF_extra_info | NETTXF_more_data;
524         req->size = 150;
525         xnb_unit_pvt.txf.req_prod_pvt++;
526
527         ext = (struct netif_extra_info*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
528             xnb_unit_pvt.txf.req_prod_pvt);
529         ext->flags = 0;
530         ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
531         ext->u.gso.size = 250;
532         ext->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
533         ext->u.gso.features = 0;
534         xnb_unit_pvt.txf.req_prod_pvt++;
535
536         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
537             xnb_unit_pvt.txf.req_prod_pvt);
538         req->flags = 0;
539         req->size = 50;
540         xnb_unit_pvt.txf.req_prod_pvt++;
541
542         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
543
544         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
545                                     xnb_unit_pvt.txb.req_cons);
546         XNB_ASSERT(num_consumed == 3);
547         XNB_ASSERT(pkt.extra.flags == 0);
548         XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
549         XNB_ASSERT(pkt.extra.u.gso.size == 250);
550         XNB_ASSERT(pkt.extra.u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4);
551         XNB_ASSERT(pkt.size == 150);
552         XNB_ASSERT(pkt.car_size == 100);
553         XNB_ASSERT(pkt.flags == NETTXF_extra_info);
554         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
555         XNB_ASSERT(pkt.list_len == 2);
556         XNB_ASSERT(pkt.car == start_idx);
557         XNB_ASSERT(pkt.cdr == start_idx + 2);
558         XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr) == req);
559 }
560
561 /**
562  * Verify that xnb_ring2pkt will consume no requests if the entire packet is
563  * not yet in the ring
564  */
565 static void
566 xnb_ring2pkt_partial(char *buffer, size_t buflen)
567 {
568         struct xnb_pkt pkt;
569         int num_consumed;
570         struct netif_tx_request *req;
571
572         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
573             xnb_unit_pvt.txf.req_prod_pvt);
574         req->flags = NETTXF_more_data;
575         req->size = 150;
576         xnb_unit_pvt.txf.req_prod_pvt++;
577
578         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
579
580         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
581                                     xnb_unit_pvt.txb.req_cons);
582         XNB_ASSERT(num_consumed == 0);
583         XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
584 }
585
586 /**
587  * Verity that xnb_ring2pkt can read a packet whose requests wrap around
588  * the end of the ring
589  */
590 static void
591 xnb_ring2pkt_wraps(char *buffer, size_t buflen)
592 {
593         struct xnb_pkt pkt;
594         int num_consumed;
595         struct netif_tx_request *req;
596         unsigned int rsize;
597
598         /*
599          * Manually tweak the ring indices to create a ring with no responses
600          * and the next request slot at position 2 from the end
601          */
602         rsize = RING_SIZE(&xnb_unit_pvt.txf);
603         xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
604         xnb_unit_pvt.txf.rsp_cons = rsize - 2;
605         xnb_unit_pvt.txs->req_prod = rsize - 2;
606         xnb_unit_pvt.txs->req_event = rsize - 1;
607         xnb_unit_pvt.txs->rsp_prod = rsize - 2;
608         xnb_unit_pvt.txs->rsp_event = rsize - 1;
609         xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
610         xnb_unit_pvt.txb.req_cons = rsize - 2;
611
612         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
613             xnb_unit_pvt.txf.req_prod_pvt);
614         req->flags = NETTXF_more_data;
615         req->size = 550;
616         xnb_unit_pvt.txf.req_prod_pvt++;
617
618         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
619             xnb_unit_pvt.txf.req_prod_pvt);
620         req->flags = NETTXF_more_data;
621         req->size = 100;
622         xnb_unit_pvt.txf.req_prod_pvt++;
623
624         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
625             xnb_unit_pvt.txf.req_prod_pvt);
626         req->flags = 0;
627         req->size = 50;
628         xnb_unit_pvt.txf.req_prod_pvt++;
629
630         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
631
632         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
633                                     xnb_unit_pvt.txb.req_cons);
634         XNB_ASSERT(num_consumed == 3);
635         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
636         XNB_ASSERT(pkt.list_len == 3);
637         XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
638 }
639
640
641 /**
642  * xnb_txpkt2rsp should do nothing for an empty packet
643  */
644 static void
645 xnb_txpkt2rsp_emptypkt(char *buffer, size_t buflen)
646 {
647         int num_consumed;
648         struct xnb_pkt pkt;
649         netif_tx_back_ring_t txb_backup = xnb_unit_pvt.txb;
650         netif_tx_sring_t txs_backup = *xnb_unit_pvt.txs;
651         pkt.list_len = 0;
652
653         /* must call xnb_ring2pkt just to intialize pkt */
654         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
655                                     xnb_unit_pvt.txb.req_cons);
656         xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
657         XNB_ASSERT(
658             memcmp(&txb_backup, &xnb_unit_pvt.txb, sizeof(txb_backup)) == 0);
659         XNB_ASSERT(
660             memcmp(&txs_backup, xnb_unit_pvt.txs, sizeof(txs_backup)) == 0);
661 }
662
663 /**
664  * xnb_txpkt2rsp responding to one request
665  */
666 static void
667 xnb_txpkt2rsp_1req(char *buffer, size_t buflen)
668 {
669         uint16_t num_consumed;
670         struct xnb_pkt pkt;
671         struct netif_tx_request *req;
672         struct netif_tx_response *rsp;
673
674         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
675             xnb_unit_pvt.txf.req_prod_pvt);
676         req->size = 1000;
677         req->flags = 0;
678         xnb_unit_pvt.txf.req_prod_pvt++;
679
680         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
681
682         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
683                                     xnb_unit_pvt.txb.req_cons);
684         xnb_unit_pvt.txb.req_cons += num_consumed;
685
686         xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
687         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
688
689         XNB_ASSERT(
690             xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
691         XNB_ASSERT(rsp->id == req->id);
692         XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
693 };
694
695 /**
696  * xnb_txpkt2rsp responding to 1 data request and 1 extra info
697  */
698 static void
699 xnb_txpkt2rsp_extra(char *buffer, size_t buflen)
700 {
701         uint16_t num_consumed;
702         struct xnb_pkt pkt;
703         struct netif_tx_request *req;
704         netif_extra_info_t *ext;
705         struct netif_tx_response *rsp;
706
707         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
708             xnb_unit_pvt.txf.req_prod_pvt);
709         req->size = 1000;
710         req->flags = NETTXF_extra_info;
711         req->id = 69;
712         xnb_unit_pvt.txf.req_prod_pvt++;
713
714         ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
715             xnb_unit_pvt.txf.req_prod_pvt);
716         ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
717         ext->flags = 0;
718         xnb_unit_pvt.txf.req_prod_pvt++;
719
720         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
721
722         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
723                                     xnb_unit_pvt.txb.req_cons);
724         xnb_unit_pvt.txb.req_cons += num_consumed;
725
726         xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
727
728         XNB_ASSERT(
729             xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
730
731         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
732         XNB_ASSERT(rsp->id == req->id);
733         XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
734
735         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
736             xnb_unit_pvt.txf.rsp_cons + 1);
737         XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
738 };
739
740 /**
741  * xnb_pkg2rsp responding to 3 data requests and 1 extra info
742  */
743 static void
744 xnb_txpkt2rsp_long(char *buffer, size_t buflen)
745 {
746         uint16_t num_consumed;
747         struct xnb_pkt pkt;
748         struct netif_tx_request *req;
749         netif_extra_info_t *ext;
750         struct netif_tx_response *rsp;
751
752         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
753             xnb_unit_pvt.txf.req_prod_pvt);
754         req->size = 1000;
755         req->flags = NETTXF_extra_info | NETTXF_more_data;
756         req->id = 254;
757         xnb_unit_pvt.txf.req_prod_pvt++;
758
759         ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
760             xnb_unit_pvt.txf.req_prod_pvt);
761         ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
762         ext->flags = 0;
763         xnb_unit_pvt.txf.req_prod_pvt++;
764
765         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
766             xnb_unit_pvt.txf.req_prod_pvt);
767         req->size = 300;
768         req->flags = NETTXF_more_data;
769         req->id = 1034;
770         xnb_unit_pvt.txf.req_prod_pvt++;
771
772         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
773             xnb_unit_pvt.txf.req_prod_pvt);
774         req->size = 400;
775         req->flags = 0;
776         req->id = 34;
777         xnb_unit_pvt.txf.req_prod_pvt++;
778
779         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
780
781         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
782                                     xnb_unit_pvt.txb.req_cons);
783         xnb_unit_pvt.txb.req_cons += num_consumed;
784
785         xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
786
787         XNB_ASSERT(
788             xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
789
790         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
791         XNB_ASSERT(rsp->id ==
792             RING_GET_REQUEST(&xnb_unit_pvt.txf, 0)->id);
793         XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
794
795         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
796             xnb_unit_pvt.txf.rsp_cons + 1);
797         XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
798
799         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
800             xnb_unit_pvt.txf.rsp_cons + 2);
801         XNB_ASSERT(rsp->id ==
802             RING_GET_REQUEST(&xnb_unit_pvt.txf, 2)->id);
803         XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
804
805         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
806             xnb_unit_pvt.txf.rsp_cons + 3);
807         XNB_ASSERT(rsp->id ==
808             RING_GET_REQUEST(&xnb_unit_pvt.txf, 3)->id);
809         XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
810 }
811
812 /**
813  * xnb_txpkt2rsp responding to an invalid packet.
814  * Note: this test will result in an error message being printed to the console
815  * such as:
816  * xnb(xnb_ring2pkt:1306): Unknown extra info type 255.  Discarding packet
817  */
818 static void
819 xnb_txpkt2rsp_invalid(char *buffer, size_t buflen)
820 {
821         uint16_t num_consumed;
822         struct xnb_pkt pkt;
823         struct netif_tx_request *req;
824         netif_extra_info_t *ext;
825         struct netif_tx_response *rsp;
826
827         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
828             xnb_unit_pvt.txf.req_prod_pvt);
829         req->size = 1000;
830         req->flags = NETTXF_extra_info;
831         req->id = 69;
832         xnb_unit_pvt.txf.req_prod_pvt++;
833
834         ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
835             xnb_unit_pvt.txf.req_prod_pvt);
836         ext->type = 0xFF;       /* Invalid extra type */
837         ext->flags = 0;
838         xnb_unit_pvt.txf.req_prod_pvt++;
839
840         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
841
842         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
843                                     xnb_unit_pvt.txb.req_cons);
844         xnb_unit_pvt.txb.req_cons += num_consumed;
845         XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
846
847         xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
848
849         XNB_ASSERT(
850             xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
851
852         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
853         XNB_ASSERT(rsp->id == req->id);
854         XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
855
856         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
857             xnb_unit_pvt.txf.rsp_cons + 1);
858         XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
859 };
860
861 /**
862  * xnb_txpkt2rsp responding to one request which caused an error
863  */
864 static void
865 xnb_txpkt2rsp_error(char *buffer, size_t buflen)
866 {
867         uint16_t num_consumed;
868         struct xnb_pkt pkt;
869         struct netif_tx_request *req;
870         struct netif_tx_response *rsp;
871
872         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
873             xnb_unit_pvt.txf.req_prod_pvt);
874         req->size = 1000;
875         req->flags = 0;
876         xnb_unit_pvt.txf.req_prod_pvt++;
877
878         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
879
880         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
881                                     xnb_unit_pvt.txb.req_cons);
882         xnb_unit_pvt.txb.req_cons += num_consumed;
883
884         xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 1);
885         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
886
887         XNB_ASSERT(
888             xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
889         XNB_ASSERT(rsp->id == req->id);
890         XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
891 };
892
893 /**
894  * xnb_txpkt2rsp's responses wrap around the end of the ring
895  */
896 static void
897 xnb_txpkt2rsp_wraps(char *buffer, size_t buflen)
898 {
899         struct xnb_pkt pkt;
900         int num_consumed;
901         struct netif_tx_request *req;
902         struct netif_tx_response *rsp;
903         unsigned int rsize;
904
905         /*
906          * Manually tweak the ring indices to create a ring with no responses
907          * and the next request slot at position 2 from the end
908          */
909         rsize = RING_SIZE(&xnb_unit_pvt.txf);
910         xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
911         xnb_unit_pvt.txf.rsp_cons = rsize - 2;
912         xnb_unit_pvt.txs->req_prod = rsize - 2;
913         xnb_unit_pvt.txs->req_event = rsize - 1;
914         xnb_unit_pvt.txs->rsp_prod = rsize - 2;
915         xnb_unit_pvt.txs->rsp_event = rsize - 1;
916         xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
917         xnb_unit_pvt.txb.req_cons = rsize - 2;
918
919         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
920             xnb_unit_pvt.txf.req_prod_pvt);
921         req->flags = NETTXF_more_data;
922         req->size = 550;
923         req->id = 1;
924         xnb_unit_pvt.txf.req_prod_pvt++;
925
926         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
927             xnb_unit_pvt.txf.req_prod_pvt);
928         req->flags = NETTXF_more_data;
929         req->size = 100;
930         req->id = 2;
931         xnb_unit_pvt.txf.req_prod_pvt++;
932
933         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
934             xnb_unit_pvt.txf.req_prod_pvt);
935         req->flags = 0;
936         req->size = 50;
937         req->id = 3;
938         xnb_unit_pvt.txf.req_prod_pvt++;
939
940         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
941
942         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
943                                     xnb_unit_pvt.txb.req_cons);
944
945         xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
946
947         XNB_ASSERT(
948             xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
949         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
950             xnb_unit_pvt.txf.rsp_cons + 2);
951         XNB_ASSERT(rsp->id == req->id);
952         XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
953 }
954
955
956 /**
957  * Helper function used to setup pkt2mbufc tests
958  * \param size     size in bytes of the single request to push to the ring
959  * \param flags         optional flags to put in the netif request
960  * \param[out] pkt the returned packet object
961  * \return number of requests consumed from the ring
962  */
963 static int
964 xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags)
965 {
966         struct netif_tx_request *req;
967
968         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
969             xnb_unit_pvt.txf.req_prod_pvt);
970         req->flags = flags;
971         req->size = size;
972         xnb_unit_pvt.txf.req_prod_pvt++;
973
974         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
975
976         return xnb_ring2pkt(pkt, &xnb_unit_pvt.txb,
977                                     xnb_unit_pvt.txb.req_cons);
978 }
979
980 /**
981  * xnb_pkt2mbufc on an empty packet
982  */
983 static void
984 xnb_pkt2mbufc_empty(char *buffer, size_t buflen)
985 {
986         int num_consumed;
987         struct xnb_pkt pkt;
988         struct mbuf *pMbuf;
989         pkt.list_len = 0;
990
991         /* must call xnb_ring2pkt just to intialize pkt */
992         num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
993                                     xnb_unit_pvt.txb.req_cons);
994         pkt.size = 0;
995         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
996         safe_m_freem(&pMbuf);
997 }
998
999 /**
1000  * xnb_pkt2mbufc on short packet that can fit in an mbuf internal buffer
1001  */
1002 static void
1003 xnb_pkt2mbufc_short(char *buffer, size_t buflen)
1004 {
1005         const size_t size = MINCLSIZE - 1;
1006         struct xnb_pkt pkt;
1007         struct mbuf *pMbuf;
1008
1009         xnb_get1pkt(&pkt, size, 0);
1010
1011         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1012         XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1013         safe_m_freem(&pMbuf);
1014 }
1015
1016 /**
1017  * xnb_pkt2mbufc on short packet whose checksum was validated by the netfron
1018  */
1019 static void
1020 xnb_pkt2mbufc_csum(char *buffer, size_t buflen)
1021 {
1022         const size_t size = MINCLSIZE - 1;
1023         struct xnb_pkt pkt;
1024         struct mbuf *pMbuf;
1025
1026         xnb_get1pkt(&pkt, size, NETTXF_data_validated);
1027
1028         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1029         XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1030         XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_CHECKED);
1031         XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_VALID);
1032         XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_DATA_VALID);
1033         XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR);
1034         safe_m_freem(&pMbuf);
1035 }
1036
1037 /**
1038  * xnb_pkt2mbufc on packet that can fit in one cluster
1039  */
1040 static void
1041 xnb_pkt2mbufc_1cluster(char *buffer, size_t buflen)
1042 {
1043         const size_t size = MINCLSIZE;
1044         struct xnb_pkt pkt;
1045         struct mbuf *pMbuf;
1046
1047         xnb_get1pkt(&pkt, size, 0);
1048
1049         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1050         XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1051         safe_m_freem(&pMbuf);
1052 }
1053
1054 /**
1055  * xnb_pkt2mbufc on packet that cannot fit in one regular cluster
1056  */
1057 static void
1058 xnb_pkt2mbufc_largecluster(char *buffer, size_t buflen)
1059 {
1060         const size_t size = MCLBYTES + 1;
1061         struct xnb_pkt pkt;
1062         struct mbuf *pMbuf;
1063
1064         xnb_get1pkt(&pkt, size, 0);
1065
1066         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1067         XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1068         safe_m_freem(&pMbuf);
1069 }
1070
1071 /**
1072  * xnb_pkt2mbufc on packet that cannot fit in one clusters
1073  */
1074 static void
1075 xnb_pkt2mbufc_2cluster(char *buffer, size_t buflen)
1076 {
1077         const size_t size = 2 * MCLBYTES + 1;
1078         size_t space = 0;
1079         struct xnb_pkt pkt;
1080         struct mbuf *pMbuf;
1081         struct mbuf *m;
1082
1083         xnb_get1pkt(&pkt, size, 0);
1084
1085         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1086
1087         for (m = pMbuf; m != NULL; m = m->m_next) {
1088                 space += M_TRAILINGSPACE(m);
1089         }
1090         XNB_ASSERT(space >= size);
1091         safe_m_freem(&pMbuf);
1092 }
1093
1094 /**
1095  * xnb_txpkt2gnttab on an empty packet.  Should return empty gnttab
1096  */
1097 static void
1098 xnb_txpkt2gnttab_empty(char *buffer, size_t buflen)
1099 {
1100         int n_entries;
1101         struct xnb_pkt pkt;
1102         struct mbuf *pMbuf;
1103         pkt.list_len = 0;
1104
1105         /* must call xnb_ring2pkt just to intialize pkt */
1106         xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1107         pkt.size = 0;
1108         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1109         n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1110             &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1111         XNB_ASSERT(n_entries == 0);
1112         safe_m_freem(&pMbuf);
1113 }
1114
1115 /**
1116  * xnb_txpkt2gnttab on a short packet, that can fit in one mbuf internal buffer
1117  * and has one request
1118  */
1119 static void
1120 xnb_txpkt2gnttab_short(char *buffer, size_t buflen)
1121 {
1122         const size_t size = MINCLSIZE - 1;
1123         int n_entries;
1124         struct xnb_pkt pkt;
1125         struct mbuf *pMbuf;
1126
1127         struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1128             xnb_unit_pvt.txf.req_prod_pvt);
1129         req->flags = 0;
1130         req->size = size;
1131         req->gref = 7;
1132         req->offset = 17;
1133         xnb_unit_pvt.txf.req_prod_pvt++;
1134
1135         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1136
1137         xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1138
1139         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1140         n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1141             &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1142         XNB_ASSERT(n_entries == 1);
1143         XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
1144         /* flags should indicate gref's for source */
1145         XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_source_gref);
1146         XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == req->offset);
1147         XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
1148         XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1149               mtod(pMbuf, vm_offset_t)));
1150         XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.u.gmfn ==
1151                 virt_to_mfn(mtod(pMbuf, vm_offset_t)));
1152         XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
1153         safe_m_freem(&pMbuf);
1154 }
1155
1156 /**
1157  * xnb_txpkt2gnttab on a packet with two requests, that can fit into a single
1158  * mbuf cluster
1159  */
1160 static void
1161 xnb_txpkt2gnttab_2req(char *buffer, size_t buflen)
1162 {
1163         int n_entries;
1164         struct xnb_pkt pkt;
1165         struct mbuf *pMbuf;
1166
1167         struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1168             xnb_unit_pvt.txf.req_prod_pvt);
1169         req->flags = NETTXF_more_data;
1170         req->size = 1900;
1171         req->gref = 7;
1172         req->offset = 0;
1173         xnb_unit_pvt.txf.req_prod_pvt++;
1174
1175         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1176             xnb_unit_pvt.txf.req_prod_pvt);
1177         req->flags = 0;
1178         req->size = 500;
1179         req->gref = 8;
1180         req->offset = 0;
1181         xnb_unit_pvt.txf.req_prod_pvt++;
1182
1183         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1184
1185         xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1186
1187         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1188         n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1189             &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1190
1191         XNB_ASSERT(n_entries == 2);
1192         XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 1400);
1193         XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1194               mtod(pMbuf, vm_offset_t)));
1195
1196         XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 500);
1197         XNB_ASSERT(xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
1198               mtod(pMbuf, vm_offset_t) + 1400));
1199         safe_m_freem(&pMbuf);
1200 }
1201
1202 /**
1203  * xnb_txpkt2gnttab on a single request that spans two mbuf clusters
1204  */
1205 static void
1206 xnb_txpkt2gnttab_2cluster(char *buffer, size_t buflen)
1207 {
1208         int n_entries;
1209         struct xnb_pkt pkt;
1210         struct mbuf *pMbuf;
1211         const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
1212
1213         struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1214             xnb_unit_pvt.txf.req_prod_pvt);
1215         req->flags = 0;
1216         req->size = data_this_transaction;
1217         req->gref = 8;
1218         req->offset = 0;
1219         xnb_unit_pvt.txf.req_prod_pvt++;
1220
1221         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1222         xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1223
1224         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1225         n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1226             &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1227
1228         if (M_TRAILINGSPACE(pMbuf) == MCLBYTES) {
1229                 /* there should be three mbufs and three gnttab entries */
1230                 XNB_ASSERT(n_entries == 3);
1231                 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == MCLBYTES);
1232                 XNB_ASSERT(
1233                     xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1234                       mtod(pMbuf, vm_offset_t)));
1235                 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
1236
1237                 XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == MCLBYTES);
1238                 XNB_ASSERT(
1239                     xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
1240                       mtod(pMbuf->m_next, vm_offset_t)));
1241                 XNB_ASSERT(xnb_unit_pvt.gnttab[1].source.offset == MCLBYTES);
1242
1243                 XNB_ASSERT(xnb_unit_pvt.gnttab[2].len == 1);
1244                 XNB_ASSERT(
1245                     xnb_unit_pvt.gnttab[2].dest.offset == virt_to_offset(
1246                       mtod(pMbuf->m_next, vm_offset_t)));
1247                 XNB_ASSERT(xnb_unit_pvt.gnttab[2].source.offset == 2 *
1248                             MCLBYTES);
1249         } else if (M_TRAILINGSPACE(pMbuf) == 2 * MCLBYTES) {
1250                 /* there should be two mbufs and two gnttab entries */
1251                 XNB_ASSERT(n_entries == 2);
1252                 XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 2 * MCLBYTES);
1253                 XNB_ASSERT(
1254                     xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1255                       mtod(pMbuf, vm_offset_t)));
1256                 XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
1257
1258                 XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 1);
1259                 XNB_ASSERT(
1260                     xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
1261                       mtod(pMbuf->m_next, vm_offset_t)));
1262                 XNB_ASSERT(
1263                     xnb_unit_pvt.gnttab[1].source.offset == 2 * MCLBYTES);
1264
1265         } else {
1266                 /* should never get here */
1267                 XNB_ASSERT(0);
1268         }
1269         if (pMbuf != NULL)
1270                 m_freem(pMbuf);
1271 }
1272
1273
1274 /**
1275  * xnb_update_mbufc on a short packet that only has one gnttab entry
1276  */
1277 static void
1278 xnb_update_mbufc_short(char *buffer, size_t buflen)
1279 {
1280         const size_t size = MINCLSIZE - 1;
1281         int n_entries;
1282         struct xnb_pkt pkt;
1283         struct mbuf *pMbuf;
1284
1285         struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1286             xnb_unit_pvt.txf.req_prod_pvt);
1287         req->flags = 0;
1288         req->size = size;
1289         req->gref = 7;
1290         req->offset = 17;
1291         xnb_unit_pvt.txf.req_prod_pvt++;
1292
1293         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1294
1295         xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1296
1297         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1298         n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1299             &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1300
1301         /* Update grant table's status fields as the hypervisor call would */
1302         xnb_unit_pvt.gnttab[0].status = GNTST_okay;
1303
1304         xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
1305         XNB_ASSERT(pMbuf->m_len == size);
1306         XNB_ASSERT(pMbuf->m_pkthdr.len == size);
1307         safe_m_freem(&pMbuf);
1308 }
1309
1310 /**
1311  * xnb_update_mbufc on a packet with two requests, that can fit into a single
1312  * mbuf cluster
1313  */
1314 static void
1315 xnb_update_mbufc_2req(char *buffer, size_t buflen)
1316 {
1317         int n_entries;
1318         struct xnb_pkt pkt;
1319         struct mbuf *pMbuf;
1320
1321         struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1322             xnb_unit_pvt.txf.req_prod_pvt);
1323         req->flags = NETTXF_more_data;
1324         req->size = 1900;
1325         req->gref = 7;
1326         req->offset = 0;
1327         xnb_unit_pvt.txf.req_prod_pvt++;
1328
1329         req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1330             xnb_unit_pvt.txf.req_prod_pvt);
1331         req->flags = 0;
1332         req->size = 500;
1333         req->gref = 8;
1334         req->offset = 0;
1335         xnb_unit_pvt.txf.req_prod_pvt++;
1336
1337         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1338
1339         xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1340
1341         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1342         n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1343             &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1344
1345         /* Update grant table's status fields as the hypervisor call would */
1346         xnb_unit_pvt.gnttab[0].status = GNTST_okay;
1347         xnb_unit_pvt.gnttab[1].status = GNTST_okay;
1348
1349         xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
1350         XNB_ASSERT(n_entries == 2);
1351         XNB_ASSERT(pMbuf->m_pkthdr.len == 1900);
1352         XNB_ASSERT(pMbuf->m_len == 1900);
1353
1354         safe_m_freem(&pMbuf);
1355 }
1356
1357 /**
1358  * xnb_update_mbufc on a single request that spans two mbuf clusters
1359  */
1360 static void
1361 xnb_update_mbufc_2cluster(char *buffer, size_t buflen)
1362 {
1363         int i;
1364         int n_entries;
1365         struct xnb_pkt pkt;
1366         struct mbuf *pMbuf;
1367         const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
1368
1369         struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1370             xnb_unit_pvt.txf.req_prod_pvt);
1371         req->flags = 0;
1372         req->size = data_this_transaction;
1373         req->gref = 8;
1374         req->offset = 0;
1375         xnb_unit_pvt.txf.req_prod_pvt++;
1376
1377         RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1378         xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1379
1380         pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1381         n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1382             &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1383
1384         /* Update grant table's status fields */
1385         for (i = 0; i < n_entries; i++) {
1386                 xnb_unit_pvt.gnttab[0].status = GNTST_okay;
1387         }
1388         xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
1389
1390         if (n_entries == 3) {
1391                 /* there should be three mbufs and three gnttab entries */
1392                 XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
1393                 XNB_ASSERT(pMbuf->m_len == MCLBYTES);
1394                 XNB_ASSERT(pMbuf->m_next->m_len == MCLBYTES);
1395                 XNB_ASSERT(pMbuf->m_next->m_next->m_len == 1);
1396         } else if (n_entries == 2) {
1397                 /* there should be two mbufs and two gnttab entries */
1398                 XNB_ASSERT(n_entries == 2);
1399                 XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
1400                 XNB_ASSERT(pMbuf->m_len == 2 * MCLBYTES);
1401                 XNB_ASSERT(pMbuf->m_next->m_len == 1);
1402         } else {
1403                 /* should never get here */
1404                 XNB_ASSERT(0);
1405         }
1406         safe_m_freem(&pMbuf);
1407 }
1408
1409 /** xnb_mbufc2pkt on an empty mbufc */
1410 static void
1411 xnb_mbufc2pkt_empty(char *buffer, size_t buflen) {
1412         struct xnb_pkt pkt;
1413         int free_slots = 64;
1414         struct mbuf *mbuf;
1415
1416         mbuf = m_get(M_WAITOK, MT_DATA);
1417         /*
1418          * note: it is illegal to set M_PKTHDR on a mbuf with no data.  Doing so
1419          * will cause m_freem to segfault
1420          */
1421         XNB_ASSERT(mbuf->m_len == 0);
1422
1423         xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
1424         XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
1425
1426         safe_m_freem(&mbuf);
1427 }
1428
1429 /** xnb_mbufc2pkt on a short mbufc */
1430 static void
1431 xnb_mbufc2pkt_short(char *buffer, size_t buflen) {
1432         struct xnb_pkt pkt;
1433         size_t size = 128;
1434         int free_slots = 64;
1435         RING_IDX start = 9;
1436         struct mbuf *mbuf;
1437
1438         mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1439         mbuf->m_flags |= M_PKTHDR;
1440         mbuf->m_pkthdr.len = size;
1441         mbuf->m_len = size;
1442
1443         xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1444         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1445         XNB_ASSERT(pkt.size == size);
1446         XNB_ASSERT(pkt.car_size == size);
1447         XNB_ASSERT(! (pkt.flags &
1448               (NETRXF_more_data | NETRXF_extra_info)));
1449         XNB_ASSERT(pkt.list_len == 1);
1450         XNB_ASSERT(pkt.car == start);
1451
1452         safe_m_freem(&mbuf);
1453 }
1454
1455 /** xnb_mbufc2pkt on a single mbuf with an mbuf cluster */
1456 static void
1457 xnb_mbufc2pkt_1cluster(char *buffer, size_t buflen) {
1458         struct xnb_pkt pkt;
1459         size_t size = MCLBYTES;
1460         int free_slots = 32;
1461         RING_IDX start = 12;
1462         struct mbuf *mbuf;
1463
1464         mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1465         mbuf->m_flags |= M_PKTHDR;
1466         mbuf->m_pkthdr.len = size;
1467         mbuf->m_len = size;
1468
1469         xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1470         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1471         XNB_ASSERT(pkt.size == size);
1472         XNB_ASSERT(pkt.car_size == size);
1473         XNB_ASSERT(! (pkt.flags &
1474               (NETRXF_more_data | NETRXF_extra_info)));
1475         XNB_ASSERT(pkt.list_len == 1);
1476         XNB_ASSERT(pkt.car == start);
1477
1478         safe_m_freem(&mbuf);
1479 }
1480
1481 /** xnb_mbufc2pkt on a two-mbuf chain with short data regions */
1482 static void
1483 xnb_mbufc2pkt_2short(char *buffer, size_t buflen) {
1484         struct xnb_pkt pkt;
1485         size_t size1 = MHLEN - 5;
1486         size_t size2 = MHLEN - 15;
1487         int free_slots = 32;
1488         RING_IDX start = 14;
1489         struct mbuf *mbufc, *mbufc2;
1490
1491         mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
1492         mbufc->m_flags |= M_PKTHDR;
1493         if (mbufc == NULL) {
1494                 XNB_ASSERT(mbufc != NULL);
1495                 return;
1496         }
1497
1498         mbufc2 = m_getm(mbufc, size2, M_WAITOK, MT_DATA);
1499         if (mbufc2 == NULL) {
1500                 XNB_ASSERT(mbufc2 != NULL);
1501                 safe_m_freem(&mbufc);
1502                 return;
1503         }
1504         mbufc2->m_pkthdr.len = size1 + size2;
1505         mbufc2->m_len = size1;
1506
1507         xnb_mbufc2pkt(mbufc2, &pkt, start, free_slots);
1508         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1509         XNB_ASSERT(pkt.size == size1 + size2);
1510         XNB_ASSERT(pkt.car == start);
1511         /*
1512          * The second m_getm may allocate a new mbuf and append
1513          * it to the chain, or it may simply extend the first mbuf.
1514          */
1515         if (mbufc2->m_next != NULL) {
1516                 XNB_ASSERT(pkt.car_size == size1);
1517                 XNB_ASSERT(pkt.list_len == 1);
1518                 XNB_ASSERT(pkt.cdr == start + 1);
1519         }
1520
1521         safe_m_freem(&mbufc2);
1522 }
1523
1524 /** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster */
1525 static void
1526 xnb_mbufc2pkt_long(char *buffer, size_t buflen) {
1527         struct xnb_pkt pkt;
1528         size_t size = 14 * MCLBYTES / 3;
1529         size_t size_remaining;
1530         int free_slots = 15;
1531         RING_IDX start = 3;
1532         struct mbuf *mbufc, *m;
1533
1534         mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1535         mbufc->m_flags |= M_PKTHDR;
1536         if (mbufc == NULL) {
1537                 XNB_ASSERT(mbufc != NULL);
1538                 return;
1539         }
1540
1541         mbufc->m_pkthdr.len = size;
1542         size_remaining = size;
1543         for (m = mbufc; m != NULL; m = m->m_next) {
1544                 m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
1545                 size_remaining -= m->m_len;
1546         }
1547
1548         xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1549         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1550         XNB_ASSERT(pkt.size == size);
1551         XNB_ASSERT(pkt.car == start);
1552         XNB_ASSERT(pkt.car_size = mbufc->m_len);
1553         /*
1554          * There should be >1 response in the packet, and there is no
1555          * extra info.
1556          */
1557         XNB_ASSERT(! (pkt.flags & NETRXF_extra_info));
1558         XNB_ASSERT(pkt.cdr == pkt.car + 1);
1559
1560         safe_m_freem(&mbufc);
1561 }
1562
1563 /** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster and extra info */
1564 static void
1565 xnb_mbufc2pkt_extra(char *buffer, size_t buflen) {
1566         struct xnb_pkt pkt;
1567         size_t size = 14 * MCLBYTES / 3;
1568         size_t size_remaining;
1569         int free_slots = 15;
1570         RING_IDX start = 3;
1571         struct mbuf *mbufc, *m;
1572
1573         mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1574         if (mbufc == NULL) {
1575                 XNB_ASSERT(mbufc != NULL);
1576                 return;
1577         }
1578
1579         mbufc->m_flags |= M_PKTHDR;
1580         mbufc->m_pkthdr.len = size;
1581         mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
1582         mbufc->m_pkthdr.tso_segsz = TCP_MSS - 40;
1583         size_remaining = size;
1584         for (m = mbufc; m != NULL; m = m->m_next) {
1585                 m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
1586                 size_remaining -= m->m_len;
1587         }
1588
1589         xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1590         XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1591         XNB_ASSERT(pkt.size == size);
1592         XNB_ASSERT(pkt.car == start);
1593         XNB_ASSERT(pkt.car_size = mbufc->m_len);
1594         /* There should be >1 response in the packet, there is extra info */
1595         XNB_ASSERT(pkt.flags & NETRXF_extra_info);
1596         XNB_ASSERT(pkt.flags & NETRXF_data_validated);
1597         XNB_ASSERT(pkt.cdr == pkt.car + 2);
1598         XNB_ASSERT(pkt.extra.u.gso.size = mbufc->m_pkthdr.tso_segsz);
1599         XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
1600         XNB_ASSERT(! (pkt.extra.flags & XEN_NETIF_EXTRA_FLAG_MORE));
1601
1602         safe_m_freem(&mbufc);
1603 }
1604
1605 /** xnb_mbufc2pkt with insufficient space in the ring */
1606 static void
1607 xnb_mbufc2pkt_nospace(char *buffer, size_t buflen) {
1608         struct xnb_pkt pkt;
1609         size_t size = 14 * MCLBYTES / 3;
1610         size_t size_remaining;
1611         int free_slots = 2;
1612         RING_IDX start = 3;
1613         struct mbuf *mbufc, *m;
1614         int error;
1615
1616         mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1617         mbufc->m_flags |= M_PKTHDR;
1618         if (mbufc == NULL) {
1619                 XNB_ASSERT(mbufc != NULL);
1620                 return;
1621         }
1622
1623         mbufc->m_pkthdr.len = size;
1624         size_remaining = size;
1625         for (m = mbufc; m != NULL; m = m->m_next) {
1626                 m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
1627                 size_remaining -= m->m_len;
1628         }
1629
1630         error = xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1631         XNB_ASSERT(error == EAGAIN);
1632         XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
1633
1634         safe_m_freem(&mbufc);
1635 }
1636
1637 /**
1638  * xnb_rxpkt2gnttab on an empty packet.  Should return empty gnttab
1639  */
1640 static void
1641 xnb_rxpkt2gnttab_empty(char *buffer, size_t buflen)
1642 {
1643         struct xnb_pkt pkt;
1644         int nr_entries;
1645         int free_slots = 60;
1646         struct mbuf *mbuf;
1647
1648         mbuf = m_get(M_WAITOK, MT_DATA);
1649
1650         xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
1651         nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1652                         &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1653
1654         XNB_ASSERT(nr_entries == 0);
1655
1656         safe_m_freem(&mbuf);
1657 }
1658
1659 /** xnb_rxpkt2gnttab on a short packet without extra data */
1660 static void
1661 xnb_rxpkt2gnttab_short(char *buffer, size_t buflen) {
1662         struct xnb_pkt pkt;
1663         int nr_entries;
1664         size_t size = 128;
1665         int free_slots = 60;
1666         RING_IDX start = 9;
1667         struct netif_rx_request *req;
1668         struct mbuf *mbuf;
1669
1670         mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1671         mbuf->m_flags |= M_PKTHDR;
1672         mbuf->m_pkthdr.len = size;
1673         mbuf->m_len = size;
1674
1675         xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1676         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
1677                                xnb_unit_pvt.txf.req_prod_pvt);
1678         req->gref = 7;
1679
1680         nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1681                                       &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1682
1683         XNB_ASSERT(nr_entries == 1);
1684         XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
1685         /* flags should indicate gref's for dest */
1686         XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_dest_gref);
1687         XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == 0);
1688         XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
1689         XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == virt_to_offset(
1690                    mtod(mbuf, vm_offset_t)));
1691         XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.u.gmfn ==
1692                    virt_to_mfn(mtod(mbuf, vm_offset_t)));
1693         XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
1694
1695         safe_m_freem(&mbuf);
1696 }
1697
1698 /**
1699  * xnb_rxpkt2gnttab on a packet with two different mbufs in a single chai
1700  */
1701 static void
1702 xnb_rxpkt2gnttab_2req(char *buffer, size_t buflen)
1703 {
1704         struct xnb_pkt pkt;
1705         int nr_entries;
1706         int i, num_mbufs;
1707         size_t total_granted_size = 0;
1708         size_t size = MJUMPAGESIZE + 1;
1709         int free_slots = 60;
1710         RING_IDX start = 11;
1711         struct netif_rx_request *req;
1712         struct mbuf *mbuf, *m;
1713
1714         mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1715         mbuf->m_flags |= M_PKTHDR;
1716         mbuf->m_pkthdr.len = size;
1717         mbuf->m_len = size;
1718
1719         xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1720
1721         for (i = 0, m=mbuf; m != NULL; i++, m = m->m_next) {
1722                 req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
1723                     xnb_unit_pvt.txf.req_prod_pvt);
1724                 req->gref = i;
1725                 req->id = 5;
1726         }
1727         num_mbufs = i;
1728
1729         nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1730                         &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1731
1732         XNB_ASSERT(nr_entries >= num_mbufs);
1733         for (i = 0; i < nr_entries; i++) {
1734                 int end_offset = xnb_unit_pvt.gnttab[i].len +
1735                         xnb_unit_pvt.gnttab[i].dest.offset;
1736                 XNB_ASSERT(end_offset <= PAGE_SIZE);
1737                 total_granted_size += xnb_unit_pvt.gnttab[i].len;
1738         }
1739         XNB_ASSERT(total_granted_size == size);
1740 }
1741
1742 /**
1743  * xnb_rxpkt2rsp on an empty packet.  Shouldn't make any response
1744  */
1745 static void
1746 xnb_rxpkt2rsp_empty(char *buffer, size_t buflen)
1747 {
1748         struct xnb_pkt pkt;
1749         int nr_entries;
1750         int nr_reqs;
1751         int free_slots = 60;
1752         netif_rx_back_ring_t rxb_backup = xnb_unit_pvt.rxb;
1753         netif_rx_sring_t rxs_backup = *xnb_unit_pvt.rxs;
1754         struct mbuf *mbuf;
1755
1756         mbuf = m_get(M_WAITOK, MT_DATA);
1757
1758         xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
1759         nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1760                         &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1761
1762         nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1763             &xnb_unit_pvt.rxb);
1764         XNB_ASSERT(nr_reqs == 0);
1765         XNB_ASSERT(
1766             memcmp(&rxb_backup, &xnb_unit_pvt.rxb, sizeof(rxb_backup)) == 0);
1767         XNB_ASSERT(
1768             memcmp(&rxs_backup, xnb_unit_pvt.rxs, sizeof(rxs_backup)) == 0);
1769
1770         safe_m_freem(&mbuf);
1771 }
1772
1773 /**
1774  * xnb_rxpkt2rsp on a short packet with no extras
1775  */
1776 static void
1777 xnb_rxpkt2rsp_short(char *buffer, size_t buflen)
1778 {
1779         struct xnb_pkt pkt;
1780         int nr_entries, nr_reqs;
1781         size_t size = 128;
1782         int free_slots = 60;
1783         RING_IDX start = 5;
1784         struct netif_rx_request *req;
1785         struct netif_rx_response *rsp;
1786         struct mbuf *mbuf;
1787
1788         mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1789         mbuf->m_flags |= M_PKTHDR;
1790         mbuf->m_pkthdr.len = size;
1791         mbuf->m_len = size;
1792
1793         xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1794         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1795         req->gref = 7;
1796         xnb_unit_pvt.rxb.req_cons = start;
1797         xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1798         xnb_unit_pvt.rxs->req_prod = start + 1;
1799         xnb_unit_pvt.rxs->rsp_prod = start;
1800
1801         nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1802                         &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1803
1804         nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1805             &xnb_unit_pvt.rxb);
1806
1807         XNB_ASSERT(nr_reqs == 1);
1808         XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
1809         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1810         XNB_ASSERT(rsp->id == req->id);
1811         XNB_ASSERT(rsp->offset == 0);
1812         XNB_ASSERT((rsp->flags & (NETRXF_more_data | NETRXF_extra_info)) == 0);
1813         XNB_ASSERT(rsp->status == size);
1814
1815         safe_m_freem(&mbuf);
1816 }
1817
1818 /**
1819  * xnb_rxpkt2rsp with extra data
1820  */
1821 static void
1822 xnb_rxpkt2rsp_extra(char *buffer, size_t buflen)
1823 {
1824         struct xnb_pkt pkt;
1825         int nr_entries, nr_reqs;
1826         size_t size = 14;
1827         int free_slots = 15;
1828         RING_IDX start = 3;
1829         uint16_t id = 49;
1830         uint16_t gref = 65;
1831         uint16_t mss = TCP_MSS - 40;
1832         struct mbuf *mbufc;
1833         struct netif_rx_request *req;
1834         struct netif_rx_response *rsp;
1835         struct netif_extra_info *ext;
1836
1837         mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1838         if (mbufc == NULL) {
1839                 XNB_ASSERT(mbufc != NULL);
1840                 return;
1841         }
1842
1843         mbufc->m_flags |= M_PKTHDR;
1844         mbufc->m_pkthdr.len = size;
1845         mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
1846         mbufc->m_pkthdr.tso_segsz = mss;
1847         mbufc->m_len = size;
1848
1849         xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1850         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1851         req->id = id;
1852         req->gref = gref;
1853         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
1854         req->id = id + 1;
1855         req->gref = gref + 1;
1856         xnb_unit_pvt.rxb.req_cons = start;
1857         xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1858         xnb_unit_pvt.rxs->req_prod = start + 2;
1859         xnb_unit_pvt.rxs->rsp_prod = start;
1860
1861         nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
1862                         &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1863
1864         nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1865             &xnb_unit_pvt.rxb);
1866
1867         XNB_ASSERT(nr_reqs == 2);
1868         XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
1869         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1870         XNB_ASSERT(rsp->id == id);
1871         XNB_ASSERT((rsp->flags & NETRXF_more_data) == 0);
1872         XNB_ASSERT((rsp->flags & NETRXF_extra_info));
1873         XNB_ASSERT((rsp->flags & NETRXF_data_validated));
1874         XNB_ASSERT((rsp->flags & NETRXF_csum_blank));
1875         XNB_ASSERT(rsp->status == size);
1876
1877         ext = (struct netif_extra_info*)
1878                 RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
1879         XNB_ASSERT(ext->type == XEN_NETIF_EXTRA_TYPE_GSO);
1880         XNB_ASSERT(! (ext->flags & XEN_NETIF_EXTRA_FLAG_MORE));
1881         XNB_ASSERT(ext->u.gso.size == mss);
1882         XNB_ASSERT(ext->u.gso.type == XEN_NETIF_EXTRA_TYPE_GSO);
1883
1884         safe_m_freem(&mbufc);
1885 }
1886
1887 /**
1888  * xnb_rxpkt2rsp on a packet with more than a pages's worth of data.  It should
1889  * generate two response slot
1890  */
1891 static void
1892 xnb_rxpkt2rsp_2slots(char *buffer, size_t buflen)
1893 {
1894         struct xnb_pkt pkt;
1895         int nr_entries, nr_reqs;
1896         size_t size = PAGE_SIZE + 100;
1897         int free_slots = 3;
1898         uint16_t id1 = 17;
1899         uint16_t id2 = 37;
1900         uint16_t gref1 = 24;
1901         uint16_t gref2 = 34;
1902         RING_IDX start = 15;
1903         struct netif_rx_request *req;
1904         struct netif_rx_response *rsp;
1905         struct mbuf *mbuf;
1906
1907         mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1908         mbuf->m_flags |= M_PKTHDR;
1909         mbuf->m_pkthdr.len = size;
1910         if (mbuf->m_next != NULL) {
1911                 size_t first_len = MIN(M_TRAILINGSPACE(mbuf), size);
1912                 mbuf->m_len = first_len;
1913                 mbuf->m_next->m_len = size - first_len;
1914
1915         } else {
1916                 mbuf->m_len = size;
1917         }
1918
1919         xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1920         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1921         req->gref = gref1;
1922         req->id = id1;
1923         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
1924         req->gref = gref2;
1925         req->id = id2;
1926         xnb_unit_pvt.rxb.req_cons = start;
1927         xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1928         xnb_unit_pvt.rxs->req_prod = start + 2;
1929         xnb_unit_pvt.rxs->rsp_prod = start;
1930
1931         nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1932                         &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1933
1934         nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1935             &xnb_unit_pvt.rxb);
1936
1937         XNB_ASSERT(nr_reqs == 2);
1938         XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
1939         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1940         XNB_ASSERT(rsp->id == id1);
1941         XNB_ASSERT(rsp->offset == 0);
1942         XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
1943         XNB_ASSERT(rsp->flags & NETRXF_more_data);
1944         XNB_ASSERT(rsp->status == PAGE_SIZE);
1945
1946         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
1947         XNB_ASSERT(rsp->id == id2);
1948         XNB_ASSERT(rsp->offset == 0);
1949         XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
1950         XNB_ASSERT(! (rsp->flags & NETRXF_more_data));
1951         XNB_ASSERT(rsp->status == size - PAGE_SIZE);
1952
1953         safe_m_freem(&mbuf);
1954 }
1955
1956 /** xnb_rxpkt2rsp on a grant table with two sub-page entries */
1957 static void
1958 xnb_rxpkt2rsp_2short(char *buffer, size_t buflen) {
1959         struct xnb_pkt pkt;
1960         int nr_reqs, nr_entries;
1961         size_t size1 = MHLEN - 5;
1962         size_t size2 = MHLEN - 15;
1963         int free_slots = 32;
1964         RING_IDX start = 14;
1965         uint16_t id = 47;
1966         uint16_t gref = 54;
1967         struct netif_rx_request *req;
1968         struct netif_rx_response *rsp;
1969         struct mbuf *mbufc;
1970
1971         mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
1972         mbufc->m_flags |= M_PKTHDR;
1973         if (mbufc == NULL) {
1974                 XNB_ASSERT(mbufc != NULL);
1975                 return;
1976         }
1977
1978         m_getm(mbufc, size2, M_WAITOK, MT_DATA);
1979         XNB_ASSERT(mbufc->m_next != NULL);
1980         mbufc->m_pkthdr.len = size1 + size2;
1981         mbufc->m_len = size1;
1982         mbufc->m_next->m_len = size2;
1983
1984         xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1985
1986         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1987         req->gref = gref;
1988         req->id = id;
1989         xnb_unit_pvt.rxb.req_cons = start;
1990         xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1991         xnb_unit_pvt.rxs->req_prod = start + 1;
1992         xnb_unit_pvt.rxs->rsp_prod = start;
1993
1994         nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
1995                         &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1996
1997         nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1998             &xnb_unit_pvt.rxb);
1999
2000         XNB_ASSERT(nr_entries == 2);
2001         XNB_ASSERT(nr_reqs == 1);
2002         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
2003         XNB_ASSERT(rsp->id == id);
2004         XNB_ASSERT(rsp->status == size1 + size2);
2005         XNB_ASSERT(rsp->offset == 0);
2006         XNB_ASSERT(! (rsp->flags & (NETRXF_more_data | NETRXF_extra_info)));
2007
2008         safe_m_freem(&mbufc);
2009 }
2010
2011 /**
2012  * xnb_rxpkt2rsp on a long packet with a hypervisor gnttab_copy error
2013  * Note: this test will result in an error message being printed to the console
2014  * such as:
2015  * xnb(xnb_rxpkt2rsp:1720): Got error -1 for hypervisor gnttab_copy status
2016  */
2017 static void
2018 xnb_rxpkt2rsp_copyerror(char *buffer, size_t buflen)
2019 {
2020         struct xnb_pkt pkt;
2021         int nr_entries, nr_reqs;
2022         int id = 7;
2023         int gref = 42;
2024         uint16_t canary = 6859;
2025         size_t size = 7 * MCLBYTES;
2026         int free_slots = 9;
2027         RING_IDX start = 2;
2028         struct netif_rx_request *req;
2029         struct netif_rx_response *rsp;
2030         struct mbuf *mbuf;
2031         
2032         mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
2033         mbuf->m_flags |= M_PKTHDR;
2034         mbuf->m_pkthdr.len = size;
2035         mbuf->m_len = size;
2036
2037         xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
2038         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
2039         req->gref = gref;
2040         req->id = id;
2041         xnb_unit_pvt.rxb.req_cons = start;
2042         xnb_unit_pvt.rxb.rsp_prod_pvt = start;
2043         xnb_unit_pvt.rxs->req_prod = start + 1;
2044         xnb_unit_pvt.rxs->rsp_prod = start;
2045         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
2046         req->gref = canary;
2047         req->id = canary;
2048
2049         nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
2050                         &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
2051         /* Inject the error*/
2052         xnb_unit_pvt.gnttab[2].status = GNTST_general_error;
2053
2054         nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
2055             &xnb_unit_pvt.rxb);
2056
2057         XNB_ASSERT(nr_reqs == 1);
2058         XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
2059         rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
2060         XNB_ASSERT(rsp->id == id);
2061         XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
2062         req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
2063         XNB_ASSERT(req->gref == canary);
2064         XNB_ASSERT(req->id == canary);
2065
2066         safe_m_freem(&mbuf);
2067 }
2068
2069 /**
2070  * xnb_add_mbuf_cksum on an ARP request packet
2071  */
2072 static void
2073 xnb_add_mbuf_cksum_arp(char *buffer, size_t buflen)
2074 {
2075         const size_t pkt_len = sizeof(struct ether_header) +
2076                 sizeof(struct ether_arp);
2077         struct mbuf *mbufc;
2078         struct ether_header *eh;
2079         struct ether_arp *ep;
2080         unsigned char pkt_orig[pkt_len];
2081
2082         mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2083         /* Fill in an example arp request */
2084         eh = mtod(mbufc, struct ether_header*);
2085         eh->ether_dhost[0] = 0xff;
2086         eh->ether_dhost[1] = 0xff;
2087         eh->ether_dhost[2] = 0xff;
2088         eh->ether_dhost[3] = 0xff;
2089         eh->ether_dhost[4] = 0xff;
2090         eh->ether_dhost[5] = 0xff;
2091         eh->ether_shost[0] = 0x00;
2092         eh->ether_shost[1] = 0x15;
2093         eh->ether_shost[2] = 0x17;
2094         eh->ether_shost[3] = 0xe9;
2095         eh->ether_shost[4] = 0x30;
2096         eh->ether_shost[5] = 0x68;
2097         eh->ether_type = htons(ETHERTYPE_ARP);
2098         ep = (struct ether_arp*)(eh + 1);
2099         ep->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
2100         ep->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
2101         ep->ea_hdr.ar_hln = 6;
2102         ep->ea_hdr.ar_pln = 4;
2103         ep->ea_hdr.ar_op = htons(ARPOP_REQUEST);
2104         ep->arp_sha[0] = 0x00;
2105         ep->arp_sha[1] = 0x15;
2106         ep->arp_sha[2] = 0x17;
2107         ep->arp_sha[3] = 0xe9;
2108         ep->arp_sha[4] = 0x30;
2109         ep->arp_sha[5] = 0x68;
2110         ep->arp_spa[0] = 0xc0;
2111         ep->arp_spa[1] = 0xa8;
2112         ep->arp_spa[2] = 0x0a;
2113         ep->arp_spa[3] = 0x04;
2114         bzero(&(ep->arp_tha), ETHER_ADDR_LEN);
2115         ep->arp_tpa[0] = 0xc0;
2116         ep->arp_tpa[1] = 0xa8;
2117         ep->arp_tpa[2] = 0x0a;
2118         ep->arp_tpa[3] = 0x06;
2119
2120         /* fill in the length field */
2121         mbufc->m_len = pkt_len;
2122         mbufc->m_pkthdr.len = pkt_len;
2123         /* indicate that the netfront uses hw-assisted checksums */
2124         mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
2125                                 CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2126
2127         /* Make a backup copy of the packet */
2128         bcopy(mtod(mbufc, const void*), pkt_orig, pkt_len);
2129
2130         /* Function under test */
2131         xnb_add_mbuf_cksum(mbufc);
2132
2133         /* Verify that the packet's data did not change */
2134         XNB_ASSERT(bcmp(mtod(mbufc, const void*), pkt_orig, pkt_len) == 0);
2135         m_freem(mbufc);
2136 }
2137
2138 /**
2139  * Helper function that populates the ethernet header and IP header used by
2140  * some of the xnb_add_mbuf_cksum unit tests.  m must already be allocated
2141  * and must be large enough
2142  */
2143 static void
2144 xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len, uint16_t ip_id,
2145                    uint16_t ip_p, uint16_t ip_off, uint16_t ip_sum)
2146 {
2147         struct ether_header *eh;
2148         struct ip *iph;
2149
2150         eh = mtod(m, struct ether_header*);
2151         eh->ether_dhost[0] = 0x00;
2152         eh->ether_dhost[1] = 0x16;
2153         eh->ether_dhost[2] = 0x3e;
2154         eh->ether_dhost[3] = 0x23;
2155         eh->ether_dhost[4] = 0x50;
2156         eh->ether_dhost[5] = 0x0b;
2157         eh->ether_shost[0] = 0x00;
2158         eh->ether_shost[1] = 0x16;
2159         eh->ether_shost[2] = 0x30;
2160         eh->ether_shost[3] = 0x00;
2161         eh->ether_shost[4] = 0x00;
2162         eh->ether_shost[5] = 0x00;
2163         eh->ether_type = htons(ETHERTYPE_IP);
2164         iph = (struct ip*)(eh + 1);
2165         iph->ip_hl = 0x5;       /* 5 dwords == 20 bytes */
2166         iph->ip_v = 4;          /* IP v4 */
2167         iph->ip_tos = 0;
2168         iph->ip_len = htons(ip_len);
2169         iph->ip_id = htons(ip_id);
2170         iph->ip_off = htons(ip_off);
2171         iph->ip_ttl = 64;
2172         iph->ip_p = ip_p;
2173         iph->ip_sum = htons(ip_sum);
2174         iph->ip_src.s_addr = htonl(0xc0a80a04);
2175         iph->ip_dst.s_addr = htonl(0xc0a80a05);
2176 }
2177
2178 /**
2179  * xnb_add_mbuf_cksum on an ICMP packet, based on a tcpdump of an actual
2180  * ICMP packet
2181  */
2182 static void
2183 xnb_add_mbuf_cksum_icmp(char *buffer, size_t buflen)
2184 {
2185         const size_t icmp_len = 64;     /* set by ping(1) */
2186         const size_t pkt_len = sizeof(struct ether_header) +
2187                 sizeof(struct ip) + icmp_len;
2188         struct mbuf *mbufc;
2189         struct ether_header *eh;
2190         struct ip *iph;
2191         struct icmp *icmph;
2192         unsigned char pkt_orig[icmp_len];
2193         uint32_t *tv_field;
2194         uint8_t *data_payload;
2195         int i;
2196         const uint16_t ICMP_CSUM = 0xaed7;
2197         const uint16_t IP_CSUM = 0xe533;
2198
2199         mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2200         /* Fill in an example ICMP ping request */
2201         eh = mtod(mbufc, struct ether_header*);
2202         xnb_fill_eh_and_ip(mbufc, 84, 28, IPPROTO_ICMP, 0, 0);
2203         iph = (struct ip*)(eh + 1);
2204         icmph = (struct icmp*)(iph + 1);
2205         icmph->icmp_type = ICMP_ECHO;
2206         icmph->icmp_code = 0;
2207         icmph->icmp_cksum = htons(ICMP_CSUM);
2208         icmph->icmp_id = htons(31492);
2209         icmph->icmp_seq = htons(0);
2210         /*
2211          * ping(1) uses bcopy to insert a native-endian timeval after icmp_seq.
2212          * For this test, we will set the bytes individually for portability.
2213          */
2214         tv_field = (uint32_t*)(&(icmph->icmp_hun));
2215         tv_field[0] = 0x4f02cfac;
2216         tv_field[1] = 0x0007c46a;
2217         /*
2218          * Remainder of packet is an incrmenting 8 bit integer, starting with 8
2219          */
2220         data_payload = (uint8_t*)(&tv_field[2]);
2221         for (i = 8; i < 37; i++) {
2222                 *data_payload++ = i;
2223         }
2224
2225         /* fill in the length field */
2226         mbufc->m_len = pkt_len;
2227         mbufc->m_pkthdr.len = pkt_len;
2228         /* indicate that the netfront uses hw-assisted checksums */
2229         mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
2230                                 CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2231
2232         bcopy(mtod(mbufc, const void*), pkt_orig, icmp_len);
2233         /* Function under test */
2234         xnb_add_mbuf_cksum(mbufc);
2235
2236         /* Check the IP checksum */
2237         XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2238
2239         /* Check that the ICMP packet did not change */
2240         XNB_ASSERT(bcmp(icmph, pkt_orig, icmp_len));
2241         m_freem(mbufc);
2242 }
2243
2244 /**
2245  * xnb_add_mbuf_cksum on a UDP packet, based on a tcpdump of an actual
2246  * UDP packet
2247  */
2248 static void
2249 xnb_add_mbuf_cksum_udp(char *buffer, size_t buflen)
2250 {
2251         const size_t udp_len = 16;
2252         const size_t pkt_len = sizeof(struct ether_header) +
2253                 sizeof(struct ip) + udp_len;
2254         struct mbuf *mbufc;
2255         struct ether_header *eh;
2256         struct ip *iph;
2257         struct udphdr *udp;
2258         uint8_t *data_payload;
2259         const uint16_t IP_CSUM = 0xe56b;
2260         const uint16_t UDP_CSUM = 0xdde2;
2261
2262         mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2263         /* Fill in an example UDP packet made by 'uname | nc -u <host> 2222 */
2264         eh = mtod(mbufc, struct ether_header*);
2265         xnb_fill_eh_and_ip(mbufc, 36, 4, IPPROTO_UDP, 0, 0xbaad);
2266         iph = (struct ip*)(eh + 1);
2267         udp = (struct udphdr*)(iph + 1);
2268         udp->uh_sport = htons(0x51ae);
2269         udp->uh_dport = htons(0x08ae);
2270         udp->uh_ulen = htons(udp_len);
2271         udp->uh_sum = htons(0xbaad);  /* xnb_add_mbuf_cksum will fill this in */
2272         data_payload = (uint8_t*)(udp + 1);
2273         data_payload[0] = 'F';
2274         data_payload[1] = 'r';
2275         data_payload[2] = 'e';
2276         data_payload[3] = 'e';
2277         data_payload[4] = 'B';
2278         data_payload[5] = 'S';
2279         data_payload[6] = 'D';
2280         data_payload[7] = '\n';
2281
2282         /* fill in the length field */
2283         mbufc->m_len = pkt_len;
2284         mbufc->m_pkthdr.len = pkt_len;
2285         /* indicate that the netfront uses hw-assisted checksums */
2286         mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
2287                                 CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2288
2289         /* Function under test */
2290         xnb_add_mbuf_cksum(mbufc);
2291
2292         /* Check the checksums */
2293         XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2294         XNB_ASSERT(udp->uh_sum == htons(UDP_CSUM));
2295
2296         m_freem(mbufc);
2297 }
2298
2299 /**
2300  * Helper function that populates a TCP packet used by all of the
2301  * xnb_add_mbuf_cksum tcp unit tests.  m must already be allocated and must be
2302  * large enough
2303  */
2304 static void
2305 xnb_fill_tcp(struct mbuf *m)
2306 {
2307         struct ether_header *eh;
2308         struct ip *iph;
2309         struct tcphdr *tcp;
2310         uint32_t *options;
2311         uint8_t *data_payload;
2312
2313         /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
2314         eh = mtod(m, struct ether_header*);
2315         xnb_fill_eh_and_ip(m, 60, 8, IPPROTO_TCP, IP_DF, 0);
2316         iph = (struct ip*)(eh + 1);
2317         tcp = (struct tcphdr*)(iph + 1);
2318         tcp->th_sport = htons(0x9cd9);
2319         tcp->th_dport = htons(2222);
2320         tcp->th_seq = htonl(0x00f72b10);
2321         tcp->th_ack = htonl(0x7f37ba6c);
2322         tcp->th_x2 = 0;
2323         tcp->th_off = 8;
2324         tcp->th_flags = 0x18;
2325         tcp->th_win = htons(0x410);
2326         /* th_sum is incorrect; will be inserted by function under test */
2327         tcp->th_sum = htons(0xbaad);
2328         tcp->th_urp = htons(0);
2329         /*
2330          * The following 12 bytes of options encode:
2331          * [nop, nop, TS val 33247 ecr 3457687679]
2332          */
2333         options = (uint32_t*)(tcp + 1);
2334         options[0] = htonl(0x0101080a);
2335         options[1] = htonl(0x000081df);
2336         options[2] = htonl(0xce18207f);
2337         data_payload = (uint8_t*)(&options[3]);
2338         data_payload[0] = 'F';
2339         data_payload[1] = 'r';
2340         data_payload[2] = 'e';
2341         data_payload[3] = 'e';
2342         data_payload[4] = 'B';
2343         data_payload[5] = 'S';
2344         data_payload[6] = 'D';
2345         data_payload[7] = '\n';
2346 }
2347
2348 /**
2349  * xnb_add_mbuf_cksum on a TCP packet, based on a tcpdump of an actual TCP
2350  * packet
2351  */
2352 static void
2353 xnb_add_mbuf_cksum_tcp(char *buffer, size_t buflen)
2354 {
2355         const size_t payload_len = 8;
2356         const size_t tcp_options_len = 12;
2357         const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
2358             sizeof(struct tcphdr) + tcp_options_len + payload_len;
2359         struct mbuf *mbufc;
2360         struct ether_header *eh;
2361         struct ip *iph;
2362         struct tcphdr *tcp;
2363         const uint16_t IP_CSUM = 0xa55a;
2364         const uint16_t TCP_CSUM = 0x2f64;
2365
2366         mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2367         /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
2368         xnb_fill_tcp(mbufc);
2369         eh = mtod(mbufc, struct ether_header*);
2370         iph = (struct ip*)(eh + 1);
2371         tcp = (struct tcphdr*)(iph + 1);
2372
2373         /* fill in the length field */
2374         mbufc->m_len = pkt_len;
2375         mbufc->m_pkthdr.len = pkt_len;
2376         /* indicate that the netfront uses hw-assisted checksums */
2377         mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
2378                                 CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2379
2380         /* Function under test */
2381         xnb_add_mbuf_cksum(mbufc);
2382
2383         /* Check the checksums */
2384         XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2385         XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
2386
2387         m_freem(mbufc);
2388 }
2389
2390 /**
2391  * xnb_add_mbuf_cksum on a TCP packet that does not use HW assisted checksums
2392  */
2393 static void
2394 xnb_add_mbuf_cksum_tcp_swcksum(char *buffer, size_t buflen)
2395 {
2396         const size_t payload_len = 8;
2397         const size_t tcp_options_len = 12;
2398         const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
2399             sizeof(struct tcphdr) + tcp_options_len + payload_len;
2400         struct mbuf *mbufc;
2401         struct ether_header *eh;
2402         struct ip *iph;
2403         struct tcphdr *tcp;
2404         /* Use deliberately bad checksums, and verify that they don't get */
2405         /* corrected by xnb_add_mbuf_cksum */
2406         const uint16_t IP_CSUM = 0xdead;
2407         const uint16_t TCP_CSUM = 0xbeef;
2408
2409         mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2410         /* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
2411         xnb_fill_tcp(mbufc);
2412         eh = mtod(mbufc, struct ether_header*);
2413         iph = (struct ip*)(eh + 1);
2414         iph->ip_sum = htons(IP_CSUM);
2415         tcp = (struct tcphdr*)(iph + 1);
2416         tcp->th_sum = htons(TCP_CSUM);
2417
2418         /* fill in the length field */
2419         mbufc->m_len = pkt_len;
2420         mbufc->m_pkthdr.len = pkt_len;
2421         /* indicate that the netfront does not use hw-assisted checksums */
2422         mbufc->m_pkthdr.csum_flags = 0;
2423
2424         /* Function under test */
2425         xnb_add_mbuf_cksum(mbufc);
2426
2427         /* Check that the checksums didn't change */
2428         XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2429         XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
2430
2431         m_freem(mbufc);
2432 }
2433
2434 /**
2435  * sscanf on unsigned chars
2436  */
2437 static void
2438 xnb_sscanf_hhu(char *buffer, size_t buflen)
2439 {
2440         const char mystr[] = "137";
2441         uint8_t dest[12];
2442         int i;
2443
2444         for (i = 0; i < 12; i++)
2445                 dest[i] = 'X';
2446
2447         sscanf(mystr, "%hhu", &dest[4]);
2448         for (i = 0; i < 12; i++)
2449                 XNB_ASSERT(dest[i] == (i == 4 ? 137 : 'X'));
2450 }
2451
2452 /**
2453  * sscanf on signed chars
2454  */
2455 static void
2456 xnb_sscanf_hhd(char *buffer, size_t buflen)
2457 {
2458         const char mystr[] = "-27";
2459         int8_t dest[12];
2460         int i;
2461
2462         for (i = 0; i < 12; i++)
2463                 dest[i] = 'X';
2464
2465         sscanf(mystr, "%hhd", &dest[4]);
2466         for (i = 0; i < 12; i++)
2467                 XNB_ASSERT(dest[i] == (i == 4 ? -27 : 'X'));
2468 }
2469
2470 /**
2471  * sscanf on signed long longs
2472  */
2473 static void
2474 xnb_sscanf_lld(char *buffer, size_t buflen)
2475 {
2476         const char mystr[] = "-123456789012345";        /* about -2**47 */
2477         long long dest[3];
2478         int i;
2479
2480         for (i = 0; i < 3; i++)
2481                 dest[i] = (long long)0xdeadbeefdeadbeef;
2482
2483         sscanf(mystr, "%lld", &dest[1]);
2484         for (i = 0; i < 3; i++)
2485                 XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
2486                     -123456789012345));
2487 }
2488
2489 /**
2490  * sscanf on unsigned long longs
2491  */
2492 static void
2493 xnb_sscanf_llu(char *buffer, size_t buflen)
2494 {
2495         const char mystr[] = "12802747070103273189";
2496         unsigned long long dest[3];
2497         int i;
2498
2499         for (i = 0; i < 3; i++)
2500                 dest[i] = (long long)0xdeadbeefdeadbeef;
2501
2502         sscanf(mystr, "%llu", &dest[1]);
2503         for (i = 0; i < 3; i++)
2504                 XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
2505                     12802747070103273189ull));
2506 }
2507
2508 /**
2509  * sscanf on unsigned short short n's
2510  */
2511 static void
2512 xnb_sscanf_hhn(char *buffer, size_t buflen)
2513 {
2514         const char mystr[] =
2515             "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
2516             "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
2517             "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f";
2518         unsigned char dest[12];
2519         int i;
2520
2521         for (i = 0; i < 12; i++)
2522                 dest[i] = (unsigned char)'X';
2523
2524         sscanf(mystr,
2525             "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
2526             "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
2527             "404142434445464748494a4b4c4d4e4f%hhn", &dest[4]);
2528         for (i = 0; i < 12; i++)
2529                 XNB_ASSERT(dest[i] == (i == 4 ? 160 : 'X'));
2530 }