xref: /freebsd/sys/dev/xen/netback/netback_unit_tests.c (revision a8b70cf26030d68631200619bd1b0ad35b34b6b8)
17e949c46SKenneth D. Merry /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
47e949c46SKenneth D. Merry  * Copyright (c) 2009-2011 Spectra Logic Corporation
57e949c46SKenneth D. Merry  * All rights reserved.
67e949c46SKenneth D. Merry  *
77e949c46SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
87e949c46SKenneth D. Merry  * modification, are permitted provided that the following conditions
97e949c46SKenneth D. Merry  * are met:
107e949c46SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
117e949c46SKenneth D. Merry  *    notice, this list of conditions, and the following disclaimer,
127e949c46SKenneth D. Merry  *    without modification.
137e949c46SKenneth D. Merry  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
147e949c46SKenneth D. Merry  *    substantially similar to the "NO WARRANTY" disclaimer below
157e949c46SKenneth D. Merry  *    ("Disclaimer") and any redistribution must be conditioned upon
167e949c46SKenneth D. Merry  *    including a substantially similar Disclaimer requirement for further
177e949c46SKenneth D. Merry  *    binary redistribution.
187e949c46SKenneth D. Merry  *
197e949c46SKenneth D. Merry  * NO WARRANTY
207e949c46SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
217e949c46SKenneth D. Merry  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
227e949c46SKenneth D. Merry  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
237e949c46SKenneth D. Merry  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
247e949c46SKenneth D. Merry  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257e949c46SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267e949c46SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277e949c46SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
287e949c46SKenneth D. Merry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
297e949c46SKenneth D. Merry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
307e949c46SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGES.
317e949c46SKenneth D. Merry  *
327e949c46SKenneth D. Merry  * Authors: Justin T. Gibbs     (Spectra Logic Corporation)
337e949c46SKenneth D. Merry  *          Alan Somers         (Spectra Logic Corporation)
347e949c46SKenneth D. Merry  *          John Suykerbuyk     (Spectra Logic Corporation)
357e949c46SKenneth D. Merry  */
367e949c46SKenneth D. Merry 
377e949c46SKenneth D. Merry #include <sys/cdefs.h>
38*a8b70cf2SRichard Scheffenegger #include <netinet/tcp.h>
397e949c46SKenneth D. Merry /**
407e949c46SKenneth D. Merry  * \file netback_unit_tests.c
417e949c46SKenneth D. Merry  *
427e949c46SKenneth D. Merry  * \brief Unit tests for the Xen netback driver.
437e949c46SKenneth D. Merry  *
447e949c46SKenneth D. Merry  * Due to the driver's use of static functions, these tests cannot be compiled
457e949c46SKenneth D. Merry  * standalone; they must be #include'd from the driver's .c file.
467e949c46SKenneth D. Merry  */
477e949c46SKenneth D. Merry 
487e949c46SKenneth D. Merry /** Helper macro used to snprintf to a buffer and update the buffer pointer */
497e949c46SKenneth D. Merry #define	SNCATF(buffer, buflen, ...) do {				\
507e949c46SKenneth D. Merry 	size_t new_chars = snprintf(buffer, buflen, __VA_ARGS__);	\
517e949c46SKenneth D. Merry 	buffer += new_chars;						\
527e949c46SKenneth D. Merry 	/* be careful; snprintf's return value can be  > buflen */	\
537e949c46SKenneth D. Merry 	buflen -= MIN(buflen, new_chars);				\
547e949c46SKenneth D. Merry } while (0)
557e949c46SKenneth D. Merry 
567e949c46SKenneth D. Merry /* STRINGIFY and TOSTRING are used only to help turn __LINE__ into a string */
577e949c46SKenneth D. Merry #define	STRINGIFY(x) #x
587e949c46SKenneth D. Merry #define	TOSTRING(x) STRINGIFY(x)
597e949c46SKenneth D. Merry 
607e949c46SKenneth D. Merry /**
619c715a09SDimitry Andric  * Writes an error message to buffer if cond is false
629c715a09SDimitry Andric  * Note the implied parameters buffer and
637e949c46SKenneth D. Merry  * buflen
647e949c46SKenneth D. Merry  */
659c715a09SDimitry Andric #define	XNB_ASSERT(cond) ({						\
667e949c46SKenneth D. Merry 	int passed = (cond);						\
677e949c46SKenneth D. Merry 	char *_buffer = (buffer);					\
687e949c46SKenneth D. Merry 	size_t _buflen = (buflen);					\
697e949c46SKenneth D. Merry 	if (! passed) {							\
707e949c46SKenneth D. Merry 		strlcat(_buffer, __func__, _buflen);			\
717e949c46SKenneth D. Merry 		strlcat(_buffer, ":" TOSTRING(__LINE__) 		\
727e949c46SKenneth D. Merry 		  " Assertion Error: " #cond "\n", _buflen);		\
737e949c46SKenneth D. Merry 	}								\
749c715a09SDimitry Andric 	})
757e949c46SKenneth D. Merry 
767e949c46SKenneth D. Merry /**
777e949c46SKenneth D. Merry  * The signature used by all testcases.  If the test writes anything
787e949c46SKenneth D. Merry  * to buffer, then it will be considered a failure
797e949c46SKenneth D. Merry  * \param buffer	Return storage for error messages
807e949c46SKenneth D. Merry  * \param buflen	The space available in the buffer
817e949c46SKenneth D. Merry  */
827e949c46SKenneth D. Merry typedef void testcase_t(char *buffer, size_t buflen);
837e949c46SKenneth D. Merry 
847e949c46SKenneth D. Merry /**
857e949c46SKenneth D. Merry  * Signature used by setup functions
867e949c46SKenneth D. Merry  * \return nonzero on error
877e949c46SKenneth D. Merry  */
887e949c46SKenneth D. Merry typedef int setup_t(void);
897e949c46SKenneth D. Merry 
907e949c46SKenneth D. Merry typedef void teardown_t(void);
917e949c46SKenneth D. Merry 
927e949c46SKenneth D. Merry /** A simple test fixture comprising setup, teardown, and test */
937e949c46SKenneth D. Merry struct test_fixture {
947e949c46SKenneth D. Merry 	/** Will be run before the test to allocate and initialize variables */
957e949c46SKenneth D. Merry 	setup_t *setup;
967e949c46SKenneth D. Merry 
977e949c46SKenneth D. Merry 	/** Will be run if setup succeeds */
987e949c46SKenneth D. Merry 	testcase_t *test;
997e949c46SKenneth D. Merry 
100453130d9SPedro F. Giffuni 	/** Cleans up test data whether or not the setup succeeded */
1017e949c46SKenneth D. Merry 	teardown_t *teardown;
1027e949c46SKenneth D. Merry };
1037e949c46SKenneth D. Merry 
1047e949c46SKenneth D. Merry typedef struct test_fixture test_fixture_t;
1057e949c46SKenneth D. Merry 
1067e949c46SKenneth D. Merry static int	xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags);
1077e949c46SKenneth D. Merry static int	xnb_unit_test_runner(test_fixture_t const tests[], int ntests,
1087e949c46SKenneth D. Merry 				     char *buffer, size_t buflen);
1097e949c46SKenneth D. Merry 
1107e949c46SKenneth D. Merry static int __unused
null_setup(void)1117e949c46SKenneth D. Merry null_setup(void) { return 0; }
1127e949c46SKenneth D. Merry 
1137e949c46SKenneth D. Merry static void __unused
null_teardown(void)1147e949c46SKenneth D. Merry null_teardown(void) { }
1157e949c46SKenneth D. Merry 
1167e949c46SKenneth D. Merry static setup_t setup_pvt_data;
1177e949c46SKenneth D. Merry static teardown_t teardown_pvt_data;
1187e949c46SKenneth D. Merry static testcase_t xnb_ring2pkt_emptyring;
1197e949c46SKenneth D. Merry static testcase_t xnb_ring2pkt_1req;
1207e949c46SKenneth D. Merry static testcase_t xnb_ring2pkt_2req;
1217e949c46SKenneth D. Merry static testcase_t xnb_ring2pkt_3req;
1227e949c46SKenneth D. Merry static testcase_t xnb_ring2pkt_extra;
1237e949c46SKenneth D. Merry static testcase_t xnb_ring2pkt_partial;
1247e949c46SKenneth D. Merry static testcase_t xnb_ring2pkt_wraps;
1257e949c46SKenneth D. Merry static testcase_t xnb_txpkt2rsp_emptypkt;
1267e949c46SKenneth D. Merry static testcase_t xnb_txpkt2rsp_1req;
1277e949c46SKenneth D. Merry static testcase_t xnb_txpkt2rsp_extra;
1287e949c46SKenneth D. Merry static testcase_t xnb_txpkt2rsp_long;
1297e949c46SKenneth D. Merry static testcase_t xnb_txpkt2rsp_invalid;
1307e949c46SKenneth D. Merry static testcase_t xnb_txpkt2rsp_error;
1317e949c46SKenneth D. Merry static testcase_t xnb_txpkt2rsp_wraps;
1327e949c46SKenneth D. Merry static testcase_t xnb_pkt2mbufc_empty;
1337e949c46SKenneth D. Merry static testcase_t xnb_pkt2mbufc_short;
1347e949c46SKenneth D. Merry static testcase_t xnb_pkt2mbufc_csum;
1357e949c46SKenneth D. Merry static testcase_t xnb_pkt2mbufc_1cluster;
1367e949c46SKenneth D. Merry static testcase_t xnb_pkt2mbufc_largecluster;
1377e949c46SKenneth D. Merry static testcase_t xnb_pkt2mbufc_2cluster;
1387e949c46SKenneth D. Merry static testcase_t xnb_txpkt2gnttab_empty;
1397e949c46SKenneth D. Merry static testcase_t xnb_txpkt2gnttab_short;
1407e949c46SKenneth D. Merry static testcase_t xnb_txpkt2gnttab_2req;
1417e949c46SKenneth D. Merry static testcase_t xnb_txpkt2gnttab_2cluster;
1427e949c46SKenneth D. Merry static testcase_t xnb_update_mbufc_short;
1437e949c46SKenneth D. Merry static testcase_t xnb_update_mbufc_2req;
1447e949c46SKenneth D. Merry static testcase_t xnb_update_mbufc_2cluster;
1457e949c46SKenneth D. Merry static testcase_t xnb_mbufc2pkt_empty;
1467e949c46SKenneth D. Merry static testcase_t xnb_mbufc2pkt_short;
1477e949c46SKenneth D. Merry static testcase_t xnb_mbufc2pkt_1cluster;
1487e949c46SKenneth D. Merry static testcase_t xnb_mbufc2pkt_2short;
1497e949c46SKenneth D. Merry static testcase_t xnb_mbufc2pkt_long;
1507e949c46SKenneth D. Merry static testcase_t xnb_mbufc2pkt_extra;
1517e949c46SKenneth D. Merry static testcase_t xnb_mbufc2pkt_nospace;
1527e949c46SKenneth D. Merry static testcase_t xnb_rxpkt2gnttab_empty;
1537e949c46SKenneth D. Merry static testcase_t xnb_rxpkt2gnttab_short;
1547e949c46SKenneth D. Merry static testcase_t xnb_rxpkt2gnttab_2req;
1557e949c46SKenneth D. Merry static testcase_t xnb_rxpkt2rsp_empty;
1567e949c46SKenneth D. Merry static testcase_t xnb_rxpkt2rsp_short;
1577e949c46SKenneth D. Merry static testcase_t xnb_rxpkt2rsp_extra;
1587e949c46SKenneth D. Merry static testcase_t xnb_rxpkt2rsp_2short;
1597e949c46SKenneth D. Merry static testcase_t xnb_rxpkt2rsp_2slots;
1607e949c46SKenneth D. Merry static testcase_t xnb_rxpkt2rsp_copyerror;
161f909bbb4SGleb Smirnoff static testcase_t xnb_sscanf_llu;
162f909bbb4SGleb Smirnoff static testcase_t xnb_sscanf_lld;
163f909bbb4SGleb Smirnoff static testcase_t xnb_sscanf_hhu;
164f909bbb4SGleb Smirnoff static testcase_t xnb_sscanf_hhd;
165f909bbb4SGleb Smirnoff static testcase_t xnb_sscanf_hhn;
166f909bbb4SGleb Smirnoff 
167f909bbb4SGleb Smirnoff #if defined(INET) || defined(INET6)
1687e949c46SKenneth D. Merry /* TODO: add test cases for xnb_add_mbuf_cksum for IPV6 tcp and udp */
1697e949c46SKenneth D. Merry static testcase_t xnb_add_mbuf_cksum_arp;
1707e949c46SKenneth D. Merry static testcase_t xnb_add_mbuf_cksum_tcp;
1717e949c46SKenneth D. Merry static testcase_t xnb_add_mbuf_cksum_udp;
1727e949c46SKenneth D. Merry static testcase_t xnb_add_mbuf_cksum_icmp;
1737e949c46SKenneth D. Merry static testcase_t xnb_add_mbuf_cksum_tcp_swcksum;
174f909bbb4SGleb Smirnoff static void	xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len,
175f909bbb4SGleb Smirnoff 				   uint16_t ip_id, uint16_t ip_p,
176f909bbb4SGleb Smirnoff 				   uint16_t ip_off, uint16_t ip_sum);
177f909bbb4SGleb Smirnoff static void	xnb_fill_tcp(struct mbuf *m);
178f909bbb4SGleb Smirnoff #endif /* INET || INET6 */
1797e949c46SKenneth D. Merry 
1807e949c46SKenneth D. Merry /** Private data used by unit tests */
1817e949c46SKenneth D. Merry static struct {
1827e949c46SKenneth D. Merry 	gnttab_copy_table 	gnttab;
1837e949c46SKenneth D. Merry 	netif_rx_back_ring_t	rxb;
1847e949c46SKenneth D. Merry 	netif_rx_front_ring_t	rxf;
1857e949c46SKenneth D. Merry 	netif_tx_back_ring_t	txb;
1867e949c46SKenneth D. Merry 	netif_tx_front_ring_t	txf;
1877e949c46SKenneth D. Merry 	struct ifnet*		ifp;
1887e949c46SKenneth D. Merry 	netif_rx_sring_t*	rxs;
1897e949c46SKenneth D. Merry 	netif_tx_sring_t*	txs;
1907e949c46SKenneth D. Merry } xnb_unit_pvt;
1917e949c46SKenneth D. Merry 
safe_m_freem(struct mbuf ** ppMbuf)1927e949c46SKenneth D. Merry static inline void safe_m_freem(struct mbuf **ppMbuf) {
1937e949c46SKenneth D. Merry 	if (*ppMbuf != NULL) {
1947e949c46SKenneth D. Merry 		m_freem(*ppMbuf);
1957e949c46SKenneth D. Merry 		*ppMbuf = NULL;
1967e949c46SKenneth D. Merry 	}
1977e949c46SKenneth D. Merry }
1987e949c46SKenneth D. Merry 
1997e949c46SKenneth D. Merry /**
2007e949c46SKenneth D. Merry  * The unit test runner.  It will run every supplied test and return an
2017e949c46SKenneth D. Merry  * output message as a string
2027e949c46SKenneth D. Merry  * \param tests		An array of tests.  Every test will be attempted.
2037e949c46SKenneth D. Merry  * \param ntests	The length of tests
2047e949c46SKenneth D. Merry  * \param buffer	Return storage for the result string
2057e949c46SKenneth D. Merry  * \param buflen	The length of buffer
2067e949c46SKenneth D. Merry  * \return		The number of tests that failed
2077e949c46SKenneth D. Merry  */
2087e949c46SKenneth D. Merry static int
xnb_unit_test_runner(test_fixture_t const tests[],int ntests,char * buffer,size_t buflen)2097e949c46SKenneth D. Merry xnb_unit_test_runner(test_fixture_t const tests[], int ntests, char *buffer,
2107e949c46SKenneth D. Merry     		     size_t buflen)
2117e949c46SKenneth D. Merry {
2127e949c46SKenneth D. Merry 	int i;
2137e949c46SKenneth D. Merry 	int n_passes;
2147e949c46SKenneth D. Merry 	int n_failures = 0;
2157e949c46SKenneth D. Merry 
2167e949c46SKenneth D. Merry 	for (i = 0; i < ntests; i++) {
2177e949c46SKenneth D. Merry 		int error = tests[i].setup();
2187e949c46SKenneth D. Merry 		if (error != 0) {
2197e949c46SKenneth D. Merry 			SNCATF(buffer, buflen,
2207e949c46SKenneth D. Merry 			    "Setup failed for test idx %d\n", i);
2217e949c46SKenneth D. Merry 			n_failures++;
2227e949c46SKenneth D. Merry 		} else {
2237e949c46SKenneth D. Merry 			size_t new_chars;
2247e949c46SKenneth D. Merry 
2257e949c46SKenneth D. Merry 			tests[i].test(buffer, buflen);
2267e949c46SKenneth D. Merry 			new_chars = strnlen(buffer, buflen);
2277e949c46SKenneth D. Merry 			buffer += new_chars;
2287e949c46SKenneth D. Merry 			buflen -= new_chars;
2297e949c46SKenneth D. Merry 
2307e949c46SKenneth D. Merry 			if (new_chars > 0) {
2317e949c46SKenneth D. Merry 				n_failures++;
2327e949c46SKenneth D. Merry 			}
2337e949c46SKenneth D. Merry 		}
2347e949c46SKenneth D. Merry 		tests[i].teardown();
2357e949c46SKenneth D. Merry 	}
2367e949c46SKenneth D. Merry 
2377e949c46SKenneth D. Merry 	n_passes = ntests - n_failures;
2387e949c46SKenneth D. Merry 	if (n_passes > 0) {
2397e949c46SKenneth D. Merry 		SNCATF(buffer, buflen, "%d Tests Passed\n", n_passes);
2407e949c46SKenneth D. Merry 	}
2417e949c46SKenneth D. Merry 	if (n_failures > 0) {
2427e949c46SKenneth D. Merry 		SNCATF(buffer, buflen, "%d Tests FAILED\n", n_failures);
2437e949c46SKenneth D. Merry 	}
2447e949c46SKenneth D. Merry 
2457e949c46SKenneth D. Merry 	return n_failures;
2467e949c46SKenneth D. Merry }
2477e949c46SKenneth D. Merry 
2487e949c46SKenneth D. Merry /** Number of unit tests.  Must match the length of the tests array below */
2497e949c46SKenneth D. Merry #define	TOTAL_TESTS	(53)
2507e949c46SKenneth D. Merry /**
2517e949c46SKenneth D. Merry  * Max memory available for returning results.  400 chars/test should give
2527e949c46SKenneth D. Merry  * enough space for a five line error message for every test
2537e949c46SKenneth D. Merry  */
2547e949c46SKenneth D. Merry #define	TOTAL_BUFLEN	(400 * TOTAL_TESTS + 2)
2557e949c46SKenneth D. Merry 
2567e949c46SKenneth D. Merry /**
2577e949c46SKenneth D. Merry  * Called from userspace by a sysctl.  Runs all internal unit tests, and
2587e949c46SKenneth D. Merry  * returns the results to userspace as a string
2597e949c46SKenneth D. Merry  * \param oidp	unused
2607e949c46SKenneth D. Merry  * \param arg1	pointer to an xnb_softc for a specific xnb device
2617e949c46SKenneth D. Merry  * \param arg2	unused
2627e949c46SKenneth D. Merry  * \param req	sysctl access structure
2637e949c46SKenneth D. Merry  * \return a string via the special SYSCTL_OUT macro.
2647e949c46SKenneth D. Merry  */
2657e949c46SKenneth D. Merry 
2667e949c46SKenneth D. Merry static int
xnb_unit_test_main(SYSCTL_HANDLER_ARGS)2677e949c46SKenneth D. Merry xnb_unit_test_main(SYSCTL_HANDLER_ARGS) {
2687e949c46SKenneth D. Merry 	test_fixture_t const tests[TOTAL_TESTS] = {
2697e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_ring2pkt_emptyring, teardown_pvt_data},
2707e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_ring2pkt_1req, teardown_pvt_data},
2717e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_ring2pkt_2req, teardown_pvt_data},
2727e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_ring2pkt_3req, teardown_pvt_data},
2737e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_ring2pkt_extra, teardown_pvt_data},
2747e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_ring2pkt_partial, teardown_pvt_data},
2757e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_ring2pkt_wraps, teardown_pvt_data},
2767e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2rsp_emptypkt, teardown_pvt_data},
2777e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2rsp_1req, teardown_pvt_data},
2787e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2rsp_extra, teardown_pvt_data},
2797e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2rsp_long, teardown_pvt_data},
2807e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2rsp_invalid, teardown_pvt_data},
2817e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2rsp_error, teardown_pvt_data},
2827e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2rsp_wraps, teardown_pvt_data},
2837e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_pkt2mbufc_empty, teardown_pvt_data},
2847e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_pkt2mbufc_short, teardown_pvt_data},
2857e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_pkt2mbufc_csum, teardown_pvt_data},
2867e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_pkt2mbufc_1cluster, teardown_pvt_data},
2877e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_pkt2mbufc_largecluster, teardown_pvt_data},
2887e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_pkt2mbufc_2cluster, teardown_pvt_data},
2897e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2gnttab_empty, teardown_pvt_data},
2907e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2gnttab_short, teardown_pvt_data},
2917e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2gnttab_2req, teardown_pvt_data},
2927e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_txpkt2gnttab_2cluster, teardown_pvt_data},
2937e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_update_mbufc_short, teardown_pvt_data},
2947e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_update_mbufc_2req, teardown_pvt_data},
2957e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_update_mbufc_2cluster, teardown_pvt_data},
2967e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_mbufc2pkt_empty, teardown_pvt_data},
2977e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_mbufc2pkt_short, teardown_pvt_data},
2987e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_mbufc2pkt_1cluster, teardown_pvt_data},
2997e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_mbufc2pkt_2short, teardown_pvt_data},
3007e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_mbufc2pkt_long, teardown_pvt_data},
3017e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_mbufc2pkt_extra, teardown_pvt_data},
3027e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_mbufc2pkt_nospace, teardown_pvt_data},
3037e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_rxpkt2gnttab_empty, teardown_pvt_data},
3047e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_rxpkt2gnttab_short, teardown_pvt_data},
3057e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_rxpkt2gnttab_2req, teardown_pvt_data},
3067e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_rxpkt2rsp_empty, teardown_pvt_data},
3077e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_rxpkt2rsp_short, teardown_pvt_data},
3087e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_rxpkt2rsp_extra, teardown_pvt_data},
3097e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_rxpkt2rsp_2short, teardown_pvt_data},
3107e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_rxpkt2rsp_2slots, teardown_pvt_data},
3117e949c46SKenneth D. Merry 		{setup_pvt_data, xnb_rxpkt2rsp_copyerror, teardown_pvt_data},
312f909bbb4SGleb Smirnoff #if defined(INET) || defined(INET6)
3137e949c46SKenneth D. Merry 		{null_setup, xnb_add_mbuf_cksum_arp, null_teardown},
3147e949c46SKenneth D. Merry 		{null_setup, xnb_add_mbuf_cksum_icmp, null_teardown},
3157e949c46SKenneth D. Merry 		{null_setup, xnb_add_mbuf_cksum_tcp, null_teardown},
3167e949c46SKenneth D. Merry 		{null_setup, xnb_add_mbuf_cksum_tcp_swcksum, null_teardown},
3177e949c46SKenneth D. Merry 		{null_setup, xnb_add_mbuf_cksum_udp, null_teardown},
318f909bbb4SGleb Smirnoff #endif
3197e949c46SKenneth D. Merry 		{null_setup, xnb_sscanf_hhd, null_teardown},
3207e949c46SKenneth D. Merry 		{null_setup, xnb_sscanf_hhu, null_teardown},
3217e949c46SKenneth D. Merry 		{null_setup, xnb_sscanf_lld, null_teardown},
3227e949c46SKenneth D. Merry 		{null_setup, xnb_sscanf_llu, null_teardown},
3237e949c46SKenneth D. Merry 		{null_setup, xnb_sscanf_hhn, null_teardown},
3247e949c46SKenneth D. Merry 	};
3257e949c46SKenneth D. Merry 	/**
3267e949c46SKenneth D. Merry 	 * results is static so that the data will persist after this function
3277e949c46SKenneth D. Merry 	 * returns.  The sysctl code expects us to return a constant string.
3287e949c46SKenneth D. Merry 	 * \todo: the static variable is not thread safe.  Put a mutex around
3297e949c46SKenneth D. Merry 	 * it.
3307e949c46SKenneth D. Merry 	 */
3317e949c46SKenneth D. Merry 	static char results[TOTAL_BUFLEN];
3327e949c46SKenneth D. Merry 
3337e949c46SKenneth D. Merry 	/* empty the result strings */
3347e949c46SKenneth D. Merry 	results[0] = 0;
3357e949c46SKenneth D. Merry 	xnb_unit_test_runner(tests, TOTAL_TESTS, results, TOTAL_BUFLEN);
3367e949c46SKenneth D. Merry 
3377e949c46SKenneth D. Merry 	return (SYSCTL_OUT(req, results, strnlen(results, TOTAL_BUFLEN)));
3387e949c46SKenneth D. Merry }
3397e949c46SKenneth D. Merry 
3407e949c46SKenneth D. Merry static int
setup_pvt_data(void)3417e949c46SKenneth D. Merry setup_pvt_data(void)
3427e949c46SKenneth D. Merry {
3437e949c46SKenneth D. Merry 	int error = 0;
3447e949c46SKenneth D. Merry 
3457e949c46SKenneth D. Merry 	bzero(xnb_unit_pvt.gnttab, sizeof(xnb_unit_pvt.gnttab));
3467e949c46SKenneth D. Merry 
3477e949c46SKenneth D. Merry 	xnb_unit_pvt.txs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
3487e949c46SKenneth D. Merry 	if (xnb_unit_pvt.txs != NULL) {
3497e949c46SKenneth D. Merry 		SHARED_RING_INIT(xnb_unit_pvt.txs);
3507e949c46SKenneth D. Merry 		BACK_RING_INIT(&xnb_unit_pvt.txb, xnb_unit_pvt.txs, PAGE_SIZE);
3517e949c46SKenneth D. Merry 		FRONT_RING_INIT(&xnb_unit_pvt.txf, xnb_unit_pvt.txs, PAGE_SIZE);
3527e949c46SKenneth D. Merry 	} else {
3537e949c46SKenneth D. Merry 		error = 1;
3547e949c46SKenneth D. Merry 	}
3557e949c46SKenneth D. Merry 
3567e949c46SKenneth D. Merry 	xnb_unit_pvt.ifp = if_alloc(IFT_ETHER);
3577e949c46SKenneth D. Merry 	if (xnb_unit_pvt.ifp == NULL) {
3587e949c46SKenneth D. Merry 		error = 1;
3597e949c46SKenneth D. Merry 	}
3607e949c46SKenneth D. Merry 
3617e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
3627e949c46SKenneth D. Merry 	if (xnb_unit_pvt.rxs != NULL) {
3637e949c46SKenneth D. Merry 		SHARED_RING_INIT(xnb_unit_pvt.rxs);
3647e949c46SKenneth D. Merry 		BACK_RING_INIT(&xnb_unit_pvt.rxb, xnb_unit_pvt.rxs, PAGE_SIZE);
3657e949c46SKenneth D. Merry 		FRONT_RING_INIT(&xnb_unit_pvt.rxf, xnb_unit_pvt.rxs, PAGE_SIZE);
3667e949c46SKenneth D. Merry 	} else {
3677e949c46SKenneth D. Merry 		error = 1;
3687e949c46SKenneth D. Merry 	}
3697e949c46SKenneth D. Merry 
3707e949c46SKenneth D. Merry 	return error;
3717e949c46SKenneth D. Merry }
3727e949c46SKenneth D. Merry 
3737e949c46SKenneth D. Merry static void
teardown_pvt_data(void)3747e949c46SKenneth D. Merry teardown_pvt_data(void)
3757e949c46SKenneth D. Merry {
3767e949c46SKenneth D. Merry 	if (xnb_unit_pvt.txs != NULL) {
3777e949c46SKenneth D. Merry 		free(xnb_unit_pvt.txs, M_XENNETBACK);
3787e949c46SKenneth D. Merry 	}
3797e949c46SKenneth D. Merry 	if (xnb_unit_pvt.rxs != NULL) {
3807e949c46SKenneth D. Merry 		free(xnb_unit_pvt.rxs, M_XENNETBACK);
3817e949c46SKenneth D. Merry 	}
3827e949c46SKenneth D. Merry 	if (xnb_unit_pvt.ifp != NULL) {
3837e949c46SKenneth D. Merry 		if_free(xnb_unit_pvt.ifp);
3847e949c46SKenneth D. Merry 	}
3857e949c46SKenneth D. Merry }
3867e949c46SKenneth D. Merry 
3877e949c46SKenneth D. Merry /**
3887e949c46SKenneth D. Merry  * Verify that xnb_ring2pkt will not consume any requests from an empty ring
3897e949c46SKenneth D. Merry  */
3907e949c46SKenneth D. Merry static void
xnb_ring2pkt_emptyring(char * buffer,size_t buflen)3917e949c46SKenneth D. Merry xnb_ring2pkt_emptyring(char *buffer, size_t buflen)
3927e949c46SKenneth D. Merry {
3937e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
3947e949c46SKenneth D. Merry 	int num_consumed;
3957e949c46SKenneth D. Merry 
3967e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
3977e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
3987e949c46SKenneth D. Merry 	XNB_ASSERT(num_consumed == 0);
3997e949c46SKenneth D. Merry }
4007e949c46SKenneth D. Merry 
4017e949c46SKenneth D. Merry /**
4027e949c46SKenneth D. Merry  * Verify that xnb_ring2pkt can convert a single request packet correctly
4037e949c46SKenneth D. Merry  */
4047e949c46SKenneth D. Merry static void
xnb_ring2pkt_1req(char * buffer,size_t buflen)4057e949c46SKenneth D. Merry xnb_ring2pkt_1req(char *buffer, size_t buflen)
4067e949c46SKenneth D. Merry {
4077e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
4087e949c46SKenneth D. Merry 	int num_consumed;
4097e949c46SKenneth D. Merry 	struct netif_tx_request *req;
4107e949c46SKenneth D. Merry 
4117e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
4127e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
4137e949c46SKenneth D. Merry 
4147e949c46SKenneth D. Merry 	req->flags = 0;
4157e949c46SKenneth D. Merry 	req->size = 69;	/* arbitrary number for test */
4167e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
4177e949c46SKenneth D. Merry 
4187e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
4197e949c46SKenneth D. Merry 
4207e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
4217e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
4227e949c46SKenneth D. Merry 	XNB_ASSERT(num_consumed == 1);
4237e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.size == 69);
4247e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car_size == 69);
4257e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.flags == 0);
4267e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
4277e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.list_len == 1);
4287e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car == 0);
4297e949c46SKenneth D. Merry }
4307e949c46SKenneth D. Merry 
4317e949c46SKenneth D. Merry /**
4327e949c46SKenneth D. Merry  * Verify that xnb_ring2pkt can convert a two request packet correctly.
4337e949c46SKenneth D. Merry  * This tests handling of the MORE_DATA flag and cdr
4347e949c46SKenneth D. Merry  */
4357e949c46SKenneth D. Merry static void
xnb_ring2pkt_2req(char * buffer,size_t buflen)4367e949c46SKenneth D. Merry xnb_ring2pkt_2req(char *buffer, size_t buflen)
4377e949c46SKenneth D. Merry {
4387e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
4397e949c46SKenneth D. Merry 	int num_consumed;
4407e949c46SKenneth D. Merry 	struct netif_tx_request *req;
4417e949c46SKenneth D. Merry 	RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
4427e949c46SKenneth D. Merry 
4437e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
4447e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
4457e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
4467e949c46SKenneth D. Merry 	req->size = 100;
4477e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
4487e949c46SKenneth D. Merry 
4497e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
4507e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
4517e949c46SKenneth D. Merry 	req->flags = 0;
4527e949c46SKenneth D. Merry 	req->size = 40;
4537e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
4547e949c46SKenneth D. Merry 
4557e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
4567e949c46SKenneth D. Merry 
4577e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
4587e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
4597e949c46SKenneth D. Merry 	XNB_ASSERT(num_consumed == 2);
4607e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.size == 100);
4617e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car_size == 60);
4627e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.flags == 0);
4637e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
4647e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.list_len == 2);
4657e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car == start_idx);
4667e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.cdr == start_idx + 1);
4677e949c46SKenneth D. Merry }
4687e949c46SKenneth D. Merry 
4697e949c46SKenneth D. Merry /**
4707e949c46SKenneth D. Merry  * Verify that xnb_ring2pkt can convert a three request packet correctly
4717e949c46SKenneth D. Merry  */
4727e949c46SKenneth D. Merry static void
xnb_ring2pkt_3req(char * buffer,size_t buflen)4737e949c46SKenneth D. Merry xnb_ring2pkt_3req(char *buffer, size_t buflen)
4747e949c46SKenneth D. Merry {
4757e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
4767e949c46SKenneth D. Merry 	int num_consumed;
4777e949c46SKenneth D. Merry 	struct netif_tx_request *req;
4787e949c46SKenneth D. Merry 	RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
4797e949c46SKenneth D. Merry 
4807e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
4817e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
4827e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
4837e949c46SKenneth D. Merry 	req->size = 200;
4847e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
4857e949c46SKenneth D. Merry 
4867e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
4877e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
4887e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
4897e949c46SKenneth D. Merry 	req->size = 40;
4907e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
4917e949c46SKenneth D. Merry 
4927e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
4937e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
4947e949c46SKenneth D. Merry 	req->flags = 0;
4957e949c46SKenneth D. Merry 	req->size = 50;
4967e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
4977e949c46SKenneth D. Merry 
4987e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
4997e949c46SKenneth D. Merry 
5007e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
5017e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
5027e949c46SKenneth D. Merry 	XNB_ASSERT(num_consumed == 3);
5037e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.size == 200);
5047e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car_size == 110);
5057e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.flags == 0);
5067e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
5077e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.list_len == 3);
5087e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car == start_idx);
5097e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.cdr == start_idx + 1);
5107e949c46SKenneth D. Merry 	XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
5117e949c46SKenneth D. Merry }
5127e949c46SKenneth D. Merry 
5137e949c46SKenneth D. Merry /**
5147e949c46SKenneth D. Merry  * Verify that xnb_ring2pkt can read extra inf
5157e949c46SKenneth D. Merry  */
5167e949c46SKenneth D. Merry static void
xnb_ring2pkt_extra(char * buffer,size_t buflen)5177e949c46SKenneth D. Merry xnb_ring2pkt_extra(char *buffer, size_t buflen)
5187e949c46SKenneth D. Merry {
5197e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
5207e949c46SKenneth D. Merry 	int num_consumed;
5217e949c46SKenneth D. Merry 	struct netif_tx_request *req;
5227e949c46SKenneth D. Merry 	struct netif_extra_info *ext;
5237e949c46SKenneth D. Merry 	RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
5247e949c46SKenneth D. Merry 
5257e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
5267e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
5277e949c46SKenneth D. Merry 	req->flags = NETTXF_extra_info | NETTXF_more_data;
5287e949c46SKenneth D. Merry 	req->size = 150;
5297e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
5307e949c46SKenneth D. Merry 
5317e949c46SKenneth D. Merry 	ext = (struct netif_extra_info*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
5327e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
5337e949c46SKenneth D. Merry 	ext->flags = 0;
5347e949c46SKenneth D. Merry 	ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
5357e949c46SKenneth D. Merry 	ext->u.gso.size = 250;
5367e949c46SKenneth D. Merry 	ext->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
5377e949c46SKenneth D. Merry 	ext->u.gso.features = 0;
5387e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
5397e949c46SKenneth D. Merry 
5407e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
5417e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
5427e949c46SKenneth D. Merry 	req->flags = 0;
5437e949c46SKenneth D. Merry 	req->size = 50;
5447e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
5457e949c46SKenneth D. Merry 
5467e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
5477e949c46SKenneth D. Merry 
5487e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
5497e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
5507e949c46SKenneth D. Merry 	XNB_ASSERT(num_consumed == 3);
5517e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.extra.flags == 0);
5527e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
5537e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.extra.u.gso.size == 250);
5547e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.extra.u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4);
5557e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.size == 150);
5567e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car_size == 100);
5577e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.flags == NETTXF_extra_info);
5587e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
5597e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.list_len == 2);
5607e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car == start_idx);
5617e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.cdr == start_idx + 2);
5627e949c46SKenneth D. Merry 	XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr) == req);
5637e949c46SKenneth D. Merry }
5647e949c46SKenneth D. Merry 
5657e949c46SKenneth D. Merry /**
5667e949c46SKenneth D. Merry  * Verify that xnb_ring2pkt will consume no requests if the entire packet is
5677e949c46SKenneth D. Merry  * not yet in the ring
5687e949c46SKenneth D. Merry  */
5697e949c46SKenneth D. Merry static void
xnb_ring2pkt_partial(char * buffer,size_t buflen)5707e949c46SKenneth D. Merry xnb_ring2pkt_partial(char *buffer, size_t buflen)
5717e949c46SKenneth D. Merry {
5727e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
5737e949c46SKenneth D. Merry 	int num_consumed;
5747e949c46SKenneth D. Merry 	struct netif_tx_request *req;
5757e949c46SKenneth D. Merry 
5767e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
5777e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
5787e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
5797e949c46SKenneth D. Merry 	req->size = 150;
5807e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
5817e949c46SKenneth D. Merry 
5827e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
5837e949c46SKenneth D. Merry 
5847e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
5857e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
5867e949c46SKenneth D. Merry 	XNB_ASSERT(num_consumed == 0);
5877e949c46SKenneth D. Merry 	XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
5887e949c46SKenneth D. Merry }
5897e949c46SKenneth D. Merry 
5907e949c46SKenneth D. Merry /**
5917e949c46SKenneth D. Merry  * Verity that xnb_ring2pkt can read a packet whose requests wrap around
5927e949c46SKenneth D. Merry  * the end of the ring
5937e949c46SKenneth D. Merry  */
5947e949c46SKenneth D. Merry static void
xnb_ring2pkt_wraps(char * buffer,size_t buflen)5957e949c46SKenneth D. Merry xnb_ring2pkt_wraps(char *buffer, size_t buflen)
5967e949c46SKenneth D. Merry {
5977e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
5987e949c46SKenneth D. Merry 	int num_consumed;
5997e949c46SKenneth D. Merry 	struct netif_tx_request *req;
6007e949c46SKenneth D. Merry 	unsigned int rsize;
6017e949c46SKenneth D. Merry 
6027e949c46SKenneth D. Merry 	/*
6037e949c46SKenneth D. Merry 	 * Manually tweak the ring indices to create a ring with no responses
6047e949c46SKenneth D. Merry 	 * and the next request slot at position 2 from the end
6057e949c46SKenneth D. Merry 	 */
6067e949c46SKenneth D. Merry 	rsize = RING_SIZE(&xnb_unit_pvt.txf);
6077e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
6087e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.rsp_cons = rsize - 2;
6097e949c46SKenneth D. Merry 	xnb_unit_pvt.txs->req_prod = rsize - 2;
6107e949c46SKenneth D. Merry 	xnb_unit_pvt.txs->req_event = rsize - 1;
6117e949c46SKenneth D. Merry 	xnb_unit_pvt.txs->rsp_prod = rsize - 2;
6127e949c46SKenneth D. Merry 	xnb_unit_pvt.txs->rsp_event = rsize - 1;
6137e949c46SKenneth D. Merry 	xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
6147e949c46SKenneth D. Merry 	xnb_unit_pvt.txb.req_cons = rsize - 2;
6157e949c46SKenneth D. Merry 
6167e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
6177e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
6187e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
6197e949c46SKenneth D. Merry 	req->size = 550;
6207e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
6217e949c46SKenneth D. Merry 
6227e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
6237e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
6247e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
6257e949c46SKenneth D. Merry 	req->size = 100;
6267e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
6277e949c46SKenneth D. Merry 
6287e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
6297e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
6307e949c46SKenneth D. Merry 	req->flags = 0;
6317e949c46SKenneth D. Merry 	req->size = 50;
6327e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
6337e949c46SKenneth D. Merry 
6347e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
6357e949c46SKenneth D. Merry 
6367e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
6377e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
6387e949c46SKenneth D. Merry 	XNB_ASSERT(num_consumed == 3);
6397e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
6407e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.list_len == 3);
6417e949c46SKenneth D. Merry 	XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
6427e949c46SKenneth D. Merry }
6437e949c46SKenneth D. Merry 
6447e949c46SKenneth D. Merry /**
6457e949c46SKenneth D. Merry  * xnb_txpkt2rsp should do nothing for an empty packet
6467e949c46SKenneth D. Merry  */
6477e949c46SKenneth D. Merry static void
xnb_txpkt2rsp_emptypkt(char * buffer,size_t buflen)6487e949c46SKenneth D. Merry xnb_txpkt2rsp_emptypkt(char *buffer, size_t buflen)
6497e949c46SKenneth D. Merry {
6507e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
6517e949c46SKenneth D. Merry 	netif_tx_back_ring_t txb_backup = xnb_unit_pvt.txb;
6527e949c46SKenneth D. Merry 	netif_tx_sring_t txs_backup = *xnb_unit_pvt.txs;
6537e949c46SKenneth D. Merry 	pkt.list_len = 0;
6547e949c46SKenneth D. Merry 
6557e949c46SKenneth D. Merry 	/* must call xnb_ring2pkt just to intialize pkt */
6567650d4b6SJohn Baldwin 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
6577e949c46SKenneth D. Merry 	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
6587e949c46SKenneth D. Merry 	XNB_ASSERT(
6597e949c46SKenneth D. Merry 	    memcmp(&txb_backup, &xnb_unit_pvt.txb, sizeof(txb_backup)) == 0);
6607e949c46SKenneth D. Merry 	XNB_ASSERT(
6617e949c46SKenneth D. Merry 	    memcmp(&txs_backup, xnb_unit_pvt.txs, sizeof(txs_backup)) == 0);
6627e949c46SKenneth D. Merry }
6637e949c46SKenneth D. Merry 
6647e949c46SKenneth D. Merry /**
6657e949c46SKenneth D. Merry  * xnb_txpkt2rsp responding to one request
6667e949c46SKenneth D. Merry  */
6677e949c46SKenneth D. Merry static void
xnb_txpkt2rsp_1req(char * buffer,size_t buflen)6687e949c46SKenneth D. Merry xnb_txpkt2rsp_1req(char *buffer, size_t buflen)
6697e949c46SKenneth D. Merry {
6707e949c46SKenneth D. Merry 	uint16_t num_consumed;
6717e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
6727e949c46SKenneth D. Merry 	struct netif_tx_request *req;
6737e949c46SKenneth D. Merry 	struct netif_tx_response *rsp;
6747e949c46SKenneth D. Merry 
6757e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
6767e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
6777e949c46SKenneth D. Merry 	req->size = 1000;
6787e949c46SKenneth D. Merry 	req->flags = 0;
6797e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
6807e949c46SKenneth D. Merry 
6817e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
6827e949c46SKenneth D. Merry 
6837e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
6847e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
6857e949c46SKenneth D. Merry 	xnb_unit_pvt.txb.req_cons += num_consumed;
6867e949c46SKenneth D. Merry 
6877e949c46SKenneth D. Merry 	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
6887e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
6897e949c46SKenneth D. Merry 
6907e949c46SKenneth D. Merry 	XNB_ASSERT(
6917e949c46SKenneth D. Merry 	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
6927e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == req->id);
6937e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
6947e949c46SKenneth D. Merry };
6957e949c46SKenneth D. Merry 
6967e949c46SKenneth D. Merry /**
6977e949c46SKenneth D. Merry  * xnb_txpkt2rsp responding to 1 data request and 1 extra info
6987e949c46SKenneth D. Merry  */
6997e949c46SKenneth D. Merry static void
xnb_txpkt2rsp_extra(char * buffer,size_t buflen)7007e949c46SKenneth D. Merry xnb_txpkt2rsp_extra(char *buffer, size_t buflen)
7017e949c46SKenneth D. Merry {
7027e949c46SKenneth D. Merry 	uint16_t num_consumed;
7037e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
7047e949c46SKenneth D. Merry 	struct netif_tx_request *req;
7057e949c46SKenneth D. Merry 	netif_extra_info_t *ext;
7067e949c46SKenneth D. Merry 	struct netif_tx_response *rsp;
7077e949c46SKenneth D. Merry 
7087e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
7097e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
7107e949c46SKenneth D. Merry 	req->size = 1000;
7117e949c46SKenneth D. Merry 	req->flags = NETTXF_extra_info;
7127e949c46SKenneth D. Merry 	req->id = 69;
7137e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
7147e949c46SKenneth D. Merry 
7157e949c46SKenneth D. Merry 	ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
7167e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
7177e949c46SKenneth D. Merry 	ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
7187e949c46SKenneth D. Merry 	ext->flags = 0;
7197e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
7207e949c46SKenneth D. Merry 
7217e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
7227e949c46SKenneth D. Merry 
7237e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
7247e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
7257e949c46SKenneth D. Merry 	xnb_unit_pvt.txb.req_cons += num_consumed;
7267e949c46SKenneth D. Merry 
7277e949c46SKenneth D. Merry 	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
7287e949c46SKenneth D. Merry 
7297e949c46SKenneth D. Merry 	XNB_ASSERT(
7307e949c46SKenneth D. Merry 	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
7317e949c46SKenneth D. Merry 
7327e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
7337e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == req->id);
7347e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
7357e949c46SKenneth D. Merry 
7367e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
7377e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.rsp_cons + 1);
7387e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
7397e949c46SKenneth D. Merry };
7407e949c46SKenneth D. Merry 
7417e949c46SKenneth D. Merry /**
7427e949c46SKenneth D. Merry  * xnb_pkg2rsp responding to 3 data requests and 1 extra info
7437e949c46SKenneth D. Merry  */
7447e949c46SKenneth D. Merry static void
xnb_txpkt2rsp_long(char * buffer,size_t buflen)7457e949c46SKenneth D. Merry xnb_txpkt2rsp_long(char *buffer, size_t buflen)
7467e949c46SKenneth D. Merry {
7477e949c46SKenneth D. Merry 	uint16_t num_consumed;
7487e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
7497e949c46SKenneth D. Merry 	struct netif_tx_request *req;
7507e949c46SKenneth D. Merry 	netif_extra_info_t *ext;
7517e949c46SKenneth D. Merry 	struct netif_tx_response *rsp;
7527e949c46SKenneth D. Merry 
7537e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
7547e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
7557e949c46SKenneth D. Merry 	req->size = 1000;
7567e949c46SKenneth D. Merry 	req->flags = NETTXF_extra_info | NETTXF_more_data;
7577e949c46SKenneth D. Merry 	req->id = 254;
7587e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
7597e949c46SKenneth D. Merry 
7607e949c46SKenneth D. Merry 	ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
7617e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
7627e949c46SKenneth D. Merry 	ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
7637e949c46SKenneth D. Merry 	ext->flags = 0;
7647e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
7657e949c46SKenneth D. Merry 
7667e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
7677e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
7687e949c46SKenneth D. Merry 	req->size = 300;
7697e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
7707e949c46SKenneth D. Merry 	req->id = 1034;
7717e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
7727e949c46SKenneth D. Merry 
7737e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
7747e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
7757e949c46SKenneth D. Merry 	req->size = 400;
7767e949c46SKenneth D. Merry 	req->flags = 0;
7777e949c46SKenneth D. Merry 	req->id = 34;
7787e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
7797e949c46SKenneth D. Merry 
7807e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
7817e949c46SKenneth D. Merry 
7827e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
7837e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
7847e949c46SKenneth D. Merry 	xnb_unit_pvt.txb.req_cons += num_consumed;
7857e949c46SKenneth D. Merry 
7867e949c46SKenneth D. Merry 	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
7877e949c46SKenneth D. Merry 
7887e949c46SKenneth D. Merry 	XNB_ASSERT(
7897e949c46SKenneth D. Merry 	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
7907e949c46SKenneth D. Merry 
7917e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
7927e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id ==
7937e949c46SKenneth D. Merry 	    RING_GET_REQUEST(&xnb_unit_pvt.txf, 0)->id);
7947e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
7957e949c46SKenneth D. Merry 
7967e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
7977e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.rsp_cons + 1);
7987e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
7997e949c46SKenneth D. Merry 
8007e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
8017e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.rsp_cons + 2);
8027e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id ==
8037e949c46SKenneth D. Merry 	    RING_GET_REQUEST(&xnb_unit_pvt.txf, 2)->id);
8047e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
8057e949c46SKenneth D. Merry 
8067e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
8077e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.rsp_cons + 3);
8087e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id ==
8097e949c46SKenneth D. Merry 	    RING_GET_REQUEST(&xnb_unit_pvt.txf, 3)->id);
8107e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
8117e949c46SKenneth D. Merry }
8127e949c46SKenneth D. Merry 
8137e949c46SKenneth D. Merry /**
8147e949c46SKenneth D. Merry  * xnb_txpkt2rsp responding to an invalid packet.
8157e949c46SKenneth D. Merry  * Note: this test will result in an error message being printed to the console
8167e949c46SKenneth D. Merry  * such as:
8177e949c46SKenneth D. Merry  * xnb(xnb_ring2pkt:1306): Unknown extra info type 255.  Discarding packet
8187e949c46SKenneth D. Merry  */
8197e949c46SKenneth D. Merry static void
xnb_txpkt2rsp_invalid(char * buffer,size_t buflen)8207e949c46SKenneth D. Merry xnb_txpkt2rsp_invalid(char *buffer, size_t buflen)
8217e949c46SKenneth D. Merry {
8227e949c46SKenneth D. Merry 	uint16_t num_consumed;
8237e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
8247e949c46SKenneth D. Merry 	struct netif_tx_request *req;
8257e949c46SKenneth D. Merry 	netif_extra_info_t *ext;
8267e949c46SKenneth D. Merry 	struct netif_tx_response *rsp;
8277e949c46SKenneth D. Merry 
8287e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
8297e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
8307e949c46SKenneth D. Merry 	req->size = 1000;
8317e949c46SKenneth D. Merry 	req->flags = NETTXF_extra_info;
8327e949c46SKenneth D. Merry 	req->id = 69;
8337e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
8347e949c46SKenneth D. Merry 
8357e949c46SKenneth D. Merry 	ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
8367e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
8377e949c46SKenneth D. Merry 	ext->type = 0xFF;	/* Invalid extra type */
8387e949c46SKenneth D. Merry 	ext->flags = 0;
8397e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
8407e949c46SKenneth D. Merry 
8417e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
8427e949c46SKenneth D. Merry 
8437e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
8447e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
8457e949c46SKenneth D. Merry 	xnb_unit_pvt.txb.req_cons += num_consumed;
8467e949c46SKenneth D. Merry 	XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
8477e949c46SKenneth D. Merry 
8487e949c46SKenneth D. Merry 	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
8497e949c46SKenneth D. Merry 
8507e949c46SKenneth D. Merry 	XNB_ASSERT(
8517e949c46SKenneth D. Merry 	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
8527e949c46SKenneth D. Merry 
8537e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
8547e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == req->id);
8557e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
8567e949c46SKenneth D. Merry 
8577e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
8587e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.rsp_cons + 1);
8597e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
8607e949c46SKenneth D. Merry };
8617e949c46SKenneth D. Merry 
8627e949c46SKenneth D. Merry /**
8637e949c46SKenneth D. Merry  * xnb_txpkt2rsp responding to one request which caused an error
8647e949c46SKenneth D. Merry  */
8657e949c46SKenneth D. Merry static void
xnb_txpkt2rsp_error(char * buffer,size_t buflen)8667e949c46SKenneth D. Merry xnb_txpkt2rsp_error(char *buffer, size_t buflen)
8677e949c46SKenneth D. Merry {
8687e949c46SKenneth D. Merry 	uint16_t num_consumed;
8697e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
8707e949c46SKenneth D. Merry 	struct netif_tx_request *req;
8717e949c46SKenneth D. Merry 	struct netif_tx_response *rsp;
8727e949c46SKenneth D. Merry 
8737e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
8747e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
8757e949c46SKenneth D. Merry 	req->size = 1000;
8767e949c46SKenneth D. Merry 	req->flags = 0;
8777e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
8787e949c46SKenneth D. Merry 
8797e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
8807e949c46SKenneth D. Merry 
8817e949c46SKenneth D. Merry 	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
8827e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
8837e949c46SKenneth D. Merry 	xnb_unit_pvt.txb.req_cons += num_consumed;
8847e949c46SKenneth D. Merry 
8857e949c46SKenneth D. Merry 	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 1);
8867e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
8877e949c46SKenneth D. Merry 
8887e949c46SKenneth D. Merry 	XNB_ASSERT(
8897e949c46SKenneth D. Merry 	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
8907e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == req->id);
8917e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
8927e949c46SKenneth D. Merry };
8937e949c46SKenneth D. Merry 
8947e949c46SKenneth D. Merry /**
8957e949c46SKenneth D. Merry  * xnb_txpkt2rsp's responses wrap around the end of the ring
8967e949c46SKenneth D. Merry  */
8977e949c46SKenneth D. Merry static void
xnb_txpkt2rsp_wraps(char * buffer,size_t buflen)8987e949c46SKenneth D. Merry xnb_txpkt2rsp_wraps(char *buffer, size_t buflen)
8997e949c46SKenneth D. Merry {
9007e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
9017e949c46SKenneth D. Merry 	struct netif_tx_request *req;
9027e949c46SKenneth D. Merry 	struct netif_tx_response *rsp;
9037e949c46SKenneth D. Merry 	unsigned int rsize;
9047e949c46SKenneth D. Merry 
9057e949c46SKenneth D. Merry 	/*
9067e949c46SKenneth D. Merry 	 * Manually tweak the ring indices to create a ring with no responses
9077e949c46SKenneth D. Merry 	 * and the next request slot at position 2 from the end
9087e949c46SKenneth D. Merry 	 */
9097e949c46SKenneth D. Merry 	rsize = RING_SIZE(&xnb_unit_pvt.txf);
9107e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
9117e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.rsp_cons = rsize - 2;
9127e949c46SKenneth D. Merry 	xnb_unit_pvt.txs->req_prod = rsize - 2;
9137e949c46SKenneth D. Merry 	xnb_unit_pvt.txs->req_event = rsize - 1;
9147e949c46SKenneth D. Merry 	xnb_unit_pvt.txs->rsp_prod = rsize - 2;
9157e949c46SKenneth D. Merry 	xnb_unit_pvt.txs->rsp_event = rsize - 1;
9167e949c46SKenneth D. Merry 	xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
9177e949c46SKenneth D. Merry 	xnb_unit_pvt.txb.req_cons = rsize - 2;
9187e949c46SKenneth D. Merry 
9197e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
9207e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
9217e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
9227e949c46SKenneth D. Merry 	req->size = 550;
9237e949c46SKenneth D. Merry 	req->id = 1;
9247e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
9257e949c46SKenneth D. Merry 
9267e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
9277e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
9287e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
9297e949c46SKenneth D. Merry 	req->size = 100;
9307e949c46SKenneth D. Merry 	req->id = 2;
9317e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
9327e949c46SKenneth D. Merry 
9337e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
9347e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
9357e949c46SKenneth D. Merry 	req->flags = 0;
9367e949c46SKenneth D. Merry 	req->size = 50;
9377e949c46SKenneth D. Merry 	req->id = 3;
9387e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
9397e949c46SKenneth D. Merry 
9407e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
9417e949c46SKenneth D. Merry 
9427650d4b6SJohn Baldwin 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
9437e949c46SKenneth D. Merry 
9447e949c46SKenneth D. Merry 	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
9457e949c46SKenneth D. Merry 
9467e949c46SKenneth D. Merry 	XNB_ASSERT(
9477e949c46SKenneth D. Merry 	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
9487e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
9497e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.rsp_cons + 2);
9507e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == req->id);
9517e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
9527e949c46SKenneth D. Merry }
9537e949c46SKenneth D. Merry 
9547e949c46SKenneth D. Merry /**
9557e949c46SKenneth D. Merry  * Helper function used to setup pkt2mbufc tests
9567e949c46SKenneth D. Merry  * \param size     size in bytes of the single request to push to the ring
9577e949c46SKenneth D. Merry  * \param flags		optional flags to put in the netif request
9587e949c46SKenneth D. Merry  * \param[out] pkt the returned packet object
9597e949c46SKenneth D. Merry  * \return number of requests consumed from the ring
9607e949c46SKenneth D. Merry  */
9617e949c46SKenneth D. Merry static int
xnb_get1pkt(struct xnb_pkt * pkt,size_t size,uint16_t flags)9627e949c46SKenneth D. Merry xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags)
9637e949c46SKenneth D. Merry {
9647e949c46SKenneth D. Merry 	struct netif_tx_request *req;
9657e949c46SKenneth D. Merry 
9667e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
9677e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
9687e949c46SKenneth D. Merry 	req->flags = flags;
9697e949c46SKenneth D. Merry 	req->size = size;
9707e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
9717e949c46SKenneth D. Merry 
9727e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
9737e949c46SKenneth D. Merry 
9747e949c46SKenneth D. Merry 	return xnb_ring2pkt(pkt, &xnb_unit_pvt.txb,
9757e949c46SKenneth D. Merry 	                            xnb_unit_pvt.txb.req_cons);
9767e949c46SKenneth D. Merry }
9777e949c46SKenneth D. Merry 
9787e949c46SKenneth D. Merry /**
9797e949c46SKenneth D. Merry  * xnb_pkt2mbufc on an empty packet
9807e949c46SKenneth D. Merry  */
9817e949c46SKenneth D. Merry static void
xnb_pkt2mbufc_empty(char * buffer,size_t buflen)9827e949c46SKenneth D. Merry xnb_pkt2mbufc_empty(char *buffer, size_t buflen)
9837e949c46SKenneth D. Merry {
9847e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
9857e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
9867e949c46SKenneth D. Merry 	pkt.list_len = 0;
9877e949c46SKenneth D. Merry 
9887e949c46SKenneth D. Merry 	/* must call xnb_ring2pkt just to intialize pkt */
9897650d4b6SJohn Baldwin 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
9907e949c46SKenneth D. Merry 	pkt.size = 0;
9917e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
9927e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
9937e949c46SKenneth D. Merry }
9947e949c46SKenneth D. Merry 
9957e949c46SKenneth D. Merry /**
9967e949c46SKenneth D. Merry  * xnb_pkt2mbufc on short packet that can fit in an mbuf internal buffer
9977e949c46SKenneth D. Merry  */
9987e949c46SKenneth D. Merry static void
xnb_pkt2mbufc_short(char * buffer,size_t buflen)9997e949c46SKenneth D. Merry xnb_pkt2mbufc_short(char *buffer, size_t buflen)
10007e949c46SKenneth D. Merry {
10017e949c46SKenneth D. Merry 	const size_t size = MINCLSIZE - 1;
10027e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
10037e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
10047e949c46SKenneth D. Merry 
10057e949c46SKenneth D. Merry 	xnb_get1pkt(&pkt, size, 0);
10067e949c46SKenneth D. Merry 
10077e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
10087e949c46SKenneth D. Merry 	XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
10097e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
10107e949c46SKenneth D. Merry }
10117e949c46SKenneth D. Merry 
10127e949c46SKenneth D. Merry /**
10137e949c46SKenneth D. Merry  * xnb_pkt2mbufc on short packet whose checksum was validated by the netfron
10147e949c46SKenneth D. Merry  */
10157e949c46SKenneth D. Merry static void
xnb_pkt2mbufc_csum(char * buffer,size_t buflen)10167e949c46SKenneth D. Merry xnb_pkt2mbufc_csum(char *buffer, size_t buflen)
10177e949c46SKenneth D. Merry {
10187e949c46SKenneth D. Merry 	const size_t size = MINCLSIZE - 1;
10197e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
10207e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
10217e949c46SKenneth D. Merry 
10227e949c46SKenneth D. Merry 	xnb_get1pkt(&pkt, size, NETTXF_data_validated);
10237e949c46SKenneth D. Merry 
10247e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
10257e949c46SKenneth D. Merry 	XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
10267e949c46SKenneth D. Merry 	XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_CHECKED);
10277e949c46SKenneth D. Merry 	XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_VALID);
10287e949c46SKenneth D. Merry 	XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_DATA_VALID);
10297e949c46SKenneth D. Merry 	XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR);
10307e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
10317e949c46SKenneth D. Merry }
10327e949c46SKenneth D. Merry 
10337e949c46SKenneth D. Merry /**
10347e949c46SKenneth D. Merry  * xnb_pkt2mbufc on packet that can fit in one cluster
10357e949c46SKenneth D. Merry  */
10367e949c46SKenneth D. Merry static void
xnb_pkt2mbufc_1cluster(char * buffer,size_t buflen)10377e949c46SKenneth D. Merry xnb_pkt2mbufc_1cluster(char *buffer, size_t buflen)
10387e949c46SKenneth D. Merry {
10397e949c46SKenneth D. Merry 	const size_t size = MINCLSIZE;
10407e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
10417e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
10427e949c46SKenneth D. Merry 
10437e949c46SKenneth D. Merry 	xnb_get1pkt(&pkt, size, 0);
10447e949c46SKenneth D. Merry 
10457e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
10467e949c46SKenneth D. Merry 	XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
10477e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
10487e949c46SKenneth D. Merry }
10497e949c46SKenneth D. Merry 
10507e949c46SKenneth D. Merry /**
10517e949c46SKenneth D. Merry  * xnb_pkt2mbufc on packet that cannot fit in one regular cluster
10527e949c46SKenneth D. Merry  */
10537e949c46SKenneth D. Merry static void
xnb_pkt2mbufc_largecluster(char * buffer,size_t buflen)10547e949c46SKenneth D. Merry xnb_pkt2mbufc_largecluster(char *buffer, size_t buflen)
10557e949c46SKenneth D. Merry {
10567e949c46SKenneth D. Merry 	const size_t size = MCLBYTES + 1;
10577e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
10587e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
10597e949c46SKenneth D. Merry 
10607e949c46SKenneth D. Merry 	xnb_get1pkt(&pkt, size, 0);
10617e949c46SKenneth D. Merry 
10627e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
10637e949c46SKenneth D. Merry 	XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
10647e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
10657e949c46SKenneth D. Merry }
10667e949c46SKenneth D. Merry 
10677e949c46SKenneth D. Merry /**
10687e949c46SKenneth D. Merry  * xnb_pkt2mbufc on packet that cannot fit in one clusters
10697e949c46SKenneth D. Merry  */
10707e949c46SKenneth D. Merry static void
xnb_pkt2mbufc_2cluster(char * buffer,size_t buflen)10717e949c46SKenneth D. Merry xnb_pkt2mbufc_2cluster(char *buffer, size_t buflen)
10727e949c46SKenneth D. Merry {
10737e949c46SKenneth D. Merry 	const size_t size = 2 * MCLBYTES + 1;
10747e949c46SKenneth D. Merry 	size_t space = 0;
10757e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
10767e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
10777e949c46SKenneth D. Merry 	struct mbuf *m;
10787e949c46SKenneth D. Merry 
10797e949c46SKenneth D. Merry 	xnb_get1pkt(&pkt, size, 0);
10807e949c46SKenneth D. Merry 
10817e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
10827e949c46SKenneth D. Merry 
10837e949c46SKenneth D. Merry 	for (m = pMbuf; m != NULL; m = m->m_next) {
10847e949c46SKenneth D. Merry 		space += M_TRAILINGSPACE(m);
10857e949c46SKenneth D. Merry 	}
10867e949c46SKenneth D. Merry 	XNB_ASSERT(space >= size);
10877e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
10887e949c46SKenneth D. Merry }
10897e949c46SKenneth D. Merry 
10907e949c46SKenneth D. Merry /**
10917e949c46SKenneth D. Merry  * xnb_txpkt2gnttab on an empty packet.  Should return empty gnttab
10927e949c46SKenneth D. Merry  */
10937e949c46SKenneth D. Merry static void
xnb_txpkt2gnttab_empty(char * buffer,size_t buflen)10947e949c46SKenneth D. Merry xnb_txpkt2gnttab_empty(char *buffer, size_t buflen)
10957e949c46SKenneth D. Merry {
10967e949c46SKenneth D. Merry 	int n_entries;
10977e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
10987e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
10997e949c46SKenneth D. Merry 	pkt.list_len = 0;
11007e949c46SKenneth D. Merry 
11017e949c46SKenneth D. Merry 	/* must call xnb_ring2pkt just to intialize pkt */
11027e949c46SKenneth D. Merry 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
11037e949c46SKenneth D. Merry 	pkt.size = 0;
11047e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
11057e949c46SKenneth D. Merry 	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
11067e949c46SKenneth D. Merry 	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
11077e949c46SKenneth D. Merry 	XNB_ASSERT(n_entries == 0);
11087e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
11097e949c46SKenneth D. Merry }
11107e949c46SKenneth D. Merry 
11117e949c46SKenneth D. Merry /**
11127e949c46SKenneth D. Merry  * xnb_txpkt2gnttab on a short packet, that can fit in one mbuf internal buffer
11137e949c46SKenneth D. Merry  * and has one request
11147e949c46SKenneth D. Merry  */
11157e949c46SKenneth D. Merry static void
xnb_txpkt2gnttab_short(char * buffer,size_t buflen)11167e949c46SKenneth D. Merry xnb_txpkt2gnttab_short(char *buffer, size_t buflen)
11177e949c46SKenneth D. Merry {
11187e949c46SKenneth D. Merry 	const size_t size = MINCLSIZE - 1;
11197e949c46SKenneth D. Merry 	int n_entries;
11207e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
11217e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
11227e949c46SKenneth D. Merry 
11237e949c46SKenneth D. Merry 	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
11247e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
11257e949c46SKenneth D. Merry 	req->flags = 0;
11267e949c46SKenneth D. Merry 	req->size = size;
11277e949c46SKenneth D. Merry 	req->gref = 7;
11287e949c46SKenneth D. Merry 	req->offset = 17;
11297e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
11307e949c46SKenneth D. Merry 
11317e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
11327e949c46SKenneth D. Merry 
11337e949c46SKenneth D. Merry 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
11347e949c46SKenneth D. Merry 
11357e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
11367e949c46SKenneth D. Merry 	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
11377e949c46SKenneth D. Merry 	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
11387e949c46SKenneth D. Merry 	XNB_ASSERT(n_entries == 1);
11397e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
11407e949c46SKenneth D. Merry 	/* flags should indicate gref's for source */
11417e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_source_gref);
11427e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == req->offset);
11437e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
11447e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
11457e949c46SKenneth D. Merry 	      mtod(pMbuf, vm_offset_t)));
11467e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.u.gmfn ==
11477e949c46SKenneth D. Merry 		virt_to_mfn(mtod(pMbuf, vm_offset_t)));
11487e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
11497e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
11507e949c46SKenneth D. Merry }
11517e949c46SKenneth D. Merry 
11527e949c46SKenneth D. Merry /**
11537e949c46SKenneth D. Merry  * xnb_txpkt2gnttab on a packet with two requests, that can fit into a single
11547e949c46SKenneth D. Merry  * mbuf cluster
11557e949c46SKenneth D. Merry  */
11567e949c46SKenneth D. Merry static void
xnb_txpkt2gnttab_2req(char * buffer,size_t buflen)11577e949c46SKenneth D. Merry xnb_txpkt2gnttab_2req(char *buffer, size_t buflen)
11587e949c46SKenneth D. Merry {
11597e949c46SKenneth D. Merry 	int n_entries;
11607e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
11617e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
11627e949c46SKenneth D. Merry 
11637e949c46SKenneth D. Merry 	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
11647e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
11657e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
11667e949c46SKenneth D. Merry 	req->size = 1900;
11677e949c46SKenneth D. Merry 	req->gref = 7;
11687e949c46SKenneth D. Merry 	req->offset = 0;
11697e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
11707e949c46SKenneth D. Merry 
11717e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
11727e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
11737e949c46SKenneth D. Merry 	req->flags = 0;
11747e949c46SKenneth D. Merry 	req->size = 500;
11757e949c46SKenneth D. Merry 	req->gref = 8;
11767e949c46SKenneth D. Merry 	req->offset = 0;
11777e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
11787e949c46SKenneth D. Merry 
11797e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
11807e949c46SKenneth D. Merry 
11817e949c46SKenneth D. Merry 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
11827e949c46SKenneth D. Merry 
11837e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
11847e949c46SKenneth D. Merry 	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
11857e949c46SKenneth D. Merry 	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
11867e949c46SKenneth D. Merry 
11877e949c46SKenneth D. Merry 	XNB_ASSERT(n_entries == 2);
11887e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 1400);
11897e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
11907e949c46SKenneth D. Merry 	      mtod(pMbuf, vm_offset_t)));
11917e949c46SKenneth D. Merry 
11927e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 500);
11937e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
11947e949c46SKenneth D. Merry 	      mtod(pMbuf, vm_offset_t) + 1400));
11957e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
11967e949c46SKenneth D. Merry }
11977e949c46SKenneth D. Merry 
11987e949c46SKenneth D. Merry /**
11997e949c46SKenneth D. Merry  * xnb_txpkt2gnttab on a single request that spans two mbuf clusters
12007e949c46SKenneth D. Merry  */
12017e949c46SKenneth D. Merry static void
xnb_txpkt2gnttab_2cluster(char * buffer,size_t buflen)12027e949c46SKenneth D. Merry xnb_txpkt2gnttab_2cluster(char *buffer, size_t buflen)
12037e949c46SKenneth D. Merry {
12047e949c46SKenneth D. Merry 	int n_entries;
12057e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
12067e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
12077e949c46SKenneth D. Merry 	const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
12087e949c46SKenneth D. Merry 
12097e949c46SKenneth D. Merry 	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
12107e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
12117e949c46SKenneth D. Merry 	req->flags = 0;
12127e949c46SKenneth D. Merry 	req->size = data_this_transaction;
12137e949c46SKenneth D. Merry 	req->gref = 8;
12147e949c46SKenneth D. Merry 	req->offset = 0;
12157e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
12167e949c46SKenneth D. Merry 
12177e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
12187e949c46SKenneth D. Merry 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
12197e949c46SKenneth D. Merry 
12207e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1221407d708cSAlan Somers 	XNB_ASSERT(pMbuf != NULL);
1222407d708cSAlan Somers 	if (pMbuf == NULL)
1223407d708cSAlan Somers 		return;
1224407d708cSAlan Somers 
12257e949c46SKenneth D. Merry 	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
12267e949c46SKenneth D. Merry 	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
12277e949c46SKenneth D. Merry 
12287e949c46SKenneth D. Merry 	if (M_TRAILINGSPACE(pMbuf) == MCLBYTES) {
12297e949c46SKenneth D. Merry 		/* there should be three mbufs and three gnttab entries */
12307e949c46SKenneth D. Merry 		XNB_ASSERT(n_entries == 3);
12317e949c46SKenneth D. Merry 		XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == MCLBYTES);
12327e949c46SKenneth D. Merry 		XNB_ASSERT(
12337e949c46SKenneth D. Merry 		    xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
12347e949c46SKenneth D. Merry 		      mtod(pMbuf, vm_offset_t)));
12357e949c46SKenneth D. Merry 		XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
12367e949c46SKenneth D. Merry 
12377e949c46SKenneth D. Merry 		XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == MCLBYTES);
12387e949c46SKenneth D. Merry 		XNB_ASSERT(
12397e949c46SKenneth D. Merry 		    xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
12407e949c46SKenneth D. Merry 		      mtod(pMbuf->m_next, vm_offset_t)));
12417e949c46SKenneth D. Merry 		XNB_ASSERT(xnb_unit_pvt.gnttab[1].source.offset == MCLBYTES);
12427e949c46SKenneth D. Merry 
12437e949c46SKenneth D. Merry 		XNB_ASSERT(xnb_unit_pvt.gnttab[2].len == 1);
12447e949c46SKenneth D. Merry 		XNB_ASSERT(
12457e949c46SKenneth D. Merry 		    xnb_unit_pvt.gnttab[2].dest.offset == virt_to_offset(
12467e949c46SKenneth D. Merry 		      mtod(pMbuf->m_next, vm_offset_t)));
12477e949c46SKenneth D. Merry 		XNB_ASSERT(xnb_unit_pvt.gnttab[2].source.offset == 2 *
12487e949c46SKenneth D. Merry 			    MCLBYTES);
12497e949c46SKenneth D. Merry 	} else if (M_TRAILINGSPACE(pMbuf) == 2 * MCLBYTES) {
12507e949c46SKenneth D. Merry 		/* there should be two mbufs and two gnttab entries */
12517e949c46SKenneth D. Merry 		XNB_ASSERT(n_entries == 2);
12527e949c46SKenneth D. Merry 		XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 2 * MCLBYTES);
12537e949c46SKenneth D. Merry 		XNB_ASSERT(
12547e949c46SKenneth D. Merry 		    xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
12557e949c46SKenneth D. Merry 		      mtod(pMbuf, vm_offset_t)));
12567e949c46SKenneth D. Merry 		XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
12577e949c46SKenneth D. Merry 
12587e949c46SKenneth D. Merry 		XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 1);
12597e949c46SKenneth D. Merry 		XNB_ASSERT(
12607e949c46SKenneth D. Merry 		    xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
12617e949c46SKenneth D. Merry 		      mtod(pMbuf->m_next, vm_offset_t)));
12627e949c46SKenneth D. Merry 		XNB_ASSERT(
12637e949c46SKenneth D. Merry 		    xnb_unit_pvt.gnttab[1].source.offset == 2 * MCLBYTES);
12647e949c46SKenneth D. Merry 
12657e949c46SKenneth D. Merry 	} else {
12667e949c46SKenneth D. Merry 		/* should never get here */
12677e949c46SKenneth D. Merry 		XNB_ASSERT(0);
12687e949c46SKenneth D. Merry 	}
12697e949c46SKenneth D. Merry 	m_freem(pMbuf);
12707e949c46SKenneth D. Merry }
12717e949c46SKenneth D. Merry 
12727e949c46SKenneth D. Merry /**
12737e949c46SKenneth D. Merry  * xnb_update_mbufc on a short packet that only has one gnttab entry
12747e949c46SKenneth D. Merry  */
12757e949c46SKenneth D. Merry static void
xnb_update_mbufc_short(char * buffer,size_t buflen)12767e949c46SKenneth D. Merry xnb_update_mbufc_short(char *buffer, size_t buflen)
12777e949c46SKenneth D. Merry {
12787e949c46SKenneth D. Merry 	const size_t size = MINCLSIZE - 1;
12797e949c46SKenneth D. Merry 	int n_entries;
12807e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
12817e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
12827e949c46SKenneth D. Merry 
12837e949c46SKenneth D. Merry 	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
12847e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
12857e949c46SKenneth D. Merry 	req->flags = 0;
12867e949c46SKenneth D. Merry 	req->size = size;
12877e949c46SKenneth D. Merry 	req->gref = 7;
12887e949c46SKenneth D. Merry 	req->offset = 17;
12897e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
12907e949c46SKenneth D. Merry 
12917e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
12927e949c46SKenneth D. Merry 
12937e949c46SKenneth D. Merry 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
12947e949c46SKenneth D. Merry 
12957e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
12967e949c46SKenneth D. Merry 	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
12977e949c46SKenneth D. Merry 	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
12987e949c46SKenneth D. Merry 
12997e949c46SKenneth D. Merry 	/* Update grant table's status fields as the hypervisor call would */
13007e949c46SKenneth D. Merry 	xnb_unit_pvt.gnttab[0].status = GNTST_okay;
13017e949c46SKenneth D. Merry 
13027e949c46SKenneth D. Merry 	xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
13037e949c46SKenneth D. Merry 	XNB_ASSERT(pMbuf->m_len == size);
13047e949c46SKenneth D. Merry 	XNB_ASSERT(pMbuf->m_pkthdr.len == size);
13057e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
13067e949c46SKenneth D. Merry }
13077e949c46SKenneth D. Merry 
13087e949c46SKenneth D. Merry /**
13097e949c46SKenneth D. Merry  * xnb_update_mbufc on a packet with two requests, that can fit into a single
13107e949c46SKenneth D. Merry  * mbuf cluster
13117e949c46SKenneth D. Merry  */
13127e949c46SKenneth D. Merry static void
xnb_update_mbufc_2req(char * buffer,size_t buflen)13137e949c46SKenneth D. Merry xnb_update_mbufc_2req(char *buffer, size_t buflen)
13147e949c46SKenneth D. Merry {
13157e949c46SKenneth D. Merry 	int n_entries;
13167e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
13177e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
13187e949c46SKenneth D. Merry 
13197e949c46SKenneth D. Merry 	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
13207e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
13217e949c46SKenneth D. Merry 	req->flags = NETTXF_more_data;
13227e949c46SKenneth D. Merry 	req->size = 1900;
13237e949c46SKenneth D. Merry 	req->gref = 7;
13247e949c46SKenneth D. Merry 	req->offset = 0;
13257e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
13267e949c46SKenneth D. Merry 
13277e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
13287e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
13297e949c46SKenneth D. Merry 	req->flags = 0;
13307e949c46SKenneth D. Merry 	req->size = 500;
13317e949c46SKenneth D. Merry 	req->gref = 8;
13327e949c46SKenneth D. Merry 	req->offset = 0;
13337e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
13347e949c46SKenneth D. Merry 
13357e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
13367e949c46SKenneth D. Merry 
13377e949c46SKenneth D. Merry 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
13387e949c46SKenneth D. Merry 
13397e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
13407e949c46SKenneth D. Merry 	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
13417e949c46SKenneth D. Merry 	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
13427e949c46SKenneth D. Merry 
13437e949c46SKenneth D. Merry 	/* Update grant table's status fields as the hypervisor call would */
13447e949c46SKenneth D. Merry 	xnb_unit_pvt.gnttab[0].status = GNTST_okay;
13457e949c46SKenneth D. Merry 	xnb_unit_pvt.gnttab[1].status = GNTST_okay;
13467e949c46SKenneth D. Merry 
13477e949c46SKenneth D. Merry 	xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
13487e949c46SKenneth D. Merry 	XNB_ASSERT(n_entries == 2);
13497e949c46SKenneth D. Merry 	XNB_ASSERT(pMbuf->m_pkthdr.len == 1900);
13507e949c46SKenneth D. Merry 	XNB_ASSERT(pMbuf->m_len == 1900);
13517e949c46SKenneth D. Merry 
13527e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
13537e949c46SKenneth D. Merry }
13547e949c46SKenneth D. Merry 
13557e949c46SKenneth D. Merry /**
13567e949c46SKenneth D. Merry  * xnb_update_mbufc on a single request that spans two mbuf clusters
13577e949c46SKenneth D. Merry  */
13587e949c46SKenneth D. Merry static void
xnb_update_mbufc_2cluster(char * buffer,size_t buflen)13597e949c46SKenneth D. Merry xnb_update_mbufc_2cluster(char *buffer, size_t buflen)
13607e949c46SKenneth D. Merry {
13617e949c46SKenneth D. Merry 	int i;
13627e949c46SKenneth D. Merry 	int n_entries;
13637e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
13647e949c46SKenneth D. Merry 	struct mbuf *pMbuf;
13657e949c46SKenneth D. Merry 	const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
13667e949c46SKenneth D. Merry 
13677e949c46SKenneth D. Merry 	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
13687e949c46SKenneth D. Merry 	    xnb_unit_pvt.txf.req_prod_pvt);
13697e949c46SKenneth D. Merry 	req->flags = 0;
13707e949c46SKenneth D. Merry 	req->size = data_this_transaction;
13717e949c46SKenneth D. Merry 	req->gref = 8;
13727e949c46SKenneth D. Merry 	req->offset = 0;
13737e949c46SKenneth D. Merry 	xnb_unit_pvt.txf.req_prod_pvt++;
13747e949c46SKenneth D. Merry 
13757e949c46SKenneth D. Merry 	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
13767e949c46SKenneth D. Merry 	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
13777e949c46SKenneth D. Merry 
13787e949c46SKenneth D. Merry 	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
13797e949c46SKenneth D. Merry 	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
13807e949c46SKenneth D. Merry 	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
13817e949c46SKenneth D. Merry 
13827e949c46SKenneth D. Merry 	/* Update grant table's status fields */
13837e949c46SKenneth D. Merry 	for (i = 0; i < n_entries; i++) {
13847e949c46SKenneth D. Merry 		xnb_unit_pvt.gnttab[0].status = GNTST_okay;
13857e949c46SKenneth D. Merry 	}
13867e949c46SKenneth D. Merry 	xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
13877e949c46SKenneth D. Merry 
13887e949c46SKenneth D. Merry 	if (n_entries == 3) {
13897e949c46SKenneth D. Merry 		/* there should be three mbufs and three gnttab entries */
13907e949c46SKenneth D. Merry 		XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
13917e949c46SKenneth D. Merry 		XNB_ASSERT(pMbuf->m_len == MCLBYTES);
13927e949c46SKenneth D. Merry 		XNB_ASSERT(pMbuf->m_next->m_len == MCLBYTES);
13937e949c46SKenneth D. Merry 		XNB_ASSERT(pMbuf->m_next->m_next->m_len == 1);
13947e949c46SKenneth D. Merry 	} else if (n_entries == 2) {
13957e949c46SKenneth D. Merry 		/* there should be two mbufs and two gnttab entries */
13967e949c46SKenneth D. Merry 		XNB_ASSERT(n_entries == 2);
13977e949c46SKenneth D. Merry 		XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
13987e949c46SKenneth D. Merry 		XNB_ASSERT(pMbuf->m_len == 2 * MCLBYTES);
13997e949c46SKenneth D. Merry 		XNB_ASSERT(pMbuf->m_next->m_len == 1);
14007e949c46SKenneth D. Merry 	} else {
14017e949c46SKenneth D. Merry 		/* should never get here */
14027e949c46SKenneth D. Merry 		XNB_ASSERT(0);
14037e949c46SKenneth D. Merry 	}
14047e949c46SKenneth D. Merry 	safe_m_freem(&pMbuf);
14057e949c46SKenneth D. Merry }
14067e949c46SKenneth D. Merry 
14077e949c46SKenneth D. Merry /** xnb_mbufc2pkt on an empty mbufc */
14087e949c46SKenneth D. Merry static void
xnb_mbufc2pkt_empty(char * buffer,size_t buflen)14097e949c46SKenneth D. Merry xnb_mbufc2pkt_empty(char *buffer, size_t buflen) {
14107e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
14117e949c46SKenneth D. Merry 	int free_slots = 64;
14127e949c46SKenneth D. Merry 	struct mbuf *mbuf;
14137e949c46SKenneth D. Merry 
14147e949c46SKenneth D. Merry 	mbuf = m_get(M_WAITOK, MT_DATA);
14157e949c46SKenneth D. Merry 	/*
14167e949c46SKenneth D. Merry 	 * note: it is illegal to set M_PKTHDR on a mbuf with no data.  Doing so
14177e949c46SKenneth D. Merry 	 * will cause m_freem to segfault
14187e949c46SKenneth D. Merry 	 */
14197e949c46SKenneth D. Merry 	XNB_ASSERT(mbuf->m_len == 0);
14207e949c46SKenneth D. Merry 
14217e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
14227e949c46SKenneth D. Merry 	XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
14237e949c46SKenneth D. Merry 
14247e949c46SKenneth D. Merry 	safe_m_freem(&mbuf);
14257e949c46SKenneth D. Merry }
14267e949c46SKenneth D. Merry 
14277e949c46SKenneth D. Merry /** xnb_mbufc2pkt on a short mbufc */
14287e949c46SKenneth D. Merry static void
xnb_mbufc2pkt_short(char * buffer,size_t buflen)14297e949c46SKenneth D. Merry xnb_mbufc2pkt_short(char *buffer, size_t buflen) {
14307e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
14317e949c46SKenneth D. Merry 	size_t size = 128;
14327e949c46SKenneth D. Merry 	int free_slots = 64;
14337e949c46SKenneth D. Merry 	RING_IDX start = 9;
14347e949c46SKenneth D. Merry 	struct mbuf *mbuf;
14357e949c46SKenneth D. Merry 
14367e949c46SKenneth D. Merry 	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
14377e949c46SKenneth D. Merry 	mbuf->m_flags |= M_PKTHDR;
14387e949c46SKenneth D. Merry 	mbuf->m_pkthdr.len = size;
14397e949c46SKenneth D. Merry 	mbuf->m_len = size;
14407e949c46SKenneth D. Merry 
14417e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
14427e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
14437e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.size == size);
14447e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car_size == size);
14457e949c46SKenneth D. Merry 	XNB_ASSERT(! (pkt.flags &
14467e949c46SKenneth D. Merry 	      (NETRXF_more_data | NETRXF_extra_info)));
14477e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.list_len == 1);
14487e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car == start);
14497e949c46SKenneth D. Merry 
14507e949c46SKenneth D. Merry 	safe_m_freem(&mbuf);
14517e949c46SKenneth D. Merry }
14527e949c46SKenneth D. Merry 
14537e949c46SKenneth D. Merry /** xnb_mbufc2pkt on a single mbuf with an mbuf cluster */
14547e949c46SKenneth D. Merry static void
xnb_mbufc2pkt_1cluster(char * buffer,size_t buflen)14557e949c46SKenneth D. Merry xnb_mbufc2pkt_1cluster(char *buffer, size_t buflen) {
14567e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
14577e949c46SKenneth D. Merry 	size_t size = MCLBYTES;
14587e949c46SKenneth D. Merry 	int free_slots = 32;
14597e949c46SKenneth D. Merry 	RING_IDX start = 12;
14607e949c46SKenneth D. Merry 	struct mbuf *mbuf;
14617e949c46SKenneth D. Merry 
14627e949c46SKenneth D. Merry 	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
14637e949c46SKenneth D. Merry 	mbuf->m_flags |= M_PKTHDR;
14647e949c46SKenneth D. Merry 	mbuf->m_pkthdr.len = size;
14657e949c46SKenneth D. Merry 	mbuf->m_len = size;
14667e949c46SKenneth D. Merry 
14677e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
14687e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
14697e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.size == size);
14707e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car_size == size);
14717e949c46SKenneth D. Merry 	XNB_ASSERT(! (pkt.flags &
14727e949c46SKenneth D. Merry 	      (NETRXF_more_data | NETRXF_extra_info)));
14737e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.list_len == 1);
14747e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car == start);
14757e949c46SKenneth D. Merry 
14767e949c46SKenneth D. Merry 	safe_m_freem(&mbuf);
14777e949c46SKenneth D. Merry }
14787e949c46SKenneth D. Merry 
14790af1b472SEitan Adler /** xnb_mbufc2pkt on a two-mbuf chain with short data regions */
14807e949c46SKenneth D. Merry static void
xnb_mbufc2pkt_2short(char * buffer,size_t buflen)14817e949c46SKenneth D. Merry xnb_mbufc2pkt_2short(char *buffer, size_t buflen) {
14827e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
14837e949c46SKenneth D. Merry 	size_t size1 = MHLEN - 5;
14847e949c46SKenneth D. Merry 	size_t size2 = MHLEN - 15;
14857e949c46SKenneth D. Merry 	int free_slots = 32;
14867e949c46SKenneth D. Merry 	RING_IDX start = 14;
14877e949c46SKenneth D. Merry 	struct mbuf *mbufc, *mbufc2;
14887e949c46SKenneth D. Merry 
14897e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
14907e949c46SKenneth D. Merry 	XNB_ASSERT(mbufc != NULL);
1491407d708cSAlan Somers 	if (mbufc == NULL)
14927e949c46SKenneth D. Merry 		return;
1493407d708cSAlan Somers 	mbufc->m_flags |= M_PKTHDR;
14947e949c46SKenneth D. Merry 
14957e949c46SKenneth D. Merry 	mbufc2 = m_getm(mbufc, size2, M_WAITOK, MT_DATA);
14967e949c46SKenneth D. Merry 	XNB_ASSERT(mbufc2 != NULL);
1497407d708cSAlan Somers 	if (mbufc2 == NULL) {
14987e949c46SKenneth D. Merry 		safe_m_freem(&mbufc);
14997e949c46SKenneth D. Merry 		return;
15007e949c46SKenneth D. Merry 	}
15017e949c46SKenneth D. Merry 	mbufc2->m_pkthdr.len = size1 + size2;
15027e949c46SKenneth D. Merry 	mbufc2->m_len = size1;
15037e949c46SKenneth D. Merry 
15047e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbufc2, &pkt, start, free_slots);
15057e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
15067e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.size == size1 + size2);
15077e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car == start);
15087e949c46SKenneth D. Merry 	/*
15097e949c46SKenneth D. Merry 	 * The second m_getm may allocate a new mbuf and append
15107e949c46SKenneth D. Merry 	 * it to the chain, or it may simply extend the first mbuf.
15117e949c46SKenneth D. Merry 	 */
15127e949c46SKenneth D. Merry 	if (mbufc2->m_next != NULL) {
15137e949c46SKenneth D. Merry 		XNB_ASSERT(pkt.car_size == size1);
15147e949c46SKenneth D. Merry 		XNB_ASSERT(pkt.list_len == 1);
15157e949c46SKenneth D. Merry 		XNB_ASSERT(pkt.cdr == start + 1);
15167e949c46SKenneth D. Merry 	}
15177e949c46SKenneth D. Merry 
15187e949c46SKenneth D. Merry 	safe_m_freem(&mbufc2);
15197e949c46SKenneth D. Merry }
15207e949c46SKenneth D. Merry 
15210af1b472SEitan Adler /** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster */
15227e949c46SKenneth D. Merry static void
xnb_mbufc2pkt_long(char * buffer,size_t buflen)15237e949c46SKenneth D. Merry xnb_mbufc2pkt_long(char *buffer, size_t buflen) {
15247e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
15257e949c46SKenneth D. Merry 	size_t size = 14 * MCLBYTES / 3;
15267e949c46SKenneth D. Merry 	size_t size_remaining;
15277e949c46SKenneth D. Merry 	int free_slots = 15;
15287e949c46SKenneth D. Merry 	RING_IDX start = 3;
15297e949c46SKenneth D. Merry 	struct mbuf *mbufc, *m;
15307e949c46SKenneth D. Merry 
15317e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
15327e949c46SKenneth D. Merry 	XNB_ASSERT(mbufc != NULL);
1533407d708cSAlan Somers 	if (mbufc == NULL)
15347e949c46SKenneth D. Merry 		return;
1535407d708cSAlan Somers 	mbufc->m_flags |= M_PKTHDR;
15367e949c46SKenneth D. Merry 
15377e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = size;
15387e949c46SKenneth D. Merry 	size_remaining = size;
15397e949c46SKenneth D. Merry 	for (m = mbufc; m != NULL; m = m->m_next) {
15407e949c46SKenneth D. Merry 		m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
15417e949c46SKenneth D. Merry 		size_remaining -= m->m_len;
15427e949c46SKenneth D. Merry 	}
15437e949c46SKenneth D. Merry 
15447e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
15457e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
15467e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.size == size);
15477e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car == start);
15487e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car_size = mbufc->m_len);
15497e949c46SKenneth D. Merry 	/*
15507e949c46SKenneth D. Merry 	 * There should be >1 response in the packet, and there is no
15517e949c46SKenneth D. Merry 	 * extra info.
15527e949c46SKenneth D. Merry 	 */
15537e949c46SKenneth D. Merry 	XNB_ASSERT(! (pkt.flags & NETRXF_extra_info));
15547e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.cdr == pkt.car + 1);
15557e949c46SKenneth D. Merry 
15567e949c46SKenneth D. Merry 	safe_m_freem(&mbufc);
15577e949c46SKenneth D. Merry }
15587e949c46SKenneth D. Merry 
15590af1b472SEitan Adler /** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster and extra info */
15607e949c46SKenneth D. Merry static void
xnb_mbufc2pkt_extra(char * buffer,size_t buflen)15617e949c46SKenneth D. Merry xnb_mbufc2pkt_extra(char *buffer, size_t buflen) {
15627e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
15637e949c46SKenneth D. Merry 	size_t size = 14 * MCLBYTES / 3;
15647e949c46SKenneth D. Merry 	size_t size_remaining;
15657e949c46SKenneth D. Merry 	int free_slots = 15;
15667e949c46SKenneth D. Merry 	RING_IDX start = 3;
15677e949c46SKenneth D. Merry 	struct mbuf *mbufc, *m;
15687e949c46SKenneth D. Merry 
15697e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
15707e949c46SKenneth D. Merry 	XNB_ASSERT(mbufc != NULL);
1571407d708cSAlan Somers 	if (mbufc == NULL)
15727e949c46SKenneth D. Merry 		return;
15737e949c46SKenneth D. Merry 
15747e949c46SKenneth D. Merry 	mbufc->m_flags |= M_PKTHDR;
15757e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = size;
15767e949c46SKenneth D. Merry 	mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
15777e949c46SKenneth D. Merry 	mbufc->m_pkthdr.tso_segsz = TCP_MSS - 40;
15787e949c46SKenneth D. Merry 	size_remaining = size;
15797e949c46SKenneth D. Merry 	for (m = mbufc; m != NULL; m = m->m_next) {
15807e949c46SKenneth D. Merry 		m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
15817e949c46SKenneth D. Merry 		size_remaining -= m->m_len;
15827e949c46SKenneth D. Merry 	}
15837e949c46SKenneth D. Merry 
15847e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
15857e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
15867e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.size == size);
15877e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car == start);
15887e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.car_size = mbufc->m_len);
15897e949c46SKenneth D. Merry 	/* There should be >1 response in the packet, there is extra info */
15907e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.flags & NETRXF_extra_info);
15917e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.flags & NETRXF_data_validated);
15927e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.cdr == pkt.car + 2);
15937e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.extra.u.gso.size = mbufc->m_pkthdr.tso_segsz);
15947e949c46SKenneth D. Merry 	XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
15957e949c46SKenneth D. Merry 	XNB_ASSERT(! (pkt.extra.flags & XEN_NETIF_EXTRA_FLAG_MORE));
15967e949c46SKenneth D. Merry 
15977e949c46SKenneth D. Merry 	safe_m_freem(&mbufc);
15987e949c46SKenneth D. Merry }
15997e949c46SKenneth D. Merry 
16007e949c46SKenneth D. Merry /** xnb_mbufc2pkt with insufficient space in the ring */
16017e949c46SKenneth D. Merry static void
xnb_mbufc2pkt_nospace(char * buffer,size_t buflen)16027e949c46SKenneth D. Merry xnb_mbufc2pkt_nospace(char *buffer, size_t buflen) {
16037e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
16047e949c46SKenneth D. Merry 	size_t size = 14 * MCLBYTES / 3;
16057e949c46SKenneth D. Merry 	size_t size_remaining;
16067e949c46SKenneth D. Merry 	int free_slots = 2;
16077e949c46SKenneth D. Merry 	RING_IDX start = 3;
16087e949c46SKenneth D. Merry 	struct mbuf *mbufc, *m;
16097e949c46SKenneth D. Merry 	int error;
16107e949c46SKenneth D. Merry 
16117e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
16127e949c46SKenneth D. Merry 	XNB_ASSERT(mbufc != NULL);
1613407d708cSAlan Somers 	if (mbufc == NULL)
16147e949c46SKenneth D. Merry 		return;
1615407d708cSAlan Somers 	mbufc->m_flags |= M_PKTHDR;
16167e949c46SKenneth D. Merry 
16177e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = size;
16187e949c46SKenneth D. Merry 	size_remaining = size;
16197e949c46SKenneth D. Merry 	for (m = mbufc; m != NULL; m = m->m_next) {
16207e949c46SKenneth D. Merry 		m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
16217e949c46SKenneth D. Merry 		size_remaining -= m->m_len;
16227e949c46SKenneth D. Merry 	}
16237e949c46SKenneth D. Merry 
16247e949c46SKenneth D. Merry 	error = xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
16257e949c46SKenneth D. Merry 	XNB_ASSERT(error == EAGAIN);
16267e949c46SKenneth D. Merry 	XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
16277e949c46SKenneth D. Merry 
16287e949c46SKenneth D. Merry 	safe_m_freem(&mbufc);
16297e949c46SKenneth D. Merry }
16307e949c46SKenneth D. Merry 
16317e949c46SKenneth D. Merry /**
16327e949c46SKenneth D. Merry  * xnb_rxpkt2gnttab on an empty packet.  Should return empty gnttab
16337e949c46SKenneth D. Merry  */
16347e949c46SKenneth D. Merry static void
xnb_rxpkt2gnttab_empty(char * buffer,size_t buflen)16357e949c46SKenneth D. Merry xnb_rxpkt2gnttab_empty(char *buffer, size_t buflen)
16367e949c46SKenneth D. Merry {
16377e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
16387e949c46SKenneth D. Merry 	int nr_entries;
16397e949c46SKenneth D. Merry 	int free_slots = 60;
16407e949c46SKenneth D. Merry 	struct mbuf *mbuf;
16417e949c46SKenneth D. Merry 
16427e949c46SKenneth D. Merry 	mbuf = m_get(M_WAITOK, MT_DATA);
16437e949c46SKenneth D. Merry 
16447e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
16457e949c46SKenneth D. Merry 	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
16467e949c46SKenneth D. Merry 			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
16477e949c46SKenneth D. Merry 
16487e949c46SKenneth D. Merry 	XNB_ASSERT(nr_entries == 0);
16497e949c46SKenneth D. Merry 
16507e949c46SKenneth D. Merry 	safe_m_freem(&mbuf);
16517e949c46SKenneth D. Merry }
16527e949c46SKenneth D. Merry 
16537e949c46SKenneth D. Merry /** xnb_rxpkt2gnttab on a short packet without extra data */
16547e949c46SKenneth D. Merry static void
xnb_rxpkt2gnttab_short(char * buffer,size_t buflen)16557e949c46SKenneth D. Merry xnb_rxpkt2gnttab_short(char *buffer, size_t buflen) {
16567e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
16577e949c46SKenneth D. Merry 	int nr_entries;
16587e949c46SKenneth D. Merry 	size_t size = 128;
16597e949c46SKenneth D. Merry 	int free_slots = 60;
16607e949c46SKenneth D. Merry 	RING_IDX start = 9;
16617e949c46SKenneth D. Merry 	struct netif_rx_request *req;
16627e949c46SKenneth D. Merry 	struct mbuf *mbuf;
16637e949c46SKenneth D. Merry 
16647e949c46SKenneth D. Merry 	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
16657e949c46SKenneth D. Merry 	mbuf->m_flags |= M_PKTHDR;
16667e949c46SKenneth D. Merry 	mbuf->m_pkthdr.len = size;
16677e949c46SKenneth D. Merry 	mbuf->m_len = size;
16687e949c46SKenneth D. Merry 
16697e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
16707e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
16717e949c46SKenneth D. Merry 			       xnb_unit_pvt.txf.req_prod_pvt);
16727e949c46SKenneth D. Merry 	req->gref = 7;
16737e949c46SKenneth D. Merry 
16747e949c46SKenneth D. Merry 	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
16757e949c46SKenneth D. Merry 				      &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
16767e949c46SKenneth D. Merry 
16777e949c46SKenneth D. Merry 	XNB_ASSERT(nr_entries == 1);
16787e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
16797e949c46SKenneth D. Merry 	/* flags should indicate gref's for dest */
16807e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_dest_gref);
16817e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == 0);
16827e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
16837e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == virt_to_offset(
16847e949c46SKenneth D. Merry 		   mtod(mbuf, vm_offset_t)));
16857e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.u.gmfn ==
16867e949c46SKenneth D. Merry 		   virt_to_mfn(mtod(mbuf, vm_offset_t)));
16877e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
16887e949c46SKenneth D. Merry 
16897e949c46SKenneth D. Merry 	safe_m_freem(&mbuf);
16907e949c46SKenneth D. Merry }
16917e949c46SKenneth D. Merry 
16927e949c46SKenneth D. Merry /**
16937e949c46SKenneth D. Merry  * xnb_rxpkt2gnttab on a packet with two different mbufs in a single chai
16947e949c46SKenneth D. Merry  */
16957e949c46SKenneth D. Merry static void
xnb_rxpkt2gnttab_2req(char * buffer,size_t buflen)16967e949c46SKenneth D. Merry xnb_rxpkt2gnttab_2req(char *buffer, size_t buflen)
16977e949c46SKenneth D. Merry {
16987e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
16997e949c46SKenneth D. Merry 	int nr_entries;
17007e949c46SKenneth D. Merry 	int i, num_mbufs;
17017e949c46SKenneth D. Merry 	size_t total_granted_size = 0;
17027e949c46SKenneth D. Merry 	size_t size = MJUMPAGESIZE + 1;
17037e949c46SKenneth D. Merry 	int free_slots = 60;
17047e949c46SKenneth D. Merry 	RING_IDX start = 11;
17057e949c46SKenneth D. Merry 	struct netif_rx_request *req;
17067e949c46SKenneth D. Merry 	struct mbuf *mbuf, *m;
17077e949c46SKenneth D. Merry 
17087e949c46SKenneth D. Merry 	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
17097e949c46SKenneth D. Merry 	mbuf->m_flags |= M_PKTHDR;
17107e949c46SKenneth D. Merry 	mbuf->m_pkthdr.len = size;
17117e949c46SKenneth D. Merry 	mbuf->m_len = size;
17127e949c46SKenneth D. Merry 
17137e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
17147e949c46SKenneth D. Merry 
17157e949c46SKenneth D. Merry 	for (i = 0, m=mbuf; m != NULL; i++, m = m->m_next) {
17167e949c46SKenneth D. Merry 		req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
17177e949c46SKenneth D. Merry 		    xnb_unit_pvt.txf.req_prod_pvt);
17187e949c46SKenneth D. Merry 		req->gref = i;
17197e949c46SKenneth D. Merry 		req->id = 5;
17207e949c46SKenneth D. Merry 	}
17217e949c46SKenneth D. Merry 	num_mbufs = i;
17227e949c46SKenneth D. Merry 
17237e949c46SKenneth D. Merry 	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
17247e949c46SKenneth D. Merry 			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
17257e949c46SKenneth D. Merry 
17267e949c46SKenneth D. Merry 	XNB_ASSERT(nr_entries >= num_mbufs);
17277e949c46SKenneth D. Merry 	for (i = 0; i < nr_entries; i++) {
17287e949c46SKenneth D. Merry 		int end_offset = xnb_unit_pvt.gnttab[i].len +
17297e949c46SKenneth D. Merry 			xnb_unit_pvt.gnttab[i].dest.offset;
17307e949c46SKenneth D. Merry 		XNB_ASSERT(end_offset <= PAGE_SIZE);
17317e949c46SKenneth D. Merry 		total_granted_size += xnb_unit_pvt.gnttab[i].len;
17327e949c46SKenneth D. Merry 	}
17337e949c46SKenneth D. Merry 	XNB_ASSERT(total_granted_size == size);
17347e949c46SKenneth D. Merry }
17357e949c46SKenneth D. Merry 
17367e949c46SKenneth D. Merry /**
17377e949c46SKenneth D. Merry  * xnb_rxpkt2rsp on an empty packet.  Shouldn't make any response
17387e949c46SKenneth D. Merry  */
17397e949c46SKenneth D. Merry static void
xnb_rxpkt2rsp_empty(char * buffer,size_t buflen)17407e949c46SKenneth D. Merry xnb_rxpkt2rsp_empty(char *buffer, size_t buflen)
17417e949c46SKenneth D. Merry {
17427e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
17437e949c46SKenneth D. Merry 	int nr_entries;
17447e949c46SKenneth D. Merry 	int nr_reqs;
17457e949c46SKenneth D. Merry 	int free_slots = 60;
17467e949c46SKenneth D. Merry 	netif_rx_back_ring_t rxb_backup = xnb_unit_pvt.rxb;
17477e949c46SKenneth D. Merry 	netif_rx_sring_t rxs_backup = *xnb_unit_pvt.rxs;
17487e949c46SKenneth D. Merry 	struct mbuf *mbuf;
17497e949c46SKenneth D. Merry 
17507e949c46SKenneth D. Merry 	mbuf = m_get(M_WAITOK, MT_DATA);
17517e949c46SKenneth D. Merry 
17527e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
17537e949c46SKenneth D. Merry 	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
17547e949c46SKenneth D. Merry 			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
17557e949c46SKenneth D. Merry 
17567e949c46SKenneth D. Merry 	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
17577e949c46SKenneth D. Merry 	    &xnb_unit_pvt.rxb);
17587e949c46SKenneth D. Merry 	XNB_ASSERT(nr_reqs == 0);
17597e949c46SKenneth D. Merry 	XNB_ASSERT(
17607e949c46SKenneth D. Merry 	    memcmp(&rxb_backup, &xnb_unit_pvt.rxb, sizeof(rxb_backup)) == 0);
17617e949c46SKenneth D. Merry 	XNB_ASSERT(
17627e949c46SKenneth D. Merry 	    memcmp(&rxs_backup, xnb_unit_pvt.rxs, sizeof(rxs_backup)) == 0);
17637e949c46SKenneth D. Merry 
17647e949c46SKenneth D. Merry 	safe_m_freem(&mbuf);
17657e949c46SKenneth D. Merry }
17667e949c46SKenneth D. Merry 
17677e949c46SKenneth D. Merry /**
17687e949c46SKenneth D. Merry  * xnb_rxpkt2rsp on a short packet with no extras
17697e949c46SKenneth D. Merry  */
17707e949c46SKenneth D. Merry static void
xnb_rxpkt2rsp_short(char * buffer,size_t buflen)17717e949c46SKenneth D. Merry xnb_rxpkt2rsp_short(char *buffer, size_t buflen)
17727e949c46SKenneth D. Merry {
17737e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
17747e949c46SKenneth D. Merry 	int nr_entries, nr_reqs;
17757e949c46SKenneth D. Merry 	size_t size = 128;
17767e949c46SKenneth D. Merry 	int free_slots = 60;
17777e949c46SKenneth D. Merry 	RING_IDX start = 5;
17787e949c46SKenneth D. Merry 	struct netif_rx_request *req;
17797e949c46SKenneth D. Merry 	struct netif_rx_response *rsp;
17807e949c46SKenneth D. Merry 	struct mbuf *mbuf;
17817e949c46SKenneth D. Merry 
17827e949c46SKenneth D. Merry 	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
17837e949c46SKenneth D. Merry 	mbuf->m_flags |= M_PKTHDR;
17847e949c46SKenneth D. Merry 	mbuf->m_pkthdr.len = size;
17857e949c46SKenneth D. Merry 	mbuf->m_len = size;
17867e949c46SKenneth D. Merry 
17877e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
17887e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
17897e949c46SKenneth D. Merry 	req->gref = 7;
17907e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.req_cons = start;
17917e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
17927e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->req_prod = start + 1;
17937e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->rsp_prod = start;
17947e949c46SKenneth D. Merry 
17957e949c46SKenneth D. Merry 	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
17967e949c46SKenneth D. Merry 			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
17977e949c46SKenneth D. Merry 
17987e949c46SKenneth D. Merry 	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
17997e949c46SKenneth D. Merry 	    &xnb_unit_pvt.rxb);
18007e949c46SKenneth D. Merry 
18017e949c46SKenneth D. Merry 	XNB_ASSERT(nr_reqs == 1);
18027e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
18037e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
18047e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == req->id);
18057e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->offset == 0);
18067e949c46SKenneth D. Merry 	XNB_ASSERT((rsp->flags & (NETRXF_more_data | NETRXF_extra_info)) == 0);
18077e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == size);
18087e949c46SKenneth D. Merry 
18097e949c46SKenneth D. Merry 	safe_m_freem(&mbuf);
18107e949c46SKenneth D. Merry }
18117e949c46SKenneth D. Merry 
18127e949c46SKenneth D. Merry /**
18137e949c46SKenneth D. Merry  * xnb_rxpkt2rsp with extra data
18147e949c46SKenneth D. Merry  */
18157e949c46SKenneth D. Merry static void
xnb_rxpkt2rsp_extra(char * buffer,size_t buflen)18167e949c46SKenneth D. Merry xnb_rxpkt2rsp_extra(char *buffer, size_t buflen)
18177e949c46SKenneth D. Merry {
18187e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
18197e949c46SKenneth D. Merry 	int nr_entries, nr_reqs;
18207e949c46SKenneth D. Merry 	size_t size = 14;
18217e949c46SKenneth D. Merry 	int free_slots = 15;
18227e949c46SKenneth D. Merry 	RING_IDX start = 3;
18237e949c46SKenneth D. Merry 	uint16_t id = 49;
18247e949c46SKenneth D. Merry 	uint16_t gref = 65;
18257e949c46SKenneth D. Merry 	uint16_t mss = TCP_MSS - 40;
18267e949c46SKenneth D. Merry 	struct mbuf *mbufc;
18277e949c46SKenneth D. Merry 	struct netif_rx_request *req;
18287e949c46SKenneth D. Merry 	struct netif_rx_response *rsp;
18297e949c46SKenneth D. Merry 	struct netif_extra_info *ext;
18307e949c46SKenneth D. Merry 
18317e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
18327e949c46SKenneth D. Merry 	XNB_ASSERT(mbufc != NULL);
1833407d708cSAlan Somers 	if (mbufc == NULL)
18347e949c46SKenneth D. Merry 		return;
18357e949c46SKenneth D. Merry 
18367e949c46SKenneth D. Merry 	mbufc->m_flags |= M_PKTHDR;
18377e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = size;
18387e949c46SKenneth D. Merry 	mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
18397e949c46SKenneth D. Merry 	mbufc->m_pkthdr.tso_segsz = mss;
18407e949c46SKenneth D. Merry 	mbufc->m_len = size;
18417e949c46SKenneth D. Merry 
18427e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
18437e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
18447e949c46SKenneth D. Merry 	req->id = id;
18457e949c46SKenneth D. Merry 	req->gref = gref;
18467e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
18477e949c46SKenneth D. Merry 	req->id = id + 1;
18487e949c46SKenneth D. Merry 	req->gref = gref + 1;
18497e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.req_cons = start;
18507e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
18517e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->req_prod = start + 2;
18527e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->rsp_prod = start;
18537e949c46SKenneth D. Merry 
18547e949c46SKenneth D. Merry 	nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
18557e949c46SKenneth D. Merry 			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
18567e949c46SKenneth D. Merry 
18577e949c46SKenneth D. Merry 	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
18587e949c46SKenneth D. Merry 	    &xnb_unit_pvt.rxb);
18597e949c46SKenneth D. Merry 
18607e949c46SKenneth D. Merry 	XNB_ASSERT(nr_reqs == 2);
18617e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
18627e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
18637e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == id);
18647e949c46SKenneth D. Merry 	XNB_ASSERT((rsp->flags & NETRXF_more_data) == 0);
18657e949c46SKenneth D. Merry 	XNB_ASSERT((rsp->flags & NETRXF_extra_info));
18667e949c46SKenneth D. Merry 	XNB_ASSERT((rsp->flags & NETRXF_data_validated));
18677e949c46SKenneth D. Merry 	XNB_ASSERT((rsp->flags & NETRXF_csum_blank));
18687e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == size);
18697e949c46SKenneth D. Merry 
18707e949c46SKenneth D. Merry 	ext = (struct netif_extra_info*)
18717e949c46SKenneth D. Merry 		RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
18727e949c46SKenneth D. Merry 	XNB_ASSERT(ext->type == XEN_NETIF_EXTRA_TYPE_GSO);
18737e949c46SKenneth D. Merry 	XNB_ASSERT(! (ext->flags & XEN_NETIF_EXTRA_FLAG_MORE));
18747e949c46SKenneth D. Merry 	XNB_ASSERT(ext->u.gso.size == mss);
18757e949c46SKenneth D. Merry 	XNB_ASSERT(ext->u.gso.type == XEN_NETIF_EXTRA_TYPE_GSO);
18767e949c46SKenneth D. Merry 
18777e949c46SKenneth D. Merry 	safe_m_freem(&mbufc);
18787e949c46SKenneth D. Merry }
18797e949c46SKenneth D. Merry 
18807e949c46SKenneth D. Merry /**
18817e949c46SKenneth D. Merry  * xnb_rxpkt2rsp on a packet with more than a pages's worth of data.  It should
18827e949c46SKenneth D. Merry  * generate two response slot
18837e949c46SKenneth D. Merry  */
18847e949c46SKenneth D. Merry static void
xnb_rxpkt2rsp_2slots(char * buffer,size_t buflen)18857e949c46SKenneth D. Merry xnb_rxpkt2rsp_2slots(char *buffer, size_t buflen)
18867e949c46SKenneth D. Merry {
18877e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
18887e949c46SKenneth D. Merry 	int nr_entries, nr_reqs;
18897e949c46SKenneth D. Merry 	size_t size = PAGE_SIZE + 100;
18907e949c46SKenneth D. Merry 	int free_slots = 3;
18917e949c46SKenneth D. Merry 	uint16_t id1 = 17;
18927e949c46SKenneth D. Merry 	uint16_t id2 = 37;
18937e949c46SKenneth D. Merry 	uint16_t gref1 = 24;
18947e949c46SKenneth D. Merry 	uint16_t gref2 = 34;
18957e949c46SKenneth D. Merry 	RING_IDX start = 15;
18967e949c46SKenneth D. Merry 	struct netif_rx_request *req;
18977e949c46SKenneth D. Merry 	struct netif_rx_response *rsp;
18987e949c46SKenneth D. Merry 	struct mbuf *mbuf;
18997e949c46SKenneth D. Merry 
19007e949c46SKenneth D. Merry 	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
19017e949c46SKenneth D. Merry 	mbuf->m_flags |= M_PKTHDR;
19027e949c46SKenneth D. Merry 	mbuf->m_pkthdr.len = size;
19037e949c46SKenneth D. Merry 	if (mbuf->m_next != NULL) {
19047e949c46SKenneth D. Merry 		size_t first_len = MIN(M_TRAILINGSPACE(mbuf), size);
19057e949c46SKenneth D. Merry 		mbuf->m_len = first_len;
19067e949c46SKenneth D. Merry 		mbuf->m_next->m_len = size - first_len;
19077e949c46SKenneth D. Merry 
19087e949c46SKenneth D. Merry 	} else {
19097e949c46SKenneth D. Merry 		mbuf->m_len = size;
19107e949c46SKenneth D. Merry 	}
19117e949c46SKenneth D. Merry 
19127e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
19137e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
19147e949c46SKenneth D. Merry 	req->gref = gref1;
19157e949c46SKenneth D. Merry 	req->id = id1;
19167e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
19177e949c46SKenneth D. Merry 	req->gref = gref2;
19187e949c46SKenneth D. Merry 	req->id = id2;
19197e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.req_cons = start;
19207e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
19217e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->req_prod = start + 2;
19227e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->rsp_prod = start;
19237e949c46SKenneth D. Merry 
19247e949c46SKenneth D. Merry 	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
19257e949c46SKenneth D. Merry 			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
19267e949c46SKenneth D. Merry 
19277e949c46SKenneth D. Merry 	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
19287e949c46SKenneth D. Merry 	    &xnb_unit_pvt.rxb);
19297e949c46SKenneth D. Merry 
19307e949c46SKenneth D. Merry 	XNB_ASSERT(nr_reqs == 2);
19317e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
19327e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
19337e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == id1);
19347e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->offset == 0);
19357e949c46SKenneth D. Merry 	XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
19367e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->flags & NETRXF_more_data);
19377e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == PAGE_SIZE);
19387e949c46SKenneth D. Merry 
19397e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
19407e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == id2);
19417e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->offset == 0);
19427e949c46SKenneth D. Merry 	XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
19437e949c46SKenneth D. Merry 	XNB_ASSERT(! (rsp->flags & NETRXF_more_data));
19447e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == size - PAGE_SIZE);
19457e949c46SKenneth D. Merry 
19467e949c46SKenneth D. Merry 	safe_m_freem(&mbuf);
19477e949c46SKenneth D. Merry }
19487e949c46SKenneth D. Merry 
19497e949c46SKenneth D. Merry /** xnb_rxpkt2rsp on a grant table with two sub-page entries */
19507e949c46SKenneth D. Merry static void
xnb_rxpkt2rsp_2short(char * buffer,size_t buflen)19517e949c46SKenneth D. Merry xnb_rxpkt2rsp_2short(char *buffer, size_t buflen) {
19527e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
19537e949c46SKenneth D. Merry 	int nr_reqs, nr_entries;
19547e949c46SKenneth D. Merry 	size_t size1 = MHLEN - 5;
19557e949c46SKenneth D. Merry 	size_t size2 = MHLEN - 15;
19567e949c46SKenneth D. Merry 	int free_slots = 32;
19577e949c46SKenneth D. Merry 	RING_IDX start = 14;
19587e949c46SKenneth D. Merry 	uint16_t id = 47;
19597e949c46SKenneth D. Merry 	uint16_t gref = 54;
19607e949c46SKenneth D. Merry 	struct netif_rx_request *req;
19617e949c46SKenneth D. Merry 	struct netif_rx_response *rsp;
19627e949c46SKenneth D. Merry 	struct mbuf *mbufc;
19637e949c46SKenneth D. Merry 
19647e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
19657e949c46SKenneth D. Merry 	XNB_ASSERT(mbufc != NULL);
1966407d708cSAlan Somers 	if (mbufc == NULL)
19677e949c46SKenneth D. Merry 		return;
1968407d708cSAlan Somers 	mbufc->m_flags |= M_PKTHDR;
19697e949c46SKenneth D. Merry 
19707e949c46SKenneth D. Merry 	m_getm(mbufc, size2, M_WAITOK, MT_DATA);
19717e949c46SKenneth D. Merry 	XNB_ASSERT(mbufc->m_next != NULL);
19727e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = size1 + size2;
19737e949c46SKenneth D. Merry 	mbufc->m_len = size1;
19747e949c46SKenneth D. Merry 	mbufc->m_next->m_len = size2;
19757e949c46SKenneth D. Merry 
19767e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
19777e949c46SKenneth D. Merry 
19787e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
19797e949c46SKenneth D. Merry 	req->gref = gref;
19807e949c46SKenneth D. Merry 	req->id = id;
19817e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.req_cons = start;
19827e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
19837e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->req_prod = start + 1;
19847e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->rsp_prod = start;
19857e949c46SKenneth D. Merry 
19867e949c46SKenneth D. Merry 	nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
19877e949c46SKenneth D. Merry 			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
19887e949c46SKenneth D. Merry 
19897e949c46SKenneth D. Merry 	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
19907e949c46SKenneth D. Merry 	    &xnb_unit_pvt.rxb);
19917e949c46SKenneth D. Merry 
19927e949c46SKenneth D. Merry 	XNB_ASSERT(nr_entries == 2);
19937e949c46SKenneth D. Merry 	XNB_ASSERT(nr_reqs == 1);
19947e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
19957e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == id);
19967e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == size1 + size2);
19977e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->offset == 0);
19987e949c46SKenneth D. Merry 	XNB_ASSERT(! (rsp->flags & (NETRXF_more_data | NETRXF_extra_info)));
19997e949c46SKenneth D. Merry 
20007e949c46SKenneth D. Merry 	safe_m_freem(&mbufc);
20017e949c46SKenneth D. Merry }
20027e949c46SKenneth D. Merry 
20037e949c46SKenneth D. Merry /**
20047e949c46SKenneth D. Merry  * xnb_rxpkt2rsp on a long packet with a hypervisor gnttab_copy error
20057e949c46SKenneth D. Merry  * Note: this test will result in an error message being printed to the console
20067e949c46SKenneth D. Merry  * such as:
20077e949c46SKenneth D. Merry  * xnb(xnb_rxpkt2rsp:1720): Got error -1 for hypervisor gnttab_copy status
20087e949c46SKenneth D. Merry  */
20097e949c46SKenneth D. Merry static void
xnb_rxpkt2rsp_copyerror(char * buffer,size_t buflen)20107e949c46SKenneth D. Merry xnb_rxpkt2rsp_copyerror(char *buffer, size_t buflen)
20117e949c46SKenneth D. Merry {
20127e949c46SKenneth D. Merry 	struct xnb_pkt pkt;
20137e949c46SKenneth D. Merry 	int nr_entries, nr_reqs;
20147e949c46SKenneth D. Merry 	int id = 7;
20157e949c46SKenneth D. Merry 	int gref = 42;
20167e949c46SKenneth D. Merry 	uint16_t canary = 6859;
20177e949c46SKenneth D. Merry 	size_t size = 7 * MCLBYTES;
20187e949c46SKenneth D. Merry 	int free_slots = 9;
20197e949c46SKenneth D. Merry 	RING_IDX start = 2;
20207e949c46SKenneth D. Merry 	struct netif_rx_request *req;
20217e949c46SKenneth D. Merry 	struct netif_rx_response *rsp;
20227e949c46SKenneth D. Merry 	struct mbuf *mbuf;
20237e949c46SKenneth D. Merry 
20247e949c46SKenneth D. Merry 	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
20257e949c46SKenneth D. Merry 	mbuf->m_flags |= M_PKTHDR;
20267e949c46SKenneth D. Merry 	mbuf->m_pkthdr.len = size;
20277e949c46SKenneth D. Merry 	mbuf->m_len = size;
20287e949c46SKenneth D. Merry 
20297e949c46SKenneth D. Merry 	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
20307e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
20317e949c46SKenneth D. Merry 	req->gref = gref;
20327e949c46SKenneth D. Merry 	req->id = id;
20337e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.req_cons = start;
20347e949c46SKenneth D. Merry 	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
20357e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->req_prod = start + 1;
20367e949c46SKenneth D. Merry 	xnb_unit_pvt.rxs->rsp_prod = start;
20377e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
20387e949c46SKenneth D. Merry 	req->gref = canary;
20397e949c46SKenneth D. Merry 	req->id = canary;
20407e949c46SKenneth D. Merry 
20417e949c46SKenneth D. Merry 	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
20427e949c46SKenneth D. Merry 			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
20437e949c46SKenneth D. Merry 	/* Inject the error*/
20447e949c46SKenneth D. Merry 	xnb_unit_pvt.gnttab[2].status = GNTST_general_error;
20457e949c46SKenneth D. Merry 
20467e949c46SKenneth D. Merry 	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
20477e949c46SKenneth D. Merry 	    &xnb_unit_pvt.rxb);
20487e949c46SKenneth D. Merry 
20497e949c46SKenneth D. Merry 	XNB_ASSERT(nr_reqs == 1);
20507e949c46SKenneth D. Merry 	XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
20517e949c46SKenneth D. Merry 	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
20527e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->id == id);
20537e949c46SKenneth D. Merry 	XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
20547e949c46SKenneth D. Merry 	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
20557e949c46SKenneth D. Merry 	XNB_ASSERT(req->gref == canary);
20567e949c46SKenneth D. Merry 	XNB_ASSERT(req->id == canary);
20577e949c46SKenneth D. Merry 
20587e949c46SKenneth D. Merry 	safe_m_freem(&mbuf);
20597e949c46SKenneth D. Merry }
20607e949c46SKenneth D. Merry 
2061f909bbb4SGleb Smirnoff #if defined(INET) || defined(INET6)
20627e949c46SKenneth D. Merry /**
20637e949c46SKenneth D. Merry  * xnb_add_mbuf_cksum on an ARP request packet
20647e949c46SKenneth D. Merry  */
20657e949c46SKenneth D. Merry static void
xnb_add_mbuf_cksum_arp(char * buffer,size_t buflen)20667e949c46SKenneth D. Merry xnb_add_mbuf_cksum_arp(char *buffer, size_t buflen)
20677e949c46SKenneth D. Merry {
20687e949c46SKenneth D. Merry 	const size_t pkt_len = sizeof(struct ether_header) +
20697e949c46SKenneth D. Merry 		sizeof(struct ether_arp);
20707e949c46SKenneth D. Merry 	struct mbuf *mbufc;
20717e949c46SKenneth D. Merry 	struct ether_header *eh;
20727e949c46SKenneth D. Merry 	struct ether_arp *ep;
20737e949c46SKenneth D. Merry 	unsigned char pkt_orig[pkt_len];
20747e949c46SKenneth D. Merry 
20757e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
20767e949c46SKenneth D. Merry 	/* Fill in an example arp request */
20777e949c46SKenneth D. Merry 	eh = mtod(mbufc, struct ether_header*);
20787e949c46SKenneth D. Merry 	eh->ether_dhost[0] = 0xff;
20797e949c46SKenneth D. Merry 	eh->ether_dhost[1] = 0xff;
20807e949c46SKenneth D. Merry 	eh->ether_dhost[2] = 0xff;
20817e949c46SKenneth D. Merry 	eh->ether_dhost[3] = 0xff;
20827e949c46SKenneth D. Merry 	eh->ether_dhost[4] = 0xff;
20837e949c46SKenneth D. Merry 	eh->ether_dhost[5] = 0xff;
20847e949c46SKenneth D. Merry 	eh->ether_shost[0] = 0x00;
20857e949c46SKenneth D. Merry 	eh->ether_shost[1] = 0x15;
20867e949c46SKenneth D. Merry 	eh->ether_shost[2] = 0x17;
20877e949c46SKenneth D. Merry 	eh->ether_shost[3] = 0xe9;
20887e949c46SKenneth D. Merry 	eh->ether_shost[4] = 0x30;
20897e949c46SKenneth D. Merry 	eh->ether_shost[5] = 0x68;
20907e949c46SKenneth D. Merry 	eh->ether_type = htons(ETHERTYPE_ARP);
20917e949c46SKenneth D. Merry 	ep = (struct ether_arp*)(eh + 1);
20927e949c46SKenneth D. Merry 	ep->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
20937e949c46SKenneth D. Merry 	ep->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
20947e949c46SKenneth D. Merry 	ep->ea_hdr.ar_hln = 6;
20957e949c46SKenneth D. Merry 	ep->ea_hdr.ar_pln = 4;
20967e949c46SKenneth D. Merry 	ep->ea_hdr.ar_op = htons(ARPOP_REQUEST);
20977e949c46SKenneth D. Merry 	ep->arp_sha[0] = 0x00;
20987e949c46SKenneth D. Merry 	ep->arp_sha[1] = 0x15;
20997e949c46SKenneth D. Merry 	ep->arp_sha[2] = 0x17;
21007e949c46SKenneth D. Merry 	ep->arp_sha[3] = 0xe9;
21017e949c46SKenneth D. Merry 	ep->arp_sha[4] = 0x30;
21027e949c46SKenneth D. Merry 	ep->arp_sha[5] = 0x68;
21037e949c46SKenneth D. Merry 	ep->arp_spa[0] = 0xc0;
21047e949c46SKenneth D. Merry 	ep->arp_spa[1] = 0xa8;
21057e949c46SKenneth D. Merry 	ep->arp_spa[2] = 0x0a;
21067e949c46SKenneth D. Merry 	ep->arp_spa[3] = 0x04;
21077e949c46SKenneth D. Merry 	bzero(&(ep->arp_tha), ETHER_ADDR_LEN);
21087e949c46SKenneth D. Merry 	ep->arp_tpa[0] = 0xc0;
21097e949c46SKenneth D. Merry 	ep->arp_tpa[1] = 0xa8;
21107e949c46SKenneth D. Merry 	ep->arp_tpa[2] = 0x0a;
21117e949c46SKenneth D. Merry 	ep->arp_tpa[3] = 0x06;
21127e949c46SKenneth D. Merry 
21137e949c46SKenneth D. Merry 	/* fill in the length field */
21147e949c46SKenneth D. Merry 	mbufc->m_len = pkt_len;
21157e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = pkt_len;
21167e949c46SKenneth D. Merry 	/* indicate that the netfront uses hw-assisted checksums */
21177e949c46SKenneth D. Merry 	mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
21187e949c46SKenneth D. Merry 				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
21197e949c46SKenneth D. Merry 
21207e949c46SKenneth D. Merry 	/* Make a backup copy of the packet */
21217e949c46SKenneth D. Merry 	bcopy(mtod(mbufc, const void*), pkt_orig, pkt_len);
21227e949c46SKenneth D. Merry 
21237e949c46SKenneth D. Merry 	/* Function under test */
21247e949c46SKenneth D. Merry 	xnb_add_mbuf_cksum(mbufc);
21257e949c46SKenneth D. Merry 
21267e949c46SKenneth D. Merry 	/* Verify that the packet's data did not change */
21277e949c46SKenneth D. Merry 	XNB_ASSERT(bcmp(mtod(mbufc, const void*), pkt_orig, pkt_len) == 0);
21287e949c46SKenneth D. Merry 	m_freem(mbufc);
21297e949c46SKenneth D. Merry }
21307e949c46SKenneth D. Merry 
21317e949c46SKenneth D. Merry /**
21327e949c46SKenneth D. Merry  * Helper function that populates the ethernet header and IP header used by
21337e949c46SKenneth D. Merry  * some of the xnb_add_mbuf_cksum unit tests.  m must already be allocated
21347e949c46SKenneth D. Merry  * and must be large enough
21357e949c46SKenneth D. Merry  */
21367e949c46SKenneth D. Merry static void
xnb_fill_eh_and_ip(struct mbuf * m,uint16_t ip_len,uint16_t ip_id,uint16_t ip_p,uint16_t ip_off,uint16_t ip_sum)21377e949c46SKenneth D. Merry xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len, uint16_t ip_id,
21387e949c46SKenneth D. Merry 		   uint16_t ip_p, uint16_t ip_off, uint16_t ip_sum)
21397e949c46SKenneth D. Merry {
21407e949c46SKenneth D. Merry 	struct ether_header *eh;
21417e949c46SKenneth D. Merry 	struct ip *iph;
21427e949c46SKenneth D. Merry 
21437e949c46SKenneth D. Merry 	eh = mtod(m, struct ether_header*);
21447e949c46SKenneth D. Merry 	eh->ether_dhost[0] = 0x00;
21457e949c46SKenneth D. Merry 	eh->ether_dhost[1] = 0x16;
21467e949c46SKenneth D. Merry 	eh->ether_dhost[2] = 0x3e;
21477e949c46SKenneth D. Merry 	eh->ether_dhost[3] = 0x23;
21487e949c46SKenneth D. Merry 	eh->ether_dhost[4] = 0x50;
21497e949c46SKenneth D. Merry 	eh->ether_dhost[5] = 0x0b;
21507e949c46SKenneth D. Merry 	eh->ether_shost[0] = 0x00;
21517e949c46SKenneth D. Merry 	eh->ether_shost[1] = 0x16;
21527e949c46SKenneth D. Merry 	eh->ether_shost[2] = 0x30;
21537e949c46SKenneth D. Merry 	eh->ether_shost[3] = 0x00;
21547e949c46SKenneth D. Merry 	eh->ether_shost[4] = 0x00;
21557e949c46SKenneth D. Merry 	eh->ether_shost[5] = 0x00;
21567e949c46SKenneth D. Merry 	eh->ether_type = htons(ETHERTYPE_IP);
21577e949c46SKenneth D. Merry 	iph = (struct ip*)(eh + 1);
21587e949c46SKenneth D. Merry 	iph->ip_hl = 0x5;	/* 5 dwords == 20 bytes */
21597e949c46SKenneth D. Merry 	iph->ip_v = 4;		/* IP v4 */
21607e949c46SKenneth D. Merry 	iph->ip_tos = 0;
21617e949c46SKenneth D. Merry 	iph->ip_len = htons(ip_len);
21627e949c46SKenneth D. Merry 	iph->ip_id = htons(ip_id);
21637e949c46SKenneth D. Merry 	iph->ip_off = htons(ip_off);
21647e949c46SKenneth D. Merry 	iph->ip_ttl = 64;
21657e949c46SKenneth D. Merry 	iph->ip_p = ip_p;
21667e949c46SKenneth D. Merry 	iph->ip_sum = htons(ip_sum);
21677e949c46SKenneth D. Merry 	iph->ip_src.s_addr = htonl(0xc0a80a04);
21687e949c46SKenneth D. Merry 	iph->ip_dst.s_addr = htonl(0xc0a80a05);
21697e949c46SKenneth D. Merry }
21707e949c46SKenneth D. Merry 
21717e949c46SKenneth D. Merry /**
21727e949c46SKenneth D. Merry  * xnb_add_mbuf_cksum on an ICMP packet, based on a tcpdump of an actual
21737e949c46SKenneth D. Merry  * ICMP packet
21747e949c46SKenneth D. Merry  */
21757e949c46SKenneth D. Merry static void
xnb_add_mbuf_cksum_icmp(char * buffer,size_t buflen)21767e949c46SKenneth D. Merry xnb_add_mbuf_cksum_icmp(char *buffer, size_t buflen)
21777e949c46SKenneth D. Merry {
21787e949c46SKenneth D. Merry 	const size_t icmp_len = 64;	/* set by ping(1) */
21797e949c46SKenneth D. Merry 	const size_t pkt_len = sizeof(struct ether_header) +
21807e949c46SKenneth D. Merry 		sizeof(struct ip) + icmp_len;
21817e949c46SKenneth D. Merry 	struct mbuf *mbufc;
21827e949c46SKenneth D. Merry 	struct ether_header *eh;
21837e949c46SKenneth D. Merry 	struct ip *iph;
21847e949c46SKenneth D. Merry 	struct icmp *icmph;
21857e949c46SKenneth D. Merry 	unsigned char pkt_orig[icmp_len];
21867e949c46SKenneth D. Merry 	uint32_t *tv_field;
21877e949c46SKenneth D. Merry 	uint8_t *data_payload;
21887e949c46SKenneth D. Merry 	int i;
21897e949c46SKenneth D. Merry 	const uint16_t ICMP_CSUM = 0xaed7;
21907e949c46SKenneth D. Merry 	const uint16_t IP_CSUM = 0xe533;
21917e949c46SKenneth D. Merry 
21927e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
21937e949c46SKenneth D. Merry 	/* Fill in an example ICMP ping request */
21947e949c46SKenneth D. Merry 	eh = mtod(mbufc, struct ether_header*);
21957e949c46SKenneth D. Merry 	xnb_fill_eh_and_ip(mbufc, 84, 28, IPPROTO_ICMP, 0, 0);
21967e949c46SKenneth D. Merry 	iph = (struct ip*)(eh + 1);
21977e949c46SKenneth D. Merry 	icmph = (struct icmp*)(iph + 1);
21987e949c46SKenneth D. Merry 	icmph->icmp_type = ICMP_ECHO;
21997e949c46SKenneth D. Merry 	icmph->icmp_code = 0;
22007e949c46SKenneth D. Merry 	icmph->icmp_cksum = htons(ICMP_CSUM);
22017e949c46SKenneth D. Merry 	icmph->icmp_id = htons(31492);
22027e949c46SKenneth D. Merry 	icmph->icmp_seq = htons(0);
22037e949c46SKenneth D. Merry 	/*
22047e949c46SKenneth D. Merry 	 * ping(1) uses bcopy to insert a native-endian timeval after icmp_seq.
22057e949c46SKenneth D. Merry 	 * For this test, we will set the bytes individually for portability.
22067e949c46SKenneth D. Merry 	 */
22077e949c46SKenneth D. Merry 	tv_field = (uint32_t*)(&(icmph->icmp_hun));
22087e949c46SKenneth D. Merry 	tv_field[0] = 0x4f02cfac;
22097e949c46SKenneth D. Merry 	tv_field[1] = 0x0007c46a;
22107e949c46SKenneth D. Merry 	/*
22117e949c46SKenneth D. Merry 	 * Remainder of packet is an incrmenting 8 bit integer, starting with 8
22127e949c46SKenneth D. Merry 	 */
22137e949c46SKenneth D. Merry 	data_payload = (uint8_t*)(&tv_field[2]);
22147e949c46SKenneth D. Merry 	for (i = 8; i < 37; i++) {
22157e949c46SKenneth D. Merry 		*data_payload++ = i;
22167e949c46SKenneth D. Merry 	}
22177e949c46SKenneth D. Merry 
22187e949c46SKenneth D. Merry 	/* fill in the length field */
22197e949c46SKenneth D. Merry 	mbufc->m_len = pkt_len;
22207e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = pkt_len;
22217e949c46SKenneth D. Merry 	/* indicate that the netfront uses hw-assisted checksums */
22227e949c46SKenneth D. Merry 	mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
22237e949c46SKenneth D. Merry 				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
22247e949c46SKenneth D. Merry 
22257e949c46SKenneth D. Merry 	bcopy(mtod(mbufc, const void*), pkt_orig, icmp_len);
22267e949c46SKenneth D. Merry 	/* Function under test */
22277e949c46SKenneth D. Merry 	xnb_add_mbuf_cksum(mbufc);
22287e949c46SKenneth D. Merry 
22297e949c46SKenneth D. Merry 	/* Check the IP checksum */
22307e949c46SKenneth D. Merry 	XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
22317e949c46SKenneth D. Merry 
22327e949c46SKenneth D. Merry 	/* Check that the ICMP packet did not change */
22337e949c46SKenneth D. Merry 	XNB_ASSERT(bcmp(icmph, pkt_orig, icmp_len));
22347e949c46SKenneth D. Merry 	m_freem(mbufc);
22357e949c46SKenneth D. Merry }
22367e949c46SKenneth D. Merry 
22377e949c46SKenneth D. Merry /**
22387e949c46SKenneth D. Merry  * xnb_add_mbuf_cksum on a UDP packet, based on a tcpdump of an actual
22397e949c46SKenneth D. Merry  * UDP packet
22407e949c46SKenneth D. Merry  */
22417e949c46SKenneth D. Merry static void
xnb_add_mbuf_cksum_udp(char * buffer,size_t buflen)22427e949c46SKenneth D. Merry xnb_add_mbuf_cksum_udp(char *buffer, size_t buflen)
22437e949c46SKenneth D. Merry {
22447e949c46SKenneth D. Merry 	const size_t udp_len = 16;
22457e949c46SKenneth D. Merry 	const size_t pkt_len = sizeof(struct ether_header) +
22467e949c46SKenneth D. Merry 		sizeof(struct ip) + udp_len;
22477e949c46SKenneth D. Merry 	struct mbuf *mbufc;
22487e949c46SKenneth D. Merry 	struct ether_header *eh;
22497e949c46SKenneth D. Merry 	struct ip *iph;
22507e949c46SKenneth D. Merry 	struct udphdr *udp;
22517e949c46SKenneth D. Merry 	uint8_t *data_payload;
22527e949c46SKenneth D. Merry 	const uint16_t IP_CSUM = 0xe56b;
22537e949c46SKenneth D. Merry 	const uint16_t UDP_CSUM = 0xdde2;
22547e949c46SKenneth D. Merry 
22557e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
22567e949c46SKenneth D. Merry 	/* Fill in an example UDP packet made by 'uname | nc -u <host> 2222 */
22577e949c46SKenneth D. Merry 	eh = mtod(mbufc, struct ether_header*);
22587e949c46SKenneth D. Merry 	xnb_fill_eh_and_ip(mbufc, 36, 4, IPPROTO_UDP, 0, 0xbaad);
22597e949c46SKenneth D. Merry 	iph = (struct ip*)(eh + 1);
22607e949c46SKenneth D. Merry 	udp = (struct udphdr*)(iph + 1);
22617e949c46SKenneth D. Merry 	udp->uh_sport = htons(0x51ae);
22627e949c46SKenneth D. Merry 	udp->uh_dport = htons(0x08ae);
22637e949c46SKenneth D. Merry 	udp->uh_ulen = htons(udp_len);
22647e949c46SKenneth D. Merry 	udp->uh_sum = htons(0xbaad);  /* xnb_add_mbuf_cksum will fill this in */
22657e949c46SKenneth D. Merry 	data_payload = (uint8_t*)(udp + 1);
22667e949c46SKenneth D. Merry 	data_payload[0] = 'F';
22677e949c46SKenneth D. Merry 	data_payload[1] = 'r';
22687e949c46SKenneth D. Merry 	data_payload[2] = 'e';
22697e949c46SKenneth D. Merry 	data_payload[3] = 'e';
22707e949c46SKenneth D. Merry 	data_payload[4] = 'B';
22717e949c46SKenneth D. Merry 	data_payload[5] = 'S';
22727e949c46SKenneth D. Merry 	data_payload[6] = 'D';
22737e949c46SKenneth D. Merry 	data_payload[7] = '\n';
22747e949c46SKenneth D. Merry 
22757e949c46SKenneth D. Merry 	/* fill in the length field */
22767e949c46SKenneth D. Merry 	mbufc->m_len = pkt_len;
22777e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = pkt_len;
22787e949c46SKenneth D. Merry 	/* indicate that the netfront uses hw-assisted checksums */
22797e949c46SKenneth D. Merry 	mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
22807e949c46SKenneth D. Merry 				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
22817e949c46SKenneth D. Merry 
22827e949c46SKenneth D. Merry 	/* Function under test */
22837e949c46SKenneth D. Merry 	xnb_add_mbuf_cksum(mbufc);
22847e949c46SKenneth D. Merry 
22857e949c46SKenneth D. Merry 	/* Check the checksums */
22867e949c46SKenneth D. Merry 	XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
22877e949c46SKenneth D. Merry 	XNB_ASSERT(udp->uh_sum == htons(UDP_CSUM));
22887e949c46SKenneth D. Merry 
22897e949c46SKenneth D. Merry 	m_freem(mbufc);
22907e949c46SKenneth D. Merry }
22917e949c46SKenneth D. Merry 
22927e949c46SKenneth D. Merry /**
22937e949c46SKenneth D. Merry  * Helper function that populates a TCP packet used by all of the
22947e949c46SKenneth D. Merry  * xnb_add_mbuf_cksum tcp unit tests.  m must already be allocated and must be
22957e949c46SKenneth D. Merry  * large enough
22967e949c46SKenneth D. Merry  */
22977e949c46SKenneth D. Merry static void
xnb_fill_tcp(struct mbuf * m)22987e949c46SKenneth D. Merry xnb_fill_tcp(struct mbuf *m)
22997e949c46SKenneth D. Merry {
23007e949c46SKenneth D. Merry 	struct ether_header *eh;
23017e949c46SKenneth D. Merry 	struct ip *iph;
23027e949c46SKenneth D. Merry 	struct tcphdr *tcp;
23037e949c46SKenneth D. Merry 	uint32_t *options;
23047e949c46SKenneth D. Merry 	uint8_t *data_payload;
23057e949c46SKenneth D. Merry 
23067e949c46SKenneth D. Merry 	/* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
23077e949c46SKenneth D. Merry 	eh = mtod(m, struct ether_header*);
23087e949c46SKenneth D. Merry 	xnb_fill_eh_and_ip(m, 60, 8, IPPROTO_TCP, IP_DF, 0);
23097e949c46SKenneth D. Merry 	iph = (struct ip*)(eh + 1);
23107e949c46SKenneth D. Merry 	tcp = (struct tcphdr*)(iph + 1);
23117e949c46SKenneth D. Merry 	tcp->th_sport = htons(0x9cd9);
23127e949c46SKenneth D. Merry 	tcp->th_dport = htons(2222);
23137e949c46SKenneth D. Merry 	tcp->th_seq = htonl(0x00f72b10);
23147e949c46SKenneth D. Merry 	tcp->th_ack = htonl(0x7f37ba6c);
2315*a8b70cf2SRichard Scheffenegger 	tcp_set_flags(tcp, TH_ACK | TH_PUSH);
23167e949c46SKenneth D. Merry 	tcp->th_off = 8;
23177e949c46SKenneth D. Merry 	tcp->th_win = htons(0x410);
23187e949c46SKenneth D. Merry 	/* th_sum is incorrect; will be inserted by function under test */
23197e949c46SKenneth D. Merry 	tcp->th_sum = htons(0xbaad);
23207e949c46SKenneth D. Merry 	tcp->th_urp = htons(0);
23217e949c46SKenneth D. Merry 	/*
23227e949c46SKenneth D. Merry 	 * The following 12 bytes of options encode:
23237e949c46SKenneth D. Merry 	 * [nop, nop, TS val 33247 ecr 3457687679]
23247e949c46SKenneth D. Merry 	 */
23257e949c46SKenneth D. Merry 	options = (uint32_t*)(tcp + 1);
23267e949c46SKenneth D. Merry 	options[0] = htonl(0x0101080a);
23277e949c46SKenneth D. Merry 	options[1] = htonl(0x000081df);
23287e949c46SKenneth D. Merry 	options[2] = htonl(0xce18207f);
23297e949c46SKenneth D. Merry 	data_payload = (uint8_t*)(&options[3]);
23307e949c46SKenneth D. Merry 	data_payload[0] = 'F';
23317e949c46SKenneth D. Merry 	data_payload[1] = 'r';
23327e949c46SKenneth D. Merry 	data_payload[2] = 'e';
23337e949c46SKenneth D. Merry 	data_payload[3] = 'e';
23347e949c46SKenneth D. Merry 	data_payload[4] = 'B';
23357e949c46SKenneth D. Merry 	data_payload[5] = 'S';
23367e949c46SKenneth D. Merry 	data_payload[6] = 'D';
23377e949c46SKenneth D. Merry 	data_payload[7] = '\n';
23387e949c46SKenneth D. Merry }
23397e949c46SKenneth D. Merry 
23407e949c46SKenneth D. Merry /**
23417e949c46SKenneth D. Merry  * xnb_add_mbuf_cksum on a TCP packet, based on a tcpdump of an actual TCP
23427e949c46SKenneth D. Merry  * packet
23437e949c46SKenneth D. Merry  */
23447e949c46SKenneth D. Merry static void
xnb_add_mbuf_cksum_tcp(char * buffer,size_t buflen)23457e949c46SKenneth D. Merry xnb_add_mbuf_cksum_tcp(char *buffer, size_t buflen)
23467e949c46SKenneth D. Merry {
23477e949c46SKenneth D. Merry 	const size_t payload_len = 8;
23487e949c46SKenneth D. Merry 	const size_t tcp_options_len = 12;
23497e949c46SKenneth D. Merry 	const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
23507e949c46SKenneth D. Merry 	    sizeof(struct tcphdr) + tcp_options_len + payload_len;
23517e949c46SKenneth D. Merry 	struct mbuf *mbufc;
23527e949c46SKenneth D. Merry 	struct ether_header *eh;
23537e949c46SKenneth D. Merry 	struct ip *iph;
23547e949c46SKenneth D. Merry 	struct tcphdr *tcp;
23557e949c46SKenneth D. Merry 	const uint16_t IP_CSUM = 0xa55a;
23567e949c46SKenneth D. Merry 	const uint16_t TCP_CSUM = 0x2f64;
23577e949c46SKenneth D. Merry 
23587e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
23597e949c46SKenneth D. Merry 	/* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
23607e949c46SKenneth D. Merry 	xnb_fill_tcp(mbufc);
23617e949c46SKenneth D. Merry 	eh = mtod(mbufc, struct ether_header*);
23627e949c46SKenneth D. Merry 	iph = (struct ip*)(eh + 1);
23637e949c46SKenneth D. Merry 	tcp = (struct tcphdr*)(iph + 1);
23647e949c46SKenneth D. Merry 
23657e949c46SKenneth D. Merry 	/* fill in the length field */
23667e949c46SKenneth D. Merry 	mbufc->m_len = pkt_len;
23677e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = pkt_len;
23687e949c46SKenneth D. Merry 	/* indicate that the netfront uses hw-assisted checksums */
23697e949c46SKenneth D. Merry 	mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
23707e949c46SKenneth D. Merry 				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
23717e949c46SKenneth D. Merry 
23727e949c46SKenneth D. Merry 	/* Function under test */
23737e949c46SKenneth D. Merry 	xnb_add_mbuf_cksum(mbufc);
23747e949c46SKenneth D. Merry 
23757e949c46SKenneth D. Merry 	/* Check the checksums */
23767e949c46SKenneth D. Merry 	XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
23777e949c46SKenneth D. Merry 	XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
23787e949c46SKenneth D. Merry 
23797e949c46SKenneth D. Merry 	m_freem(mbufc);
23807e949c46SKenneth D. Merry }
23817e949c46SKenneth D. Merry 
23827e949c46SKenneth D. Merry /**
23837e949c46SKenneth D. Merry  * xnb_add_mbuf_cksum on a TCP packet that does not use HW assisted checksums
23847e949c46SKenneth D. Merry  */
23857e949c46SKenneth D. Merry static void
xnb_add_mbuf_cksum_tcp_swcksum(char * buffer,size_t buflen)23867e949c46SKenneth D. Merry xnb_add_mbuf_cksum_tcp_swcksum(char *buffer, size_t buflen)
23877e949c46SKenneth D. Merry {
23887e949c46SKenneth D. Merry 	const size_t payload_len = 8;
23897e949c46SKenneth D. Merry 	const size_t tcp_options_len = 12;
23907e949c46SKenneth D. Merry 	const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
23917e949c46SKenneth D. Merry 	    sizeof(struct tcphdr) + tcp_options_len + payload_len;
23927e949c46SKenneth D. Merry 	struct mbuf *mbufc;
23937e949c46SKenneth D. Merry 	struct ether_header *eh;
23947e949c46SKenneth D. Merry 	struct ip *iph;
23957e949c46SKenneth D. Merry 	struct tcphdr *tcp;
23967e949c46SKenneth D. Merry 	/* Use deliberately bad checksums, and verify that they don't get */
23977e949c46SKenneth D. Merry 	/* corrected by xnb_add_mbuf_cksum */
23987e949c46SKenneth D. Merry 	const uint16_t IP_CSUM = 0xdead;
23997e949c46SKenneth D. Merry 	const uint16_t TCP_CSUM = 0xbeef;
24007e949c46SKenneth D. Merry 
24017e949c46SKenneth D. Merry 	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
24027e949c46SKenneth D. Merry 	/* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
24037e949c46SKenneth D. Merry 	xnb_fill_tcp(mbufc);
24047e949c46SKenneth D. Merry 	eh = mtod(mbufc, struct ether_header*);
24057e949c46SKenneth D. Merry 	iph = (struct ip*)(eh + 1);
24067e949c46SKenneth D. Merry 	iph->ip_sum = htons(IP_CSUM);
24077e949c46SKenneth D. Merry 	tcp = (struct tcphdr*)(iph + 1);
24087e949c46SKenneth D. Merry 	tcp->th_sum = htons(TCP_CSUM);
24097e949c46SKenneth D. Merry 
24107e949c46SKenneth D. Merry 	/* fill in the length field */
24117e949c46SKenneth D. Merry 	mbufc->m_len = pkt_len;
24127e949c46SKenneth D. Merry 	mbufc->m_pkthdr.len = pkt_len;
24137e949c46SKenneth D. Merry 	/* indicate that the netfront does not use hw-assisted checksums */
24147e949c46SKenneth D. Merry 	mbufc->m_pkthdr.csum_flags = 0;
24157e949c46SKenneth D. Merry 
24167e949c46SKenneth D. Merry 	/* Function under test */
24177e949c46SKenneth D. Merry 	xnb_add_mbuf_cksum(mbufc);
24187e949c46SKenneth D. Merry 
24197e949c46SKenneth D. Merry 	/* Check that the checksums didn't change */
24207e949c46SKenneth D. Merry 	XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
24217e949c46SKenneth D. Merry 	XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
24227e949c46SKenneth D. Merry 
24237e949c46SKenneth D. Merry 	m_freem(mbufc);
24247e949c46SKenneth D. Merry }
2425f909bbb4SGleb Smirnoff #endif /* INET || INET6 */
24267e949c46SKenneth D. Merry 
24277e949c46SKenneth D. Merry /**
24287e949c46SKenneth D. Merry  * sscanf on unsigned chars
24297e949c46SKenneth D. Merry  */
24307e949c46SKenneth D. Merry static void
xnb_sscanf_hhu(char * buffer,size_t buflen)24317e949c46SKenneth D. Merry xnb_sscanf_hhu(char *buffer, size_t buflen)
24327e949c46SKenneth D. Merry {
24337e949c46SKenneth D. Merry 	const char mystr[] = "137";
24347e949c46SKenneth D. Merry 	uint8_t dest[12];
24357e949c46SKenneth D. Merry 	int i;
24367e949c46SKenneth D. Merry 
24377e949c46SKenneth D. Merry 	for (i = 0; i < 12; i++)
24387e949c46SKenneth D. Merry 		dest[i] = 'X';
24397e949c46SKenneth D. Merry 
2440407d708cSAlan Somers 	XNB_ASSERT(sscanf(mystr, "%hhu", &dest[4]) == 1);
24417e949c46SKenneth D. Merry 	for (i = 0; i < 12; i++)
24427e949c46SKenneth D. Merry 		XNB_ASSERT(dest[i] == (i == 4 ? 137 : 'X'));
24437e949c46SKenneth D. Merry }
24447e949c46SKenneth D. Merry 
24457e949c46SKenneth D. Merry /**
24467e949c46SKenneth D. Merry  * sscanf on signed chars
24477e949c46SKenneth D. Merry  */
24487e949c46SKenneth D. Merry static void
xnb_sscanf_hhd(char * buffer,size_t buflen)24497e949c46SKenneth D. Merry xnb_sscanf_hhd(char *buffer, size_t buflen)
24507e949c46SKenneth D. Merry {
24517e949c46SKenneth D. Merry 	const char mystr[] = "-27";
24527e949c46SKenneth D. Merry 	int8_t dest[12];
24537e949c46SKenneth D. Merry 	int i;
24547e949c46SKenneth D. Merry 
24557e949c46SKenneth D. Merry 	for (i = 0; i < 12; i++)
24567e949c46SKenneth D. Merry 		dest[i] = 'X';
24577e949c46SKenneth D. Merry 
2458407d708cSAlan Somers 	XNB_ASSERT(sscanf(mystr, "%hhd", &dest[4]) == 1);
24597e949c46SKenneth D. Merry 	for (i = 0; i < 12; i++)
24607e949c46SKenneth D. Merry 		XNB_ASSERT(dest[i] == (i == 4 ? -27 : 'X'));
24617e949c46SKenneth D. Merry }
24627e949c46SKenneth D. Merry 
24637e949c46SKenneth D. Merry /**
24647e949c46SKenneth D. Merry  * sscanf on signed long longs
24657e949c46SKenneth D. Merry  */
24667e949c46SKenneth D. Merry static void
xnb_sscanf_lld(char * buffer,size_t buflen)24677e949c46SKenneth D. Merry xnb_sscanf_lld(char *buffer, size_t buflen)
24687e949c46SKenneth D. Merry {
24697e949c46SKenneth D. Merry 	const char mystr[] = "-123456789012345";	/* about -2**47 */
24707e949c46SKenneth D. Merry 	long long dest[3];
24717e949c46SKenneth D. Merry 	int i;
24727e949c46SKenneth D. Merry 
24737e949c46SKenneth D. Merry 	for (i = 0; i < 3; i++)
24747e949c46SKenneth D. Merry 		dest[i] = (long long)0xdeadbeefdeadbeef;
24757e949c46SKenneth D. Merry 
2476407d708cSAlan Somers 	XNB_ASSERT(sscanf(mystr, "%lld", &dest[1]) == 1);
24777e949c46SKenneth D. Merry 	for (i = 0; i < 3; i++)
24787e949c46SKenneth D. Merry 		XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
24797e949c46SKenneth D. Merry 		    -123456789012345));
24807e949c46SKenneth D. Merry }
24817e949c46SKenneth D. Merry 
24827e949c46SKenneth D. Merry /**
24837e949c46SKenneth D. Merry  * sscanf on unsigned long longs
24847e949c46SKenneth D. Merry  */
24857e949c46SKenneth D. Merry static void
xnb_sscanf_llu(char * buffer,size_t buflen)24867e949c46SKenneth D. Merry xnb_sscanf_llu(char *buffer, size_t buflen)
24877e949c46SKenneth D. Merry {
24887e949c46SKenneth D. Merry 	const char mystr[] = "12802747070103273189";
24897e949c46SKenneth D. Merry 	unsigned long long dest[3];
24907e949c46SKenneth D. Merry 	int i;
24917e949c46SKenneth D. Merry 
24927e949c46SKenneth D. Merry 	for (i = 0; i < 3; i++)
24937e949c46SKenneth D. Merry 		dest[i] = (long long)0xdeadbeefdeadbeef;
24947e949c46SKenneth D. Merry 
2495407d708cSAlan Somers 	XNB_ASSERT(sscanf(mystr, "%llu", &dest[1]) == 1);
24967e949c46SKenneth D. Merry 	for (i = 0; i < 3; i++)
24977e949c46SKenneth D. Merry 		XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
24987e949c46SKenneth D. Merry 		    12802747070103273189ull));
24997e949c46SKenneth D. Merry }
25007e949c46SKenneth D. Merry 
25017e949c46SKenneth D. Merry /**
25027e949c46SKenneth D. Merry  * sscanf on unsigned short short n's
25037e949c46SKenneth D. Merry  */
25047e949c46SKenneth D. Merry static void
xnb_sscanf_hhn(char * buffer,size_t buflen)25057e949c46SKenneth D. Merry xnb_sscanf_hhn(char *buffer, size_t buflen)
25067e949c46SKenneth D. Merry {
25077e949c46SKenneth D. Merry 	const char mystr[] =
25087e949c46SKenneth D. Merry 	    "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
25097e949c46SKenneth D. Merry 	    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
25107e949c46SKenneth D. Merry 	    "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f";
25117e949c46SKenneth D. Merry 	unsigned char dest[12];
25127e949c46SKenneth D. Merry 	int i;
25137e949c46SKenneth D. Merry 
25147e949c46SKenneth D. Merry 	for (i = 0; i < 12; i++)
25157e949c46SKenneth D. Merry 		dest[i] = (unsigned char)'X';
25167e949c46SKenneth D. Merry 
2517407d708cSAlan Somers 	XNB_ASSERT(sscanf(mystr,
25187e949c46SKenneth D. Merry 	    "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
25197e949c46SKenneth D. Merry 	    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
252065244d58SAlan Somers 	    "404142434445464748494a4b4c4d4e4f%hhn", &dest[4]) == 0);
25217e949c46SKenneth D. Merry 	for (i = 0; i < 12; i++)
25227e949c46SKenneth D. Merry 		XNB_ASSERT(dest[i] == (i == 4 ? 160 : 'X'));
25237e949c46SKenneth D. Merry }
2524