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