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