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