1230587Sken/*-
2230587Sken * Copyright (c) 2009-2011 Spectra Logic Corporation
3230587Sken * All rights reserved.
4230587Sken *
5230587Sken * Redistribution and use in source and binary forms, with or without
6230587Sken * modification, are permitted provided that the following conditions
7230587Sken * are met:
8230587Sken * 1. Redistributions of source code must retain the above copyright
9230587Sken *    notice, this list of conditions, and the following disclaimer,
10230587Sken *    without modification.
11230587Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12230587Sken *    substantially similar to the "NO WARRANTY" disclaimer below
13230587Sken *    ("Disclaimer") and any redistribution must be conditioned upon
14230587Sken *    including a substantially similar Disclaimer requirement for further
15230587Sken *    binary redistribution.
16230587Sken *
17230587Sken * NO WARRANTY
18230587Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19230587Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20230587Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21230587Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22230587Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23230587Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24230587Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25230587Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26230587Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27230587Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28230587Sken * POSSIBILITY OF SUCH DAMAGES.
29230587Sken *
30230587Sken * Authors: Justin T. Gibbs     (Spectra Logic Corporation)
31230587Sken *          Alan Somers         (Spectra Logic Corporation)
32230587Sken *          John Suykerbuyk     (Spectra Logic Corporation)
33230587Sken */
34230587Sken
35230587Sken#include <sys/cdefs.h>
36230587Sken__FBSDID("$FreeBSD: stable/11/sys/dev/xen/netback/netback_unit_tests.c 316362 2017-04-01 16:51:49Z asomers $");
37230587Sken
38230587Sken/**
39230587Sken * \file netback_unit_tests.c
40230587Sken *
41230587Sken * \brief Unit tests for the Xen netback driver.
42230587Sken *
43230587Sken * Due to the driver's use of static functions, these tests cannot be compiled
44230587Sken * standalone; they must be #include'd from the driver's .c file.
45230587Sken */
46230587Sken
47230587Sken
48230587Sken/** Helper macro used to snprintf to a buffer and update the buffer pointer */
49230587Sken#define	SNCATF(buffer, buflen, ...) do {				\
50230587Sken	size_t new_chars = snprintf(buffer, buflen, __VA_ARGS__);	\
51230587Sken	buffer += new_chars;						\
52230587Sken	/* be careful; snprintf's return value can be  > buflen */	\
53230587Sken	buflen -= MIN(buflen, new_chars);				\
54230587Sken} while (0)
55230587Sken
56230587Sken/* STRINGIFY and TOSTRING are used only to help turn __LINE__ into a string */
57230587Sken#define	STRINGIFY(x) #x
58230587Sken#define	TOSTRING(x) STRINGIFY(x)
59230587Sken
60230587Sken/**
61242934Sdim * Writes an error message to buffer if cond is false
62242934Sdim * Note the implied parameters buffer and
63230587Sken * buflen
64230587Sken */
65242934Sdim#define	XNB_ASSERT(cond) ({						\
66230587Sken	int passed = (cond);						\
67230587Sken	char *_buffer = (buffer);					\
68230587Sken	size_t _buflen = (buflen);					\
69230587Sken	if (! passed) {							\
70230587Sken		strlcat(_buffer, __func__, _buflen);			\
71230587Sken		strlcat(_buffer, ":" TOSTRING(__LINE__) 		\
72230587Sken		  " Assertion Error: " #cond "\n", _buflen);		\
73230587Sken	}								\
74242934Sdim	})
75230587Sken
76230587Sken
77230587Sken/**
78230587Sken * The signature used by all testcases.  If the test writes anything
79230587Sken * to buffer, then it will be considered a failure
80230587Sken * \param buffer	Return storage for error messages
81230587Sken * \param buflen	The space available in the buffer
82230587Sken */
83230587Skentypedef void testcase_t(char *buffer, size_t buflen);
84230587Sken
85230587Sken/**
86230587Sken * Signature used by setup functions
87230587Sken * \return nonzero on error
88230587Sken */
89230587Skentypedef int setup_t(void);
90230587Sken
91230587Skentypedef void teardown_t(void);
92230587Sken
93230587Sken/** A simple test fixture comprising setup, teardown, and test */
94230587Skenstruct test_fixture {
95230587Sken	/** Will be run before the test to allocate and initialize variables */
96230587Sken	setup_t *setup;
97230587Sken
98230587Sken	/** Will be run if setup succeeds */
99230587Sken	testcase_t *test;
100230587Sken
101298955Spfg	/** Cleans up test data whether or not the setup succeeded */
102230587Sken	teardown_t *teardown;
103230587Sken};
104230587Sken
105230587Skentypedef struct test_fixture test_fixture_t;
106230587Sken
107230587Skenstatic int	xnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags);
108230587Skenstatic int	xnb_unit_test_runner(test_fixture_t const tests[], int ntests,
109230587Sken				     char *buffer, size_t buflen);
110230587Sken
111230587Skenstatic int __unused
112230587Skennull_setup(void) { return 0; }
113230587Sken
114230587Skenstatic void __unused
115230587Skennull_teardown(void) { }
116230587Sken
117230587Skenstatic setup_t setup_pvt_data;
118230587Skenstatic teardown_t teardown_pvt_data;
119230587Skenstatic testcase_t xnb_ring2pkt_emptyring;
120230587Skenstatic testcase_t xnb_ring2pkt_1req;
121230587Skenstatic testcase_t xnb_ring2pkt_2req;
122230587Skenstatic testcase_t xnb_ring2pkt_3req;
123230587Skenstatic testcase_t xnb_ring2pkt_extra;
124230587Skenstatic testcase_t xnb_ring2pkt_partial;
125230587Skenstatic testcase_t xnb_ring2pkt_wraps;
126230587Skenstatic testcase_t xnb_txpkt2rsp_emptypkt;
127230587Skenstatic testcase_t xnb_txpkt2rsp_1req;
128230587Skenstatic testcase_t xnb_txpkt2rsp_extra;
129230587Skenstatic testcase_t xnb_txpkt2rsp_long;
130230587Skenstatic testcase_t xnb_txpkt2rsp_invalid;
131230587Skenstatic testcase_t xnb_txpkt2rsp_error;
132230587Skenstatic testcase_t xnb_txpkt2rsp_wraps;
133230587Skenstatic testcase_t xnb_pkt2mbufc_empty;
134230587Skenstatic testcase_t xnb_pkt2mbufc_short;
135230587Skenstatic testcase_t xnb_pkt2mbufc_csum;
136230587Skenstatic testcase_t xnb_pkt2mbufc_1cluster;
137230587Skenstatic testcase_t xnb_pkt2mbufc_largecluster;
138230587Skenstatic testcase_t xnb_pkt2mbufc_2cluster;
139230587Skenstatic testcase_t xnb_txpkt2gnttab_empty;
140230587Skenstatic testcase_t xnb_txpkt2gnttab_short;
141230587Skenstatic testcase_t xnb_txpkt2gnttab_2req;
142230587Skenstatic testcase_t xnb_txpkt2gnttab_2cluster;
143230587Skenstatic testcase_t xnb_update_mbufc_short;
144230587Skenstatic testcase_t xnb_update_mbufc_2req;
145230587Skenstatic testcase_t xnb_update_mbufc_2cluster;
146230587Skenstatic testcase_t xnb_mbufc2pkt_empty;
147230587Skenstatic testcase_t xnb_mbufc2pkt_short;
148230587Skenstatic testcase_t xnb_mbufc2pkt_1cluster;
149230587Skenstatic testcase_t xnb_mbufc2pkt_2short;
150230587Skenstatic testcase_t xnb_mbufc2pkt_long;
151230587Skenstatic testcase_t xnb_mbufc2pkt_extra;
152230587Skenstatic testcase_t xnb_mbufc2pkt_nospace;
153230587Skenstatic testcase_t xnb_rxpkt2gnttab_empty;
154230587Skenstatic testcase_t xnb_rxpkt2gnttab_short;
155230587Skenstatic testcase_t xnb_rxpkt2gnttab_2req;
156230587Skenstatic testcase_t xnb_rxpkt2rsp_empty;
157230587Skenstatic testcase_t xnb_rxpkt2rsp_short;
158230587Skenstatic testcase_t xnb_rxpkt2rsp_extra;
159230587Skenstatic testcase_t xnb_rxpkt2rsp_2short;
160230587Skenstatic testcase_t xnb_rxpkt2rsp_2slots;
161230587Skenstatic testcase_t xnb_rxpkt2rsp_copyerror;
162257515Sglebiusstatic testcase_t xnb_sscanf_llu;
163257515Sglebiusstatic testcase_t xnb_sscanf_lld;
164257515Sglebiusstatic testcase_t xnb_sscanf_hhu;
165257515Sglebiusstatic testcase_t xnb_sscanf_hhd;
166257515Sglebiusstatic testcase_t xnb_sscanf_hhn;
167257515Sglebius
168257515Sglebius#if defined(INET) || defined(INET6)
169230587Sken/* TODO: add test cases for xnb_add_mbuf_cksum for IPV6 tcp and udp */
170230587Skenstatic testcase_t xnb_add_mbuf_cksum_arp;
171230587Skenstatic testcase_t xnb_add_mbuf_cksum_tcp;
172230587Skenstatic testcase_t xnb_add_mbuf_cksum_udp;
173230587Skenstatic testcase_t xnb_add_mbuf_cksum_icmp;
174230587Skenstatic testcase_t xnb_add_mbuf_cksum_tcp_swcksum;
175257515Sglebiusstatic void	xnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len,
176257515Sglebius				   uint16_t ip_id, uint16_t ip_p,
177257515Sglebius				   uint16_t ip_off, uint16_t ip_sum);
178257515Sglebiusstatic void	xnb_fill_tcp(struct mbuf *m);
179257515Sglebius#endif /* INET || INET6 */
180230587Sken
181230587Sken/** Private data used by unit tests */
182230587Skenstatic struct {
183230587Sken	gnttab_copy_table 	gnttab;
184230587Sken	netif_rx_back_ring_t	rxb;
185230587Sken	netif_rx_front_ring_t	rxf;
186230587Sken	netif_tx_back_ring_t	txb;
187230587Sken	netif_tx_front_ring_t	txf;
188230587Sken	struct ifnet*		ifp;
189230587Sken	netif_rx_sring_t*	rxs;
190230587Sken	netif_tx_sring_t*	txs;
191230587Sken} xnb_unit_pvt;
192230587Sken
193230587Skenstatic inline void safe_m_freem(struct mbuf **ppMbuf) {
194230587Sken	if (*ppMbuf != NULL) {
195230587Sken		m_freem(*ppMbuf);
196230587Sken		*ppMbuf = NULL;
197230587Sken	}
198230587Sken}
199230587Sken
200230587Sken/**
201230587Sken * The unit test runner.  It will run every supplied test and return an
202230587Sken * output message as a string
203230587Sken * \param tests		An array of tests.  Every test will be attempted.
204230587Sken * \param ntests	The length of tests
205230587Sken * \param buffer	Return storage for the result string
206230587Sken * \param buflen	The length of buffer
207230587Sken * \return		The number of tests that failed
208230587Sken */
209230587Skenstatic int
210230587Skenxnb_unit_test_runner(test_fixture_t const tests[], int ntests, char *buffer,
211230587Sken    		     size_t buflen)
212230587Sken{
213230587Sken	int i;
214230587Sken	int n_passes;
215230587Sken	int n_failures = 0;
216230587Sken
217230587Sken	for (i = 0; i < ntests; i++) {
218230587Sken		int error = tests[i].setup();
219230587Sken		if (error != 0) {
220230587Sken			SNCATF(buffer, buflen,
221230587Sken			    "Setup failed for test idx %d\n", i);
222230587Sken			n_failures++;
223230587Sken		} else {
224230587Sken			size_t new_chars;
225230587Sken
226230587Sken			tests[i].test(buffer, buflen);
227230587Sken			new_chars = strnlen(buffer, buflen);
228230587Sken			buffer += new_chars;
229230587Sken			buflen -= new_chars;
230230587Sken
231230587Sken			if (new_chars > 0) {
232230587Sken				n_failures++;
233230587Sken			}
234230587Sken		}
235230587Sken		tests[i].teardown();
236230587Sken	}
237230587Sken
238230587Sken	n_passes = ntests - n_failures;
239230587Sken	if (n_passes > 0) {
240230587Sken		SNCATF(buffer, buflen, "%d Tests Passed\n", n_passes);
241230587Sken	}
242230587Sken	if (n_failures > 0) {
243230587Sken		SNCATF(buffer, buflen, "%d Tests FAILED\n", n_failures);
244230587Sken	}
245230587Sken
246230587Sken	return n_failures;
247230587Sken}
248230587Sken
249230587Sken/** Number of unit tests.  Must match the length of the tests array below */
250230587Sken#define	TOTAL_TESTS	(53)
251230587Sken/**
252230587Sken * Max memory available for returning results.  400 chars/test should give
253230587Sken * enough space for a five line error message for every test
254230587Sken */
255230587Sken#define	TOTAL_BUFLEN	(400 * TOTAL_TESTS + 2)
256230587Sken
257230587Sken/**
258230587Sken * Called from userspace by a sysctl.  Runs all internal unit tests, and
259230587Sken * returns the results to userspace as a string
260230587Sken * \param oidp	unused
261230587Sken * \param arg1	pointer to an xnb_softc for a specific xnb device
262230587Sken * \param arg2	unused
263230587Sken * \param req	sysctl access structure
264230587Sken * \return a string via the special SYSCTL_OUT macro.
265230587Sken */
266230587Sken
267230587Skenstatic int
268230587Skenxnb_unit_test_main(SYSCTL_HANDLER_ARGS) {
269230587Sken	test_fixture_t const tests[TOTAL_TESTS] = {
270230587Sken		{setup_pvt_data, xnb_ring2pkt_emptyring, teardown_pvt_data},
271230587Sken		{setup_pvt_data, xnb_ring2pkt_1req, teardown_pvt_data},
272230587Sken		{setup_pvt_data, xnb_ring2pkt_2req, teardown_pvt_data},
273230587Sken		{setup_pvt_data, xnb_ring2pkt_3req, teardown_pvt_data},
274230587Sken		{setup_pvt_data, xnb_ring2pkt_extra, teardown_pvt_data},
275230587Sken		{setup_pvt_data, xnb_ring2pkt_partial, teardown_pvt_data},
276230587Sken		{setup_pvt_data, xnb_ring2pkt_wraps, teardown_pvt_data},
277230587Sken		{setup_pvt_data, xnb_txpkt2rsp_emptypkt, teardown_pvt_data},
278230587Sken		{setup_pvt_data, xnb_txpkt2rsp_1req, teardown_pvt_data},
279230587Sken		{setup_pvt_data, xnb_txpkt2rsp_extra, teardown_pvt_data},
280230587Sken		{setup_pvt_data, xnb_txpkt2rsp_long, teardown_pvt_data},
281230587Sken		{setup_pvt_data, xnb_txpkt2rsp_invalid, teardown_pvt_data},
282230587Sken		{setup_pvt_data, xnb_txpkt2rsp_error, teardown_pvt_data},
283230587Sken		{setup_pvt_data, xnb_txpkt2rsp_wraps, teardown_pvt_data},
284230587Sken		{setup_pvt_data, xnb_pkt2mbufc_empty, teardown_pvt_data},
285230587Sken		{setup_pvt_data, xnb_pkt2mbufc_short, teardown_pvt_data},
286230587Sken		{setup_pvt_data, xnb_pkt2mbufc_csum, teardown_pvt_data},
287230587Sken		{setup_pvt_data, xnb_pkt2mbufc_1cluster, teardown_pvt_data},
288230587Sken		{setup_pvt_data, xnb_pkt2mbufc_largecluster, teardown_pvt_data},
289230587Sken		{setup_pvt_data, xnb_pkt2mbufc_2cluster, teardown_pvt_data},
290230587Sken		{setup_pvt_data, xnb_txpkt2gnttab_empty, teardown_pvt_data},
291230587Sken		{setup_pvt_data, xnb_txpkt2gnttab_short, teardown_pvt_data},
292230587Sken		{setup_pvt_data, xnb_txpkt2gnttab_2req, teardown_pvt_data},
293230587Sken		{setup_pvt_data, xnb_txpkt2gnttab_2cluster, teardown_pvt_data},
294230587Sken		{setup_pvt_data, xnb_update_mbufc_short, teardown_pvt_data},
295230587Sken		{setup_pvt_data, xnb_update_mbufc_2req, teardown_pvt_data},
296230587Sken		{setup_pvt_data, xnb_update_mbufc_2cluster, teardown_pvt_data},
297230587Sken		{setup_pvt_data, xnb_mbufc2pkt_empty, teardown_pvt_data},
298230587Sken		{setup_pvt_data, xnb_mbufc2pkt_short, teardown_pvt_data},
299230587Sken		{setup_pvt_data, xnb_mbufc2pkt_1cluster, teardown_pvt_data},
300230587Sken		{setup_pvt_data, xnb_mbufc2pkt_2short, teardown_pvt_data},
301230587Sken		{setup_pvt_data, xnb_mbufc2pkt_long, teardown_pvt_data},
302230587Sken		{setup_pvt_data, xnb_mbufc2pkt_extra, teardown_pvt_data},
303230587Sken		{setup_pvt_data, xnb_mbufc2pkt_nospace, teardown_pvt_data},
304230587Sken		{setup_pvt_data, xnb_rxpkt2gnttab_empty, teardown_pvt_data},
305230587Sken		{setup_pvt_data, xnb_rxpkt2gnttab_short, teardown_pvt_data},
306230587Sken		{setup_pvt_data, xnb_rxpkt2gnttab_2req, teardown_pvt_data},
307230587Sken		{setup_pvt_data, xnb_rxpkt2rsp_empty, teardown_pvt_data},
308230587Sken		{setup_pvt_data, xnb_rxpkt2rsp_short, teardown_pvt_data},
309230587Sken		{setup_pvt_data, xnb_rxpkt2rsp_extra, teardown_pvt_data},
310230587Sken		{setup_pvt_data, xnb_rxpkt2rsp_2short, teardown_pvt_data},
311230587Sken		{setup_pvt_data, xnb_rxpkt2rsp_2slots, teardown_pvt_data},
312230587Sken		{setup_pvt_data, xnb_rxpkt2rsp_copyerror, teardown_pvt_data},
313257515Sglebius#if defined(INET) || defined(INET6)
314230587Sken		{null_setup, xnb_add_mbuf_cksum_arp, null_teardown},
315230587Sken		{null_setup, xnb_add_mbuf_cksum_icmp, null_teardown},
316230587Sken		{null_setup, xnb_add_mbuf_cksum_tcp, null_teardown},
317230587Sken		{null_setup, xnb_add_mbuf_cksum_tcp_swcksum, null_teardown},
318230587Sken		{null_setup, xnb_add_mbuf_cksum_udp, null_teardown},
319257515Sglebius#endif
320230587Sken		{null_setup, xnb_sscanf_hhd, null_teardown},
321230587Sken		{null_setup, xnb_sscanf_hhu, null_teardown},
322230587Sken		{null_setup, xnb_sscanf_lld, null_teardown},
323230587Sken		{null_setup, xnb_sscanf_llu, null_teardown},
324230587Sken		{null_setup, xnb_sscanf_hhn, null_teardown},
325230587Sken	};
326230587Sken	/**
327230587Sken	 * results is static so that the data will persist after this function
328230587Sken	 * returns.  The sysctl code expects us to return a constant string.
329230587Sken	 * \todo: the static variable is not thread safe.  Put a mutex around
330230587Sken	 * it.
331230587Sken	 */
332230587Sken	static char results[TOTAL_BUFLEN];
333230587Sken
334230587Sken	/* empty the result strings */
335230587Sken	results[0] = 0;
336230587Sken	xnb_unit_test_runner(tests, TOTAL_TESTS, results, TOTAL_BUFLEN);
337230587Sken
338230587Sken	return (SYSCTL_OUT(req, results, strnlen(results, TOTAL_BUFLEN)));
339230587Sken}
340230587Sken
341230587Skenstatic int
342230587Skensetup_pvt_data(void)
343230587Sken{
344230587Sken	int error = 0;
345230587Sken
346230587Sken	bzero(xnb_unit_pvt.gnttab, sizeof(xnb_unit_pvt.gnttab));
347230587Sken
348230587Sken	xnb_unit_pvt.txs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
349230587Sken	if (xnb_unit_pvt.txs != NULL) {
350230587Sken		SHARED_RING_INIT(xnb_unit_pvt.txs);
351230587Sken		BACK_RING_INIT(&xnb_unit_pvt.txb, xnb_unit_pvt.txs, PAGE_SIZE);
352230587Sken		FRONT_RING_INIT(&xnb_unit_pvt.txf, xnb_unit_pvt.txs, PAGE_SIZE);
353230587Sken	} else {
354230587Sken		error = 1;
355230587Sken	}
356230587Sken
357230587Sken	xnb_unit_pvt.ifp = if_alloc(IFT_ETHER);
358230587Sken	if (xnb_unit_pvt.ifp == NULL) {
359230587Sken		error = 1;
360230587Sken	}
361230587Sken
362230587Sken	xnb_unit_pvt.rxs = malloc(PAGE_SIZE, M_XENNETBACK, M_WAITOK|M_ZERO);
363230587Sken	if (xnb_unit_pvt.rxs != NULL) {
364230587Sken		SHARED_RING_INIT(xnb_unit_pvt.rxs);
365230587Sken		BACK_RING_INIT(&xnb_unit_pvt.rxb, xnb_unit_pvt.rxs, PAGE_SIZE);
366230587Sken		FRONT_RING_INIT(&xnb_unit_pvt.rxf, xnb_unit_pvt.rxs, PAGE_SIZE);
367230587Sken	} else {
368230587Sken		error = 1;
369230587Sken	}
370230587Sken
371230587Sken	return error;
372230587Sken}
373230587Sken
374230587Skenstatic void
375230587Skenteardown_pvt_data(void)
376230587Sken{
377230587Sken	if (xnb_unit_pvt.txs != NULL) {
378230587Sken		free(xnb_unit_pvt.txs, M_XENNETBACK);
379230587Sken	}
380230587Sken	if (xnb_unit_pvt.rxs != NULL) {
381230587Sken		free(xnb_unit_pvt.rxs, M_XENNETBACK);
382230587Sken	}
383230587Sken	if (xnb_unit_pvt.ifp != NULL) {
384230587Sken		if_free(xnb_unit_pvt.ifp);
385230587Sken	}
386230587Sken}
387230587Sken
388230587Sken/**
389230587Sken * Verify that xnb_ring2pkt will not consume any requests from an empty ring
390230587Sken */
391230587Skenstatic void
392230587Skenxnb_ring2pkt_emptyring(char *buffer, size_t buflen)
393230587Sken{
394230587Sken	struct xnb_pkt pkt;
395230587Sken	int num_consumed;
396230587Sken
397230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
398230587Sken	                            xnb_unit_pvt.txb.req_cons);
399230587Sken	XNB_ASSERT(num_consumed == 0);
400230587Sken}
401230587Sken
402230587Sken/**
403230587Sken * Verify that xnb_ring2pkt can convert a single request packet correctly
404230587Sken */
405230587Skenstatic void
406230587Skenxnb_ring2pkt_1req(char *buffer, size_t buflen)
407230587Sken{
408230587Sken	struct xnb_pkt pkt;
409230587Sken	int num_consumed;
410230587Sken	struct netif_tx_request *req;
411230587Sken
412230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
413230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
414230587Sken
415230587Sken	req->flags = 0;
416230587Sken	req->size = 69;	/* arbitrary number for test */
417230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
418230587Sken
419230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
420230587Sken
421230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
422230587Sken	                            xnb_unit_pvt.txb.req_cons);
423230587Sken	XNB_ASSERT(num_consumed == 1);
424230587Sken	XNB_ASSERT(pkt.size == 69);
425230587Sken	XNB_ASSERT(pkt.car_size == 69);
426230587Sken	XNB_ASSERT(pkt.flags == 0);
427230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
428230587Sken	XNB_ASSERT(pkt.list_len == 1);
429230587Sken	XNB_ASSERT(pkt.car == 0);
430230587Sken}
431230587Sken
432230587Sken/**
433230587Sken * Verify that xnb_ring2pkt can convert a two request packet correctly.
434230587Sken * This tests handling of the MORE_DATA flag and cdr
435230587Sken */
436230587Skenstatic void
437230587Skenxnb_ring2pkt_2req(char *buffer, size_t buflen)
438230587Sken{
439230587Sken	struct xnb_pkt pkt;
440230587Sken	int num_consumed;
441230587Sken	struct netif_tx_request *req;
442230587Sken	RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
443230587Sken
444230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
445230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
446230587Sken	req->flags = NETTXF_more_data;
447230587Sken	req->size = 100;
448230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
449230587Sken
450230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
451230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
452230587Sken	req->flags = 0;
453230587Sken	req->size = 40;
454230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
455230587Sken
456230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
457230587Sken
458230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
459230587Sken	                            xnb_unit_pvt.txb.req_cons);
460230587Sken	XNB_ASSERT(num_consumed == 2);
461230587Sken	XNB_ASSERT(pkt.size == 100);
462230587Sken	XNB_ASSERT(pkt.car_size == 60);
463230587Sken	XNB_ASSERT(pkt.flags == 0);
464230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
465230587Sken	XNB_ASSERT(pkt.list_len == 2);
466230587Sken	XNB_ASSERT(pkt.car == start_idx);
467230587Sken	XNB_ASSERT(pkt.cdr == start_idx + 1);
468230587Sken}
469230587Sken
470230587Sken/**
471230587Sken * Verify that xnb_ring2pkt can convert a three request packet correctly
472230587Sken */
473230587Skenstatic void
474230587Skenxnb_ring2pkt_3req(char *buffer, size_t buflen)
475230587Sken{
476230587Sken	struct xnb_pkt pkt;
477230587Sken	int num_consumed;
478230587Sken	struct netif_tx_request *req;
479230587Sken	RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
480230587Sken
481230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
482230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
483230587Sken	req->flags = NETTXF_more_data;
484230587Sken	req->size = 200;
485230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
486230587Sken
487230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
488230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
489230587Sken	req->flags = NETTXF_more_data;
490230587Sken	req->size = 40;
491230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
492230587Sken
493230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
494230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
495230587Sken	req->flags = 0;
496230587Sken	req->size = 50;
497230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
498230587Sken
499230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
500230587Sken
501230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
502230587Sken	                            xnb_unit_pvt.txb.req_cons);
503230587Sken	XNB_ASSERT(num_consumed == 3);
504230587Sken	XNB_ASSERT(pkt.size == 200);
505230587Sken	XNB_ASSERT(pkt.car_size == 110);
506230587Sken	XNB_ASSERT(pkt.flags == 0);
507230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
508230587Sken	XNB_ASSERT(pkt.list_len == 3);
509230587Sken	XNB_ASSERT(pkt.car == start_idx);
510230587Sken	XNB_ASSERT(pkt.cdr == start_idx + 1);
511230587Sken	XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
512230587Sken}
513230587Sken
514230587Sken/**
515230587Sken * Verify that xnb_ring2pkt can read extra inf
516230587Sken */
517230587Skenstatic void
518230587Skenxnb_ring2pkt_extra(char *buffer, size_t buflen)
519230587Sken{
520230587Sken	struct xnb_pkt pkt;
521230587Sken	int num_consumed;
522230587Sken	struct netif_tx_request *req;
523230587Sken	struct netif_extra_info *ext;
524230587Sken	RING_IDX start_idx = xnb_unit_pvt.txf.req_prod_pvt;
525230587Sken
526230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
527230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
528230587Sken	req->flags = NETTXF_extra_info | NETTXF_more_data;
529230587Sken	req->size = 150;
530230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
531230587Sken
532230587Sken	ext = (struct netif_extra_info*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
533230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
534230587Sken	ext->flags = 0;
535230587Sken	ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
536230587Sken	ext->u.gso.size = 250;
537230587Sken	ext->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
538230587Sken	ext->u.gso.features = 0;
539230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
540230587Sken
541230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
542230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
543230587Sken	req->flags = 0;
544230587Sken	req->size = 50;
545230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
546230587Sken
547230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
548230587Sken
549230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
550230587Sken	                            xnb_unit_pvt.txb.req_cons);
551230587Sken	XNB_ASSERT(num_consumed == 3);
552230587Sken	XNB_ASSERT(pkt.extra.flags == 0);
553230587Sken	XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
554230587Sken	XNB_ASSERT(pkt.extra.u.gso.size == 250);
555230587Sken	XNB_ASSERT(pkt.extra.u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4);
556230587Sken	XNB_ASSERT(pkt.size == 150);
557230587Sken	XNB_ASSERT(pkt.car_size == 100);
558230587Sken	XNB_ASSERT(pkt.flags == NETTXF_extra_info);
559230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
560230587Sken	XNB_ASSERT(pkt.list_len == 2);
561230587Sken	XNB_ASSERT(pkt.car == start_idx);
562230587Sken	XNB_ASSERT(pkt.cdr == start_idx + 2);
563230587Sken	XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr) == req);
564230587Sken}
565230587Sken
566230587Sken/**
567230587Sken * Verify that xnb_ring2pkt will consume no requests if the entire packet is
568230587Sken * not yet in the ring
569230587Sken */
570230587Skenstatic void
571230587Skenxnb_ring2pkt_partial(char *buffer, size_t buflen)
572230587Sken{
573230587Sken	struct xnb_pkt pkt;
574230587Sken	int num_consumed;
575230587Sken	struct netif_tx_request *req;
576230587Sken
577230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
578230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
579230587Sken	req->flags = NETTXF_more_data;
580230587Sken	req->size = 150;
581230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
582230587Sken
583230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
584230587Sken
585230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
586230587Sken	                            xnb_unit_pvt.txb.req_cons);
587230587Sken	XNB_ASSERT(num_consumed == 0);
588230587Sken	XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
589230587Sken}
590230587Sken
591230587Sken/**
592230587Sken * Verity that xnb_ring2pkt can read a packet whose requests wrap around
593230587Sken * the end of the ring
594230587Sken */
595230587Skenstatic void
596230587Skenxnb_ring2pkt_wraps(char *buffer, size_t buflen)
597230587Sken{
598230587Sken	struct xnb_pkt pkt;
599230587Sken	int num_consumed;
600230587Sken	struct netif_tx_request *req;
601230587Sken	unsigned int rsize;
602230587Sken
603230587Sken	/*
604230587Sken	 * Manually tweak the ring indices to create a ring with no responses
605230587Sken	 * and the next request slot at position 2 from the end
606230587Sken	 */
607230587Sken	rsize = RING_SIZE(&xnb_unit_pvt.txf);
608230587Sken	xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
609230587Sken	xnb_unit_pvt.txf.rsp_cons = rsize - 2;
610230587Sken	xnb_unit_pvt.txs->req_prod = rsize - 2;
611230587Sken	xnb_unit_pvt.txs->req_event = rsize - 1;
612230587Sken	xnb_unit_pvt.txs->rsp_prod = rsize - 2;
613230587Sken	xnb_unit_pvt.txs->rsp_event = rsize - 1;
614230587Sken	xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
615230587Sken	xnb_unit_pvt.txb.req_cons = rsize - 2;
616230587Sken
617230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
618230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
619230587Sken	req->flags = NETTXF_more_data;
620230587Sken	req->size = 550;
621230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
622230587Sken
623230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
624230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
625230587Sken	req->flags = NETTXF_more_data;
626230587Sken	req->size = 100;
627230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
628230587Sken
629230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
630230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
631230587Sken	req->flags = 0;
632230587Sken	req->size = 50;
633230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
634230587Sken
635230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
636230587Sken
637230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
638230587Sken	                            xnb_unit_pvt.txb.req_cons);
639230587Sken	XNB_ASSERT(num_consumed == 3);
640230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
641230587Sken	XNB_ASSERT(pkt.list_len == 3);
642230587Sken	XNB_ASSERT(RING_GET_REQUEST(&xnb_unit_pvt.txb, pkt.cdr + 1) == req);
643230587Sken}
644230587Sken
645230587Sken
646230587Sken/**
647230587Sken * xnb_txpkt2rsp should do nothing for an empty packet
648230587Sken */
649230587Skenstatic void
650230587Skenxnb_txpkt2rsp_emptypkt(char *buffer, size_t buflen)
651230587Sken{
652230587Sken	int num_consumed;
653230587Sken	struct xnb_pkt pkt;
654230587Sken	netif_tx_back_ring_t txb_backup = xnb_unit_pvt.txb;
655230587Sken	netif_tx_sring_t txs_backup = *xnb_unit_pvt.txs;
656230587Sken	pkt.list_len = 0;
657230587Sken
658230587Sken	/* must call xnb_ring2pkt just to intialize pkt */
659230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
660230587Sken	                            xnb_unit_pvt.txb.req_cons);
661230587Sken	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
662230587Sken	XNB_ASSERT(
663230587Sken	    memcmp(&txb_backup, &xnb_unit_pvt.txb, sizeof(txb_backup)) == 0);
664230587Sken	XNB_ASSERT(
665230587Sken	    memcmp(&txs_backup, xnb_unit_pvt.txs, sizeof(txs_backup)) == 0);
666230587Sken}
667230587Sken
668230587Sken/**
669230587Sken * xnb_txpkt2rsp responding to one request
670230587Sken */
671230587Skenstatic void
672230587Skenxnb_txpkt2rsp_1req(char *buffer, size_t buflen)
673230587Sken{
674230587Sken	uint16_t num_consumed;
675230587Sken	struct xnb_pkt pkt;
676230587Sken	struct netif_tx_request *req;
677230587Sken	struct netif_tx_response *rsp;
678230587Sken
679230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
680230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
681230587Sken	req->size = 1000;
682230587Sken	req->flags = 0;
683230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
684230587Sken
685230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
686230587Sken
687230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
688230587Sken	                            xnb_unit_pvt.txb.req_cons);
689230587Sken	xnb_unit_pvt.txb.req_cons += num_consumed;
690230587Sken
691230587Sken	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
692230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
693230587Sken
694230587Sken	XNB_ASSERT(
695230587Sken	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
696230587Sken	XNB_ASSERT(rsp->id == req->id);
697230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
698230587Sken};
699230587Sken
700230587Sken/**
701230587Sken * xnb_txpkt2rsp responding to 1 data request and 1 extra info
702230587Sken */
703230587Skenstatic void
704230587Skenxnb_txpkt2rsp_extra(char *buffer, size_t buflen)
705230587Sken{
706230587Sken	uint16_t num_consumed;
707230587Sken	struct xnb_pkt pkt;
708230587Sken	struct netif_tx_request *req;
709230587Sken	netif_extra_info_t *ext;
710230587Sken	struct netif_tx_response *rsp;
711230587Sken
712230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
713230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
714230587Sken	req->size = 1000;
715230587Sken	req->flags = NETTXF_extra_info;
716230587Sken	req->id = 69;
717230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
718230587Sken
719230587Sken	ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
720230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
721230587Sken	ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
722230587Sken	ext->flags = 0;
723230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
724230587Sken
725230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
726230587Sken
727230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
728230587Sken	                            xnb_unit_pvt.txb.req_cons);
729230587Sken	xnb_unit_pvt.txb.req_cons += num_consumed;
730230587Sken
731230587Sken	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
732230587Sken
733230587Sken	XNB_ASSERT(
734230587Sken	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
735230587Sken
736230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
737230587Sken	XNB_ASSERT(rsp->id == req->id);
738230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
739230587Sken
740230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
741230587Sken	    xnb_unit_pvt.txf.rsp_cons + 1);
742230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
743230587Sken};
744230587Sken
745230587Sken/**
746230587Sken * xnb_pkg2rsp responding to 3 data requests and 1 extra info
747230587Sken */
748230587Skenstatic void
749230587Skenxnb_txpkt2rsp_long(char *buffer, size_t buflen)
750230587Sken{
751230587Sken	uint16_t num_consumed;
752230587Sken	struct xnb_pkt pkt;
753230587Sken	struct netif_tx_request *req;
754230587Sken	netif_extra_info_t *ext;
755230587Sken	struct netif_tx_response *rsp;
756230587Sken
757230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
758230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
759230587Sken	req->size = 1000;
760230587Sken	req->flags = NETTXF_extra_info | NETTXF_more_data;
761230587Sken	req->id = 254;
762230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
763230587Sken
764230587Sken	ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
765230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
766230587Sken	ext->type = XEN_NETIF_EXTRA_TYPE_GSO;
767230587Sken	ext->flags = 0;
768230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
769230587Sken
770230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
771230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
772230587Sken	req->size = 300;
773230587Sken	req->flags = NETTXF_more_data;
774230587Sken	req->id = 1034;
775230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
776230587Sken
777230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
778230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
779230587Sken	req->size = 400;
780230587Sken	req->flags = 0;
781230587Sken	req->id = 34;
782230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
783230587Sken
784230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
785230587Sken
786230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
787230587Sken	                            xnb_unit_pvt.txb.req_cons);
788230587Sken	xnb_unit_pvt.txb.req_cons += num_consumed;
789230587Sken
790230587Sken	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
791230587Sken
792230587Sken	XNB_ASSERT(
793230587Sken	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
794230587Sken
795230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
796230587Sken	XNB_ASSERT(rsp->id ==
797230587Sken	    RING_GET_REQUEST(&xnb_unit_pvt.txf, 0)->id);
798230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
799230587Sken
800230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
801230587Sken	    xnb_unit_pvt.txf.rsp_cons + 1);
802230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
803230587Sken
804230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
805230587Sken	    xnb_unit_pvt.txf.rsp_cons + 2);
806230587Sken	XNB_ASSERT(rsp->id ==
807230587Sken	    RING_GET_REQUEST(&xnb_unit_pvt.txf, 2)->id);
808230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
809230587Sken
810230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
811230587Sken	    xnb_unit_pvt.txf.rsp_cons + 3);
812230587Sken	XNB_ASSERT(rsp->id ==
813230587Sken	    RING_GET_REQUEST(&xnb_unit_pvt.txf, 3)->id);
814230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
815230587Sken}
816230587Sken
817230587Sken/**
818230587Sken * xnb_txpkt2rsp responding to an invalid packet.
819230587Sken * Note: this test will result in an error message being printed to the console
820230587Sken * such as:
821230587Sken * xnb(xnb_ring2pkt:1306): Unknown extra info type 255.  Discarding packet
822230587Sken */
823230587Skenstatic void
824230587Skenxnb_txpkt2rsp_invalid(char *buffer, size_t buflen)
825230587Sken{
826230587Sken	uint16_t num_consumed;
827230587Sken	struct xnb_pkt pkt;
828230587Sken	struct netif_tx_request *req;
829230587Sken	netif_extra_info_t *ext;
830230587Sken	struct netif_tx_response *rsp;
831230587Sken
832230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
833230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
834230587Sken	req->size = 1000;
835230587Sken	req->flags = NETTXF_extra_info;
836230587Sken	req->id = 69;
837230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
838230587Sken
839230587Sken	ext = (netif_extra_info_t*) RING_GET_REQUEST(&xnb_unit_pvt.txf,
840230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
841230587Sken	ext->type = 0xFF;	/* Invalid extra type */
842230587Sken	ext->flags = 0;
843230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
844230587Sken
845230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
846230587Sken
847230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
848230587Sken	                            xnb_unit_pvt.txb.req_cons);
849230587Sken	xnb_unit_pvt.txb.req_cons += num_consumed;
850230587Sken	XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
851230587Sken
852230587Sken	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
853230587Sken
854230587Sken	XNB_ASSERT(
855230587Sken	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
856230587Sken
857230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
858230587Sken	XNB_ASSERT(rsp->id == req->id);
859230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
860230587Sken
861230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
862230587Sken	    xnb_unit_pvt.txf.rsp_cons + 1);
863230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_NULL);
864230587Sken};
865230587Sken
866230587Sken/**
867230587Sken * xnb_txpkt2rsp responding to one request which caused an error
868230587Sken */
869230587Skenstatic void
870230587Skenxnb_txpkt2rsp_error(char *buffer, size_t buflen)
871230587Sken{
872230587Sken	uint16_t num_consumed;
873230587Sken	struct xnb_pkt pkt;
874230587Sken	struct netif_tx_request *req;
875230587Sken	struct netif_tx_response *rsp;
876230587Sken
877230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
878230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
879230587Sken	req->size = 1000;
880230587Sken	req->flags = 0;
881230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
882230587Sken
883230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
884230587Sken
885230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
886230587Sken	                            xnb_unit_pvt.txb.req_cons);
887230587Sken	xnb_unit_pvt.txb.req_cons += num_consumed;
888230587Sken
889230587Sken	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 1);
890230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb, xnb_unit_pvt.txf.rsp_cons);
891230587Sken
892230587Sken	XNB_ASSERT(
893230587Sken	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
894230587Sken	XNB_ASSERT(rsp->id == req->id);
895230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
896230587Sken};
897230587Sken
898230587Sken/**
899230587Sken * xnb_txpkt2rsp's responses wrap around the end of the ring
900230587Sken */
901230587Skenstatic void
902230587Skenxnb_txpkt2rsp_wraps(char *buffer, size_t buflen)
903230587Sken{
904230587Sken	struct xnb_pkt pkt;
905230587Sken	int num_consumed;
906230587Sken	struct netif_tx_request *req;
907230587Sken	struct netif_tx_response *rsp;
908230587Sken	unsigned int rsize;
909230587Sken
910230587Sken	/*
911230587Sken	 * Manually tweak the ring indices to create a ring with no responses
912230587Sken	 * and the next request slot at position 2 from the end
913230587Sken	 */
914230587Sken	rsize = RING_SIZE(&xnb_unit_pvt.txf);
915230587Sken	xnb_unit_pvt.txf.req_prod_pvt = rsize - 2;
916230587Sken	xnb_unit_pvt.txf.rsp_cons = rsize - 2;
917230587Sken	xnb_unit_pvt.txs->req_prod = rsize - 2;
918230587Sken	xnb_unit_pvt.txs->req_event = rsize - 1;
919230587Sken	xnb_unit_pvt.txs->rsp_prod = rsize - 2;
920230587Sken	xnb_unit_pvt.txs->rsp_event = rsize - 1;
921230587Sken	xnb_unit_pvt.txb.rsp_prod_pvt = rsize - 2;
922230587Sken	xnb_unit_pvt.txb.req_cons = rsize - 2;
923230587Sken
924230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
925230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
926230587Sken	req->flags = NETTXF_more_data;
927230587Sken	req->size = 550;
928230587Sken	req->id = 1;
929230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
930230587Sken
931230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
932230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
933230587Sken	req->flags = NETTXF_more_data;
934230587Sken	req->size = 100;
935230587Sken	req->id = 2;
936230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
937230587Sken
938230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
939230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
940230587Sken	req->flags = 0;
941230587Sken	req->size = 50;
942230587Sken	req->id = 3;
943230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
944230587Sken
945230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
946230587Sken
947230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
948230587Sken	                            xnb_unit_pvt.txb.req_cons);
949230587Sken
950230587Sken	xnb_txpkt2rsp(&pkt, &xnb_unit_pvt.txb, 0);
951230587Sken
952230587Sken	XNB_ASSERT(
953230587Sken	    xnb_unit_pvt.txb.rsp_prod_pvt == xnb_unit_pvt.txs->req_prod);
954230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.txb,
955230587Sken	    xnb_unit_pvt.txf.rsp_cons + 2);
956230587Sken	XNB_ASSERT(rsp->id == req->id);
957230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_OKAY);
958230587Sken}
959230587Sken
960230587Sken
961230587Sken/**
962230587Sken * Helper function used to setup pkt2mbufc tests
963230587Sken * \param size     size in bytes of the single request to push to the ring
964230587Sken * \param flags		optional flags to put in the netif request
965230587Sken * \param[out] pkt the returned packet object
966230587Sken * \return number of requests consumed from the ring
967230587Sken */
968230587Skenstatic int
969230587Skenxnb_get1pkt(struct xnb_pkt *pkt, size_t size, uint16_t flags)
970230587Sken{
971230587Sken	struct netif_tx_request *req;
972230587Sken
973230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
974230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
975230587Sken	req->flags = flags;
976230587Sken	req->size = size;
977230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
978230587Sken
979230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
980230587Sken
981230587Sken	return xnb_ring2pkt(pkt, &xnb_unit_pvt.txb,
982230587Sken	                            xnb_unit_pvt.txb.req_cons);
983230587Sken}
984230587Sken
985230587Sken/**
986230587Sken * xnb_pkt2mbufc on an empty packet
987230587Sken */
988230587Skenstatic void
989230587Skenxnb_pkt2mbufc_empty(char *buffer, size_t buflen)
990230587Sken{
991230587Sken	int num_consumed;
992230587Sken	struct xnb_pkt pkt;
993230587Sken	struct mbuf *pMbuf;
994230587Sken	pkt.list_len = 0;
995230587Sken
996230587Sken	/* must call xnb_ring2pkt just to intialize pkt */
997230587Sken	num_consumed = xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb,
998230587Sken	                            xnb_unit_pvt.txb.req_cons);
999230587Sken	pkt.size = 0;
1000230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1001230587Sken	safe_m_freem(&pMbuf);
1002230587Sken}
1003230587Sken
1004230587Sken/**
1005230587Sken * xnb_pkt2mbufc on short packet that can fit in an mbuf internal buffer
1006230587Sken */
1007230587Skenstatic void
1008230587Skenxnb_pkt2mbufc_short(char *buffer, size_t buflen)
1009230587Sken{
1010230587Sken	const size_t size = MINCLSIZE - 1;
1011230587Sken	struct xnb_pkt pkt;
1012230587Sken	struct mbuf *pMbuf;
1013230587Sken
1014230587Sken	xnb_get1pkt(&pkt, size, 0);
1015230587Sken
1016230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1017230587Sken	XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1018230587Sken	safe_m_freem(&pMbuf);
1019230587Sken}
1020230587Sken
1021230587Sken/**
1022230587Sken * xnb_pkt2mbufc on short packet whose checksum was validated by the netfron
1023230587Sken */
1024230587Skenstatic void
1025230587Skenxnb_pkt2mbufc_csum(char *buffer, size_t buflen)
1026230587Sken{
1027230587Sken	const size_t size = MINCLSIZE - 1;
1028230587Sken	struct xnb_pkt pkt;
1029230587Sken	struct mbuf *pMbuf;
1030230587Sken
1031230587Sken	xnb_get1pkt(&pkt, size, NETTXF_data_validated);
1032230587Sken
1033230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1034230587Sken	XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1035230587Sken	XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_CHECKED);
1036230587Sken	XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_IP_VALID);
1037230587Sken	XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_DATA_VALID);
1038230587Sken	XNB_ASSERT(pMbuf->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR);
1039230587Sken	safe_m_freem(&pMbuf);
1040230587Sken}
1041230587Sken
1042230587Sken/**
1043230587Sken * xnb_pkt2mbufc on packet that can fit in one cluster
1044230587Sken */
1045230587Skenstatic void
1046230587Skenxnb_pkt2mbufc_1cluster(char *buffer, size_t buflen)
1047230587Sken{
1048230587Sken	const size_t size = MINCLSIZE;
1049230587Sken	struct xnb_pkt pkt;
1050230587Sken	struct mbuf *pMbuf;
1051230587Sken
1052230587Sken	xnb_get1pkt(&pkt, size, 0);
1053230587Sken
1054230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1055230587Sken	XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1056230587Sken	safe_m_freem(&pMbuf);
1057230587Sken}
1058230587Sken
1059230587Sken/**
1060230587Sken * xnb_pkt2mbufc on packet that cannot fit in one regular cluster
1061230587Sken */
1062230587Skenstatic void
1063230587Skenxnb_pkt2mbufc_largecluster(char *buffer, size_t buflen)
1064230587Sken{
1065230587Sken	const size_t size = MCLBYTES + 1;
1066230587Sken	struct xnb_pkt pkt;
1067230587Sken	struct mbuf *pMbuf;
1068230587Sken
1069230587Sken	xnb_get1pkt(&pkt, size, 0);
1070230587Sken
1071230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1072230587Sken	XNB_ASSERT(M_TRAILINGSPACE(pMbuf) >= size);
1073230587Sken	safe_m_freem(&pMbuf);
1074230587Sken}
1075230587Sken
1076230587Sken/**
1077230587Sken * xnb_pkt2mbufc on packet that cannot fit in one clusters
1078230587Sken */
1079230587Skenstatic void
1080230587Skenxnb_pkt2mbufc_2cluster(char *buffer, size_t buflen)
1081230587Sken{
1082230587Sken	const size_t size = 2 * MCLBYTES + 1;
1083230587Sken	size_t space = 0;
1084230587Sken	struct xnb_pkt pkt;
1085230587Sken	struct mbuf *pMbuf;
1086230587Sken	struct mbuf *m;
1087230587Sken
1088230587Sken	xnb_get1pkt(&pkt, size, 0);
1089230587Sken
1090230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1091230587Sken
1092230587Sken	for (m = pMbuf; m != NULL; m = m->m_next) {
1093230587Sken		space += M_TRAILINGSPACE(m);
1094230587Sken	}
1095230587Sken	XNB_ASSERT(space >= size);
1096230587Sken	safe_m_freem(&pMbuf);
1097230587Sken}
1098230587Sken
1099230587Sken/**
1100230587Sken * xnb_txpkt2gnttab on an empty packet.  Should return empty gnttab
1101230587Sken */
1102230587Skenstatic void
1103230587Skenxnb_txpkt2gnttab_empty(char *buffer, size_t buflen)
1104230587Sken{
1105230587Sken	int n_entries;
1106230587Sken	struct xnb_pkt pkt;
1107230587Sken	struct mbuf *pMbuf;
1108230587Sken	pkt.list_len = 0;
1109230587Sken
1110230587Sken	/* must call xnb_ring2pkt just to intialize pkt */
1111230587Sken	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1112230587Sken	pkt.size = 0;
1113230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1114230587Sken	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1115230587Sken	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1116230587Sken	XNB_ASSERT(n_entries == 0);
1117230587Sken	safe_m_freem(&pMbuf);
1118230587Sken}
1119230587Sken
1120230587Sken/**
1121230587Sken * xnb_txpkt2gnttab on a short packet, that can fit in one mbuf internal buffer
1122230587Sken * and has one request
1123230587Sken */
1124230587Skenstatic void
1125230587Skenxnb_txpkt2gnttab_short(char *buffer, size_t buflen)
1126230587Sken{
1127230587Sken	const size_t size = MINCLSIZE - 1;
1128230587Sken	int n_entries;
1129230587Sken	struct xnb_pkt pkt;
1130230587Sken	struct mbuf *pMbuf;
1131230587Sken
1132230587Sken	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1133230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
1134230587Sken	req->flags = 0;
1135230587Sken	req->size = size;
1136230587Sken	req->gref = 7;
1137230587Sken	req->offset = 17;
1138230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
1139230587Sken
1140230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1141230587Sken
1142230587Sken	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1143230587Sken
1144230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1145230587Sken	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1146230587Sken	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1147230587Sken	XNB_ASSERT(n_entries == 1);
1148230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
1149230587Sken	/* flags should indicate gref's for source */
1150230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_source_gref);
1151230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == req->offset);
1152230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
1153230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1154230587Sken	      mtod(pMbuf, vm_offset_t)));
1155230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.u.gmfn ==
1156230587Sken		virt_to_mfn(mtod(pMbuf, vm_offset_t)));
1157230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
1158230587Sken	safe_m_freem(&pMbuf);
1159230587Sken}
1160230587Sken
1161230587Sken/**
1162230587Sken * xnb_txpkt2gnttab on a packet with two requests, that can fit into a single
1163230587Sken * mbuf cluster
1164230587Sken */
1165230587Skenstatic void
1166230587Skenxnb_txpkt2gnttab_2req(char *buffer, size_t buflen)
1167230587Sken{
1168230587Sken	int n_entries;
1169230587Sken	struct xnb_pkt pkt;
1170230587Sken	struct mbuf *pMbuf;
1171230587Sken
1172230587Sken	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1173230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
1174230587Sken	req->flags = NETTXF_more_data;
1175230587Sken	req->size = 1900;
1176230587Sken	req->gref = 7;
1177230587Sken	req->offset = 0;
1178230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
1179230587Sken
1180230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1181230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
1182230587Sken	req->flags = 0;
1183230587Sken	req->size = 500;
1184230587Sken	req->gref = 8;
1185230587Sken	req->offset = 0;
1186230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
1187230587Sken
1188230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1189230587Sken
1190230587Sken	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1191230587Sken
1192230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1193230587Sken	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1194230587Sken	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1195230587Sken
1196230587Sken	XNB_ASSERT(n_entries == 2);
1197230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 1400);
1198230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1199230587Sken	      mtod(pMbuf, vm_offset_t)));
1200230587Sken
1201230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 500);
1202230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
1203230587Sken	      mtod(pMbuf, vm_offset_t) + 1400));
1204230587Sken	safe_m_freem(&pMbuf);
1205230587Sken}
1206230587Sken
1207230587Sken/**
1208230587Sken * xnb_txpkt2gnttab on a single request that spans two mbuf clusters
1209230587Sken */
1210230587Skenstatic void
1211230587Skenxnb_txpkt2gnttab_2cluster(char *buffer, size_t buflen)
1212230587Sken{
1213230587Sken	int n_entries;
1214230587Sken	struct xnb_pkt pkt;
1215230587Sken	struct mbuf *pMbuf;
1216230587Sken	const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
1217230587Sken
1218230587Sken	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1219230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
1220230587Sken	req->flags = 0;
1221230587Sken	req->size = data_this_transaction;
1222230587Sken	req->gref = 8;
1223230587Sken	req->offset = 0;
1224230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
1225230587Sken
1226230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1227230587Sken	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1228230587Sken
1229230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1230316362Sasomers	XNB_ASSERT(pMbuf != NULL);
1231316362Sasomers	if (pMbuf == NULL)
1232316362Sasomers		return;
1233316362Sasomers
1234230587Sken	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1235230587Sken	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1236230587Sken
1237230587Sken	if (M_TRAILINGSPACE(pMbuf) == MCLBYTES) {
1238230587Sken		/* there should be three mbufs and three gnttab entries */
1239230587Sken		XNB_ASSERT(n_entries == 3);
1240230587Sken		XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == MCLBYTES);
1241230587Sken		XNB_ASSERT(
1242230587Sken		    xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1243230587Sken		      mtod(pMbuf, vm_offset_t)));
1244230587Sken		XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
1245230587Sken
1246230587Sken		XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == MCLBYTES);
1247230587Sken		XNB_ASSERT(
1248230587Sken		    xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
1249230587Sken		      mtod(pMbuf->m_next, vm_offset_t)));
1250230587Sken		XNB_ASSERT(xnb_unit_pvt.gnttab[1].source.offset == MCLBYTES);
1251230587Sken
1252230587Sken		XNB_ASSERT(xnb_unit_pvt.gnttab[2].len == 1);
1253230587Sken		XNB_ASSERT(
1254230587Sken		    xnb_unit_pvt.gnttab[2].dest.offset == virt_to_offset(
1255230587Sken		      mtod(pMbuf->m_next, vm_offset_t)));
1256230587Sken		XNB_ASSERT(xnb_unit_pvt.gnttab[2].source.offset == 2 *
1257230587Sken			    MCLBYTES);
1258230587Sken	} else if (M_TRAILINGSPACE(pMbuf) == 2 * MCLBYTES) {
1259230587Sken		/* there should be two mbufs and two gnttab entries */
1260230587Sken		XNB_ASSERT(n_entries == 2);
1261230587Sken		XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == 2 * MCLBYTES);
1262230587Sken		XNB_ASSERT(
1263230587Sken		    xnb_unit_pvt.gnttab[0].dest.offset == virt_to_offset(
1264230587Sken		      mtod(pMbuf, vm_offset_t)));
1265230587Sken		XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == 0);
1266230587Sken
1267230587Sken		XNB_ASSERT(xnb_unit_pvt.gnttab[1].len == 1);
1268230587Sken		XNB_ASSERT(
1269230587Sken		    xnb_unit_pvt.gnttab[1].dest.offset == virt_to_offset(
1270230587Sken		      mtod(pMbuf->m_next, vm_offset_t)));
1271230587Sken		XNB_ASSERT(
1272230587Sken		    xnb_unit_pvt.gnttab[1].source.offset == 2 * MCLBYTES);
1273230587Sken
1274230587Sken	} else {
1275230587Sken		/* should never get here */
1276230587Sken		XNB_ASSERT(0);
1277230587Sken	}
1278316362Sasomers	m_freem(pMbuf);
1279230587Sken}
1280230587Sken
1281230587Sken
1282230587Sken/**
1283230587Sken * xnb_update_mbufc on a short packet that only has one gnttab entry
1284230587Sken */
1285230587Skenstatic void
1286230587Skenxnb_update_mbufc_short(char *buffer, size_t buflen)
1287230587Sken{
1288230587Sken	const size_t size = MINCLSIZE - 1;
1289230587Sken	int n_entries;
1290230587Sken	struct xnb_pkt pkt;
1291230587Sken	struct mbuf *pMbuf;
1292230587Sken
1293230587Sken	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1294230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
1295230587Sken	req->flags = 0;
1296230587Sken	req->size = size;
1297230587Sken	req->gref = 7;
1298230587Sken	req->offset = 17;
1299230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
1300230587Sken
1301230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1302230587Sken
1303230587Sken	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1304230587Sken
1305230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1306230587Sken	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1307230587Sken	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1308230587Sken
1309230587Sken	/* Update grant table's status fields as the hypervisor call would */
1310230587Sken	xnb_unit_pvt.gnttab[0].status = GNTST_okay;
1311230587Sken
1312230587Sken	xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
1313230587Sken	XNB_ASSERT(pMbuf->m_len == size);
1314230587Sken	XNB_ASSERT(pMbuf->m_pkthdr.len == size);
1315230587Sken	safe_m_freem(&pMbuf);
1316230587Sken}
1317230587Sken
1318230587Sken/**
1319230587Sken * xnb_update_mbufc on a packet with two requests, that can fit into a single
1320230587Sken * mbuf cluster
1321230587Sken */
1322230587Skenstatic void
1323230587Skenxnb_update_mbufc_2req(char *buffer, size_t buflen)
1324230587Sken{
1325230587Sken	int n_entries;
1326230587Sken	struct xnb_pkt pkt;
1327230587Sken	struct mbuf *pMbuf;
1328230587Sken
1329230587Sken	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1330230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
1331230587Sken	req->flags = NETTXF_more_data;
1332230587Sken	req->size = 1900;
1333230587Sken	req->gref = 7;
1334230587Sken	req->offset = 0;
1335230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
1336230587Sken
1337230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1338230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
1339230587Sken	req->flags = 0;
1340230587Sken	req->size = 500;
1341230587Sken	req->gref = 8;
1342230587Sken	req->offset = 0;
1343230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
1344230587Sken
1345230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1346230587Sken
1347230587Sken	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1348230587Sken
1349230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1350230587Sken	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1351230587Sken	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1352230587Sken
1353230587Sken	/* Update grant table's status fields as the hypervisor call would */
1354230587Sken	xnb_unit_pvt.gnttab[0].status = GNTST_okay;
1355230587Sken	xnb_unit_pvt.gnttab[1].status = GNTST_okay;
1356230587Sken
1357230587Sken	xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
1358230587Sken	XNB_ASSERT(n_entries == 2);
1359230587Sken	XNB_ASSERT(pMbuf->m_pkthdr.len == 1900);
1360230587Sken	XNB_ASSERT(pMbuf->m_len == 1900);
1361230587Sken
1362230587Sken	safe_m_freem(&pMbuf);
1363230587Sken}
1364230587Sken
1365230587Sken/**
1366230587Sken * xnb_update_mbufc on a single request that spans two mbuf clusters
1367230587Sken */
1368230587Skenstatic void
1369230587Skenxnb_update_mbufc_2cluster(char *buffer, size_t buflen)
1370230587Sken{
1371230587Sken	int i;
1372230587Sken	int n_entries;
1373230587Sken	struct xnb_pkt pkt;
1374230587Sken	struct mbuf *pMbuf;
1375230587Sken	const uint16_t data_this_transaction = (MCLBYTES*2) + 1;
1376230587Sken
1377230587Sken	struct netif_tx_request *req = RING_GET_REQUEST(&xnb_unit_pvt.txf,
1378230587Sken	    xnb_unit_pvt.txf.req_prod_pvt);
1379230587Sken	req->flags = 0;
1380230587Sken	req->size = data_this_transaction;
1381230587Sken	req->gref = 8;
1382230587Sken	req->offset = 0;
1383230587Sken	xnb_unit_pvt.txf.req_prod_pvt++;
1384230587Sken
1385230587Sken	RING_PUSH_REQUESTS(&xnb_unit_pvt.txf);
1386230587Sken	xnb_ring2pkt(&pkt, &xnb_unit_pvt.txb, xnb_unit_pvt.txb.req_cons);
1387230587Sken
1388230587Sken	pMbuf = xnb_pkt2mbufc(&pkt, xnb_unit_pvt.ifp);
1389230587Sken	n_entries = xnb_txpkt2gnttab(&pkt, pMbuf, xnb_unit_pvt.gnttab,
1390230587Sken	    &xnb_unit_pvt.txb, DOMID_FIRST_RESERVED);
1391230587Sken
1392230587Sken	/* Update grant table's status fields */
1393230587Sken	for (i = 0; i < n_entries; i++) {
1394230587Sken		xnb_unit_pvt.gnttab[0].status = GNTST_okay;
1395230587Sken	}
1396230587Sken	xnb_update_mbufc(pMbuf, xnb_unit_pvt.gnttab, n_entries);
1397230587Sken
1398230587Sken	if (n_entries == 3) {
1399230587Sken		/* there should be three mbufs and three gnttab entries */
1400230587Sken		XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
1401230587Sken		XNB_ASSERT(pMbuf->m_len == MCLBYTES);
1402230587Sken		XNB_ASSERT(pMbuf->m_next->m_len == MCLBYTES);
1403230587Sken		XNB_ASSERT(pMbuf->m_next->m_next->m_len == 1);
1404230587Sken	} else if (n_entries == 2) {
1405230587Sken		/* there should be two mbufs and two gnttab entries */
1406230587Sken		XNB_ASSERT(n_entries == 2);
1407230587Sken		XNB_ASSERT(pMbuf->m_pkthdr.len == data_this_transaction);
1408230587Sken		XNB_ASSERT(pMbuf->m_len == 2 * MCLBYTES);
1409230587Sken		XNB_ASSERT(pMbuf->m_next->m_len == 1);
1410230587Sken	} else {
1411230587Sken		/* should never get here */
1412230587Sken		XNB_ASSERT(0);
1413230587Sken	}
1414230587Sken	safe_m_freem(&pMbuf);
1415230587Sken}
1416230587Sken
1417230587Sken/** xnb_mbufc2pkt on an empty mbufc */
1418230587Skenstatic void
1419230587Skenxnb_mbufc2pkt_empty(char *buffer, size_t buflen) {
1420230587Sken	struct xnb_pkt pkt;
1421230587Sken	int free_slots = 64;
1422230587Sken	struct mbuf *mbuf;
1423230587Sken
1424230587Sken	mbuf = m_get(M_WAITOK, MT_DATA);
1425230587Sken	/*
1426230587Sken	 * note: it is illegal to set M_PKTHDR on a mbuf with no data.  Doing so
1427230587Sken	 * will cause m_freem to segfault
1428230587Sken	 */
1429230587Sken	XNB_ASSERT(mbuf->m_len == 0);
1430230587Sken
1431230587Sken	xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
1432230587Sken	XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
1433230587Sken
1434230587Sken	safe_m_freem(&mbuf);
1435230587Sken}
1436230587Sken
1437230587Sken/** xnb_mbufc2pkt on a short mbufc */
1438230587Skenstatic void
1439230587Skenxnb_mbufc2pkt_short(char *buffer, size_t buflen) {
1440230587Sken	struct xnb_pkt pkt;
1441230587Sken	size_t size = 128;
1442230587Sken	int free_slots = 64;
1443230587Sken	RING_IDX start = 9;
1444230587Sken	struct mbuf *mbuf;
1445230587Sken
1446230587Sken	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1447230587Sken	mbuf->m_flags |= M_PKTHDR;
1448230587Sken	mbuf->m_pkthdr.len = size;
1449230587Sken	mbuf->m_len = size;
1450230587Sken
1451230587Sken	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1452230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1453230587Sken	XNB_ASSERT(pkt.size == size);
1454230587Sken	XNB_ASSERT(pkt.car_size == size);
1455230587Sken	XNB_ASSERT(! (pkt.flags &
1456230587Sken	      (NETRXF_more_data | NETRXF_extra_info)));
1457230587Sken	XNB_ASSERT(pkt.list_len == 1);
1458230587Sken	XNB_ASSERT(pkt.car == start);
1459230587Sken
1460230587Sken	safe_m_freem(&mbuf);
1461230587Sken}
1462230587Sken
1463230587Sken/** xnb_mbufc2pkt on a single mbuf with an mbuf cluster */
1464230587Skenstatic void
1465230587Skenxnb_mbufc2pkt_1cluster(char *buffer, size_t buflen) {
1466230587Sken	struct xnb_pkt pkt;
1467230587Sken	size_t size = MCLBYTES;
1468230587Sken	int free_slots = 32;
1469230587Sken	RING_IDX start = 12;
1470230587Sken	struct mbuf *mbuf;
1471230587Sken
1472230587Sken	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1473230587Sken	mbuf->m_flags |= M_PKTHDR;
1474230587Sken	mbuf->m_pkthdr.len = size;
1475230587Sken	mbuf->m_len = size;
1476230587Sken
1477230587Sken	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1478230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1479230587Sken	XNB_ASSERT(pkt.size == size);
1480230587Sken	XNB_ASSERT(pkt.car_size == size);
1481230587Sken	XNB_ASSERT(! (pkt.flags &
1482230587Sken	      (NETRXF_more_data | NETRXF_extra_info)));
1483230587Sken	XNB_ASSERT(pkt.list_len == 1);
1484230587Sken	XNB_ASSERT(pkt.car == start);
1485230587Sken
1486230587Sken	safe_m_freem(&mbuf);
1487230587Sken}
1488230587Sken
1489240521Seadler/** xnb_mbufc2pkt on a two-mbuf chain with short data regions */
1490230587Skenstatic void
1491230587Skenxnb_mbufc2pkt_2short(char *buffer, size_t buflen) {
1492230587Sken	struct xnb_pkt pkt;
1493230587Sken	size_t size1 = MHLEN - 5;
1494230587Sken	size_t size2 = MHLEN - 15;
1495230587Sken	int free_slots = 32;
1496230587Sken	RING_IDX start = 14;
1497230587Sken	struct mbuf *mbufc, *mbufc2;
1498230587Sken
1499230587Sken	mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
1500316362Sasomers	XNB_ASSERT(mbufc != NULL);
1501316362Sasomers	if (mbufc == NULL)
1502316362Sasomers		return;
1503230587Sken	mbufc->m_flags |= M_PKTHDR;
1504230587Sken
1505230587Sken	mbufc2 = m_getm(mbufc, size2, M_WAITOK, MT_DATA);
1506316362Sasomers	XNB_ASSERT(mbufc2 != NULL);
1507230587Sken	if (mbufc2 == NULL) {
1508230587Sken		safe_m_freem(&mbufc);
1509230587Sken		return;
1510230587Sken	}
1511230587Sken	mbufc2->m_pkthdr.len = size1 + size2;
1512230587Sken	mbufc2->m_len = size1;
1513230587Sken
1514230587Sken	xnb_mbufc2pkt(mbufc2, &pkt, start, free_slots);
1515230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1516230587Sken	XNB_ASSERT(pkt.size == size1 + size2);
1517230587Sken	XNB_ASSERT(pkt.car == start);
1518230587Sken	/*
1519230587Sken	 * The second m_getm may allocate a new mbuf and append
1520230587Sken	 * it to the chain, or it may simply extend the first mbuf.
1521230587Sken	 */
1522230587Sken	if (mbufc2->m_next != NULL) {
1523230587Sken		XNB_ASSERT(pkt.car_size == size1);
1524230587Sken		XNB_ASSERT(pkt.list_len == 1);
1525230587Sken		XNB_ASSERT(pkt.cdr == start + 1);
1526230587Sken	}
1527230587Sken
1528230587Sken	safe_m_freem(&mbufc2);
1529230587Sken}
1530230587Sken
1531240521Seadler/** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster */
1532230587Skenstatic void
1533230587Skenxnb_mbufc2pkt_long(char *buffer, size_t buflen) {
1534230587Sken	struct xnb_pkt pkt;
1535230587Sken	size_t size = 14 * MCLBYTES / 3;
1536230587Sken	size_t size_remaining;
1537230587Sken	int free_slots = 15;
1538230587Sken	RING_IDX start = 3;
1539230587Sken	struct mbuf *mbufc, *m;
1540230587Sken
1541230587Sken	mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1542316362Sasomers	XNB_ASSERT(mbufc != NULL);
1543316362Sasomers	if (mbufc == NULL)
1544316362Sasomers		return;
1545230587Sken	mbufc->m_flags |= M_PKTHDR;
1546230587Sken
1547230587Sken	mbufc->m_pkthdr.len = size;
1548230587Sken	size_remaining = size;
1549230587Sken	for (m = mbufc; m != NULL; m = m->m_next) {
1550230587Sken		m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
1551230587Sken		size_remaining -= m->m_len;
1552230587Sken	}
1553230587Sken
1554230587Sken	xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1555230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1556230587Sken	XNB_ASSERT(pkt.size == size);
1557230587Sken	XNB_ASSERT(pkt.car == start);
1558230587Sken	XNB_ASSERT(pkt.car_size = mbufc->m_len);
1559230587Sken	/*
1560230587Sken	 * There should be >1 response in the packet, and there is no
1561230587Sken	 * extra info.
1562230587Sken	 */
1563230587Sken	XNB_ASSERT(! (pkt.flags & NETRXF_extra_info));
1564230587Sken	XNB_ASSERT(pkt.cdr == pkt.car + 1);
1565230587Sken
1566230587Sken	safe_m_freem(&mbufc);
1567230587Sken}
1568230587Sken
1569240521Seadler/** xnb_mbufc2pkt on a mbuf chain with >1 mbuf cluster and extra info */
1570230587Skenstatic void
1571230587Skenxnb_mbufc2pkt_extra(char *buffer, size_t buflen) {
1572230587Sken	struct xnb_pkt pkt;
1573230587Sken	size_t size = 14 * MCLBYTES / 3;
1574230587Sken	size_t size_remaining;
1575230587Sken	int free_slots = 15;
1576230587Sken	RING_IDX start = 3;
1577230587Sken	struct mbuf *mbufc, *m;
1578230587Sken
1579230587Sken	mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1580316362Sasomers	XNB_ASSERT(mbufc != NULL);
1581316362Sasomers	if (mbufc == NULL)
1582230587Sken		return;
1583230587Sken
1584230587Sken	mbufc->m_flags |= M_PKTHDR;
1585230587Sken	mbufc->m_pkthdr.len = size;
1586230587Sken	mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
1587230587Sken	mbufc->m_pkthdr.tso_segsz = TCP_MSS - 40;
1588230587Sken	size_remaining = size;
1589230587Sken	for (m = mbufc; m != NULL; m = m->m_next) {
1590230587Sken		m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
1591230587Sken		size_remaining -= m->m_len;
1592230587Sken	}
1593230587Sken
1594230587Sken	xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1595230587Sken	XNB_ASSERT(xnb_pkt_is_valid(&pkt));
1596230587Sken	XNB_ASSERT(pkt.size == size);
1597230587Sken	XNB_ASSERT(pkt.car == start);
1598230587Sken	XNB_ASSERT(pkt.car_size = mbufc->m_len);
1599230587Sken	/* There should be >1 response in the packet, there is extra info */
1600230587Sken	XNB_ASSERT(pkt.flags & NETRXF_extra_info);
1601230587Sken	XNB_ASSERT(pkt.flags & NETRXF_data_validated);
1602230587Sken	XNB_ASSERT(pkt.cdr == pkt.car + 2);
1603230587Sken	XNB_ASSERT(pkt.extra.u.gso.size = mbufc->m_pkthdr.tso_segsz);
1604230587Sken	XNB_ASSERT(pkt.extra.type == XEN_NETIF_EXTRA_TYPE_GSO);
1605230587Sken	XNB_ASSERT(! (pkt.extra.flags & XEN_NETIF_EXTRA_FLAG_MORE));
1606230587Sken
1607230587Sken	safe_m_freem(&mbufc);
1608230587Sken}
1609230587Sken
1610230587Sken/** xnb_mbufc2pkt with insufficient space in the ring */
1611230587Skenstatic void
1612230587Skenxnb_mbufc2pkt_nospace(char *buffer, size_t buflen) {
1613230587Sken	struct xnb_pkt pkt;
1614230587Sken	size_t size = 14 * MCLBYTES / 3;
1615230587Sken	size_t size_remaining;
1616230587Sken	int free_slots = 2;
1617230587Sken	RING_IDX start = 3;
1618230587Sken	struct mbuf *mbufc, *m;
1619230587Sken	int error;
1620230587Sken
1621230587Sken	mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1622316362Sasomers	XNB_ASSERT(mbufc != NULL);
1623316362Sasomers	if (mbufc == NULL)
1624316362Sasomers		return;
1625230587Sken	mbufc->m_flags |= M_PKTHDR;
1626230587Sken
1627230587Sken	mbufc->m_pkthdr.len = size;
1628230587Sken	size_remaining = size;
1629230587Sken	for (m = mbufc; m != NULL; m = m->m_next) {
1630230587Sken		m->m_len = MAX(M_TRAILINGSPACE(m), size_remaining);
1631230587Sken		size_remaining -= m->m_len;
1632230587Sken	}
1633230587Sken
1634230587Sken	error = xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1635230587Sken	XNB_ASSERT(error == EAGAIN);
1636230587Sken	XNB_ASSERT(! xnb_pkt_is_valid(&pkt));
1637230587Sken
1638230587Sken	safe_m_freem(&mbufc);
1639230587Sken}
1640230587Sken
1641230587Sken/**
1642230587Sken * xnb_rxpkt2gnttab on an empty packet.  Should return empty gnttab
1643230587Sken */
1644230587Skenstatic void
1645230587Skenxnb_rxpkt2gnttab_empty(char *buffer, size_t buflen)
1646230587Sken{
1647230587Sken	struct xnb_pkt pkt;
1648230587Sken	int nr_entries;
1649230587Sken	int free_slots = 60;
1650230587Sken	struct mbuf *mbuf;
1651230587Sken
1652230587Sken	mbuf = m_get(M_WAITOK, MT_DATA);
1653230587Sken
1654230587Sken	xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
1655230587Sken	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1656230587Sken			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1657230587Sken
1658230587Sken	XNB_ASSERT(nr_entries == 0);
1659230587Sken
1660230587Sken	safe_m_freem(&mbuf);
1661230587Sken}
1662230587Sken
1663230587Sken/** xnb_rxpkt2gnttab on a short packet without extra data */
1664230587Skenstatic void
1665230587Skenxnb_rxpkt2gnttab_short(char *buffer, size_t buflen) {
1666230587Sken	struct xnb_pkt pkt;
1667230587Sken	int nr_entries;
1668230587Sken	size_t size = 128;
1669230587Sken	int free_slots = 60;
1670230587Sken	RING_IDX start = 9;
1671230587Sken	struct netif_rx_request *req;
1672230587Sken	struct mbuf *mbuf;
1673230587Sken
1674230587Sken	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1675230587Sken	mbuf->m_flags |= M_PKTHDR;
1676230587Sken	mbuf->m_pkthdr.len = size;
1677230587Sken	mbuf->m_len = size;
1678230587Sken
1679230587Sken	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1680230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
1681230587Sken			       xnb_unit_pvt.txf.req_prod_pvt);
1682230587Sken	req->gref = 7;
1683230587Sken
1684230587Sken	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1685230587Sken				      &xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1686230587Sken
1687230587Sken	XNB_ASSERT(nr_entries == 1);
1688230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].len == size);
1689230587Sken	/* flags should indicate gref's for dest */
1690230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].flags & GNTCOPY_dest_gref);
1691230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.offset == 0);
1692230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.domid == DOMID_SELF);
1693230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.offset == virt_to_offset(
1694230587Sken		   mtod(mbuf, vm_offset_t)));
1695230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].source.u.gmfn ==
1696230587Sken		   virt_to_mfn(mtod(mbuf, vm_offset_t)));
1697230587Sken	XNB_ASSERT(xnb_unit_pvt.gnttab[0].dest.domid == DOMID_FIRST_RESERVED);
1698230587Sken
1699230587Sken	safe_m_freem(&mbuf);
1700230587Sken}
1701230587Sken
1702230587Sken/**
1703230587Sken * xnb_rxpkt2gnttab on a packet with two different mbufs in a single chai
1704230587Sken */
1705230587Skenstatic void
1706230587Skenxnb_rxpkt2gnttab_2req(char *buffer, size_t buflen)
1707230587Sken{
1708230587Sken	struct xnb_pkt pkt;
1709230587Sken	int nr_entries;
1710230587Sken	int i, num_mbufs;
1711230587Sken	size_t total_granted_size = 0;
1712230587Sken	size_t size = MJUMPAGESIZE + 1;
1713230587Sken	int free_slots = 60;
1714230587Sken	RING_IDX start = 11;
1715230587Sken	struct netif_rx_request *req;
1716230587Sken	struct mbuf *mbuf, *m;
1717230587Sken
1718230587Sken	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1719230587Sken	mbuf->m_flags |= M_PKTHDR;
1720230587Sken	mbuf->m_pkthdr.len = size;
1721230587Sken	mbuf->m_len = size;
1722230587Sken
1723230587Sken	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1724230587Sken
1725230587Sken	for (i = 0, m=mbuf; m != NULL; i++, m = m->m_next) {
1726230587Sken		req = RING_GET_REQUEST(&xnb_unit_pvt.rxf,
1727230587Sken		    xnb_unit_pvt.txf.req_prod_pvt);
1728230587Sken		req->gref = i;
1729230587Sken		req->id = 5;
1730230587Sken	}
1731230587Sken	num_mbufs = i;
1732230587Sken
1733230587Sken	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1734230587Sken			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1735230587Sken
1736230587Sken	XNB_ASSERT(nr_entries >= num_mbufs);
1737230587Sken	for (i = 0; i < nr_entries; i++) {
1738230587Sken		int end_offset = xnb_unit_pvt.gnttab[i].len +
1739230587Sken			xnb_unit_pvt.gnttab[i].dest.offset;
1740230587Sken		XNB_ASSERT(end_offset <= PAGE_SIZE);
1741230587Sken		total_granted_size += xnb_unit_pvt.gnttab[i].len;
1742230587Sken	}
1743230587Sken	XNB_ASSERT(total_granted_size == size);
1744230587Sken}
1745230587Sken
1746230587Sken/**
1747230587Sken * xnb_rxpkt2rsp on an empty packet.  Shouldn't make any response
1748230587Sken */
1749230587Skenstatic void
1750230587Skenxnb_rxpkt2rsp_empty(char *buffer, size_t buflen)
1751230587Sken{
1752230587Sken	struct xnb_pkt pkt;
1753230587Sken	int nr_entries;
1754230587Sken	int nr_reqs;
1755230587Sken	int free_slots = 60;
1756230587Sken	netif_rx_back_ring_t rxb_backup = xnb_unit_pvt.rxb;
1757230587Sken	netif_rx_sring_t rxs_backup = *xnb_unit_pvt.rxs;
1758230587Sken	struct mbuf *mbuf;
1759230587Sken
1760230587Sken	mbuf = m_get(M_WAITOK, MT_DATA);
1761230587Sken
1762230587Sken	xnb_mbufc2pkt(mbuf, &pkt, 0, free_slots);
1763230587Sken	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1764230587Sken			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1765230587Sken
1766230587Sken	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1767230587Sken	    &xnb_unit_pvt.rxb);
1768230587Sken	XNB_ASSERT(nr_reqs == 0);
1769230587Sken	XNB_ASSERT(
1770230587Sken	    memcmp(&rxb_backup, &xnb_unit_pvt.rxb, sizeof(rxb_backup)) == 0);
1771230587Sken	XNB_ASSERT(
1772230587Sken	    memcmp(&rxs_backup, xnb_unit_pvt.rxs, sizeof(rxs_backup)) == 0);
1773230587Sken
1774230587Sken	safe_m_freem(&mbuf);
1775230587Sken}
1776230587Sken
1777230587Sken/**
1778230587Sken * xnb_rxpkt2rsp on a short packet with no extras
1779230587Sken */
1780230587Skenstatic void
1781230587Skenxnb_rxpkt2rsp_short(char *buffer, size_t buflen)
1782230587Sken{
1783230587Sken	struct xnb_pkt pkt;
1784230587Sken	int nr_entries, nr_reqs;
1785230587Sken	size_t size = 128;
1786230587Sken	int free_slots = 60;
1787230587Sken	RING_IDX start = 5;
1788230587Sken	struct netif_rx_request *req;
1789230587Sken	struct netif_rx_response *rsp;
1790230587Sken	struct mbuf *mbuf;
1791230587Sken
1792230587Sken	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1793230587Sken	mbuf->m_flags |= M_PKTHDR;
1794230587Sken	mbuf->m_pkthdr.len = size;
1795230587Sken	mbuf->m_len = size;
1796230587Sken
1797230587Sken	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1798230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1799230587Sken	req->gref = 7;
1800230587Sken	xnb_unit_pvt.rxb.req_cons = start;
1801230587Sken	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1802230587Sken	xnb_unit_pvt.rxs->req_prod = start + 1;
1803230587Sken	xnb_unit_pvt.rxs->rsp_prod = start;
1804230587Sken
1805230587Sken	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1806230587Sken			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1807230587Sken
1808230587Sken	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1809230587Sken	    &xnb_unit_pvt.rxb);
1810230587Sken
1811230587Sken	XNB_ASSERT(nr_reqs == 1);
1812230587Sken	XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
1813230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1814230587Sken	XNB_ASSERT(rsp->id == req->id);
1815230587Sken	XNB_ASSERT(rsp->offset == 0);
1816230587Sken	XNB_ASSERT((rsp->flags & (NETRXF_more_data | NETRXF_extra_info)) == 0);
1817230587Sken	XNB_ASSERT(rsp->status == size);
1818230587Sken
1819230587Sken	safe_m_freem(&mbuf);
1820230587Sken}
1821230587Sken
1822230587Sken/**
1823230587Sken * xnb_rxpkt2rsp with extra data
1824230587Sken */
1825230587Skenstatic void
1826230587Skenxnb_rxpkt2rsp_extra(char *buffer, size_t buflen)
1827230587Sken{
1828230587Sken	struct xnb_pkt pkt;
1829230587Sken	int nr_entries, nr_reqs;
1830230587Sken	size_t size = 14;
1831230587Sken	int free_slots = 15;
1832230587Sken	RING_IDX start = 3;
1833230587Sken	uint16_t id = 49;
1834230587Sken	uint16_t gref = 65;
1835230587Sken	uint16_t mss = TCP_MSS - 40;
1836230587Sken	struct mbuf *mbufc;
1837230587Sken	struct netif_rx_request *req;
1838230587Sken	struct netif_rx_response *rsp;
1839230587Sken	struct netif_extra_info *ext;
1840230587Sken
1841230587Sken	mbufc = m_getm(NULL, size, M_WAITOK, MT_DATA);
1842316362Sasomers	XNB_ASSERT(mbufc != NULL);
1843316362Sasomers	if (mbufc == NULL)
1844230587Sken		return;
1845230587Sken
1846230587Sken	mbufc->m_flags |= M_PKTHDR;
1847230587Sken	mbufc->m_pkthdr.len = size;
1848230587Sken	mbufc->m_pkthdr.csum_flags |= CSUM_TSO;
1849230587Sken	mbufc->m_pkthdr.tso_segsz = mss;
1850230587Sken	mbufc->m_len = size;
1851230587Sken
1852230587Sken	xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1853230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1854230587Sken	req->id = id;
1855230587Sken	req->gref = gref;
1856230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
1857230587Sken	req->id = id + 1;
1858230587Sken	req->gref = gref + 1;
1859230587Sken	xnb_unit_pvt.rxb.req_cons = start;
1860230587Sken	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1861230587Sken	xnb_unit_pvt.rxs->req_prod = start + 2;
1862230587Sken	xnb_unit_pvt.rxs->rsp_prod = start;
1863230587Sken
1864230587Sken	nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
1865230587Sken			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1866230587Sken
1867230587Sken	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1868230587Sken	    &xnb_unit_pvt.rxb);
1869230587Sken
1870230587Sken	XNB_ASSERT(nr_reqs == 2);
1871230587Sken	XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
1872230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1873230587Sken	XNB_ASSERT(rsp->id == id);
1874230587Sken	XNB_ASSERT((rsp->flags & NETRXF_more_data) == 0);
1875230587Sken	XNB_ASSERT((rsp->flags & NETRXF_extra_info));
1876230587Sken	XNB_ASSERT((rsp->flags & NETRXF_data_validated));
1877230587Sken	XNB_ASSERT((rsp->flags & NETRXF_csum_blank));
1878230587Sken	XNB_ASSERT(rsp->status == size);
1879230587Sken
1880230587Sken	ext = (struct netif_extra_info*)
1881230587Sken		RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
1882230587Sken	XNB_ASSERT(ext->type == XEN_NETIF_EXTRA_TYPE_GSO);
1883230587Sken	XNB_ASSERT(! (ext->flags & XEN_NETIF_EXTRA_FLAG_MORE));
1884230587Sken	XNB_ASSERT(ext->u.gso.size == mss);
1885230587Sken	XNB_ASSERT(ext->u.gso.type == XEN_NETIF_EXTRA_TYPE_GSO);
1886230587Sken
1887230587Sken	safe_m_freem(&mbufc);
1888230587Sken}
1889230587Sken
1890230587Sken/**
1891230587Sken * xnb_rxpkt2rsp on a packet with more than a pages's worth of data.  It should
1892230587Sken * generate two response slot
1893230587Sken */
1894230587Skenstatic void
1895230587Skenxnb_rxpkt2rsp_2slots(char *buffer, size_t buflen)
1896230587Sken{
1897230587Sken	struct xnb_pkt pkt;
1898230587Sken	int nr_entries, nr_reqs;
1899230587Sken	size_t size = PAGE_SIZE + 100;
1900230587Sken	int free_slots = 3;
1901230587Sken	uint16_t id1 = 17;
1902230587Sken	uint16_t id2 = 37;
1903230587Sken	uint16_t gref1 = 24;
1904230587Sken	uint16_t gref2 = 34;
1905230587Sken	RING_IDX start = 15;
1906230587Sken	struct netif_rx_request *req;
1907230587Sken	struct netif_rx_response *rsp;
1908230587Sken	struct mbuf *mbuf;
1909230587Sken
1910230587Sken	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
1911230587Sken	mbuf->m_flags |= M_PKTHDR;
1912230587Sken	mbuf->m_pkthdr.len = size;
1913230587Sken	if (mbuf->m_next != NULL) {
1914230587Sken		size_t first_len = MIN(M_TRAILINGSPACE(mbuf), size);
1915230587Sken		mbuf->m_len = first_len;
1916230587Sken		mbuf->m_next->m_len = size - first_len;
1917230587Sken
1918230587Sken	} else {
1919230587Sken		mbuf->m_len = size;
1920230587Sken	}
1921230587Sken
1922230587Sken	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
1923230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1924230587Sken	req->gref = gref1;
1925230587Sken	req->id = id1;
1926230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
1927230587Sken	req->gref = gref2;
1928230587Sken	req->id = id2;
1929230587Sken	xnb_unit_pvt.rxb.req_cons = start;
1930230587Sken	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1931230587Sken	xnb_unit_pvt.rxs->req_prod = start + 2;
1932230587Sken	xnb_unit_pvt.rxs->rsp_prod = start;
1933230587Sken
1934230587Sken	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
1935230587Sken			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1936230587Sken
1937230587Sken	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
1938230587Sken	    &xnb_unit_pvt.rxb);
1939230587Sken
1940230587Sken	XNB_ASSERT(nr_reqs == 2);
1941230587Sken	XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 2);
1942230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
1943230587Sken	XNB_ASSERT(rsp->id == id1);
1944230587Sken	XNB_ASSERT(rsp->offset == 0);
1945230587Sken	XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
1946230587Sken	XNB_ASSERT(rsp->flags & NETRXF_more_data);
1947230587Sken	XNB_ASSERT(rsp->status == PAGE_SIZE);
1948230587Sken
1949230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start + 1);
1950230587Sken	XNB_ASSERT(rsp->id == id2);
1951230587Sken	XNB_ASSERT(rsp->offset == 0);
1952230587Sken	XNB_ASSERT((rsp->flags & NETRXF_extra_info) == 0);
1953230587Sken	XNB_ASSERT(! (rsp->flags & NETRXF_more_data));
1954230587Sken	XNB_ASSERT(rsp->status == size - PAGE_SIZE);
1955230587Sken
1956230587Sken	safe_m_freem(&mbuf);
1957230587Sken}
1958230587Sken
1959230587Sken/** xnb_rxpkt2rsp on a grant table with two sub-page entries */
1960230587Skenstatic void
1961230587Skenxnb_rxpkt2rsp_2short(char *buffer, size_t buflen) {
1962230587Sken	struct xnb_pkt pkt;
1963230587Sken	int nr_reqs, nr_entries;
1964230587Sken	size_t size1 = MHLEN - 5;
1965230587Sken	size_t size2 = MHLEN - 15;
1966230587Sken	int free_slots = 32;
1967230587Sken	RING_IDX start = 14;
1968230587Sken	uint16_t id = 47;
1969230587Sken	uint16_t gref = 54;
1970230587Sken	struct netif_rx_request *req;
1971230587Sken	struct netif_rx_response *rsp;
1972230587Sken	struct mbuf *mbufc;
1973230587Sken
1974230587Sken	mbufc = m_getm(NULL, size1, M_WAITOK, MT_DATA);
1975316362Sasomers	XNB_ASSERT(mbufc != NULL);
1976316362Sasomers	if (mbufc == NULL)
1977316362Sasomers		return;
1978230587Sken	mbufc->m_flags |= M_PKTHDR;
1979230587Sken
1980230587Sken	m_getm(mbufc, size2, M_WAITOK, MT_DATA);
1981230587Sken	XNB_ASSERT(mbufc->m_next != NULL);
1982230587Sken	mbufc->m_pkthdr.len = size1 + size2;
1983230587Sken	mbufc->m_len = size1;
1984230587Sken	mbufc->m_next->m_len = size2;
1985230587Sken
1986230587Sken	xnb_mbufc2pkt(mbufc, &pkt, start, free_slots);
1987230587Sken
1988230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
1989230587Sken	req->gref = gref;
1990230587Sken	req->id = id;
1991230587Sken	xnb_unit_pvt.rxb.req_cons = start;
1992230587Sken	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
1993230587Sken	xnb_unit_pvt.rxs->req_prod = start + 1;
1994230587Sken	xnb_unit_pvt.rxs->rsp_prod = start;
1995230587Sken
1996230587Sken	nr_entries = xnb_rxpkt2gnttab(&pkt, mbufc, xnb_unit_pvt.gnttab,
1997230587Sken			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
1998230587Sken
1999230587Sken	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
2000230587Sken	    &xnb_unit_pvt.rxb);
2001230587Sken
2002230587Sken	XNB_ASSERT(nr_entries == 2);
2003230587Sken	XNB_ASSERT(nr_reqs == 1);
2004230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
2005230587Sken	XNB_ASSERT(rsp->id == id);
2006230587Sken	XNB_ASSERT(rsp->status == size1 + size2);
2007230587Sken	XNB_ASSERT(rsp->offset == 0);
2008230587Sken	XNB_ASSERT(! (rsp->flags & (NETRXF_more_data | NETRXF_extra_info)));
2009230587Sken
2010230587Sken	safe_m_freem(&mbufc);
2011230587Sken}
2012230587Sken
2013230587Sken/**
2014230587Sken * xnb_rxpkt2rsp on a long packet with a hypervisor gnttab_copy error
2015230587Sken * Note: this test will result in an error message being printed to the console
2016230587Sken * such as:
2017230587Sken * xnb(xnb_rxpkt2rsp:1720): Got error -1 for hypervisor gnttab_copy status
2018230587Sken */
2019230587Skenstatic void
2020230587Skenxnb_rxpkt2rsp_copyerror(char *buffer, size_t buflen)
2021230587Sken{
2022230587Sken	struct xnb_pkt pkt;
2023230587Sken	int nr_entries, nr_reqs;
2024230587Sken	int id = 7;
2025230587Sken	int gref = 42;
2026230587Sken	uint16_t canary = 6859;
2027230587Sken	size_t size = 7 * MCLBYTES;
2028230587Sken	int free_slots = 9;
2029230587Sken	RING_IDX start = 2;
2030230587Sken	struct netif_rx_request *req;
2031230587Sken	struct netif_rx_response *rsp;
2032230587Sken	struct mbuf *mbuf;
2033230587Sken
2034230587Sken	mbuf = m_getm(NULL, size, M_WAITOK, MT_DATA);
2035230587Sken	mbuf->m_flags |= M_PKTHDR;
2036230587Sken	mbuf->m_pkthdr.len = size;
2037230587Sken	mbuf->m_len = size;
2038230587Sken
2039230587Sken	xnb_mbufc2pkt(mbuf, &pkt, start, free_slots);
2040230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start);
2041230587Sken	req->gref = gref;
2042230587Sken	req->id = id;
2043230587Sken	xnb_unit_pvt.rxb.req_cons = start;
2044230587Sken	xnb_unit_pvt.rxb.rsp_prod_pvt = start;
2045230587Sken	xnb_unit_pvt.rxs->req_prod = start + 1;
2046230587Sken	xnb_unit_pvt.rxs->rsp_prod = start;
2047230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
2048230587Sken	req->gref = canary;
2049230587Sken	req->id = canary;
2050230587Sken
2051230587Sken	nr_entries = xnb_rxpkt2gnttab(&pkt, mbuf, xnb_unit_pvt.gnttab,
2052230587Sken			&xnb_unit_pvt.rxb, DOMID_FIRST_RESERVED);
2053230587Sken	/* Inject the error*/
2054230587Sken	xnb_unit_pvt.gnttab[2].status = GNTST_general_error;
2055230587Sken
2056230587Sken	nr_reqs = xnb_rxpkt2rsp(&pkt, xnb_unit_pvt.gnttab, nr_entries,
2057230587Sken	    &xnb_unit_pvt.rxb);
2058230587Sken
2059230587Sken	XNB_ASSERT(nr_reqs == 1);
2060230587Sken	XNB_ASSERT(xnb_unit_pvt.rxb.rsp_prod_pvt == start + 1);
2061230587Sken	rsp = RING_GET_RESPONSE(&xnb_unit_pvt.rxb, start);
2062230587Sken	XNB_ASSERT(rsp->id == id);
2063230587Sken	XNB_ASSERT(rsp->status == NETIF_RSP_ERROR);
2064230587Sken	req = RING_GET_REQUEST(&xnb_unit_pvt.rxf, start + 1);
2065230587Sken	XNB_ASSERT(req->gref == canary);
2066230587Sken	XNB_ASSERT(req->id == canary);
2067230587Sken
2068230587Sken	safe_m_freem(&mbuf);
2069230587Sken}
2070230587Sken
2071257515Sglebius#if defined(INET) || defined(INET6)
2072230587Sken/**
2073230587Sken * xnb_add_mbuf_cksum on an ARP request packet
2074230587Sken */
2075230587Skenstatic void
2076230587Skenxnb_add_mbuf_cksum_arp(char *buffer, size_t buflen)
2077230587Sken{
2078230587Sken	const size_t pkt_len = sizeof(struct ether_header) +
2079230587Sken		sizeof(struct ether_arp);
2080230587Sken	struct mbuf *mbufc;
2081230587Sken	struct ether_header *eh;
2082230587Sken	struct ether_arp *ep;
2083230587Sken	unsigned char pkt_orig[pkt_len];
2084230587Sken
2085230587Sken	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2086230587Sken	/* Fill in an example arp request */
2087230587Sken	eh = mtod(mbufc, struct ether_header*);
2088230587Sken	eh->ether_dhost[0] = 0xff;
2089230587Sken	eh->ether_dhost[1] = 0xff;
2090230587Sken	eh->ether_dhost[2] = 0xff;
2091230587Sken	eh->ether_dhost[3] = 0xff;
2092230587Sken	eh->ether_dhost[4] = 0xff;
2093230587Sken	eh->ether_dhost[5] = 0xff;
2094230587Sken	eh->ether_shost[0] = 0x00;
2095230587Sken	eh->ether_shost[1] = 0x15;
2096230587Sken	eh->ether_shost[2] = 0x17;
2097230587Sken	eh->ether_shost[3] = 0xe9;
2098230587Sken	eh->ether_shost[4] = 0x30;
2099230587Sken	eh->ether_shost[5] = 0x68;
2100230587Sken	eh->ether_type = htons(ETHERTYPE_ARP);
2101230587Sken	ep = (struct ether_arp*)(eh + 1);
2102230587Sken	ep->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
2103230587Sken	ep->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
2104230587Sken	ep->ea_hdr.ar_hln = 6;
2105230587Sken	ep->ea_hdr.ar_pln = 4;
2106230587Sken	ep->ea_hdr.ar_op = htons(ARPOP_REQUEST);
2107230587Sken	ep->arp_sha[0] = 0x00;
2108230587Sken	ep->arp_sha[1] = 0x15;
2109230587Sken	ep->arp_sha[2] = 0x17;
2110230587Sken	ep->arp_sha[3] = 0xe9;
2111230587Sken	ep->arp_sha[4] = 0x30;
2112230587Sken	ep->arp_sha[5] = 0x68;
2113230587Sken	ep->arp_spa[0] = 0xc0;
2114230587Sken	ep->arp_spa[1] = 0xa8;
2115230587Sken	ep->arp_spa[2] = 0x0a;
2116230587Sken	ep->arp_spa[3] = 0x04;
2117230587Sken	bzero(&(ep->arp_tha), ETHER_ADDR_LEN);
2118230587Sken	ep->arp_tpa[0] = 0xc0;
2119230587Sken	ep->arp_tpa[1] = 0xa8;
2120230587Sken	ep->arp_tpa[2] = 0x0a;
2121230587Sken	ep->arp_tpa[3] = 0x06;
2122230587Sken
2123230587Sken	/* fill in the length field */
2124230587Sken	mbufc->m_len = pkt_len;
2125230587Sken	mbufc->m_pkthdr.len = pkt_len;
2126230587Sken	/* indicate that the netfront uses hw-assisted checksums */
2127230587Sken	mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
2128230587Sken				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2129230587Sken
2130230587Sken	/* Make a backup copy of the packet */
2131230587Sken	bcopy(mtod(mbufc, const void*), pkt_orig, pkt_len);
2132230587Sken
2133230587Sken	/* Function under test */
2134230587Sken	xnb_add_mbuf_cksum(mbufc);
2135230587Sken
2136230587Sken	/* Verify that the packet's data did not change */
2137230587Sken	XNB_ASSERT(bcmp(mtod(mbufc, const void*), pkt_orig, pkt_len) == 0);
2138230587Sken	m_freem(mbufc);
2139230587Sken}
2140230587Sken
2141230587Sken/**
2142230587Sken * Helper function that populates the ethernet header and IP header used by
2143230587Sken * some of the xnb_add_mbuf_cksum unit tests.  m must already be allocated
2144230587Sken * and must be large enough
2145230587Sken */
2146230587Skenstatic void
2147230587Skenxnb_fill_eh_and_ip(struct mbuf *m, uint16_t ip_len, uint16_t ip_id,
2148230587Sken		   uint16_t ip_p, uint16_t ip_off, uint16_t ip_sum)
2149230587Sken{
2150230587Sken	struct ether_header *eh;
2151230587Sken	struct ip *iph;
2152230587Sken
2153230587Sken	eh = mtod(m, struct ether_header*);
2154230587Sken	eh->ether_dhost[0] = 0x00;
2155230587Sken	eh->ether_dhost[1] = 0x16;
2156230587Sken	eh->ether_dhost[2] = 0x3e;
2157230587Sken	eh->ether_dhost[3] = 0x23;
2158230587Sken	eh->ether_dhost[4] = 0x50;
2159230587Sken	eh->ether_dhost[5] = 0x0b;
2160230587Sken	eh->ether_shost[0] = 0x00;
2161230587Sken	eh->ether_shost[1] = 0x16;
2162230587Sken	eh->ether_shost[2] = 0x30;
2163230587Sken	eh->ether_shost[3] = 0x00;
2164230587Sken	eh->ether_shost[4] = 0x00;
2165230587Sken	eh->ether_shost[5] = 0x00;
2166230587Sken	eh->ether_type = htons(ETHERTYPE_IP);
2167230587Sken	iph = (struct ip*)(eh + 1);
2168230587Sken	iph->ip_hl = 0x5;	/* 5 dwords == 20 bytes */
2169230587Sken	iph->ip_v = 4;		/* IP v4 */
2170230587Sken	iph->ip_tos = 0;
2171230587Sken	iph->ip_len = htons(ip_len);
2172230587Sken	iph->ip_id = htons(ip_id);
2173230587Sken	iph->ip_off = htons(ip_off);
2174230587Sken	iph->ip_ttl = 64;
2175230587Sken	iph->ip_p = ip_p;
2176230587Sken	iph->ip_sum = htons(ip_sum);
2177230587Sken	iph->ip_src.s_addr = htonl(0xc0a80a04);
2178230587Sken	iph->ip_dst.s_addr = htonl(0xc0a80a05);
2179230587Sken}
2180230587Sken
2181230587Sken/**
2182230587Sken * xnb_add_mbuf_cksum on an ICMP packet, based on a tcpdump of an actual
2183230587Sken * ICMP packet
2184230587Sken */
2185230587Skenstatic void
2186230587Skenxnb_add_mbuf_cksum_icmp(char *buffer, size_t buflen)
2187230587Sken{
2188230587Sken	const size_t icmp_len = 64;	/* set by ping(1) */
2189230587Sken	const size_t pkt_len = sizeof(struct ether_header) +
2190230587Sken		sizeof(struct ip) + icmp_len;
2191230587Sken	struct mbuf *mbufc;
2192230587Sken	struct ether_header *eh;
2193230587Sken	struct ip *iph;
2194230587Sken	struct icmp *icmph;
2195230587Sken	unsigned char pkt_orig[icmp_len];
2196230587Sken	uint32_t *tv_field;
2197230587Sken	uint8_t *data_payload;
2198230587Sken	int i;
2199230587Sken	const uint16_t ICMP_CSUM = 0xaed7;
2200230587Sken	const uint16_t IP_CSUM = 0xe533;
2201230587Sken
2202230587Sken	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2203230587Sken	/* Fill in an example ICMP ping request */
2204230587Sken	eh = mtod(mbufc, struct ether_header*);
2205230587Sken	xnb_fill_eh_and_ip(mbufc, 84, 28, IPPROTO_ICMP, 0, 0);
2206230587Sken	iph = (struct ip*)(eh + 1);
2207230587Sken	icmph = (struct icmp*)(iph + 1);
2208230587Sken	icmph->icmp_type = ICMP_ECHO;
2209230587Sken	icmph->icmp_code = 0;
2210230587Sken	icmph->icmp_cksum = htons(ICMP_CSUM);
2211230587Sken	icmph->icmp_id = htons(31492);
2212230587Sken	icmph->icmp_seq = htons(0);
2213230587Sken	/*
2214230587Sken	 * ping(1) uses bcopy to insert a native-endian timeval after icmp_seq.
2215230587Sken	 * For this test, we will set the bytes individually for portability.
2216230587Sken	 */
2217230587Sken	tv_field = (uint32_t*)(&(icmph->icmp_hun));
2218230587Sken	tv_field[0] = 0x4f02cfac;
2219230587Sken	tv_field[1] = 0x0007c46a;
2220230587Sken	/*
2221230587Sken	 * Remainder of packet is an incrmenting 8 bit integer, starting with 8
2222230587Sken	 */
2223230587Sken	data_payload = (uint8_t*)(&tv_field[2]);
2224230587Sken	for (i = 8; i < 37; i++) {
2225230587Sken		*data_payload++ = i;
2226230587Sken	}
2227230587Sken
2228230587Sken	/* fill in the length field */
2229230587Sken	mbufc->m_len = pkt_len;
2230230587Sken	mbufc->m_pkthdr.len = pkt_len;
2231230587Sken	/* indicate that the netfront uses hw-assisted checksums */
2232230587Sken	mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
2233230587Sken				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2234230587Sken
2235230587Sken	bcopy(mtod(mbufc, const void*), pkt_orig, icmp_len);
2236230587Sken	/* Function under test */
2237230587Sken	xnb_add_mbuf_cksum(mbufc);
2238230587Sken
2239230587Sken	/* Check the IP checksum */
2240230587Sken	XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2241230587Sken
2242230587Sken	/* Check that the ICMP packet did not change */
2243230587Sken	XNB_ASSERT(bcmp(icmph, pkt_orig, icmp_len));
2244230587Sken	m_freem(mbufc);
2245230587Sken}
2246230587Sken
2247230587Sken/**
2248230587Sken * xnb_add_mbuf_cksum on a UDP packet, based on a tcpdump of an actual
2249230587Sken * UDP packet
2250230587Sken */
2251230587Skenstatic void
2252230587Skenxnb_add_mbuf_cksum_udp(char *buffer, size_t buflen)
2253230587Sken{
2254230587Sken	const size_t udp_len = 16;
2255230587Sken	const size_t pkt_len = sizeof(struct ether_header) +
2256230587Sken		sizeof(struct ip) + udp_len;
2257230587Sken	struct mbuf *mbufc;
2258230587Sken	struct ether_header *eh;
2259230587Sken	struct ip *iph;
2260230587Sken	struct udphdr *udp;
2261230587Sken	uint8_t *data_payload;
2262230587Sken	const uint16_t IP_CSUM = 0xe56b;
2263230587Sken	const uint16_t UDP_CSUM = 0xdde2;
2264230587Sken
2265230587Sken	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2266230587Sken	/* Fill in an example UDP packet made by 'uname | nc -u <host> 2222 */
2267230587Sken	eh = mtod(mbufc, struct ether_header*);
2268230587Sken	xnb_fill_eh_and_ip(mbufc, 36, 4, IPPROTO_UDP, 0, 0xbaad);
2269230587Sken	iph = (struct ip*)(eh + 1);
2270230587Sken	udp = (struct udphdr*)(iph + 1);
2271230587Sken	udp->uh_sport = htons(0x51ae);
2272230587Sken	udp->uh_dport = htons(0x08ae);
2273230587Sken	udp->uh_ulen = htons(udp_len);
2274230587Sken	udp->uh_sum = htons(0xbaad);  /* xnb_add_mbuf_cksum will fill this in */
2275230587Sken	data_payload = (uint8_t*)(udp + 1);
2276230587Sken	data_payload[0] = 'F';
2277230587Sken	data_payload[1] = 'r';
2278230587Sken	data_payload[2] = 'e';
2279230587Sken	data_payload[3] = 'e';
2280230587Sken	data_payload[4] = 'B';
2281230587Sken	data_payload[5] = 'S';
2282230587Sken	data_payload[6] = 'D';
2283230587Sken	data_payload[7] = '\n';
2284230587Sken
2285230587Sken	/* fill in the length field */
2286230587Sken	mbufc->m_len = pkt_len;
2287230587Sken	mbufc->m_pkthdr.len = pkt_len;
2288230587Sken	/* indicate that the netfront uses hw-assisted checksums */
2289230587Sken	mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
2290230587Sken				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2291230587Sken
2292230587Sken	/* Function under test */
2293230587Sken	xnb_add_mbuf_cksum(mbufc);
2294230587Sken
2295230587Sken	/* Check the checksums */
2296230587Sken	XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2297230587Sken	XNB_ASSERT(udp->uh_sum == htons(UDP_CSUM));
2298230587Sken
2299230587Sken	m_freem(mbufc);
2300230587Sken}
2301230587Sken
2302230587Sken/**
2303230587Sken * Helper function that populates a TCP packet used by all of the
2304230587Sken * xnb_add_mbuf_cksum tcp unit tests.  m must already be allocated and must be
2305230587Sken * large enough
2306230587Sken */
2307230587Skenstatic void
2308230587Skenxnb_fill_tcp(struct mbuf *m)
2309230587Sken{
2310230587Sken	struct ether_header *eh;
2311230587Sken	struct ip *iph;
2312230587Sken	struct tcphdr *tcp;
2313230587Sken	uint32_t *options;
2314230587Sken	uint8_t *data_payload;
2315230587Sken
2316230587Sken	/* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
2317230587Sken	eh = mtod(m, struct ether_header*);
2318230587Sken	xnb_fill_eh_and_ip(m, 60, 8, IPPROTO_TCP, IP_DF, 0);
2319230587Sken	iph = (struct ip*)(eh + 1);
2320230587Sken	tcp = (struct tcphdr*)(iph + 1);
2321230587Sken	tcp->th_sport = htons(0x9cd9);
2322230587Sken	tcp->th_dport = htons(2222);
2323230587Sken	tcp->th_seq = htonl(0x00f72b10);
2324230587Sken	tcp->th_ack = htonl(0x7f37ba6c);
2325230587Sken	tcp->th_x2 = 0;
2326230587Sken	tcp->th_off = 8;
2327230587Sken	tcp->th_flags = 0x18;
2328230587Sken	tcp->th_win = htons(0x410);
2329230587Sken	/* th_sum is incorrect; will be inserted by function under test */
2330230587Sken	tcp->th_sum = htons(0xbaad);
2331230587Sken	tcp->th_urp = htons(0);
2332230587Sken	/*
2333230587Sken	 * The following 12 bytes of options encode:
2334230587Sken	 * [nop, nop, TS val 33247 ecr 3457687679]
2335230587Sken	 */
2336230587Sken	options = (uint32_t*)(tcp + 1);
2337230587Sken	options[0] = htonl(0x0101080a);
2338230587Sken	options[1] = htonl(0x000081df);
2339230587Sken	options[2] = htonl(0xce18207f);
2340230587Sken	data_payload = (uint8_t*)(&options[3]);
2341230587Sken	data_payload[0] = 'F';
2342230587Sken	data_payload[1] = 'r';
2343230587Sken	data_payload[2] = 'e';
2344230587Sken	data_payload[3] = 'e';
2345230587Sken	data_payload[4] = 'B';
2346230587Sken	data_payload[5] = 'S';
2347230587Sken	data_payload[6] = 'D';
2348230587Sken	data_payload[7] = '\n';
2349230587Sken}
2350230587Sken
2351230587Sken/**
2352230587Sken * xnb_add_mbuf_cksum on a TCP packet, based on a tcpdump of an actual TCP
2353230587Sken * packet
2354230587Sken */
2355230587Skenstatic void
2356230587Skenxnb_add_mbuf_cksum_tcp(char *buffer, size_t buflen)
2357230587Sken{
2358230587Sken	const size_t payload_len = 8;
2359230587Sken	const size_t tcp_options_len = 12;
2360230587Sken	const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
2361230587Sken	    sizeof(struct tcphdr) + tcp_options_len + payload_len;
2362230587Sken	struct mbuf *mbufc;
2363230587Sken	struct ether_header *eh;
2364230587Sken	struct ip *iph;
2365230587Sken	struct tcphdr *tcp;
2366230587Sken	const uint16_t IP_CSUM = 0xa55a;
2367230587Sken	const uint16_t TCP_CSUM = 0x2f64;
2368230587Sken
2369230587Sken	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2370230587Sken	/* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
2371230587Sken	xnb_fill_tcp(mbufc);
2372230587Sken	eh = mtod(mbufc, struct ether_header*);
2373230587Sken	iph = (struct ip*)(eh + 1);
2374230587Sken	tcp = (struct tcphdr*)(iph + 1);
2375230587Sken
2376230587Sken	/* fill in the length field */
2377230587Sken	mbufc->m_len = pkt_len;
2378230587Sken	mbufc->m_pkthdr.len = pkt_len;
2379230587Sken	/* indicate that the netfront uses hw-assisted checksums */
2380230587Sken	mbufc->m_pkthdr.csum_flags = CSUM_IP_CHECKED | CSUM_IP_VALID   |
2381230587Sken				CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
2382230587Sken
2383230587Sken	/* Function under test */
2384230587Sken	xnb_add_mbuf_cksum(mbufc);
2385230587Sken
2386230587Sken	/* Check the checksums */
2387230587Sken	XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2388230587Sken	XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
2389230587Sken
2390230587Sken	m_freem(mbufc);
2391230587Sken}
2392230587Sken
2393230587Sken/**
2394230587Sken * xnb_add_mbuf_cksum on a TCP packet that does not use HW assisted checksums
2395230587Sken */
2396230587Skenstatic void
2397230587Skenxnb_add_mbuf_cksum_tcp_swcksum(char *buffer, size_t buflen)
2398230587Sken{
2399230587Sken	const size_t payload_len = 8;
2400230587Sken	const size_t tcp_options_len = 12;
2401230587Sken	const size_t pkt_len = sizeof(struct ether_header) + sizeof(struct ip) +
2402230587Sken	    sizeof(struct tcphdr) + tcp_options_len + payload_len;
2403230587Sken	struct mbuf *mbufc;
2404230587Sken	struct ether_header *eh;
2405230587Sken	struct ip *iph;
2406230587Sken	struct tcphdr *tcp;
2407230587Sken	/* Use deliberately bad checksums, and verify that they don't get */
2408230587Sken	/* corrected by xnb_add_mbuf_cksum */
2409230587Sken	const uint16_t IP_CSUM = 0xdead;
2410230587Sken	const uint16_t TCP_CSUM = 0xbeef;
2411230587Sken
2412230587Sken	mbufc = m_getm(NULL, pkt_len, M_WAITOK, MT_DATA);
2413230587Sken	/* Fill in an example TCP packet made by 'uname | nc <host> 2222' */
2414230587Sken	xnb_fill_tcp(mbufc);
2415230587Sken	eh = mtod(mbufc, struct ether_header*);
2416230587Sken	iph = (struct ip*)(eh + 1);
2417230587Sken	iph->ip_sum = htons(IP_CSUM);
2418230587Sken	tcp = (struct tcphdr*)(iph + 1);
2419230587Sken	tcp->th_sum = htons(TCP_CSUM);
2420230587Sken
2421230587Sken	/* fill in the length field */
2422230587Sken	mbufc->m_len = pkt_len;
2423230587Sken	mbufc->m_pkthdr.len = pkt_len;
2424230587Sken	/* indicate that the netfront does not use hw-assisted checksums */
2425230587Sken	mbufc->m_pkthdr.csum_flags = 0;
2426230587Sken
2427230587Sken	/* Function under test */
2428230587Sken	xnb_add_mbuf_cksum(mbufc);
2429230587Sken
2430230587Sken	/* Check that the checksums didn't change */
2431230587Sken	XNB_ASSERT(iph->ip_sum == htons(IP_CSUM));
2432230587Sken	XNB_ASSERT(tcp->th_sum == htons(TCP_CSUM));
2433230587Sken
2434230587Sken	m_freem(mbufc);
2435230587Sken}
2436257515Sglebius#endif /* INET || INET6 */
2437230587Sken
2438230587Sken/**
2439230587Sken * sscanf on unsigned chars
2440230587Sken */
2441230587Skenstatic void
2442230587Skenxnb_sscanf_hhu(char *buffer, size_t buflen)
2443230587Sken{
2444230587Sken	const char mystr[] = "137";
2445230587Sken	uint8_t dest[12];
2446230587Sken	int i;
2447230587Sken
2448230587Sken	for (i = 0; i < 12; i++)
2449230587Sken		dest[i] = 'X';
2450230587Sken
2451316362Sasomers	XNB_ASSERT(sscanf(mystr, "%hhu", &dest[4]) == 1);
2452230587Sken	for (i = 0; i < 12; i++)
2453230587Sken		XNB_ASSERT(dest[i] == (i == 4 ? 137 : 'X'));
2454230587Sken}
2455230587Sken
2456230587Sken/**
2457230587Sken * sscanf on signed chars
2458230587Sken */
2459230587Skenstatic void
2460230587Skenxnb_sscanf_hhd(char *buffer, size_t buflen)
2461230587Sken{
2462230587Sken	const char mystr[] = "-27";
2463230587Sken	int8_t dest[12];
2464230587Sken	int i;
2465230587Sken
2466230587Sken	for (i = 0; i < 12; i++)
2467230587Sken		dest[i] = 'X';
2468230587Sken
2469316362Sasomers	XNB_ASSERT(sscanf(mystr, "%hhd", &dest[4]) == 1);
2470230587Sken	for (i = 0; i < 12; i++)
2471230587Sken		XNB_ASSERT(dest[i] == (i == 4 ? -27 : 'X'));
2472230587Sken}
2473230587Sken
2474230587Sken/**
2475230587Sken * sscanf on signed long longs
2476230587Sken */
2477230587Skenstatic void
2478230587Skenxnb_sscanf_lld(char *buffer, size_t buflen)
2479230587Sken{
2480230587Sken	const char mystr[] = "-123456789012345";	/* about -2**47 */
2481230587Sken	long long dest[3];
2482230587Sken	int i;
2483230587Sken
2484230587Sken	for (i = 0; i < 3; i++)
2485230587Sken		dest[i] = (long long)0xdeadbeefdeadbeef;
2486230587Sken
2487316362Sasomers	XNB_ASSERT(sscanf(mystr, "%lld", &dest[1]) == 1);
2488230587Sken	for (i = 0; i < 3; i++)
2489230587Sken		XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
2490230587Sken		    -123456789012345));
2491230587Sken}
2492230587Sken
2493230587Sken/**
2494230587Sken * sscanf on unsigned long longs
2495230587Sken */
2496230587Skenstatic void
2497230587Skenxnb_sscanf_llu(char *buffer, size_t buflen)
2498230587Sken{
2499230587Sken	const char mystr[] = "12802747070103273189";
2500230587Sken	unsigned long long dest[3];
2501230587Sken	int i;
2502230587Sken
2503230587Sken	for (i = 0; i < 3; i++)
2504230587Sken		dest[i] = (long long)0xdeadbeefdeadbeef;
2505230587Sken
2506316362Sasomers	XNB_ASSERT(sscanf(mystr, "%llu", &dest[1]) == 1);
2507230587Sken	for (i = 0; i < 3; i++)
2508230587Sken		XNB_ASSERT(dest[i] == (i != 1 ? (long long)0xdeadbeefdeadbeef :
2509230587Sken		    12802747070103273189ull));
2510230587Sken}
2511230587Sken
2512230587Sken/**
2513230587Sken * sscanf on unsigned short short n's
2514230587Sken */
2515230587Skenstatic void
2516230587Skenxnb_sscanf_hhn(char *buffer, size_t buflen)
2517230587Sken{
2518230587Sken	const char mystr[] =
2519230587Sken	    "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
2520230587Sken	    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
2521230587Sken	    "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f";
2522230587Sken	unsigned char dest[12];
2523230587Sken	int i;
2524230587Sken
2525230587Sken	for (i = 0; i < 12; i++)
2526230587Sken		dest[i] = (unsigned char)'X';
2527230587Sken
2528316362Sasomers	XNB_ASSERT(sscanf(mystr,
2529230587Sken	    "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
2530230587Sken	    "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
2531316362Sasomers	    "404142434445464748494a4b4c4d4e4f%hhn", &dest[4]) == 0);
2532230587Sken	for (i = 0; i < 12; i++)
2533230587Sken		XNB_ASSERT(dest[i] == (i == 4 ? 160 : 'X'));
2534230587Sken}
2535