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