summaryrefslogtreecommitdiffstats
path: root/contrib/netbsd-tests/net
diff options
context:
space:
mode:
authorngie <ngie@FreeBSD.org>2014-12-31 20:13:31 +0000
committerngie <ngie@FreeBSD.org>2014-12-31 20:13:31 +0000
commitb429a2bfd1380c777b9d59e54e17886b3855073e (patch)
treef5eb9fb5c3b79a2f3a7cba500581d24f4676622d /contrib/netbsd-tests/net
parent155ee9c2f7fcb97a502844e0ca346b9f919b8cb2 (diff)
downloadFreeBSD-src-b429a2bfd1380c777b9d59e54e17886b3855073e.zip
FreeBSD-src-b429a2bfd1380c777b9d59e54e17886b3855073e.tar.gz
MFC r272343,r272458,r272890,r272891,r272901,r272902,r272903,r272905,r272908,r272909,r272910,r272914,r272915,r272979,r272980,r273010,r273011,r273012,r273015,r273017,r273019,r273020,r273021,r273022,r273023,r273024,r273025,r273389,r273390,r273391,r273393,r273395,r273396,r273397,r273410,r273516,r273517,r273520,r273521,r273522,r273523,r273524,r273525,r273526,r273527,r273528,r273529,r273530,r273533,r273534,r273535,r273536,r273537,r273538,r273539,r273540,r273572,r273574,r273578,r273579,r273591,r273592,r273928,r273933,r273935,r273936,r273937,r273938,r273942,r273943,r273945,r273946,r273947,r273948,r273949,r273950,r273951,r273952,r274061,r274062,r274066,r274067,r274072,r274074,r274079,r274090,r274142,r274143,r274571,r274572,r274573,r274574,r274575,r274576,r274577,r274579,r274597,r274598,r274599,r274600,r274601,r274626,r275033,r276046,r276430:
r272343: r272458: Import the NetBSD test suite from ^/vendor/NetBSD/tests/09.30.2014_20.45 , minus the vendor Makefiles Provide directions for how to bootstrap the vendor sources in FREEBSD-upgrade MFC after 2 weeks Discussed with: rpaulo Sponsored by: EMC / Isilon Storage Division r272890: Only build/run hsearch_basic and hsearch_r_basic on NetBSD hdestroy1 is not present on FreeBSD Sponsored by: EMC / Isilon Storage Division r272891: Expect SIGSEGV in lib/libc/stdlib/t_getenv:setenv_basic See bin/189805 for more details In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r272901: Disable tests that don't pass on FreeBSD due to missing support in humanize_number(3). Bringing in additional revisions from NetBSD's humanize_number(3) will fix the tests Account for the fact that util.h on NetBSD is libutil.h on FreeBSD Submitted by: pho Sponsored by: EMC / Isilon Storage Division r272902: Add missing #include <sys/time.h> for gettimeofday Sponsored by: EMC / Isilon Storage Division r272903: FreeBSD returns ENOTTY instead of EBADF in ttyname_r; mark it as an expected failure PR: 191936 In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r272905: FreeBSD doesn't support strings greater than MAXHOSTNAMELEN-1 in {get,set}{domain,host}name. Adjust the tests to not exceed that value when testing out the code Add a positive and negative test for MAXHOSTNAMELEN-1 and MAXHOSTNAMELEN, respectively PR: 181127 In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r272908: Disable the invalid pointer test on FreeBSD FreeBSD segfaults on invalid pointers passed to getcwd because it throbs the address passed in in libc, whereas NetBSD just passes the information off to the syscall, which allows the kernel to return EFAULT on bad pointers. In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r272909: Handle getting/setting niceness/priority correctly on FreeBSD vs NetBSD This might be fallout from PR: 189821 Submitted by: pho Sponsored by: EMC / Isilon Storage Division r272910: SIGPWR does not exist on FreeBSD Sponsored by: EMC / Isilon Storage Division r272914: Skip over t_spawn_open_nonexistent_diag because it requires NetBSD specific additions to posix_spawn Sponsored by: EMC / Isilon Storage Division r272915: Port the testcase to FreeBSD - Make #include path to h_macros.h a non-relative path - __gl_stat_t is synonymous with struct stat on FreeBSD - FreeBSD doesn't have _DIRENT_RECLEN - Skip over glob_star on FreeBSD (testcase doesn't pass) In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r272979: Only #include <sys/tls.h> on NetBSD Sponsored by: EMC / Isilon Storage Division r272980: #include libutil.h for fparseln on FreeBSD Sponsored by: EMC / Isilon Storage Division r273010: Implement 64MB memory limit for test to ensure that it fails reliably in 600 seconds; it would previously fail inconsistently when run in some virtual machine configurations This patch might need to be reverted or revisited later (see the attached PR for more details) PR: 169302 Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273011: Fix compilation errors with missing wide-type headers and fix compilation warnings with -Wformat In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r273012: - Add libutil #include for fparseln - Change ATF_REQUIRE_EQ_MSG to ATF_CHECK_EQ_MSG to gather all failing results possible (currently 12 with leftassoc) - Mark leftassoc "atf_tc_expect_fail" on FreeBSD (PR coming soon after further analysis is done on the code) In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r273015: Expect nice_err to fail on FreeBSD with unprivileged users PR: 189821 Sponsored by: EMC / Isilon Storage Division r273017: Add #include <stdio.h> for printf Sponsored by: EMC / Isilon Storage Division r273019: Do initial port of contrib/netbsd-tests/lib/libc/locale t_io: - Expect failures potentially related to implementation-specific knowledge of the zh_TW.Big5 locale [*] t_mbrtowc: - Handle unknown locales more gracefully (do not test if the locale doesn't exist) - Expect failure with mbrtowc_internal dealing with Japanese locales (potentially related to implementation detail knowledge of the ja_* locales) [*]. t_mbstowcs, t_mbtowc, t_wctomb: - Handle unknown locales more gracefully (do not test if the locale doesn't exist) t_wcstod: - Treat FreeBSD like NetBSD and Linux in the XXX: FIXME section [*] More investigation is required to determine the root cause of the failures Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273020: memmem with NUL length "needle" (aka small) strings on FreeBSD/OSX returns NULL instead of the "haystack" value (aka big) Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273021: Use 1 as a random seed, as recommended in srandom(3). Adjust the random values accordingly Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273022: Add #include <stdio.h> to get sys_nerr definition Sponsored by: EMC / Isilon Storage Division r273023: __isnanl is automatically picked according to data type in <math.h>. There isn't a need for the explicit __isnanl test Sponsored by: EMC / Isilon Storage Division r273024: Only test the return value in mktime_negyear Testing for the errno is an optional requirement according to POSIX, and FreeBSD doesn't document that errno would be set on failure with mktime Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273025: Change ATF_REQUIRE_MSG calls to ATF_CHECK_MSG to get as many errors as possible t_strptime:common.. - Expect the testcase body as a whole to fail. Multiple PRs will be filed to track the issues (there are 18 check failures) t_strptime:day.. - %EA and %OA seem to be case insensitive on FreeBSD r273389: Port lib/libc/gen/t_siginfo to FreeBSD - mcontext_t on FreeBSD doesn't have a __gregs field (it's split out on FreeBSD into separate fields). In order to avoid muddying the test code with MD code, the debugging trace info has not been implemented - FreeBSD does not implement the si_stime and si_utime fields in siginfo_t, so omit the debugging code that dumps the values - sys/inttypes.h doesn't exist on FreeBSD Sponsored by: EMC / Isilon Storage Division r273390: libutil.h is required for fparseln on FreeBSD Sponsored by: EMC / Isilon Storage Division r273391: Add missing #include for sys/stat.h for fchmod Sponsored by: EMC / Isilon Storage Division r273393: Port t_write to FreeBSD - Mark the signo variable for the signal handle __unused - Use limits.h instead of sys/syslimits.h (the latter does not exist on FreeBSD) Sponsored by: EMC / Isilon Storage Division r273395: Mark osi __unused so this compiles cleanly on FreeBSD Sponsored by: EMC / Isilon Storage Division r273396: unlink("/") fails with EISDIR instead of EBUSY on FreeBSD; test for that instead Sponsored by: EMC / Isilon Storage Division r273397: Port t_chroot to FreeBSD - Add missing #include sys/stat.h for mkdir(2) - Omit the fchroot(2) tests because the support is not present on FreeBSD Sponsored by: EMC / Isilon Storage Division r273410: Add sys/socket.h #include for bind(2), et al Sponsored by: EMC / Isilon Storage Division r273516: Add netinet/in.h for struct sockaddr_in Sponsored by: EMC / Isilon Storage Division r273517: Expect getgroups_err to fail on FreeBSD PR: 189941 Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273520: Port t_pipe2.c to FreeBSD - Omit the pipe2_nosigpipe testcase on FreeBSD (FreeBSD doesn't have O_NOSIGPIPE). - Convert "fcntl(n, F_CLOSEM)" to "closefrom(n)". - Save and restore the resource limit on the number of files (RLIMIT_NOFILE). In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r273521: Convert "fcntl(n, F_CLOSEM)" to "closefrom(n)" Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273522: - Mark unused parameters __unused in handler - Call sigqueue with getpid() instead of 0 -- the latter idiom appears to only be valid on NetBSD In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r273523: Add limits.h #include for LINE_MAX Sponsored by: EMC / Isilon Storage Division r273524: Add sys/socket.h #include for struct sockaddr_in Sponsored by: EMC / Isilon Storage Division r273525: Port t_mmap.c to FreeBSD - Add needed headers for the testcases - Omit mmap_block on non-NetBSD OSes - Use "security.bsd.map_at_zero" instead of "vm.user_va0_disable" Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273526: Omit the pollts testcases on FreeBSD Sponsored by: EMC / Isilon Storage Division r273527: Omit all of the testcases as revoke(2) is only implemented on devfs(5) Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273528: Mark signo __unused in handler(..) Sponsored by: EMC / Isilon Storage Division r273529: - Omit the poll testcases on FreeBSD (they require pollts) - Add necessary headers for the testcases Sponsored by: EMC / Isilon Storage Division r273530: Add limits.h #include for INT_MAX Sponsored by: EMC / Isilon Storage Division r273533: Use <atf_srcdir>/truncate_test.root_owned instead of /usr/bin/fpr as fpr does not exist on FreeBSD truncate_test.root_owned will be generated at build time and owned by root In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r273534: - Mark sig/signo __unused - Do not provide a relative path via #include "h_macros.h" Sponsored by: EMC / Isilon Storage Division r273535: - Omit setrlimit_nthr testcase on FreeBSD (requires lwp.h, et al) - Expect overflow with rlim_max at INT64_MAX, not UINT64_MAX (rlim_t is int64_t on FreeBSD) In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r273536: Add limits.h #include for SSIZE_MAX Sponsored by: EMC / Isilon Storage Division r273537: Add limits.h #include for SSIZE_MAX Sponsored by: EMC / Isilon Storage Division r273538: Fix a typo (__FreeBSD__ -> __NetBSD__ when omitting setrlimit_nthr) r273539: Mark signum __unused Sponsored by: EMC / Isilon Storage Division r273540: Omit the mprotect_exec testcase on FreeBSD Sponsored by: EMC / Isilon Storage Division r273572: - Ignore EINVAL check with mknod(path, S_IFCHR, -1) as the testcase is always executed on a non-devfs filesystem - Expect mknod(path, S_IFREG, 0) to fail on FreeBSD Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273574: - Test for EINVAL requirement when passing an invalid flag in to msync(2) - Expect ENOMEM instead of EFAULT when msync'ing a previously munmap'ed region on FreeBSD Submitted by: pho Sponsored by: EMC / Isilon Storage Division r273578: - Add inttypes.h and stdint.h in lieu of int_limits.h from NetBSD - Use #include "h_macros.h" instead of relative path analog Sponsored by: EMC / Isilon Storage Division r273579: - Mark signo __unused in the signal handler function - Effectively #if 0 out some code that does not fail on FreeBSD In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r273591: Correct my previous commit: - getrusage_utime_back succeeds reliably on FreeBSD - getrusage_utime_zero passes/fails in a seemingly non-deterministic manner. Skip it for now (and fix it later) In the initial port of this testcase to FreeBSD, the results failed reliably in the same manner as it does on NetBSD Sponsored by: EMC / Isilon Storage Division r273592: - Add sys/types.h for the APIs in sys/sysctl.h - Poke at VM_MIN_ADDRESS in machine/vmparam.h because FreeBSD doesn't have a vm.minaddress sysctl analog - Expect ENOMEM instead of EAGAIN in mlock_limits - Provide mlock an mmap'ed page twice to simulate MAP_WIRED on NetBSD In collaboration with: pho Sponsored by: EMC / Isilon Storage Division r273928: Put mtree test files into a subdirectory. Kyua 0.11 points TMPDIR to the test's work directory, and atf_check creates auxiliary files in TMPDIR. This confuses a couple of mtree tests that were using the work directory's root to validate the contents of the directory. Fix the two affected tests by creating an auxiliary directory to use for the mtree tests. (Kyua should probably do this on its own; filed bug #133 upstream to take a look at this.) r273933: Don't prune duplicate services in the expected output from /etc/services on FreeBSD Submitted by: pho r273935: Port tests to FreeBSD/Linux Some of the testcases don't work outside of NetBSD, and the behavior of ether_aton_r differs between FreeBSD, Linux, and NetBSD, and the calls to the API need to be massaged for FreeBSD and Linux. Submitted by: pho r273936: Port lib/libc/net/h_dns_server to FreeBSD Submitted by: pho r273937: Port lib/libc/sys/t_dup to FreeBSD/Linux - The requirements differ between FreeBSD/Linux when dealing with oldd/newd being equal (both fail with EINVAL, not EBADF) - Add an EBADF testcase - Fix compilation issues on clang In collaboration with: pho r273938: getitimer on FreeBSD returns the last set time instead of the remaining time; test for that instead Submitted by: pho r273942: Skip :sethostname_basic because it messes up the test host's hostname Convert code from #if defined(__FreeBSD__) to #ifdef __FreeBSD__ r273943: Port t_kevent to FreeBSD Submitted by: pho r273945: Port t_mincore to FreeBSD Mark :mincore_resid as atf_tc_expect_fail on FreeBSD because of new bug discovered in running the tests (it succeeded from earlier on in the year to September/October on FreeBSD, at least) Submitted by: pho r273946: Port h_atexit to FreeBSD __cxa_atexit varies between FreeBSD and NetBSD, and thus we must use pointers instead of static fields in the BSS. More extensive discussion is included in the source code In collaboration with: kib Submitted by: pho r273947: Expect :snprintf_posarg_error to blow up with a SIGSEGV on !NetBSD OSes r273948: Disable testcases 12 and 15-22 on FreeBSD Submitted by: pho r273949: Add new atf_tc_expect_fail to fflush_err; this is a new (within the past couple months) bug r273950: Skip :fopen_regular on !NetBSD because it's a NetBSD specific test Submitted by: pho r273951: Expect :sscanf_whitespace to fail on !NetBSD OSes Submitted by: pho r273952: Port h_hash and t_sha2 to FreeBSD t_sha2 contains dirty copy-paste hacks that need to be fixed with the openssh OpenBSD compat layer Submitted by: pho r274061: Port t_db.sh to FreeBSD - The blocksize on FreeBSD is 32kB, not 64kB - Add some detection for MK_DICT == no; /nonexistent is echoed along with atf_skip to ensure that the test will fail if dict(..) is called in the non-final stage of the pipeline Submitted by: pho r274062: inet_network on FreeBSD returns NULL when provided "0x" to inet_network Submitted by: pho r274066: Port lib/libc/ssp to FreeBSD In most cases, the buffers and data were resized, but when dealing with the helpers, some of the code was adjusted to fail more reliably Submitted by: pho r274067: rpc_control on FreeBSD is a public-ish API (not prefixed with __), not private like NetBSD Submitted by: pho r274072: Finish off lib/libc/stdlib/t_strtod.c port by checking for "y" twice on FreeBSD, and always assume long long double exists on FreeBSD Submitted by: pho r274074: Add Makefile snippet to ease porting NetBSD testcases to FreeBSD from contrib/netbsd-tests This Makefile snippet handles polluting testcases with -lnetbsd, specific headers for ATF version differences, and does necessary rewriting for the testcases to match the format discussed on the TestSuite wiki page (t_<foo> -> <foo>_test) One must define SRCTOP (inspired by projects/bmake), OBJTOP, and TESTSRC (e.g. contrib/netbsd-tests/lib/libc/gen) to use the Makefile snippet Test programs are specific either via NETBSD_ATF_TESTS_C or NETBSD_ATF_TESTS_SH C++ analogs aren't currently implemented. The imported testcases will be cleaned up to use this Makefile snippet pseudo "API". r274079: Import proper fix for misc/49356 (/usr/include/atf-c/config.h) after atf-c/config.h was removed from the build Pointyhat to: me (again, for not running make delete-old after running test builds) r274090: Fix the Jenkins test run by skipping the negative testcases earlier The problem is that lib.libc.locale.t_io:bad_big5_wprintf was printing out illegal Unicode characters, which causes XML parsers to bail immediately, e.g. % kyua report-junit > ~/report.junit % python2 -c 'import xml.dom.minidom as md; md.parse("/home/ngie/report.junit")' Traceback (most recent call last): File "<string>", line 1, in <module> File "/usr/local/lib/python2.7/xml/dom/minidom.py", line 1918, in parse return expatbuilder.parse(file) File "/usr/local/lib/python2.7/xml/dom/expatbuilder.py", line 924, in parse result = builder.parseFile(fp) File "/usr/local/lib/python2.7/xml/dom/expatbuilder.py", line 207, in parseFile parser.Parse(buffer, 0) xml.parsers.expat.ExpatError: not well-formed (invalid token): line 27137, column 13 r274142: Remove expected failure from lib.libc.sys.t_mincore:mincore_resid The failure was added based on observation seen on 11.0-CURRENT @ r273153, not based on internal testing at EMC/Isilon PR: 194829 Tested with the following configuration: - amd64/i386 - 11.0-CURRENT @ r273153 - 100 times in a tight loop as root with the following commands... -- kyua test lib/libc -- kyua test lib/libc/sys -- kyua test lib/libc/sys/mincore_test r274143: Expect lib.libc.sys.getcontext_test.setcontext_link to fail on amd64; add additional debugging to make the underlying problem more visible Calling setcontext(2) on amd64 as shown in the test program is failing on amd64, not i386, with a return code of -1 and an errno of EINVAL Further investigation is being done in the PR to determine the root cause for the failure PR: 194828 Tested with the following configuration: - amd64/i386 - 11.0-CURRENT @ r273153 - 100 times in a tight loop as root with the following commands... -- kyua test lib/libc -- kyua test lib/libc/sys -- kyua test lib/libc/sys/getcontext_test r274571: Use _exit instead of exit so the file descriptors aren't flushed twice in the child processes Submitted by: pho r274572: Only expect timeouts on powerpc with NetBSD Submitted by: pho r274573: Expect :pthread_detach to fail with EINVAL instead of ESRCH on FreeBSD PR: 191906 In collaboration with: pho r274574: Add pthread_np.h #include and initialize the pthread attribute on FreeBSD Submitted by: pho r274575: #ifdef out a printf on !NetBSD that causes the testcase to fail when comparing the output from the helper program Submitted by: pho r274576: Port helper program to FreeBSD, similar to ../../lib/libc/stdlib/h_atexit.c Submitted by: pho In collaboration with: kib r274577: Add missing sys/time.h #include for timespecsub macro in lib/libnetbsd/sys/time.h r274579: Call sem_unlink on semaphores before attempting to create them Due to the lack of uniqueness in the semaphore name, and the fact that the tests don't have cleanup routines, an interrupted test can leave a semaphore "laying around", causing all subsequent attempts to run the test to fail I will file a NetBSD PR for this issue soon r274597: Skip the long-double epsilon checks on FreeBSD/i386 Sponsored by: EMC / Isilon Storage Division r274598: Reset errno to 0 before running scalbn to be sure that the tested errno is valid Sponsored by: EMC / Isilon Storage Division r274599: Alias isinff to isinf on FreeBSD isinf on FreeBSD automatically picks the appropriate type per math.h Sponsored by: EMC / Isilon Storage Division r274600: - Expect exp2_powers to fail on FreeBSD/i386 - Expect exp2_values to fail on FreeBSD due to the small epsilon Sponsored by: EMC / Isilon Storage Division r274601: - Skip over the testcases that call cbrtl on platforms where LDBL_PREC == 53 (arm, mips, powerpc). This fixes the build on these platforms, based on some ad hoc tinderbox runs I did a while ago - Skip cast the arguments to powl as long double so powl properly interprets those arugments at compile-time when picking the type Sponsored by: EMC / Isilon Storage Division r274626: Mechanically replace #if defined(__FreeBSD__) and #if defined(__NetBSD__) with their #ifdef equivalents for everything changed in contrib/netbsd-tests. There are some items from the vendor tree that use #if defined(__FreeBSD__) or #if defined(__NetBSD__) which are being left alone Requested by: bde, rpaulo Sponsored by: EMC / Isilon Storage Division r275033: Only pass 6 arguments to the 'run' function on amd64. amd64's makecontext on FreeBSD only supports a maximum of 6 arguments. This fixes the setcontext_link test on amd64. PR: 194828 r276046: Add __FreeBSD_version guards around hsearch_r to ease MFCing the code to stable/10 It was added when __FreeBSD_version was ~1100027 r276430: Expect access_test:access_inval to fail before __FreeBSD_version == 1100033 This will allow me to MFC the test, as jilles@ requested that I don't MFC the access(2) KBI change to 10-STABLE in r271655
Diffstat (limited to 'contrib/netbsd-tests/net')
-rw-r--r--contrib/netbsd-tests/net/bpf/h_bpf.h171
-rw-r--r--contrib/netbsd-tests/net/bpf/t_bpf.c177
-rw-r--r--contrib/netbsd-tests/net/bpf/t_div-by-zero.c52
-rw-r--r--contrib/netbsd-tests/net/bpf/t_mbuf.c961
-rw-r--r--contrib/netbsd-tests/net/bpfilter/t_bpfilter.c400
-rw-r--r--contrib/netbsd-tests/net/bpfjit/t_bpfjit.c3979
-rw-r--r--contrib/netbsd-tests/net/bpfjit/t_cop.c757
-rw-r--r--contrib/netbsd-tests/net/bpfjit/t_extmem.c506
-rw-r--r--contrib/netbsd-tests/net/bpfjit/t_mbuf.c982
-rw-r--r--contrib/netbsd-tests/net/carp/t_basic.c221
-rw-r--r--contrib/netbsd-tests/net/config/netconfig.c231
-rw-r--r--contrib/netbsd-tests/net/fdpass/fdpass.c231
-rwxr-xr-xcontrib/netbsd-tests/net/fdpass/t_fdpass.sh99
-rw-r--r--contrib/netbsd-tests/net/icmp/t_forward.c169
-rw-r--r--contrib/netbsd-tests/net/icmp/t_ping.c438
-rwxr-xr-xcontrib/netbsd-tests/net/icmp/t_ping2.sh78
-rw-r--r--contrib/netbsd-tests/net/if/t_compat.c83
-rwxr-xr-xcontrib/netbsd-tests/net/if_bridge/t_bridge.sh312
-rw-r--r--contrib/netbsd-tests/net/if_loop/t_pr.c229
-rwxr-xr-xcontrib/netbsd-tests/net/mpls/t_ldp_regen.sh178
-rwxr-xr-xcontrib/netbsd-tests/net/mpls/t_mpls_fw.sh188
-rwxr-xr-xcontrib/netbsd-tests/net/mpls/t_rfc4182.sh165
-rw-r--r--contrib/netbsd-tests/net/net/t_pktinfo.c194
-rw-r--r--contrib/netbsd-tests/net/net/t_raw.c41
-rw-r--r--contrib/netbsd-tests/net/net/t_tcp.c220
-rw-r--r--contrib/netbsd-tests/net/net/t_udp.c110
-rw-r--r--contrib/netbsd-tests/net/net/t_unix.c328
-rwxr-xr-xcontrib/netbsd-tests/net/npf/t_npf.sh63
-rwxr-xr-xcontrib/netbsd-tests/net/route/t_change.sh65
-rw-r--r--contrib/netbsd-tests/net/sys/t_rfc6056.c152
30 files changed, 11780 insertions, 0 deletions
diff --git a/contrib/netbsd-tests/net/bpf/h_bpf.h b/contrib/netbsd-tests/net/bpf/h_bpf.h
new file mode 100644
index 0000000..307bc50
--- /dev/null
+++ b/contrib/netbsd-tests/net/bpf/h_bpf.h
@@ -0,0 +1,171 @@
+/* $NetBSD: h_bpf.h,v 1.2 2014/07/08 21:44:26 alnsn Exp $ */
+
+/*-
+ * Copyright (c) 2014 Alexander Nasonov.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _TESTS_NET_BPF_H_BPF_H_
+#define _TESTS_NET_BPF_H_BPF_H_
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include <net/bpf.h>
+#include <net/bpfjit.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include <stdint.h>
+#include <string.h>
+
+/* XXX These declarations don't look kosher. */
+int rumpns_bpf_validate(const struct bpf_insn *, int);
+unsigned int rumpns_bpf_filter_ext(const bpf_ctx_t *,
+ const struct bpf_insn *, bpf_args_t *);
+bpfjit_func_t rumpns_bpfjit_generate_code(const bpf_ctx_t *,
+ const struct bpf_insn *, size_t);
+void rumpns_bpfjit_free_code(bpfjit_func_t);
+
+/*
+ * Init mbuf chain with one or two chunks. The first chunk holds
+ * [pkt, pkt + split] bytes, the second chunk (if it's not empty)
+ * holds (pkt + split, pkt + pktsize) bytes.
+ * The function returns (const uint8_t *)mb1.
+ */
+static inline const uint8_t *
+init_mchain2(struct mbuf *mb1, struct mbuf *mb2,
+ unsigned char pkt[], size_t pktsize, size_t split)
+{
+
+ (void)memset(mb1, 0, sizeof(*mb1));
+ mb1->m_data = (char *)pkt;
+ mb1->m_next = (split < pktsize) ? mb2 : NULL;
+ mb1->m_len = (split < pktsize) ? split : pktsize;
+
+ if (split < pktsize) {
+ (void)memset(mb2, 0, sizeof(*mb2));
+ mb2->m_next = NULL;
+ mb2->m_data = (char *)&pkt[split];
+ mb2->m_len = pktsize - split;
+ }
+
+ return (const uint8_t*)mb1;
+}
+
+/*
+ * Compile and run a filter program.
+ */
+static inline unsigned int
+exec_prog(struct bpf_insn *insns, size_t insn_count,
+ unsigned char pkt[], size_t pktsize)
+{
+ bpfjit_func_t fn;
+ bpf_args_t args;
+ unsigned int res;
+
+ args.pkt = (const uint8_t *)pkt;
+ args.buflen = pktsize;
+ args.wirelen = pktsize;
+
+ rump_schedule();
+ fn = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+
+ res = fn(NULL, &args);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(fn);
+ rump_unschedule();
+
+ return res;
+}
+
+/*
+ * Interpret a filter program with mbuf chain passed to bpf_filter_ext().
+ */
+static inline unsigned int
+interp_prog_mchain2(struct bpf_insn *insns,
+ unsigned char pkt[], size_t pktsize, size_t split)
+{
+ uint32_t mem[BPF_MEMWORDS];
+ struct mbuf mb1, mb2;
+ bpf_args_t args;
+ unsigned int res;
+
+ args.pkt = init_mchain2(&mb1, &mb2, pkt, pktsize, split);
+ args.buflen = 0;
+ args.wirelen = pktsize;
+ args.mem = mem;
+
+ rump_schedule();
+ res = rumpns_bpf_filter_ext(NULL, insns, &args);
+ rump_unschedule();
+
+ return res;
+}
+
+/*
+ * Compile and run a filter program with mbuf chain passed to compiled function.
+ */
+static inline unsigned int
+exec_prog_mchain2(struct bpf_insn *insns, size_t insn_count,
+ unsigned char pkt[], size_t pktsize, size_t split)
+{
+ bpfjit_func_t fn;
+ struct mbuf mb1, mb2;
+ bpf_args_t args;
+ unsigned int res;
+
+ args.pkt = init_mchain2(&mb1, &mb2, pkt, pktsize, split);
+ args.buflen = 0;
+ args.wirelen = pktsize;
+
+ rump_schedule();
+ fn = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+
+ res = fn(NULL, &args);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(fn);
+ rump_unschedule();
+
+ return res;
+}
+
+static inline bool
+prog_validate(struct bpf_insn *insns, size_t insn_count)
+{
+ bool res;
+
+ rump_schedule();
+ res = rumpns_bpf_validate(insns, insn_count);
+ rump_unschedule();
+
+ return res;
+}
+
+#endif /* _TESTS_NET_BPF_H_BPF_H_ */
diff --git a/contrib/netbsd-tests/net/bpf/t_bpf.c b/contrib/netbsd-tests/net/bpf/t_bpf.c
new file mode 100644
index 0000000..95ca2fc
--- /dev/null
+++ b/contrib/netbsd-tests/net/bpf/t_bpf.c
@@ -0,0 +1,177 @@
+/* $NetBSD: t_bpf.c,v 1.5 2012/08/14 19:40:30 alnsn Exp $ */
+
+/*-
+ * Copyright (c) 2010 Antti Kantee. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_bpf.c,v 1.5 2012/08/14 19:40:30 alnsn Exp $");
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <net/bpf.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+/* XXX: atf-c.h has collisions with mbuf */
+#undef m_type
+#undef m_data
+#include <atf-c.h>
+
+#include "../../h_macros.h"
+#include "../config/netconfig.c"
+
+ATF_TC(bpfwriteleak);
+ATF_TC_HEAD(bpfwriteleak, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Checks that writing to /dev/bpf "
+ "does not leak mbufs");
+}
+
+static int
+getmtdata(void)
+{
+ struct mbstat mbstat;
+ size_t mbstatlen = sizeof(mbstat);
+ const int mbstat_mib[] = { CTL_KERN, KERN_MBUF, MBUF_STATS };
+
+ RL(rump_sys___sysctl(mbstat_mib, __arraycount(mbstat_mib),
+ &mbstat, &mbstatlen, NULL, 0));
+ return mbstat.m_mtypes[MT_DATA];
+}
+
+ATF_TC_BODY(bpfwriteleak, tc)
+{
+ char buf[28]; /* sizeof(garbage) > etherhdrlen */
+ struct ifreq ifr;
+ int ifnum, bpfd;
+
+ RZ(rump_init());
+ RZ(rump_pub_shmif_create(NULL, &ifnum));
+ sprintf(ifr.ifr_name, "shmif%d", ifnum);
+
+ RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
+ RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
+ RL(rump_sys_ioctl(bpfd, BIOCSFEEDBACK, &ifr));
+
+ if (getmtdata() != 0)
+ atf_tc_fail("test precondition failed: MT_DATA mbufs != 0");
+
+ ATF_REQUIRE_ERRNO(ENETDOWN, rump_sys_write(bpfd, buf, sizeof(buf))==-1);
+
+ ATF_REQUIRE_EQ(getmtdata(), 0);
+}
+
+#if (SIZE_MAX > UINT_MAX)
+ATF_TC(bpfwritetrunc);
+ATF_TC_HEAD(bpfwritetrunc, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Checks that write to /dev/bpf "
+ "does not truncate size_t to int");
+}
+
+ATF_TC_BODY(bpfwritetrunc, tc)
+{
+ int bpfd;
+ struct ifreq ifr;
+ struct iovec *iov;
+ size_t iovlen, sz;
+ const size_t extra_bytes = 28;
+ const size_t total = extra_bytes + UINT_MAX + 1;
+ long iov_max, vm_page_size; /* round_page wants vm_page_size variable */
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ iov_max = sysconf(_SC_IOV_MAX);
+ vm_page_size = sysconf(_SC_PAGE_SIZE);
+ ATF_REQUIRE(iov_max > 1 && vm_page_size > 1);
+
+ /*
+ * Minimize memory consumption by using many iovecs
+ * all pointing to one memory region.
+ */
+ iov = calloc(iov_max, sizeof(struct iovec));
+ ATF_REQUIRE(iov != NULL);
+
+ sz = round_page((total + (iov_max - 1)) / iov_max);
+
+ iov[0].iov_len = sz;
+ iov[0].iov_base = mmap(NULL, sz, PROT_READ, MAP_ANON, -1, 0);
+ ATF_REQUIRE(iov[0].iov_base != MAP_FAILED);
+
+ iovlen = 1;
+ while (sz + iov[0].iov_len <= total)
+ {
+ iov[iovlen].iov_len = iov[0].iov_len;
+ iov[iovlen].iov_base = iov[0].iov_base;
+ sz += iov[0].iov_len;
+ iovlen++;
+ }
+
+ if (sz < total)
+ {
+ iov[iovlen].iov_len = total - sz;
+ iov[iovlen].iov_base = iov[0].iov_base;
+ iovlen++;
+ }
+
+ /* Sanity checks */
+ ATF_REQUIRE(iovlen >= 1 && iovlen <= (size_t)iov_max);
+ ATF_REQUIRE_EQ(iov[iovlen-1].iov_len, total % iov[0].iov_len);
+
+ RZ(rump_init());
+ netcfg_rump_makeshmif("bpfwritetrunc", ifr.ifr_name);
+ netcfg_rump_if(ifr.ifr_name, "10.1.1.1", "255.0.0.0");
+
+ RL(bpfd = rump_sys_open("/dev/bpf", O_RDWR));
+ RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
+
+ ATF_CHECK_ERRNO(EMSGSIZE, rump_sys_writev(bpfd, iov, iovlen) == -1);
+
+ munmap(iov[0].iov_base, iov[0].iov_len);
+ free(iov);
+}
+#endif /* #if (SIZE_MAX > UINT_MAX) */
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, bpfwriteleak);
+#if (SIZE_MAX > UINT_MAX)
+ ATF_TP_ADD_TC(tp, bpfwritetrunc);
+#endif
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/bpf/t_div-by-zero.c b/contrib/netbsd-tests/net/bpf/t_div-by-zero.c
new file mode 100644
index 0000000..542d08a
--- /dev/null
+++ b/contrib/netbsd-tests/net/bpf/t_div-by-zero.c
@@ -0,0 +1,52 @@
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <net/bpf.h>
+
+#include <atf-c.h>
+#include <fcntl.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+ATF_TC(div_by_zero);
+ATF_TC_HEAD(div_by_zero, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF rejects a filter "
+ "which divides by 0");
+}
+
+ATF_TC_BODY(div_by_zero, tc)
+{
+ struct bpf_program bp;
+ int fd;
+
+ /*
+ * Source code for following program:
+ * link[0:4]/0 = 2
+ */
+ struct bpf_insn bins[] = {
+ { 0x20, 0, 0, 0x00000000 },
+ { 0x34, 0, 0, 0x00000000 },
+ { 0x15, 0, 1, 0x00000002 },
+ { 0x6, 0, 0, 0x00000060 },
+ { 0x6, 0, 0, 0x00000000 },
+ };
+
+ bp.bf_len = __arraycount(bins);
+ bp.bf_insns = bins;
+
+ rump_init();
+ fd = rump_sys_open("/dev/bpf", O_RDWR);
+ ATF_CHECK(fd != -1);
+ ATF_REQUIRE_EQ_MSG(rump_sys_ioctl(fd, BIOCSETF, &bp), -1,
+ "bpf accepted program with division by zero");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, div_by_zero);
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/bpf/t_mbuf.c b/contrib/netbsd-tests/net/bpf/t_mbuf.c
new file mode 100644
index 0000000..965dd02
--- /dev/null
+++ b/contrib/netbsd-tests/net/bpf/t_mbuf.c
@@ -0,0 +1,961 @@
+/* $NetBSD: t_mbuf.c,v 1.2 2014/07/08 21:44:26 alnsn Exp $ */
+
+/*-
+ * Copyright (c) 2014 Alexander Nasonov.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_mbuf.c,v 1.2 2014/07/08 21:44:26 alnsn Exp $");
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include <net/bpf.h>
+
+#include <stdint.h>
+#include <string.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include "../../net/bpf/h_bpf.h"
+
+/* XXX: atf-c.h has collisions with mbuf */
+#undef m_type
+#undef m_data
+#include <atf-c.h>
+
+#include "../../h_macros.h"
+
+static bool
+test_ldb_abs(size_t split)
+{
+ /* Return a product of all packet bytes. */
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A <- P[0] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 1), /* A <- P[1] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 2), /* A <- P[2] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 3), /* A <- P[3] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 4), /* A <- P[4] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 120;
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldh_abs(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 0), /* A <- P[0:2] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 1), /* A <- P[1:2] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 2), /* A <- P[2:2] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 3), /* A <- P[3:2] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 0x0a0e; /* 10 14 */
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldw_abs(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* A <- P[0:4] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 1), /* A <- P[1:4] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 0x03050709;
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldb_ind(size_t split)
+{
+ /* Return a sum of all packet bytes. */
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 0), /* A <- P[0+X] */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1), /* A <- P[1+X] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1), /* A <- P[1+X] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 2), /* A <- P[2+X] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 3), /* A <- P[3+X] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 15;
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldw_ind(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 0), /* A <- P[X+0:4] */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 0), /* A <- P[X+0:4] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0), /* X <- 0 */
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1), /* A <- P[X+1:4] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 0x05080b0e;
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldh_ind(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 0), /* A <- P[X+0:2] */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1), /* A <- P[X+1:2] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1), /* A <- P[X+1:2] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 2), /* A <- P[X+2:2] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 0x0a0e; /* 10 14 */
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == res;
+}
+
+static bool
+test_msh(size_t split)
+{
+ /* Return a product of all packet bytes. */
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 1), /* A <- 1 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 0), /* X <- 4*(P[0]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 1), /* X <- 4*(P[1]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 2), /* X <- 4*(P[2]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 3), /* X <- 4*(P[3]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 4), /* X <- 4*(P[4]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 120;
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldb_abs_overflow(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 5),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldh_abs_overflow(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldw_abs_overflow(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 2),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldb_ind_overflow1(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 5),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldb_ind_overflow2(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 4),
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldb_ind_overflow3(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldh_ind_overflow1(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 4),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldh_ind_overflow2(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldh_ind_overflow3(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldw_ind_overflow1(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 2),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldw_ind_overflow2(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldw_ind_overflow3(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_msh_overflow(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 5),
+ BPF_STMT(BPF_MISC+BPF_TXA, 0),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+
+ if (!prog_validate(insns, sizeof(insns) / sizeof(insns[0])))
+ return false;
+
+ return interp_prog_mchain2(insns, P, sizeof(P), split) == 0;
+}
+
+ATF_TC(bpf_mbuf_ldb_abs);
+ATF_TC_HEAD(bpf_mbuf_ldb_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_ABS "
+ "loads bytes from mbuf correctly");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldb_abs, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_abs(0));
+ ATF_CHECK(test_ldb_abs(1));
+ ATF_CHECK(test_ldb_abs(2));
+ ATF_CHECK(test_ldb_abs(3));
+ ATF_CHECK(test_ldb_abs(4));
+ ATF_CHECK(test_ldb_abs(5));
+}
+
+ATF_TC(bpf_mbuf_ldh_abs);
+ATF_TC_HEAD(bpf_mbuf_ldh_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_ABS "
+ "loads halfwords from mbuf correctly");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldh_abs, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_abs(0));
+ ATF_CHECK(test_ldh_abs(1));
+ ATF_CHECK(test_ldh_abs(2));
+ ATF_CHECK(test_ldh_abs(3));
+ ATF_CHECK(test_ldh_abs(4));
+ ATF_CHECK(test_ldh_abs(5));
+}
+
+ATF_TC(bpf_mbuf_ldw_abs);
+ATF_TC_HEAD(bpf_mbuf_ldw_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_ABS "
+ "loads words from mbuf correctly");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldw_abs, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_abs(0));
+ ATF_CHECK(test_ldw_abs(1));
+ ATF_CHECK(test_ldw_abs(2));
+ ATF_CHECK(test_ldw_abs(3));
+ ATF_CHECK(test_ldw_abs(4));
+ ATF_CHECK(test_ldw_abs(5));
+}
+
+ATF_TC(bpf_mbuf_ldb_ind);
+ATF_TC_HEAD(bpf_mbuf_ldb_ind, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_IND "
+ "loads bytes from mbuf correctly");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldb_ind, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_ind(0));
+ ATF_CHECK(test_ldb_ind(1));
+ ATF_CHECK(test_ldb_ind(2));
+ ATF_CHECK(test_ldb_ind(3));
+ ATF_CHECK(test_ldb_ind(4));
+ ATF_CHECK(test_ldb_ind(5));
+}
+
+ATF_TC(bpf_mbuf_ldh_ind);
+ATF_TC_HEAD(bpf_mbuf_ldh_ind, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_IND "
+ "loads halfwords from mbuf correctly");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldh_ind, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_ind(0));
+ ATF_CHECK(test_ldh_ind(1));
+ ATF_CHECK(test_ldh_ind(2));
+ ATF_CHECK(test_ldh_ind(3));
+ ATF_CHECK(test_ldh_ind(4));
+ ATF_CHECK(test_ldh_ind(5));
+}
+
+ATF_TC(bpf_mbuf_ldw_ind);
+ATF_TC_HEAD(bpf_mbuf_ldw_ind, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_IND "
+ "loads words from mbuf correctly");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldw_ind, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_ind(0));
+ ATF_CHECK(test_ldw_ind(1));
+ ATF_CHECK(test_ldw_ind(2));
+ ATF_CHECK(test_ldw_ind(3));
+ ATF_CHECK(test_ldw_ind(4));
+ ATF_CHECK(test_ldw_ind(5));
+}
+
+ATF_TC(bpf_mbuf_msh);
+ATF_TC_HEAD(bpf_mbuf_msh, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LDX+BPF_B+BPF_MSH "
+ "loads bytes from mbuf correctly");
+}
+
+ATF_TC_BODY(bpf_mbuf_msh, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_msh(0));
+ ATF_CHECK(test_msh(1));
+ ATF_CHECK(test_msh(2));
+ ATF_CHECK(test_msh(3));
+ ATF_CHECK(test_msh(4));
+ ATF_CHECK(test_msh(5));
+}
+
+ATF_TC(bpf_mbuf_ldb_abs_overflow);
+ATF_TC_HEAD(bpf_mbuf_ldb_abs_overflow, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_ABS "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldb_abs_overflow, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_abs_overflow(0));
+ ATF_CHECK(test_ldb_abs_overflow(1));
+ ATF_CHECK(test_ldb_abs_overflow(2));
+ ATF_CHECK(test_ldb_abs_overflow(3));
+ ATF_CHECK(test_ldb_abs_overflow(4));
+ ATF_CHECK(test_ldb_abs_overflow(5));
+}
+
+ATF_TC(bpf_mbuf_ldh_abs_overflow);
+ATF_TC_HEAD(bpf_mbuf_ldh_abs_overflow, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_ABS "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldh_abs_overflow, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_abs_overflow(0));
+ ATF_CHECK(test_ldh_abs_overflow(1));
+ ATF_CHECK(test_ldh_abs_overflow(2));
+ ATF_CHECK(test_ldh_abs_overflow(3));
+ ATF_CHECK(test_ldh_abs_overflow(4));
+ ATF_CHECK(test_ldh_abs_overflow(5));
+}
+
+ATF_TC(bpf_mbuf_ldw_abs_overflow);
+ATF_TC_HEAD(bpf_mbuf_ldw_abs_overflow, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_ABS "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldw_abs_overflow, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_abs_overflow(0));
+ ATF_CHECK(test_ldw_abs_overflow(1));
+ ATF_CHECK(test_ldw_abs_overflow(2));
+ ATF_CHECK(test_ldw_abs_overflow(3));
+ ATF_CHECK(test_ldw_abs_overflow(4));
+ ATF_CHECK(test_ldw_abs_overflow(5));
+}
+
+ATF_TC(bpf_mbuf_ldb_ind_overflow1);
+ATF_TC_HEAD(bpf_mbuf_ldb_ind_overflow1, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldb_ind_overflow1, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_ind_overflow1(0));
+ ATF_CHECK(test_ldb_ind_overflow1(1));
+ ATF_CHECK(test_ldb_ind_overflow1(2));
+ ATF_CHECK(test_ldb_ind_overflow1(3));
+ ATF_CHECK(test_ldb_ind_overflow1(4));
+ ATF_CHECK(test_ldb_ind_overflow1(5));
+}
+
+ATF_TC(bpf_mbuf_ldb_ind_overflow2);
+ATF_TC_HEAD(bpf_mbuf_ldb_ind_overflow2, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldb_ind_overflow2, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_ind_overflow2(0));
+ ATF_CHECK(test_ldb_ind_overflow2(1));
+ ATF_CHECK(test_ldb_ind_overflow2(2));
+ ATF_CHECK(test_ldb_ind_overflow2(3));
+ ATF_CHECK(test_ldb_ind_overflow2(4));
+ ATF_CHECK(test_ldb_ind_overflow2(5));
+}
+
+ATF_TC(bpf_mbuf_ldb_ind_overflow3);
+ATF_TC_HEAD(bpf_mbuf_ldb_ind_overflow3, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldb_ind_overflow3, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_ind_overflow3(0));
+ ATF_CHECK(test_ldb_ind_overflow3(1));
+ ATF_CHECK(test_ldb_ind_overflow3(2));
+ ATF_CHECK(test_ldb_ind_overflow3(3));
+ ATF_CHECK(test_ldb_ind_overflow3(4));
+ ATF_CHECK(test_ldb_ind_overflow3(5));
+}
+
+ATF_TC(bpf_mbuf_ldh_ind_overflow1);
+ATF_TC_HEAD(bpf_mbuf_ldh_ind_overflow1, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldh_ind_overflow1, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_ind_overflow1(0));
+ ATF_CHECK(test_ldh_ind_overflow1(1));
+ ATF_CHECK(test_ldh_ind_overflow1(2));
+ ATF_CHECK(test_ldh_ind_overflow1(3));
+ ATF_CHECK(test_ldh_ind_overflow1(4));
+ ATF_CHECK(test_ldh_ind_overflow1(5));
+}
+
+ATF_TC(bpf_mbuf_ldh_ind_overflow2);
+ATF_TC_HEAD(bpf_mbuf_ldh_ind_overflow2, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldh_ind_overflow2, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_ind_overflow2(0));
+ ATF_CHECK(test_ldh_ind_overflow2(1));
+ ATF_CHECK(test_ldh_ind_overflow2(2));
+ ATF_CHECK(test_ldh_ind_overflow2(3));
+ ATF_CHECK(test_ldh_ind_overflow2(4));
+ ATF_CHECK(test_ldh_ind_overflow2(5));
+}
+
+ATF_TC(bpf_mbuf_ldh_ind_overflow3);
+ATF_TC_HEAD(bpf_mbuf_ldh_ind_overflow3, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldh_ind_overflow3, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_ind_overflow3(0));
+ ATF_CHECK(test_ldh_ind_overflow3(1));
+ ATF_CHECK(test_ldh_ind_overflow3(2));
+ ATF_CHECK(test_ldh_ind_overflow3(3));
+ ATF_CHECK(test_ldh_ind_overflow3(4));
+ ATF_CHECK(test_ldh_ind_overflow3(5));
+}
+
+ATF_TC(bpf_mbuf_ldw_ind_overflow1);
+ATF_TC_HEAD(bpf_mbuf_ldw_ind_overflow1, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldw_ind_overflow1, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_ind_overflow1(0));
+ ATF_CHECK(test_ldw_ind_overflow1(1));
+ ATF_CHECK(test_ldw_ind_overflow1(2));
+ ATF_CHECK(test_ldw_ind_overflow1(3));
+ ATF_CHECK(test_ldw_ind_overflow1(4));
+ ATF_CHECK(test_ldw_ind_overflow1(5));
+}
+
+ATF_TC(bpf_mbuf_ldw_ind_overflow2);
+ATF_TC_HEAD(bpf_mbuf_ldw_ind_overflow2, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldw_ind_overflow2, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_ind_overflow2(0));
+ ATF_CHECK(test_ldw_ind_overflow2(1));
+ ATF_CHECK(test_ldw_ind_overflow2(2));
+ ATF_CHECK(test_ldw_ind_overflow2(3));
+ ATF_CHECK(test_ldw_ind_overflow2(4));
+ ATF_CHECK(test_ldw_ind_overflow2(5));
+}
+
+ATF_TC(bpf_mbuf_ldw_ind_overflow3);
+ATF_TC_HEAD(bpf_mbuf_ldw_ind_overflow3, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_ldw_ind_overflow3, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_ind_overflow3(0));
+ ATF_CHECK(test_ldw_ind_overflow3(1));
+ ATF_CHECK(test_ldw_ind_overflow3(2));
+ ATF_CHECK(test_ldw_ind_overflow3(3));
+ ATF_CHECK(test_ldw_ind_overflow3(4));
+ ATF_CHECK(test_ldw_ind_overflow3(5));
+}
+
+ATF_TC(bpf_mbuf_msh_overflow);
+ATF_TC_HEAD(bpf_mbuf_msh_overflow, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LDX+BPF_B+BPF_MSH "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpf_mbuf_msh_overflow, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_msh_overflow(0));
+ ATF_CHECK(test_msh_overflow(1));
+ ATF_CHECK(test_msh_overflow(2));
+ ATF_CHECK(test_msh_overflow(3));
+ ATF_CHECK(test_msh_overflow(4));
+ ATF_CHECK(test_msh_overflow(5));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ /*
+ * For every new test please also add a similar test
+ * to ../../net/bpfjit/t_mbuf.c
+ */
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldb_abs);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldh_abs);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldw_abs);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldb_ind);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldh_ind);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldw_ind);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_msh);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldb_abs_overflow);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldh_abs_overflow);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldw_abs_overflow);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldb_ind_overflow1);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldb_ind_overflow2);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldb_ind_overflow3);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldh_ind_overflow1);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldh_ind_overflow2);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldh_ind_overflow3);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldw_ind_overflow1);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldw_ind_overflow2);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_ldw_ind_overflow3);
+ ATF_TP_ADD_TC(tp, bpf_mbuf_msh_overflow);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/bpfilter/t_bpfilter.c b/contrib/netbsd-tests/net/bpfilter/t_bpfilter.c
new file mode 100644
index 0000000..9d8d56f
--- /dev/null
+++ b/contrib/netbsd-tests/net/bpfilter/t_bpfilter.c
@@ -0,0 +1,400 @@
+/* $NetBSD: t_bpfilter.c,v 1.8 2014/06/24 11:32:36 alnsn Exp $ */
+
+/*-
+ * Copyright (c) 2012 The NetBSD Foundation, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_bpfilter.c,v 1.8 2014/06/24 11:32:36 alnsn Exp $");
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/bpf.h>
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+/* XXX: atf-c.h has collisions with mbuf */
+#undef m_type
+#undef m_data
+#include <atf-c.h>
+
+#include "../../h_macros.h"
+#include "../config/netconfig.c"
+
+
+#define SNAPLEN UINT32_MAX
+
+#define BMAGIC UINT32_C(0x37)
+#define HMAGIC UINT32_C(0xc2c2)
+#define WMAGIC UINT32_C(0x7d7d7d7d)
+
+static const char magic_echo_reply_tail[7] = {
+ BMAGIC,
+ HMAGIC & 0xff,
+ HMAGIC & 0xff,
+ WMAGIC & 0xff,
+ WMAGIC & 0xff,
+ WMAGIC & 0xff,
+ WMAGIC & 0xff
+};
+
+/*
+ * Match ICMP_ECHOREPLY packet with 7 magic bytes at the end.
+ */
+static struct bpf_insn magic_echo_reply_prog[] = {
+ BPF_STMT(BPF_LD+BPF_ABS+BPF_B,
+ sizeof(struct ip) + offsetof(struct icmp, icmp_type)),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ICMP_ECHOREPLY, 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0), /* A <- len */
+ BPF_STMT(BPF_ALU+BPF_SUB+BPF_K, 7), /* A <- A - 7 */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_IND+BPF_B, 0),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, BMAGIC, 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+
+ BPF_STMT(BPF_LD+BPF_IND+BPF_H, 1),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, HMAGIC, 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+
+ BPF_STMT(BPF_LD+BPF_IND+BPF_W, 3),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, WMAGIC, 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+
+ BPF_STMT(BPF_RET+BPF_K, SNAPLEN)
+};
+
+static struct bpf_insn badmem_prog[] = {
+ BPF_STMT(BPF_LD+BPF_MEM, 5),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+};
+
+static struct bpf_insn noinitA_prog[] = {
+ BPF_STMT(BPF_RET+BPF_A, 0),
+};
+
+static struct bpf_insn noinitX_prog[] = {
+ BPF_STMT(BPF_MISC+BPF_TXA, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+};
+
+static uint16_t
+in_cksum(void *data, size_t len)
+{
+ uint16_t *buf = data;
+ unsigned sum;
+
+ for (sum = 0; len > 1; len -= 2)
+ sum += *buf++;
+ if (len)
+ sum += *(uint8_t *)buf;
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+
+ return ~sum;
+}
+
+/*
+ * Based on netcfg_rump_pingtest().
+ */
+static bool __unused
+pingtest(const char *dst, unsigned int wirelen, const char tail[7])
+{
+ struct timeval tv;
+ struct sockaddr_in sin;
+ struct icmp *icmp;
+ char *pkt;
+ unsigned int pktsize;
+ socklen_t slen;
+ int s;
+ bool rv = false;
+
+ if (wirelen < ETHER_HDR_LEN + sizeof(struct ip))
+ return false;
+
+ pktsize = wirelen - ETHER_HDR_LEN - sizeof(struct ip);
+ if (pktsize < sizeof(struct icmp) + 7)
+ return false;
+
+ s = rump_sys_socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (s == -1)
+ return false;
+
+ pkt = NULL;
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ if (rump_sys_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
+ &tv, sizeof(tv)) == -1)
+ goto out;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(dst);
+
+ pkt = calloc(1, pktsize);
+ icmp = (struct icmp *)pkt;
+ if (pkt == NULL)
+ goto out;
+
+ memcpy(pkt + pktsize - 7, tail, 7);
+ icmp->icmp_type = ICMP_ECHO;
+ icmp->icmp_id = htons(37);
+ icmp->icmp_seq = htons(1);
+ icmp->icmp_cksum = in_cksum(pkt, pktsize);
+
+ slen = sizeof(sin);
+ if (rump_sys_sendto(s, pkt, pktsize, 0,
+ (struct sockaddr *)&sin, slen) == -1) {
+ goto out;
+ }
+
+ if (rump_sys_recvfrom(s, pkt, pktsize, 0,
+ (struct sockaddr *)&sin, &slen) == -1)
+ goto out;
+
+ rv = true;
+ out:
+ if (pkt != NULL)
+ free(pkt);
+ rump_sys_close(s);
+ return rv;
+}
+
+static void
+magic_ping_test(const char *name, unsigned int wirelen)
+{
+ struct bpf_program prog;
+ struct bpf_stat bstat;
+ struct ifreq ifr;
+ struct timeval tv;
+ unsigned int bufsize;
+ bool pinged;
+ ssize_t n;
+ char *buf;
+ pid_t child;
+ int bpfd;
+ char token;
+ int channel[2];
+
+ struct bpf_hdr *hdr;
+
+ RL(pipe(channel));
+
+ prog.bf_len = __arraycount(magic_echo_reply_prog);
+ prog.bf_insns = magic_echo_reply_prog;
+
+ child = fork();
+ RZ(rump_init());
+ netcfg_rump_makeshmif(name, ifr.ifr_name);
+
+ switch (child) {
+ case -1:
+ atf_tc_fail_errno("fork failed");
+ case 0:
+ netcfg_rump_if(ifr.ifr_name, "10.1.1.10", "255.0.0.0");
+ close(channel[0]);
+ ATF_CHECK(write(channel[1], "U", 1) == 1);
+ close(channel[1]);
+ pause();
+ return;
+ default:
+ break;
+ }
+
+ netcfg_rump_if(ifr.ifr_name, "10.1.1.20", "255.0.0.0");
+
+ RL(bpfd = rump_sys_open("/dev/bpf", O_RDONLY));
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 500;
+ RL(rump_sys_ioctl(bpfd, BIOCSRTIMEOUT, &tv));
+
+ RL(rump_sys_ioctl(bpfd, BIOCGBLEN, &bufsize));
+ RL(rump_sys_ioctl(bpfd, BIOCSETF, &prog));
+ RL(rump_sys_ioctl(bpfd, BIOCSETIF, &ifr));
+
+ close(channel[1]);
+ ATF_CHECK(read(channel[0], &token, 1) == 1 && token == 'U');
+
+ pinged = pingtest("10.1.1.10", wirelen, magic_echo_reply_tail);
+ ATF_CHECK(pinged);
+
+ buf = malloc(bufsize);
+ hdr = (struct bpf_hdr *)buf;
+ ATF_REQUIRE(buf != NULL);
+ ATF_REQUIRE(bufsize > sizeof(struct bpf_hdr));
+
+ n = rump_sys_read(bpfd, buf, bufsize);
+
+ ATF_CHECK(n > (int)sizeof(struct bpf_hdr));
+ ATF_CHECK(hdr->bh_caplen == MIN(SNAPLEN, wirelen));
+
+ RL(rump_sys_ioctl(bpfd, BIOCGSTATS, &bstat));
+ ATF_CHECK(bstat.bs_capt >= 1); /* XXX == 1 */
+
+ rump_sys_close(bpfd);
+ free(buf);
+
+ close(channel[0]);
+
+ kill(child, SIGKILL);
+}
+
+static int
+send_bpf_prog(const char *ifname, struct bpf_program *prog)
+{
+ struct ifreq ifr;
+ int bpfd, e, rv;
+
+ RZ(rump_init());
+ netcfg_rump_makeshmif(ifname, ifr.ifr_name);
+ netcfg_rump_if(ifr.ifr_name, "10.1.1.20", "255.0.0.0");
+
+ RL(bpfd = rump_sys_open("/dev/bpf", O_RDONLY));
+
+ rv = rump_sys_ioctl(bpfd, BIOCSETF, prog);
+ e = errno;
+
+ rump_sys_close(bpfd);
+ errno = e;
+
+ return rv;
+}
+
+ATF_TC(bpfiltercontig);
+ATF_TC_HEAD(bpfiltercontig, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Checks that bpf program "
+ "can read bytes from contiguous buffer.");
+ atf_tc_set_md_var(tc, "timeout", "30");
+}
+
+ATF_TC_BODY(bpfiltercontig, tc)
+{
+
+ magic_ping_test("bpfiltercontig", 128);
+}
+
+
+ATF_TC(bpfiltermchain);
+ATF_TC_HEAD(bpfiltermchain, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Checks that bpf program "
+ "can read bytes from mbuf chain.");
+ atf_tc_set_md_var(tc, "timeout", "30");
+}
+
+ATF_TC_BODY(bpfiltermchain, tc)
+{
+
+ magic_ping_test("bpfiltermchain", MINCLSIZE + 1);
+}
+
+
+ATF_TC(bpfilterbadmem);
+ATF_TC_HEAD(bpfilterbadmem, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Checks that bpf program that "
+ "doesn't initialize memomy store is rejected by the kernel");
+ atf_tc_set_md_var(tc, "timeout", "30");
+}
+
+ATF_TC_BODY(bpfilterbadmem, tc)
+{
+ struct bpf_program prog;
+
+ prog.bf_len = __arraycount(badmem_prog);
+ prog.bf_insns = badmem_prog;
+ ATF_CHECK_ERRNO(EINVAL, send_bpf_prog("bpfilterbadmem", &prog) == -1);
+}
+
+ATF_TC(bpfilternoinitA);
+ATF_TC_HEAD(bpfilternoinitA, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Checks that bpf program that "
+ "doesn't initialize the A register is accepted by the kernel");
+ atf_tc_set_md_var(tc, "timeout", "30");
+}
+
+ATF_TC_BODY(bpfilternoinitA, tc)
+{
+ struct bpf_program prog;
+
+ prog.bf_len = __arraycount(noinitA_prog);
+ prog.bf_insns = noinitA_prog;
+ RL(send_bpf_prog("bpfilternoinitA", &prog));
+}
+
+ATF_TC(bpfilternoinitX);
+ATF_TC_HEAD(bpfilternoinitX, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Checks that bpf program that "
+ "doesn't initialize the X register is accepted by the kernel");
+ atf_tc_set_md_var(tc, "timeout", "30");
+}
+
+ATF_TC_BODY(bpfilternoinitX, tc)
+{
+ struct bpf_program prog;
+
+ prog.bf_len = __arraycount(noinitX_prog);
+ prog.bf_insns = noinitX_prog;
+ RL(send_bpf_prog("bpfilternoinitX", &prog));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, bpfiltercontig);
+ ATF_TP_ADD_TC(tp, bpfiltermchain);
+ ATF_TP_ADD_TC(tp, bpfilterbadmem);
+ ATF_TP_ADD_TC(tp, bpfilternoinitA);
+ ATF_TP_ADD_TC(tp, bpfilternoinitX);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/bpfjit/t_bpfjit.c b/contrib/netbsd-tests/net/bpfjit/t_bpfjit.c
new file mode 100644
index 0000000..a9f8f41
--- /dev/null
+++ b/contrib/netbsd-tests/net/bpfjit/t_bpfjit.c
@@ -0,0 +1,3979 @@
+/* $NetBSD: t_bpfjit.c,v 1.2 2014/07/08 21:44:26 alnsn Exp $ */
+
+/*-
+ * Copyright (c) 2011-2012, 2014 Alexander Nasonov.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_bpfjit.c,v 1.2 2014/07/08 21:44:26 alnsn Exp $");
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <unistd.h>
+
+#include <net/bpf.h>
+#include <net/bpfjit.h>
+
+#include <stdint.h>
+#include <string.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include "../../net/bpf/h_bpf.h"
+
+/* XXX: atf-c.h has collisions with mbuf */
+#undef m_type
+#undef m_data
+#include <atf-c.h>
+
+#include "../../h_macros.h"
+
+
+static uint8_t deadbeef_at_5[16] = {
+ 0, 0xf1, 2, 0xf3, 4, 0xde, 0xad, 0xbe, 0xef, 0xff
+};
+
+static inline
+unsigned int jitcall(bpfjit_func_t fn,
+ const uint8_t *pkt, unsigned int wirelen, unsigned int buflen)
+{
+ bpf_args_t args;
+
+ args.pkt = pkt;
+ args.wirelen = wirelen;
+ args.buflen = buflen;
+
+ return fn(NULL, &args);
+}
+
+ATF_TC(bpfjit_empty);
+ATF_TC_HEAD(bpfjit_empty, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test that JIT compilation of an empty bpf program fails");
+}
+
+ATF_TC_BODY(bpfjit_empty, tc)
+{
+ struct bpf_insn dummy;
+ bpfjit_func_t fn;
+
+ RZ(rump_init());
+
+ rump_schedule();
+ fn = rumpns_bpfjit_generate_code(NULL, &dummy, 0);
+ rump_unschedule();
+
+ ATF_CHECK(fn == NULL);
+}
+
+ATF_TC(bpfjit_alu_add_k);
+ATF_TC_HEAD(bpfjit_alu_add_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_ADD+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_alu_add_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 3),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 2),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 5);
+}
+
+ATF_TC(bpfjit_alu_sub_k);
+ATF_TC_HEAD(bpfjit_alu_sub_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_SUB+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_alu_sub_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 1),
+ BPF_STMT(BPF_ALU+BPF_SUB+BPF_K, 2),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == UINT32_MAX);
+}
+
+ATF_TC(bpfjit_alu_mul_k);
+ATF_TC_HEAD(bpfjit_alu_mul_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_MUL+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_alu_mul_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(0xffffffff)),
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_K, 3),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xfffffffd);
+}
+
+ATF_TC(bpfjit_alu_div0_k);
+ATF_TC_HEAD(bpfjit_alu_div0_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_K with k=0");
+}
+
+ATF_TC_BODY(bpfjit_alu_div0_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ //ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0);
+}
+
+ATF_TC(bpfjit_alu_div1_k);
+ATF_TC_HEAD(bpfjit_alu_div1_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_K with k=1");
+}
+
+ATF_TC_BODY(bpfjit_alu_div1_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 7),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 7);
+}
+
+ATF_TC(bpfjit_alu_div2_k);
+ATF_TC_HEAD(bpfjit_alu_div2_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_K with k=2");
+}
+
+ATF_TC_BODY(bpfjit_alu_div2_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 7),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 2),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 3);
+}
+
+ATF_TC(bpfjit_alu_div4_k);
+ATF_TC_HEAD(bpfjit_alu_div4_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_K with k=4");
+}
+
+ATF_TC_BODY(bpfjit_alu_div4_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(0xffffffff)),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0x3fffffff);
+}
+
+ATF_TC(bpfjit_alu_div10_k);
+ATF_TC_HEAD(bpfjit_alu_div10_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_K with k=10");
+}
+
+ATF_TC_BODY(bpfjit_alu_div10_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(4294843849)),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 10),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 429484384);
+}
+
+ATF_TC(bpfjit_alu_div10000_k);
+ATF_TC_HEAD(bpfjit_alu_div10000_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_K with k=10000");
+}
+
+ATF_TC_BODY(bpfjit_alu_div10000_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(4294843849)),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 10000),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 429484);
+}
+
+ATF_TC(bpfjit_alu_div7609801_k);
+ATF_TC_HEAD(bpfjit_alu_div7609801_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_K with k=7609801");
+}
+
+ATF_TC_BODY(bpfjit_alu_div7609801_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(4294967295)),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, UINT32_C(7609801)),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 564);
+}
+
+ATF_TC(bpfjit_alu_div80000000_k);
+ATF_TC_HEAD(bpfjit_alu_div80000000_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_K with k=0x80000000");
+}
+
+ATF_TC_BODY(bpfjit_alu_div80000000_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(0xffffffde)),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, UINT32_C(0x80000000)),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 1);
+}
+
+ATF_TC(bpfjit_alu_and_k);
+ATF_TC_HEAD(bpfjit_alu_and_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_AND+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_alu_and_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdead),
+ BPF_STMT(BPF_ALU+BPF_AND+BPF_K, 0xbeef),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == (0xdead&0xbeef));
+}
+
+ATF_TC(bpfjit_alu_or_k);
+ATF_TC_HEAD(bpfjit_alu_or_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_OR+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_alu_or_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdead0000),
+ BPF_STMT(BPF_ALU+BPF_OR+BPF_K, 0x0000beef),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xdeadbeef);
+}
+
+ATF_TC(bpfjit_alu_lsh_k);
+ATF_TC_HEAD(bpfjit_alu_lsh_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_LSH+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_alu_lsh_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdeadbeef),
+ BPF_STMT(BPF_ALU+BPF_LSH+BPF_K, 16),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xbeef0000);
+}
+
+ATF_TC(bpfjit_alu_lsh0_k);
+ATF_TC_HEAD(bpfjit_alu_lsh0_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_LSH+BPF_K with k=0");
+}
+
+ATF_TC_BODY(bpfjit_alu_lsh0_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdeadbeef),
+ BPF_STMT(BPF_ALU+BPF_LSH+BPF_K, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xdeadbeef);
+}
+
+ATF_TC(bpfjit_alu_rsh_k);
+ATF_TC_HEAD(bpfjit_alu_rsh_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_RSH+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_alu_rsh_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdeadbeef),
+ BPF_STMT(BPF_ALU+BPF_RSH+BPF_K, 16),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0x0000dead);
+}
+
+ATF_TC(bpfjit_alu_rsh0_k);
+ATF_TC_HEAD(bpfjit_alu_rsh0_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_RSH+BPF_K with k=0");
+}
+
+ATF_TC_BODY(bpfjit_alu_rsh0_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdeadbeef),
+ BPF_STMT(BPF_ALU+BPF_RSH+BPF_K, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xdeadbeef);
+}
+
+ATF_TC(bpfjit_alu_modulo_k);
+ATF_TC_HEAD(bpfjit_alu_modulo_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of modulo logic of BPF_ALU+BPF_K operations");
+}
+
+ATF_TC_BODY(bpfjit_alu_modulo_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(0x7fffff77)),
+
+ /* (7FFFFF77 * 0FFFFF77) = 07FFFFB2,F0004951 */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_K, UINT32_C(0x0fffff77)),
+
+ /* 07FFFFB2,F0004951 << 1 = 0FFFFF65,E00092A2 */
+ BPF_STMT(BPF_ALU+BPF_LSH+BPF_K, 1),
+
+ /* 0FFFFF65,E00092A2 + DDDDDDDD = 0FFFFF66,BDDE707F */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, UINT32_C(0xdddddddd)),
+
+ /* 0FFFFF66,BDDE707F - FFFFFFFF = 0FFFFF65,BDDE7080 */
+ BPF_STMT(BPF_ALU+BPF_SUB+BPF_K, UINT32_C(0xffffffff)),
+
+ /* 0FFFFF65,BDDE7080 | 0000030C = 0FFFFF65,BDDE738C */
+ BPF_STMT(BPF_ALU+BPF_OR+BPF_K, UINT32_C(0x0000030c)),
+
+ /* -0FFFFF65,BDDE738C mod(2^64) = F000009A,42218C74 */
+ BPF_STMT(BPF_ALU+BPF_NEG, 0),
+
+ /* F000009A,42218C74 & FFFFFF0F = F000009A,42218C04 */
+ BPF_STMT(BPF_ALU+BPF_AND+BPF_K, UINT32_C(0xffffff0f)),
+
+ /* F000009A,42218C74 >> 3 = 1E000013,48443180 */
+ /* 00000000,42218C74 >> 3 = 00000000,08443180 */
+ BPF_STMT(BPF_ALU+BPF_RSH+BPF_K, 3),
+
+ /* 00000000,08443180 * 7FFFFF77 = 042218BB,93818280 */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_K, UINT32_C(0x7fffff77)),
+
+ /* 042218BB,93818280 / DEAD = 000004C0,71CBBBC3 */
+ /* 00000000,93818280 / DEAD = 00000000,0000A994 */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, UINT32_C(0xdead)),
+
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) != UINT32_C(0x71cbbbc3));
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == UINT32_C(0x0000a994));
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_alu_add_x);
+ATF_TC_HEAD(bpfjit_alu_add_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_ADD+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_alu_add_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 3),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 5);
+}
+
+ATF_TC(bpfjit_alu_sub_x);
+ATF_TC_HEAD(bpfjit_alu_sub_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_SUB+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_alu_sub_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 1),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2),
+ BPF_STMT(BPF_ALU+BPF_SUB+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == UINT32_MAX);
+}
+
+ATF_TC(bpfjit_alu_mul_x);
+ATF_TC_HEAD(bpfjit_alu_mul_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_MUL+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_alu_mul_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(0xffffffff)),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 3),
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xfffffffd);
+}
+
+ATF_TC(bpfjit_alu_div0_x);
+ATF_TC_HEAD(bpfjit_alu_div0_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_X with X=0");
+}
+
+ATF_TC_BODY(bpfjit_alu_div0_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0);
+}
+
+ATF_TC(bpfjit_alu_div1_x);
+ATF_TC_HEAD(bpfjit_alu_div1_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_X with X=1");
+}
+
+ATF_TC_BODY(bpfjit_alu_div1_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 7),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 7);
+}
+
+ATF_TC(bpfjit_alu_div2_x);
+ATF_TC_HEAD(bpfjit_alu_div2_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_X with X=2");
+}
+
+ATF_TC_BODY(bpfjit_alu_div2_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 7),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 3);
+}
+
+ATF_TC(bpfjit_alu_div4_x);
+ATF_TC_HEAD(bpfjit_alu_div4_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_X with X=4");
+}
+
+ATF_TC_BODY(bpfjit_alu_div4_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(0xffffffff)),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 4),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0x3fffffff);
+}
+
+ATF_TC(bpfjit_alu_div10_x);
+ATF_TC_HEAD(bpfjit_alu_div10_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_X with X=10");
+}
+
+ATF_TC_BODY(bpfjit_alu_div10_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(4294843849)),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 10),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 429484384);
+}
+
+ATF_TC(bpfjit_alu_div10000_x);
+ATF_TC_HEAD(bpfjit_alu_div10000_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_X with X=10000");
+}
+
+ATF_TC_BODY(bpfjit_alu_div10000_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(4294843849)),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 10000),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 429484);
+}
+
+ATF_TC(bpfjit_alu_div7609801_x);
+ATF_TC_HEAD(bpfjit_alu_div7609801_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_X with X=7609801");
+}
+
+ATF_TC_BODY(bpfjit_alu_div7609801_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(4294967295)),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(7609801)),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 564);
+}
+
+ATF_TC(bpfjit_alu_div80000000_x);
+ATF_TC_HEAD(bpfjit_alu_div80000000_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_DIV+BPF_X with X=0x80000000");
+}
+
+ATF_TC_BODY(bpfjit_alu_div80000000_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_MAX - 33),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(0x80000000)),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 1);
+}
+
+ATF_TC(bpfjit_alu_and_x);
+ATF_TC_HEAD(bpfjit_alu_and_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_AND+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_alu_and_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdead),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0xbeef),
+ BPF_STMT(BPF_ALU+BPF_AND+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == (0xdead&0xbeef));
+}
+
+ATF_TC(bpfjit_alu_or_x);
+ATF_TC_HEAD(bpfjit_alu_or_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_OR+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_alu_or_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdead0000),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0x0000beef),
+ BPF_STMT(BPF_ALU+BPF_OR+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xdeadbeef);
+}
+
+ATF_TC(bpfjit_alu_lsh_x);
+ATF_TC_HEAD(bpfjit_alu_lsh_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_LSH+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_alu_lsh_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdeadbeef),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 16),
+ BPF_STMT(BPF_ALU+BPF_LSH+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xbeef0000);
+}
+
+ATF_TC(bpfjit_alu_lsh0_x);
+ATF_TC_HEAD(bpfjit_alu_lsh0_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_LSH+BPF_X with k=0");
+}
+
+ATF_TC_BODY(bpfjit_alu_lsh0_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdeadbeef),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0),
+ BPF_STMT(BPF_ALU+BPF_LSH+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xdeadbeef);
+}
+
+ATF_TC(bpfjit_alu_rsh_x);
+ATF_TC_HEAD(bpfjit_alu_rsh_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_RSH+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_alu_rsh_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdeadbeef),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 16),
+ BPF_STMT(BPF_ALU+BPF_RSH+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0x0000dead);
+}
+
+ATF_TC(bpfjit_alu_rsh0_x);
+ATF_TC_HEAD(bpfjit_alu_rsh0_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_RSH+BPF_X with k=0");
+}
+
+ATF_TC_BODY(bpfjit_alu_rsh0_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 0xdeadbeef),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0),
+ BPF_STMT(BPF_ALU+BPF_RSH+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0xdeadbeef);
+}
+
+ATF_TC(bpfjit_alu_modulo_x);
+ATF_TC_HEAD(bpfjit_alu_modulo_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of modulo logic of BPF_ALU+BPF_X operations");
+}
+
+ATF_TC_BODY(bpfjit_alu_modulo_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(0x7fffff77)),
+
+ /* (7FFFFF77 * 0FFFFF77) = 07FFFFB2,F0004951 */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_K, UINT32_C(0x0fffff77)),
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0),
+
+ /* 07FFFFB2,F0004951 << 1 = 0FFFFF65,E00092A2 */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_K, 1),
+ BPF_STMT(BPF_ALU+BPF_LSH+BPF_X, 0),
+
+ /* 0FFFFF65,E00092A2 + DDDDDDDD = 0FFFFF66,BDDE707F */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_K, UINT32_C(0xdddddddd)),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+
+ /* 0FFFFF66,BDDE707F - FFFFFFFF = 0FFFFF65,BDDE7080 */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_K, UINT32_C(0xffffffff)),
+ BPF_STMT(BPF_ALU+BPF_SUB+BPF_X, 0),
+
+ /* 0FFFFF65,BDDE7080 | 0000030C = 0FFFFF65,BDDE738C */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_K, UINT32_C(0x0000030c)),
+ BPF_STMT(BPF_ALU+BPF_OR+BPF_X, 0),
+
+ /* -0FFFFF65,BDDE738C mod(2^64) = F000009A,42218C74 */
+ BPF_STMT(BPF_ALU+BPF_NEG, 0),
+
+ /* F000009A,42218C74 & FFFFFF0F = F000009A,42218C04 */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_K, UINT32_C(0xffffff0f)),
+ BPF_STMT(BPF_ALU+BPF_AND+BPF_X, 0),
+
+ /* F000009A,42218C74 >> 3 = 1E000013,48443180 */
+ /* 00000000,42218C74 >> 3 = 00000000,08443180 */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_K, 3),
+ BPF_STMT(BPF_ALU+BPF_RSH+BPF_X, 0),
+
+ /* 00000000,08443180 * 7FFFFF77 = 042218BB,93818280 */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_K, UINT32_C(0x7fffff77)),
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0),
+
+ /* 042218BB,93818280 / DEAD = 000004C0,71CBBBC3 */
+ /* 00000000,93818280 / DEAD = 00000000,0000A994 */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_K, UINT32_C(0xdead)),
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0),
+
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) != UINT32_C(0x71cbbbc3));
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == UINT32_C(0x0000a994));
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_alu_neg);
+ATF_TC_HEAD(bpfjit_alu_neg, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ALU+BPF_NEG");
+}
+
+ATF_TC_BODY(bpfjit_alu_neg, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 777),
+ BPF_STMT(BPF_ALU+BPF_NEG, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0u-777u);
+}
+
+ATF_TC(bpfjit_jmp_ja);
+ATF_TC_HEAD(bpfjit_jmp_ja, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_JMP+BPF_JA");
+}
+
+ATF_TC_BODY(bpfjit_jmp_ja, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_JMP+BPF_JA, 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == UINT32_MAX);
+}
+
+ATF_TC(bpfjit_jmp_jgt_k);
+ATF_TC_HEAD(bpfjit_jmp_jgt_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_JMP+BPF_JGT+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_jmp_jgt_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 7, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 2, 2, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 9, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 4, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 6, 2, 3),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 5, 3, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 0, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, 8)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[8]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 1);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 1);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 7);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 7);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 7);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 8);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 5);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_jmp_jge_k);
+ATF_TC_HEAD(bpfjit_jmp_jge_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_JMP+BPF_JGE+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_jmp_jge_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 8, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 3, 2, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 9, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 5, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 7, 2, 3),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 6, 3, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 1, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, 8)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[8]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 1);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 1);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 7);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 7);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 7);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 8);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 5);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_jmp_jeq_k);
+ATF_TC_HEAD(bpfjit_jmp_jeq_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_JMP+BPF_JEQ+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_jmp_jeq_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 8, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 3, 1, 0),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 9, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 5, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 7, 2, 3),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 6, 3, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 1, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, 8)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[8]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 7);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 7);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 1);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 7);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 7);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 8);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 5);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_jmp_jset_k);
+ATF_TC_HEAD(bpfjit_jmp_jset_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_JMP+BPF_JSET+BPF_K");
+}
+
+ATF_TC_BODY(bpfjit_jmp_jset_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 8, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 4, 2, 0),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 3, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 2, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 1, 2, 3),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 2, 3, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 7, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, 8)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[8]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 1);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 1);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 1);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 7);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 5);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 8);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 5);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_jmp_modulo_k);
+ATF_TC_HEAD(bpfjit_jmp_modulo_k, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of modulo logic of BPF_JMP+BPF_K operations");
+}
+
+ATF_TC_BODY(bpfjit_jmp_modulo_k, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(0x7fffff77)),
+ BPF_STMT(BPF_ALU+BPF_LSH+BPF_K, 4),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, UINT32_C(0xfffff770), 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, UINT32_C(0xfffff770), 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, UINT32_C(0xfffff771), 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, UINT32_C(0xfffff770), 0, 3),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, UINT32_C(0xfffff770), 2, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, UINT32_C(0xfffff771), 1, 0),
+ BPF_STMT(BPF_JMP+BPF_JA, 1),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+
+ /* FFFFF770+FFFFF770 = 00000001,FFFFEEE0 */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, UINT32_C(0xfffff770)),
+
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, UINT32_C(0xffffeee0), 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, UINT32_C(0xffffeee0), 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, UINT32_C(0xffffeee1), 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, UINT32_C(0xffffeee0), 0, 3),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, UINT32_C(0xffffeee0), 2, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, UINT32_C(0xffffeee1), 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 7)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == UINT32_MAX);
+}
+
+ATF_TC(bpfjit_jmp_jgt_x);
+ATF_TC_HEAD(bpfjit_jmp_jgt_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_JMP+BPF_JGT+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_jmp_jgt_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 7),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 3, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 9),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 4),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 6),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 2, 3),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 5),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 4, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, 8)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[8]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 1);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 1);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 7);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 7);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 7);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 8);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 5);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_jmp_jge_x);
+ATF_TC_HEAD(bpfjit_jmp_jge_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_JMP+BPF_JGE+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_jmp_jge_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 8),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 3),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 3, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 9),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 5),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 7),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 2, 3),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 6),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 4, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, 8)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[8]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 1);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 1);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 7);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 7);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 7);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 8);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 5);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_jmp_jeq_x);
+ATF_TC_HEAD(bpfjit_jmp_jeq_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_JMP+BPF_JEQ+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_jmp_jeq_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 8),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 3),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 2, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 9),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 5),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 7),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 2, 3),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 6),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 3, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 1, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, 8)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[8]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 7);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 7);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 1);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 7);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 7);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 8);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 5);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_jmp_jset_x);
+ATF_TC_HEAD(bpfjit_jmp_jset_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_JMP+BPF_JSET+BPF_X");
+}
+
+ATF_TC_BODY(bpfjit_jmp_jset_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 8),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_X, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 4),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_X, 0, 2, 0),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_X, 3, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_X, 0, 1, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_X, 0, 2, 3),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_X, 0, 4, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 7),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_X, 0, 0, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, 8)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[8]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 1);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 1);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 1);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 7);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 5);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 8);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 5);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_jmp_modulo_x);
+ATF_TC_HEAD(bpfjit_jmp_modulo_x, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of modulo logic of BPF_JMP+BPF_X operations");
+}
+
+ATF_TC_BODY(bpfjit_jmp_modulo_x, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_C(0x7fffff77)),
+ /* FFFFF770 << 4 = FFFFF770 */
+ BPF_STMT(BPF_ALU+BPF_LSH+BPF_K, 4),
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(0xfffff770)),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(0xfffff771)),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(0xfffff770)),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 0, 4),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 3, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(0xfffff771)),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 1, 0),
+ BPF_STMT(BPF_JMP+BPF_JA, 1),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+
+ /* FFFFF770+FFFFF770 = 00000001,FFFFEEE0 */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, UINT32_C(0xfffff770)),
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(0xffffeee0)),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 4),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 5),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(0xffffeee1)),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 6),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(0xffffeee0)),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 0, 4),
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 3, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_C(0xffffeee1)),
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 7)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == UINT32_MAX);
+}
+
+ATF_TC(bpfjit_ld_abs);
+ATF_TC_HEAD(bpfjit_ld_abs, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LD+BPF_ABS");
+}
+
+ATF_TC_BODY(bpfjit_ld_abs, tc)
+{
+ static struct bpf_insn insns[3][2] = {
+ {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 5),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 5),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 5),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ }
+ };
+
+ static size_t lengths[3] = { 1, 2, 4 };
+ static unsigned int expected[3] = { 0xde, 0xdead, 0xdeadbeef };
+
+ size_t i, l;
+ uint8_t *pkt = deadbeef_at_5;
+ size_t pktsize = sizeof(deadbeef_at_5);
+
+ size_t insn_count = sizeof(insns[0]) / sizeof(insns[0][0]);
+
+ RZ(rump_init());
+
+ for (i = 0; i < 3; i++) {
+ bpfjit_func_t code;
+
+ ATF_CHECK(prog_validate(insns[i], insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns[i], insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (l = 1; l < 5 + lengths[i]; l++) {
+ ATF_CHECK(jitcall(code, pkt, l, l) == 0);
+ ATF_CHECK(jitcall(code, pkt, pktsize, l) == 0);
+ }
+
+ l = 5 + lengths[i];
+ ATF_CHECK(jitcall(code, pkt, l, l) == expected[i]);
+ ATF_CHECK(jitcall(code, pkt, pktsize, l) == expected[i]);
+
+ l = pktsize;
+ ATF_CHECK(jitcall(code, pkt, l, l) == expected[i]);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+ }
+}
+
+ATF_TC(bpfjit_ld_abs_k_overflow);
+ATF_TC_HEAD(bpfjit_ld_abs_k_overflow, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LD+BPF_ABS with overflow in k+4");
+}
+
+ATF_TC_BODY(bpfjit_ld_abs_k_overflow, tc)
+{
+ static struct bpf_insn insns[12][3] = {
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, UINT32_MAX - 1),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, UINT32_MAX - 1),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, UINT32_MAX - 2),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, UINT32_MAX - 3),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, UINT32_MAX - 1),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, UINT32_MAX - 1),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, UINT32_MAX - 2),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, UINT32_MAX - 3),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ }
+ };
+
+ int i;
+ uint8_t pkt[8] = { 0 };
+
+ size_t insn_count = sizeof(insns[0]) / sizeof(insns[0][0]);
+
+ RZ(rump_init());
+
+ for (i = 0; i < 3; i++) {
+ ATF_CHECK(prog_validate(insns[i], insn_count));
+ ATF_CHECK(exec_prog(insns[i], insn_count, pkt, 8) == 0);
+ }
+}
+
+ATF_TC(bpfjit_ld_ind);
+ATF_TC_HEAD(bpfjit_ld_ind, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LD+BPF_IND");
+}
+
+ATF_TC_BODY(bpfjit_ld_ind, tc)
+{
+ static struct bpf_insn insns[6][3] = {
+ {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 3),
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 2),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ },
+ {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 2),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ },
+ {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 3),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 2),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ },
+ {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 5),
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ },
+ {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 5),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ },
+ {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 5),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ }
+ };
+
+ static size_t lengths[6] = { 1, 2, 4, 1, 2, 4 };
+
+ static unsigned int expected[6] = {
+ 0xde, 0xdead, 0xdeadbeef,
+ 0xde, 0xdead, 0xdeadbeef
+ };
+
+ size_t i, l;
+ uint8_t *pkt = deadbeef_at_5;
+ size_t pktsize = sizeof(deadbeef_at_5);
+
+ size_t insn_count = sizeof(insns[0]) / sizeof(insns[0][0]);
+
+ RZ(rump_init());
+
+ for (i = 0; i < 3; i++) {
+ bpfjit_func_t code;
+
+ ATF_CHECK(prog_validate(insns[i], insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns[i], insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (l = 1; l < 5 + lengths[i]; l++) {
+ ATF_CHECK(jitcall(code, pkt, l, l) == 0);
+ ATF_CHECK(jitcall(code, pkt, pktsize, l) == 0);
+ }
+
+ l = 5 + lengths[i];
+ ATF_CHECK(jitcall(code, pkt, l, l) == expected[i]);
+ ATF_CHECK(jitcall(code, pkt, pktsize, l) == expected[i]);
+
+ l = pktsize;
+ ATF_CHECK(jitcall(code, pkt, l, l) == expected[i]);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+ }
+}
+
+ATF_TC(bpfjit_ld_ind_k_overflow);
+ATF_TC_HEAD(bpfjit_ld_ind_k_overflow, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LD+BPF_IND with overflow in k+4");
+}
+
+ATF_TC_BODY(bpfjit_ld_ind_k_overflow, tc)
+{
+ static struct bpf_insn insns[12][3] = {
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, UINT32_MAX - 1),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, UINT32_MAX - 1),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, UINT32_MAX - 2),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, UINT32_MAX - 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, UINT32_MAX - 1),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, UINT32_MAX - 1),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, UINT32_MAX - 2),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ },
+ {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 7),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, UINT32_MAX - 3),
+ BPF_STMT(BPF_RET+BPF_K, 1)
+ }
+ };
+
+ int i;
+ uint8_t pkt[8] = { 0 };
+
+ size_t insn_count = sizeof(insns[0]) / sizeof(insns[0][0]);
+
+ RZ(rump_init());
+
+ for (i = 0; i < 3; i++) {
+
+ ATF_CHECK(prog_validate(insns[i], insn_count));
+ ATF_CHECK(exec_prog(insns[i], insn_count, pkt, 8) == 0);
+ }
+}
+
+ATF_TC(bpfjit_ld_ind_x_overflow1);
+ATF_TC_HEAD(bpfjit_ld_ind_x_overflow1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LD+BPF_IND with overflow in X+4");
+}
+
+ATF_TC_BODY(bpfjit_ld_ind_x_overflow1, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_LEN, 0),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, UINT32_C(0xffffffff)),
+ BPF_STMT(BPF_MISC+BPF_TAX, 0),
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ size_t i;
+ bpfjit_func_t code;
+ uint8_t pkt[8] = { 10, 20, 30, 40, 50, 60, 70, 80 };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 1; i <= sizeof(pkt); i++) {
+ //ATF_CHECK(bpf_filter(insns, pkt, i, i) == 10 * i);
+ ATF_CHECK(jitcall(code, pkt, i, i) == 10 * i);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_ld_ind_x_overflow2);
+ATF_TC_HEAD(bpfjit_ld_ind_x_overflow2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LD+BPF_IND with overflow in X+4");
+}
+
+ATF_TC_BODY(bpfjit_ld_ind_x_overflow2, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_LEN, 0),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, UINT32_C(0xffffffff)),
+ BPF_STMT(BPF_ST, 3),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 3),
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ size_t i;
+ bpfjit_func_t code;
+ uint8_t pkt[8] = { 10, 20, 30, 40, 50, 60, 70, 80 };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 1; i <= sizeof(pkt); i++) {
+ //ATF_CHECK(bpf_filter(insns, pkt, i, i) == 10 * i);
+ ATF_CHECK(jitcall(code, pkt, i, i) == 10 * i);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_ld_len);
+ATF_TC_HEAD(bpfjit_ld_len, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LD+BPF_W+BPF_LEN");
+}
+
+ATF_TC_BODY(bpfjit_ld_len, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ size_t i;
+ bpfjit_func_t code;
+ uint8_t pkt[32]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 0; i < sizeof(pkt); i++)
+ ATF_CHECK(jitcall(code, pkt, i, 1) == i);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_ld_imm);
+ATF_TC_HEAD(bpfjit_ld_imm, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LD+BPF_IMM");
+}
+
+ATF_TC_BODY(bpfjit_ld_imm, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == UINT32_MAX);
+}
+
+ATF_TC(bpfjit_ldx_imm1);
+ATF_TC_HEAD(bpfjit_ldx_imm1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LDX+BPF_IMM");
+}
+
+ATF_TC_BODY(bpfjit_ldx_imm1, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_MAX - 5),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == UINT32_MAX - 5);
+}
+
+ATF_TC(bpfjit_ldx_imm2);
+ATF_TC_HEAD(bpfjit_ldx_imm2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LDX+BPF_IMM");
+}
+
+ATF_TC_BODY(bpfjit_ldx_imm2, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 5),
+ BPF_STMT(BPF_LD+BPF_IMM, 5),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == UINT32_MAX);
+}
+
+ATF_TC(bpfjit_ldx_len1);
+ATF_TC_HEAD(bpfjit_ldx_len1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LDX+BPF_LEN");
+}
+
+ATF_TC_BODY(bpfjit_ldx_len1, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ size_t i;
+ bpfjit_func_t code;
+ uint8_t pkt[5]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 1; i < sizeof(pkt); i++) {
+ ATF_CHECK(jitcall(code, pkt, i, 1) == i);
+ ATF_CHECK(jitcall(code, pkt, i + 1, i) == i + 1);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_ldx_len2);
+ATF_TC_HEAD(bpfjit_ldx_len2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LDX+BPF_LEN");
+}
+
+ATF_TC_BODY(bpfjit_ldx_len2, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_LD+BPF_IMM, 5),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 1, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[5]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 5, 1) == UINT32_MAX);
+ ATF_CHECK(jitcall(code, pkt, 6, 5) == 7);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_ldx_msh);
+ATF_TC_HEAD(bpfjit_ldx_msh, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_LDX+BPF_MSH");
+}
+
+ATF_TC_BODY(bpfjit_ldx_msh, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[2] = { 0, 0x7a };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 2) == 40);
+}
+
+ATF_TC(bpfjit_misc_tax);
+ATF_TC_HEAD(bpfjit_misc_tax, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_MISC+BPF_TAX");
+}
+
+ATF_TC_BODY(bpfjit_misc_tax, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 3),
+ BPF_STMT(BPF_MISC+BPF_TAX, 0),
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 2),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[6] = { 0, 11, 22, 33, 44, 55 };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 6) == 55);
+}
+
+ATF_TC(bpfjit_misc_txa);
+ATF_TC_HEAD(bpfjit_misc_txa, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_MISC+BPF_TXA");
+}
+
+ATF_TC_BODY(bpfjit_misc_txa, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 391),
+ BPF_STMT(BPF_MISC+BPF_TXA, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 391);
+}
+
+ATF_TC(bpfjit_st1);
+ATF_TC_HEAD(bpfjit_st1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ST");
+}
+
+ATF_TC_BODY(bpfjit_st1, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_ST, 0),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_LD+BPF_MEM, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ size_t i;
+ bpfjit_func_t code;
+ uint8_t pkt[16]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 1; i <= sizeof(pkt); i++)
+ ATF_CHECK(jitcall(code, pkt, i, sizeof(pkt)) == i);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_st2);
+ATF_TC_HEAD(bpfjit_st2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ST");
+}
+
+ATF_TC_BODY(bpfjit_st2, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_ST, 0),
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_ST, BPF_MEMWORDS-1),
+ BPF_STMT(BPF_LD+BPF_MEM, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0);
+}
+
+ATF_TC(bpfjit_st3);
+ATF_TC_HEAD(bpfjit_st3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ST");
+}
+
+ATF_TC_BODY(bpfjit_st3, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_ST, 0),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 100),
+ BPF_STMT(BPF_ST, BPF_MEMWORDS-1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 200),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 301, 2, 0),
+ BPF_STMT(BPF_LD+BPF_MEM, BPF_MEMWORDS-1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ BPF_STMT(BPF_LD+BPF_MEM, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[2]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ ATF_REQUIRE(BPF_MEMWORDS > 1);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 1);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 102);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_st4);
+ATF_TC_HEAD(bpfjit_st4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ST");
+}
+
+ATF_TC_BODY(bpfjit_st4, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_ST, 5),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 100),
+ BPF_STMT(BPF_ST, BPF_MEMWORDS-1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 200),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 301, 2, 0),
+ BPF_STMT(BPF_LD+BPF_MEM, BPF_MEMWORDS-1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ BPF_STMT(BPF_LD+BPF_MEM, 5),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[2]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ ATF_REQUIRE(BPF_MEMWORDS > 6);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 1);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 102);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_st5);
+ATF_TC_HEAD(bpfjit_st5, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_ST");
+}
+
+ATF_TC_BODY(bpfjit_st5, tc)
+{
+ struct bpf_insn insns[5*BPF_MEMWORDS+2];
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ size_t k;
+ bpfjit_func_t code;
+ uint8_t pkt[BPF_MEMWORDS]; /* the program doesn't read any data */
+
+ memset(insns, 0, sizeof(insns));
+
+ /* for each k do M[k] = k */
+ for (k = 0; k < BPF_MEMWORDS; k++) {
+ insns[2*k].code = BPF_LD+BPF_IMM;
+ insns[2*k].k = 3*k;
+ insns[2*k+1].code = BPF_ST;
+ insns[2*k+1].k = k;
+ }
+
+ /* load wirelen into A */
+ insns[2*BPF_MEMWORDS].code = BPF_LD+BPF_W+BPF_LEN;
+
+ /* for each k, if (A == k + 1) return M[k] */
+ for (k = 0; k < BPF_MEMWORDS; k++) {
+ insns[2*BPF_MEMWORDS+3*k+1].code = BPF_JMP+BPF_JEQ+BPF_K;
+ insns[2*BPF_MEMWORDS+3*k+1].k = k+1;
+ insns[2*BPF_MEMWORDS+3*k+1].jt = 0;
+ insns[2*BPF_MEMWORDS+3*k+1].jf = 2;
+ insns[2*BPF_MEMWORDS+3*k+2].code = BPF_LD+BPF_MEM;
+ insns[2*BPF_MEMWORDS+3*k+2].k = k;
+ insns[2*BPF_MEMWORDS+3*k+3].code = BPF_RET+BPF_A;
+ insns[2*BPF_MEMWORDS+3*k+3].k = 0;
+ }
+
+ insns[5*BPF_MEMWORDS+1].code = BPF_RET+BPF_K;
+ insns[5*BPF_MEMWORDS+1].k = UINT32_MAX;
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (k = 1; k <= sizeof(pkt); k++)
+ ATF_CHECK(jitcall(code, pkt, k, k) == 3*(k-1));
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_stx1);
+ATF_TC_HEAD(bpfjit_stx1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_STX");
+}
+
+ATF_TC_BODY(bpfjit_stx1, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_STX, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ size_t i;
+ bpfjit_func_t code;
+ uint8_t pkt[16]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 1; i <= sizeof(pkt); i++)
+ ATF_CHECK(jitcall(code, pkt, i, sizeof(pkt)) == i);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_stx2);
+ATF_TC_HEAD(bpfjit_stx2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_STX");
+}
+
+ATF_TC_BODY(bpfjit_stx2, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_ST, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_STX, BPF_MEMWORDS-1),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0),
+ BPF_STMT(BPF_MISC+BPF_TXA, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == 0);
+}
+
+ATF_TC(bpfjit_stx3);
+ATF_TC_HEAD(bpfjit_stx3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_STX");
+}
+
+ATF_TC_BODY(bpfjit_stx3, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_STX, 6),
+ BPF_STMT(BPF_ST, 1),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_LEN, 0),
+ BPF_STMT(BPF_STX, 5),
+ BPF_STMT(BPF_STX, 2),
+ BPF_STMT(BPF_STX, 3),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 2),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 3),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 5),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 6),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ size_t i;
+ bpfjit_func_t code;
+ uint8_t pkt[16]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 1; i <= sizeof(pkt); i++)
+ ATF_CHECK(jitcall(code, pkt, i, sizeof(pkt)) == 3 * i);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_stx4);
+ATF_TC_HEAD(bpfjit_stx4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation of BPF_STX");
+}
+
+ATF_TC_BODY(bpfjit_stx4, tc)
+{
+ struct bpf_insn insns[5*BPF_MEMWORDS+2];
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ size_t k;
+ bpfjit_func_t code;
+ uint8_t pkt[BPF_MEMWORDS]; /* the program doesn't read any data */
+
+ memset(insns, 0, sizeof(insns));
+
+ /* for each k do M[k] = k */
+ for (k = 0; k < BPF_MEMWORDS; k++) {
+ insns[2*k].code = BPF_LDX+BPF_W+BPF_IMM;
+ insns[2*k].k = 3*k;
+ insns[2*k+1].code = BPF_STX;
+ insns[2*k+1].k = k;
+ }
+
+ /* load wirelen into A */
+ insns[2*BPF_MEMWORDS].code = BPF_LD+BPF_W+BPF_LEN;
+
+ /* for each k, if (A == k + 1) return M[k] */
+ for (k = 0; k < BPF_MEMWORDS; k++) {
+ insns[2*BPF_MEMWORDS+3*k+1].code = BPF_JMP+BPF_JEQ+BPF_K;
+ insns[2*BPF_MEMWORDS+3*k+1].k = k+1;
+ insns[2*BPF_MEMWORDS+3*k+1].jt = 0;
+ insns[2*BPF_MEMWORDS+3*k+1].jf = 2;
+ insns[2*BPF_MEMWORDS+3*k+2].code = BPF_LD+BPF_MEM;
+ insns[2*BPF_MEMWORDS+3*k+2].k = k;
+ insns[2*BPF_MEMWORDS+3*k+3].code = BPF_RET+BPF_A;
+ insns[2*BPF_MEMWORDS+3*k+3].k = 0;
+ }
+
+ insns[5*BPF_MEMWORDS+1].code = BPF_RET+BPF_K;
+ insns[5*BPF_MEMWORDS+1].k = UINT32_MAX;
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (k = 1; k <= sizeof(pkt); k++)
+ ATF_CHECK(jitcall(code, pkt, k, k) == 3*(k-1));
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_opt_ld_abs_1);
+ATF_TC_HEAD(bpfjit_opt_ld_abs_1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation with length optimization "
+ "applied to BPF_LD+BPF_ABS");
+}
+
+ATF_TC_BODY(bpfjit_opt_ld_abs_1, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x800, 0, 8),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 26),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 2),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 3, 4),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 3),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ size_t i, j;
+ bpfjit_func_t code;
+ uint8_t pkt[2][34] = {
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x0f,
+ 0x80, 0x03, 0x70, 0x23
+ },
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x23,
+ 0x80, 0x03, 0x70, 0x0f
+ }
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 0; i < 2; i++) {
+ for (j = 1; j < sizeof(pkt[i]); j++)
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == 0);
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == UINT32_MAX);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_opt_ld_abs_2);
+ATF_TC_HEAD(bpfjit_opt_ld_abs_2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation with length optimization "
+ "applied to BPF_LD+BPF_ABS");
+}
+
+ATF_TC_BODY(bpfjit_opt_ld_abs_2, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 26),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 2),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 3, 6),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 5),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x800, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ size_t i, j;
+ bpfjit_func_t code;
+ uint8_t pkt[2][34] = {
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x0f,
+ 0x80, 0x03, 0x70, 0x23
+ },
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x23,
+ 0x80, 0x03, 0x70, 0x0f
+ }
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 0; i < 2; i++) {
+ for (j = 1; j < sizeof(pkt[i]); j++)
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == 0);
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == UINT32_MAX);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_opt_ld_abs_3);
+ATF_TC_HEAD(bpfjit_opt_ld_abs_3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation with length optimization "
+ "applied to BPF_LD+BPF_ABS");
+}
+
+ATF_TC_BODY(bpfjit_opt_ld_abs_3, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 2),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 26),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 3, 6),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 5),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 26),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x800, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ size_t i, j;
+ bpfjit_func_t code;
+ uint8_t pkt[2][34] = {
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x0f,
+ 0x80, 0x03, 0x70, 0x23
+ },
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x23,
+ 0x80, 0x03, 0x70, 0x0f
+ }
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 0; i < 2; i++) {
+ for (j = 1; j < sizeof(pkt[i]); j++)
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == 0);
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == UINT32_MAX);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_opt_ld_ind_1);
+ATF_TC_HEAD(bpfjit_opt_ld_ind_1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation with length optimization "
+ "applied to BPF_LD+BPF_IND");
+}
+
+ATF_TC_BODY(bpfjit_opt_ld_ind_1, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 12),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 0),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x800, 0, 8),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 14),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 2),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 18),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 3, 4),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 3),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 18),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ size_t i, j;
+ bpfjit_func_t code;
+ uint8_t pkt[2][34] = {
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x0f,
+ 0x80, 0x03, 0x70, 0x23
+ },
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x23,
+ 0x80, 0x03, 0x70, 0x0f
+ }
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 0; i < 2; i++) {
+ for (j = 1; j < sizeof(pkt[i]); j++)
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == 0);
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == UINT32_MAX);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_opt_ld_ind_2);
+ATF_TC_HEAD(bpfjit_opt_ld_ind_2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation with length optimization "
+ "applied to BPF_LD+BPF_IND");
+}
+
+ATF_TC_BODY(bpfjit_opt_ld_ind_2, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 26),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 2),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 30),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 3, 6),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 5),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 30),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x800, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ size_t i, j;
+ bpfjit_func_t code;
+ uint8_t pkt[2][34] = {
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x0f,
+ 0x80, 0x03, 0x70, 0x23
+ },
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x23,
+ 0x80, 0x03, 0x70, 0x0f
+ }
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 0; i < 2; i++) {
+ for (j = 1; j < sizeof(pkt[i]); j++)
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == 0);
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == UINT32_MAX);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_opt_ld_ind_3);
+ATF_TC_HEAD(bpfjit_opt_ld_ind_3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation with length optimization "
+ "applied to BPF_LD+BPF_IND");
+}
+
+ATF_TC_BODY(bpfjit_opt_ld_ind_3, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 15),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 15),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 2),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 11),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 3, 7),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 6),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 11),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 4),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x800, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ size_t i, j;
+ bpfjit_func_t code;
+ uint8_t pkt[2][34] = {
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x0f,
+ 0x80, 0x03, 0x70, 0x23
+ },
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x23,
+ 0x80, 0x03, 0x70, 0x0f
+ }
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 0; i < 2; i++) {
+ for (j = 1; j < sizeof(pkt[i]); j++)
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == 0);
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == UINT32_MAX);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_opt_ld_ind_4);
+ATF_TC_HEAD(bpfjit_opt_ld_ind_4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test JIT compilation with length optimization "
+ "applied to BPF_LD+BPF_IND");
+}
+
+ATF_TC_BODY(bpfjit_opt_ld_ind_4, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 11),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 19),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 2),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 15),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 3, 7),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 6),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 15),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 4),
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x800, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ size_t i, j;
+ bpfjit_func_t code;
+ uint8_t pkt[2][34] = {
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x0f,
+ 0x80, 0x03, 0x70, 0x23
+ },
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0x08, 0x00,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
+ 0x80, 0x03, 0x70, 0x23,
+ 0x80, 0x03, 0x70, 0x0f
+ }
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ for (i = 0; i < 2; i++) {
+ for (j = 1; j < sizeof(pkt[i]); j++)
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == 0);
+ ATF_CHECK(jitcall(code, pkt[i], j, j) == UINT32_MAX);
+ }
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_abc_ja);
+ATF_TC_HEAD(bpfjit_abc_ja, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test ABC optimization with a single BPF_JMP+BPF_JA");
+}
+
+ATF_TC_BODY(bpfjit_abc_ja, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 3), /* min. length 4 */
+ BPF_STMT(BPF_JMP+BPF_JA, 2),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, UINT32_MAX - 1),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 2), /* min. length 6 */
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 6),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 7),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[6] = {0, 0, /* UINT32_MAX: */ 255, 255, 255, 255};
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == UINT32_MAX);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_abc_ja_over);
+ATF_TC_HEAD(bpfjit_abc_ja_over, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test ABC optimization when BPF_JMP+BPF_JA jumps over all loads");
+}
+
+ATF_TC_BODY(bpfjit_abc_ja_over, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_JMP+BPF_JA, 2),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 3),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 4),
+ BPF_STMT(BPF_RET+BPF_K, 1),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 5),
+ BPF_STMT(BPF_RET+BPF_K, 2),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 6),
+ BPF_STMT(BPF_RET+BPF_K, 3),
+ };
+
+ uint8_t pkt[1]; /* the program doesn't read any data */
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+ ATF_CHECK(exec_prog(insns, insn_count, pkt, 1) == UINT32_MAX);
+}
+
+ATF_TC(bpfjit_abc_ld_chain);
+ATF_TC_HEAD(bpfjit_abc_ld_chain, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test ABC optimization of a chain of BPF_LD instructions "
+ "with exits leading to a single BPF_RET");
+}
+
+ATF_TC_BODY(bpfjit_abc_ld_chain, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 3), /* min. length 4 */
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 8, 0, 4),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), /* min. length 6 */
+ BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 7, 0, 2),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 6), /* min. length 10 */
+ BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 6, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 123456789),
+ BPF_STMT(BPF_RET+BPF_K, 987654321),
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[10] = {};
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ /* Packet is too short. */
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+
+ /* !(pkt[3] == 8) => return 123456789 */
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 123456789);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 123456789);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 123456789);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 123456789);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 123456789);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 123456789);
+
+ /* !(pkt[4:2] >= 7) => too short or return 123456789 */
+ pkt[3] = 8;
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 123456789);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 123456789);
+
+ /* !(pkt[6:4] > 6) => too short or return 987654321 */
+ pkt[4] = pkt[5] = 1;
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 0);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 0);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 0);
+ ATF_CHECK(jitcall(code, pkt, 10, 10) == 987654321);
+
+ /* (pkt[6:4] > 6) => too short or return 123456789 */
+ pkt[6] = pkt[7] = pkt[8] = pkt[9] = 1;
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 0);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 0);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 0);
+ ATF_CHECK(jitcall(code, pkt, 10, 10) == 123456789);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_examples_1);
+ATF_TC_HEAD(bpfjit_examples_1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test the first example from bpf(4) - "
+ "accept Reverse ARP requests");
+}
+
+ATF_TC_BODY(bpfjit_examples_1, tc)
+{
+ /*
+ * The following filter is taken from the Reverse ARP
+ * Daemon. It accepts only Reverse ARP requests.
+ */
+ struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8035, 0, 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 3, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, 42),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[22] = {};
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ /* Packet is too short. */
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 0);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 0);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 0);
+ ATF_CHECK(jitcall(code, pkt, 10, 10) == 0);
+ ATF_CHECK(jitcall(code, pkt, 11, 11) == 0);
+ ATF_CHECK(jitcall(code, pkt, 12, 12) == 0);
+ ATF_CHECK(jitcall(code, pkt, 13, 13) == 0);
+ ATF_CHECK(jitcall(code, pkt, 14, 14) == 0);
+ ATF_CHECK(jitcall(code, pkt, 15, 15) == 0);
+ ATF_CHECK(jitcall(code, pkt, 16, 16) == 0);
+ ATF_CHECK(jitcall(code, pkt, 17, 17) == 0);
+ ATF_CHECK(jitcall(code, pkt, 18, 18) == 0);
+ ATF_CHECK(jitcall(code, pkt, 19, 19) == 0);
+ ATF_CHECK(jitcall(code, pkt, 20, 20) == 0);
+ ATF_CHECK(jitcall(code, pkt, 21, 21) == 0);
+
+ /* The packet doesn't match. */
+ ATF_CHECK(jitcall(code, pkt, 22, 22) == 0);
+
+ /* Still no match after setting the protocol field. */
+ pkt[12] = 0x80; pkt[13] = 0x35;
+ ATF_CHECK(jitcall(code, pkt, 22, 22) == 0);
+
+ /* Set RARP message type. */
+ pkt[21] = 3;
+ ATF_CHECK(jitcall(code, pkt, 22, 22) == 42);
+
+ /* Packet is too short. */
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 0);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 0);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 0);
+ ATF_CHECK(jitcall(code, pkt, 10, 10) == 0);
+ ATF_CHECK(jitcall(code, pkt, 11, 11) == 0);
+ ATF_CHECK(jitcall(code, pkt, 12, 12) == 0);
+ ATF_CHECK(jitcall(code, pkt, 13, 13) == 0);
+ ATF_CHECK(jitcall(code, pkt, 14, 14) == 0);
+ ATF_CHECK(jitcall(code, pkt, 15, 15) == 0);
+ ATF_CHECK(jitcall(code, pkt, 16, 16) == 0);
+ ATF_CHECK(jitcall(code, pkt, 17, 17) == 0);
+ ATF_CHECK(jitcall(code, pkt, 18, 18) == 0);
+ ATF_CHECK(jitcall(code, pkt, 19, 19) == 0);
+ ATF_CHECK(jitcall(code, pkt, 20, 20) == 0);
+ ATF_CHECK(jitcall(code, pkt, 21, 21) == 0);
+
+ /* Change RARP message type. */
+ pkt[20] = 3;
+ ATF_CHECK(jitcall(code, pkt, 22, 22) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_examples_2);
+ATF_TC_HEAD(bpfjit_examples_2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test the second example from bpf(4) - "
+ "accept IP packets between two specified hosts");
+}
+
+ATF_TC_BODY(bpfjit_examples_2, tc)
+{
+ /*
+ * This filter accepts only IP packets between host 128.3.112.15
+ * and 128.3.112.35.
+ */
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x0800, 0, 8),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 26),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 2),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 3, 4),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x80037023, 0, 3),
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 30),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x8003700f, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[34] = {};
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ /* Packet is too short. */
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 0);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 0);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 0);
+ ATF_CHECK(jitcall(code, pkt, 10, 10) == 0);
+ ATF_CHECK(jitcall(code, pkt, 11, 11) == 0);
+ ATF_CHECK(jitcall(code, pkt, 12, 12) == 0);
+ ATF_CHECK(jitcall(code, pkt, 13, 13) == 0);
+ ATF_CHECK(jitcall(code, pkt, 14, 14) == 0);
+ ATF_CHECK(jitcall(code, pkt, 15, 15) == 0);
+ ATF_CHECK(jitcall(code, pkt, 16, 16) == 0);
+ ATF_CHECK(jitcall(code, pkt, 17, 17) == 0);
+ ATF_CHECK(jitcall(code, pkt, 18, 18) == 0);
+ ATF_CHECK(jitcall(code, pkt, 19, 19) == 0);
+ ATF_CHECK(jitcall(code, pkt, 20, 20) == 0);
+ ATF_CHECK(jitcall(code, pkt, 21, 21) == 0);
+ ATF_CHECK(jitcall(code, pkt, 22, 22) == 0);
+ ATF_CHECK(jitcall(code, pkt, 23, 23) == 0);
+ ATF_CHECK(jitcall(code, pkt, 24, 24) == 0);
+ ATF_CHECK(jitcall(code, pkt, 25, 25) == 0);
+ ATF_CHECK(jitcall(code, pkt, 26, 26) == 0);
+ ATF_CHECK(jitcall(code, pkt, 27, 27) == 0);
+ ATF_CHECK(jitcall(code, pkt, 28, 28) == 0);
+ ATF_CHECK(jitcall(code, pkt, 29, 29) == 0);
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == 0);
+ ATF_CHECK(jitcall(code, pkt, 31, 31) == 0);
+ ATF_CHECK(jitcall(code, pkt, 32, 32) == 0);
+ ATF_CHECK(jitcall(code, pkt, 33, 33) == 0);
+
+ /* The packet doesn't match. */
+ ATF_CHECK(jitcall(code, pkt, 34, 34) == 0);
+
+ /* Still no match after setting the protocol field. */
+ pkt[12] = 8;
+ ATF_CHECK(jitcall(code, pkt, 34, 34) == 0);
+
+ pkt[26] = 128; pkt[27] = 3; pkt[28] = 112; pkt[29] = 15;
+ ATF_CHECK(jitcall(code, pkt, 34, 34) == 0);
+
+ pkt[30] = 128; pkt[31] = 3; pkt[32] = 112; pkt[33] = 35;
+ ATF_CHECK(jitcall(code, pkt, 34, 34) == UINT32_MAX);
+
+ /* Swap the ip addresses. */
+ pkt[26] = 128; pkt[27] = 3; pkt[28] = 112; pkt[29] = 35;
+ ATF_CHECK(jitcall(code, pkt, 34, 34) == 0);
+
+ pkt[30] = 128; pkt[31] = 3; pkt[32] = 112; pkt[33] = 15;
+ ATF_CHECK(jitcall(code, pkt, 34, 34) == UINT32_MAX);
+
+ /* Packet is too short. */
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 0);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 0);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 0);
+ ATF_CHECK(jitcall(code, pkt, 10, 10) == 0);
+ ATF_CHECK(jitcall(code, pkt, 11, 11) == 0);
+ ATF_CHECK(jitcall(code, pkt, 12, 12) == 0);
+ ATF_CHECK(jitcall(code, pkt, 13, 13) == 0);
+ ATF_CHECK(jitcall(code, pkt, 14, 14) == 0);
+ ATF_CHECK(jitcall(code, pkt, 15, 15) == 0);
+ ATF_CHECK(jitcall(code, pkt, 16, 16) == 0);
+ ATF_CHECK(jitcall(code, pkt, 17, 17) == 0);
+ ATF_CHECK(jitcall(code, pkt, 18, 18) == 0);
+ ATF_CHECK(jitcall(code, pkt, 19, 19) == 0);
+ ATF_CHECK(jitcall(code, pkt, 20, 20) == 0);
+ ATF_CHECK(jitcall(code, pkt, 21, 21) == 0);
+ ATF_CHECK(jitcall(code, pkt, 22, 22) == 0);
+ ATF_CHECK(jitcall(code, pkt, 23, 23) == 0);
+ ATF_CHECK(jitcall(code, pkt, 24, 24) == 0);
+ ATF_CHECK(jitcall(code, pkt, 25, 25) == 0);
+ ATF_CHECK(jitcall(code, pkt, 26, 26) == 0);
+ ATF_CHECK(jitcall(code, pkt, 27, 27) == 0);
+ ATF_CHECK(jitcall(code, pkt, 28, 28) == 0);
+ ATF_CHECK(jitcall(code, pkt, 29, 29) == 0);
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == 0);
+ ATF_CHECK(jitcall(code, pkt, 31, 31) == 0);
+ ATF_CHECK(jitcall(code, pkt, 32, 32) == 0);
+ ATF_CHECK(jitcall(code, pkt, 33, 33) == 0);
+
+ /* Change the protocol field. */
+ pkt[13] = 8;
+ ATF_CHECK(jitcall(code, pkt, 34, 34) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_examples_3);
+ATF_TC_HEAD(bpfjit_examples_3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test the third example from bpf(4) - "
+ "accept TCP finger packets");
+}
+
+ATF_TC_BODY(bpfjit_examples_3, tc)
+{
+ /*
+ * This filter returns only TCP finger packets.
+ */
+ struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x0800, 0, 10),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 23),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 6, 0, 8),
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 6, 0),
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 14),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 14),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 2, 0),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 16),
+ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 79, 0, 1),
+ BPF_STMT(BPF_RET+BPF_K, UINT32_MAX),
+ BPF_STMT(BPF_RET+BPF_K, 0),
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[30] = {};
+
+ /* Set IP fragment offset to non-zero. */
+ pkt[20] = 1; pkt[21] = 1;
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ /* Packet is too short. */
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 0);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 0);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 0);
+ ATF_CHECK(jitcall(code, pkt, 10, 10) == 0);
+ ATF_CHECK(jitcall(code, pkt, 11, 11) == 0);
+ ATF_CHECK(jitcall(code, pkt, 12, 12) == 0);
+ ATF_CHECK(jitcall(code, pkt, 13, 13) == 0);
+ ATF_CHECK(jitcall(code, pkt, 14, 14) == 0);
+ ATF_CHECK(jitcall(code, pkt, 15, 15) == 0);
+ ATF_CHECK(jitcall(code, pkt, 16, 16) == 0);
+ ATF_CHECK(jitcall(code, pkt, 17, 17) == 0);
+ ATF_CHECK(jitcall(code, pkt, 18, 18) == 0);
+ ATF_CHECK(jitcall(code, pkt, 19, 19) == 0);
+ ATF_CHECK(jitcall(code, pkt, 20, 20) == 0);
+ ATF_CHECK(jitcall(code, pkt, 21, 21) == 0);
+ ATF_CHECK(jitcall(code, pkt, 22, 22) == 0);
+ ATF_CHECK(jitcall(code, pkt, 23, 23) == 0);
+ ATF_CHECK(jitcall(code, pkt, 24, 24) == 0);
+ ATF_CHECK(jitcall(code, pkt, 25, 25) == 0);
+ ATF_CHECK(jitcall(code, pkt, 26, 26) == 0);
+ ATF_CHECK(jitcall(code, pkt, 27, 27) == 0);
+ ATF_CHECK(jitcall(code, pkt, 28, 28) == 0);
+ ATF_CHECK(jitcall(code, pkt, 29, 29) == 0);
+
+ /* The packet doesn't match. */
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == 0);
+
+ /* Still no match after setting the protocol field. */
+ pkt[12] = 8;
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == 0);
+
+ /* Get one step closer to the match. */
+ pkt[23] = 6;
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == 0);
+
+ /* Set IP fragment offset to zero. */
+ pkt[20] = 0x20; pkt[21] = 0;
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == 0);
+
+ /* Set IP header length to 12. */
+ pkt[14] = 0xd3;
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == 0);
+
+ /* Match one branch of the program. */
+ pkt[27] = 79;
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == UINT32_MAX);
+
+ /* Match the other branch of the program. */
+ pkt[29] = 79; pkt[27] = 0;
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == UINT32_MAX);
+
+ /* Packet is too short. */
+ ATF_CHECK(jitcall(code, pkt, 1, 1) == 0);
+ ATF_CHECK(jitcall(code, pkt, 2, 2) == 0);
+ ATF_CHECK(jitcall(code, pkt, 3, 3) == 0);
+ ATF_CHECK(jitcall(code, pkt, 4, 4) == 0);
+ ATF_CHECK(jitcall(code, pkt, 5, 5) == 0);
+ ATF_CHECK(jitcall(code, pkt, 6, 6) == 0);
+ ATF_CHECK(jitcall(code, pkt, 7, 7) == 0);
+ ATF_CHECK(jitcall(code, pkt, 8, 8) == 0);
+ ATF_CHECK(jitcall(code, pkt, 9, 9) == 0);
+ ATF_CHECK(jitcall(code, pkt, 10, 10) == 0);
+ ATF_CHECK(jitcall(code, pkt, 11, 11) == 0);
+ ATF_CHECK(jitcall(code, pkt, 12, 12) == 0);
+ ATF_CHECK(jitcall(code, pkt, 13, 13) == 0);
+ ATF_CHECK(jitcall(code, pkt, 14, 14) == 0);
+ ATF_CHECK(jitcall(code, pkt, 15, 15) == 0);
+ ATF_CHECK(jitcall(code, pkt, 16, 16) == 0);
+ ATF_CHECK(jitcall(code, pkt, 17, 17) == 0);
+ ATF_CHECK(jitcall(code, pkt, 18, 18) == 0);
+ ATF_CHECK(jitcall(code, pkt, 19, 19) == 0);
+ ATF_CHECK(jitcall(code, pkt, 20, 20) == 0);
+ ATF_CHECK(jitcall(code, pkt, 21, 21) == 0);
+ ATF_CHECK(jitcall(code, pkt, 22, 22) == 0);
+ ATF_CHECK(jitcall(code, pkt, 23, 23) == 0);
+ ATF_CHECK(jitcall(code, pkt, 24, 24) == 0);
+ ATF_CHECK(jitcall(code, pkt, 25, 25) == 0);
+ ATF_CHECK(jitcall(code, pkt, 26, 26) == 0);
+ ATF_CHECK(jitcall(code, pkt, 27, 27) == 0);
+ ATF_CHECK(jitcall(code, pkt, 28, 28) == 0);
+ ATF_CHECK(jitcall(code, pkt, 29, 29) == 0);
+
+ /* Set IP header length to 16. Packet is too short. */
+ pkt[14] = 4;
+ ATF_CHECK(jitcall(code, pkt, 30, 30) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_cop_no_ctx);
+ATF_TC_HEAD(bpfjit_cop_no_ctx, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test that BPF_MISC|BPF_COP "
+ "instruction can't be accepted without a context");
+}
+
+ATF_TC_BODY(bpfjit_cop_no_ctx, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_MISC+BPF_COP, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7)
+ };
+
+ bpfjit_func_t code;
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(!prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_CHECK(code == NULL);
+}
+
+ATF_TC(bpfjit_copx_no_ctx);
+ATF_TC_HEAD(bpfjit_copx_no_ctx, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test that BPF_MISC|BPF_COPX "
+ "instruction can't be accepted without a context");
+}
+
+ATF_TC_BODY(bpfjit_copx_no_ctx, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_MISC+BPF_COPX, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7)
+ };
+
+ bpfjit_func_t code;
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(!prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_CHECK(code == NULL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ /*
+ * For every new test please also add a similar test
+ * to ../../lib/libbpfjit/t_bpfjit.c
+ */
+ ATF_TP_ADD_TC(tp, bpfjit_empty);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_add_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_sub_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_mul_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div0_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div1_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div2_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div4_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div10_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div10000_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div7609801_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div80000000_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_and_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_or_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_lsh_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_lsh0_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_rsh_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_rsh0_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_modulo_k);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_add_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_sub_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_mul_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div0_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div1_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div2_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div4_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div10_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div10000_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div7609801_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_div80000000_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_and_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_or_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_lsh_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_lsh0_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_rsh_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_rsh0_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_modulo_x);
+ ATF_TP_ADD_TC(tp, bpfjit_alu_neg);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_ja);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_jgt_k);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_jge_k);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_jeq_k);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_jset_k);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_modulo_k);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_jgt_x);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_jge_x);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_jeq_x);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_jset_x);
+ ATF_TP_ADD_TC(tp, bpfjit_jmp_modulo_x);
+ ATF_TP_ADD_TC(tp, bpfjit_ld_abs);
+ ATF_TP_ADD_TC(tp, bpfjit_ld_abs_k_overflow);
+ ATF_TP_ADD_TC(tp, bpfjit_ld_ind);
+ ATF_TP_ADD_TC(tp, bpfjit_ld_ind_k_overflow);
+ ATF_TP_ADD_TC(tp, bpfjit_ld_ind_x_overflow1);
+ ATF_TP_ADD_TC(tp, bpfjit_ld_ind_x_overflow2);
+ ATF_TP_ADD_TC(tp, bpfjit_ld_len);
+ ATF_TP_ADD_TC(tp, bpfjit_ld_imm);
+ ATF_TP_ADD_TC(tp, bpfjit_ldx_imm1);
+ ATF_TP_ADD_TC(tp, bpfjit_ldx_imm2);
+ ATF_TP_ADD_TC(tp, bpfjit_ldx_len1);
+ ATF_TP_ADD_TC(tp, bpfjit_ldx_len2);
+ ATF_TP_ADD_TC(tp, bpfjit_ldx_msh);
+ ATF_TP_ADD_TC(tp, bpfjit_misc_tax);
+ ATF_TP_ADD_TC(tp, bpfjit_misc_txa);
+ ATF_TP_ADD_TC(tp, bpfjit_st1);
+ ATF_TP_ADD_TC(tp, bpfjit_st2);
+ ATF_TP_ADD_TC(tp, bpfjit_st3);
+ ATF_TP_ADD_TC(tp, bpfjit_st4);
+ ATF_TP_ADD_TC(tp, bpfjit_st5);
+ ATF_TP_ADD_TC(tp, bpfjit_stx1);
+ ATF_TP_ADD_TC(tp, bpfjit_stx2);
+ ATF_TP_ADD_TC(tp, bpfjit_stx3);
+ ATF_TP_ADD_TC(tp, bpfjit_stx4);
+ ATF_TP_ADD_TC(tp, bpfjit_opt_ld_abs_1);
+ ATF_TP_ADD_TC(tp, bpfjit_opt_ld_abs_2);
+ ATF_TP_ADD_TC(tp, bpfjit_opt_ld_abs_3);
+ ATF_TP_ADD_TC(tp, bpfjit_opt_ld_ind_1);
+ ATF_TP_ADD_TC(tp, bpfjit_opt_ld_ind_2);
+ ATF_TP_ADD_TC(tp, bpfjit_opt_ld_ind_3);
+ ATF_TP_ADD_TC(tp, bpfjit_opt_ld_ind_4);
+ ATF_TP_ADD_TC(tp, bpfjit_abc_ja);
+ ATF_TP_ADD_TC(tp, bpfjit_abc_ja_over);
+ ATF_TP_ADD_TC(tp, bpfjit_abc_ld_chain);
+ ATF_TP_ADD_TC(tp, bpfjit_examples_1);
+ ATF_TP_ADD_TC(tp, bpfjit_examples_2);
+ ATF_TP_ADD_TC(tp, bpfjit_examples_3);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_no_ctx);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_no_ctx);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/bpfjit/t_cop.c b/contrib/netbsd-tests/net/bpfjit/t_cop.c
new file mode 100644
index 0000000..5a007e6
--- /dev/null
+++ b/contrib/netbsd-tests/net/bpfjit/t_cop.c
@@ -0,0 +1,757 @@
+/* $NetBSD: t_cop.c,v 1.3 2014/07/13 21:35:33 alnsn Exp $ */
+
+/*-
+ * Copyright (c) 2014 Alexander Nasonov.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_cop.c,v 1.3 2014/07/13 21:35:33 alnsn Exp $");
+
+#include <stdint.h>
+#include <string.h>
+
+#define __BPF_PRIVATE
+#include <net/bpf.h>
+#include <net/bpfjit.h>
+
+#include "../../net/bpf/h_bpf.h"
+
+/* XXX: atf-c.h has collisions with mbuf */
+#undef m_type
+#undef m_data
+#include <atf-c.h>
+
+#include "../../h_macros.h"
+
+static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
+static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
+static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
+static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
+static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
+
+static const bpf_copfunc_t copfuncs[] = {
+ &retA,
+ &retBL,
+ &retWL,
+ &retNF,
+ &setARG
+};
+
+static const bpf_ctx_t ctx = {
+ .copfuncs = copfuncs,
+ .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
+ .extwords = 0
+};
+
+static uint32_t
+retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
+{
+
+ return A;
+}
+
+static uint32_t
+retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
+{
+
+ return args->buflen;
+}
+
+static uint32_t
+retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
+{
+
+ return args->wirelen;
+}
+
+static uint32_t
+retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
+{
+
+ return bc->nfuncs;
+}
+
+/*
+ * COP function with a side effect.
+ */
+static uint32_t
+setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
+{
+ bool *arg = (bool *)args->arg;
+ bool old = *arg;
+
+ *arg = true;
+ return old;
+}
+
+ATF_TC(bpfjit_cop_no_ctx);
+ATF_TC_HEAD(bpfjit_cop_no_ctx, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP "
+ "instruction isn't valid without a context");
+}
+
+ATF_TC_BODY(bpfjit_cop_no_ctx, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_MISC+BPF_COP, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7)
+ };
+
+ bpfjit_func_t code;
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(!prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_CHECK(code == NULL);
+}
+
+ATF_TC(bpfjit_cop_ret_A);
+ATF_TC_HEAD(bpfjit_cop_ret_A, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns a content of the A register");
+}
+
+ATF_TC_BODY(bpfjit_cop_ret_A, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_MISC+BPF_COP, 0), // retA
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 13);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_cop_ret_buflen);
+ATF_TC_HEAD(bpfjit_cop_ret_buflen, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns the buflen argument");
+}
+
+ATF_TC_BODY(bpfjit_cop_ret_buflen, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt)
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_cop_ret_wirelen);
+ATF_TC_HEAD(bpfjit_cop_ret_wirelen, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns the wirelen argument");
+}
+
+ATF_TC_BODY(bpfjit_cop_ret_wirelen, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt)
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_cop_ret_nfuncs);
+ATF_TC_HEAD(bpfjit_cop_ret_nfuncs, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns nfuncs member of the context argument");
+}
+
+ATF_TC_BODY(bpfjit_cop_ret_nfuncs, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt)
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_cop_side_effect);
+ATF_TC_HEAD(bpfjit_cop_side_effect, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test that ABC optimization doesn't skip BPF_COP call");
+}
+
+ATF_TC_BODY(bpfjit_cop_side_effect, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
+ BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ bool arg = false;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ .mem = NULL,
+ .arg = &arg
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 0);
+ ATF_CHECK(arg == true);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_cop_copx);
+ATF_TC_HEAD(bpfjit_cop_copx, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test BPF_COP call followed by BPF_COPX call");
+}
+
+ATF_TC_BODY(bpfjit_cop_copx, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 1), /* A <- 1 */
+ BPF_STMT(BPF_MISC+BPF_COP, 0), /* retA */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retNF */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 2 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_cop_invalid_index);
+ATF_TC_HEAD(bpfjit_cop_invalid_index, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test that out-of-range coprocessor function fails validation");
+}
+
+ATF_TC_BODY(bpfjit_cop_invalid_index, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index
+ BPF_STMT(BPF_RET+BPF_K, 27)
+ };
+
+ bpfjit_func_t code;
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_CHECK(code == NULL);
+}
+
+ATF_TC(bpfjit_copx_no_ctx);
+ATF_TC_HEAD(bpfjit_copx_no_ctx, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
+ "instruction isn't valid without a context");
+}
+
+ATF_TC_BODY(bpfjit_copx_no_ctx, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_MISC+BPF_COP, 0),
+ BPF_STMT(BPF_RET+BPF_K, 7)
+ };
+
+ bpfjit_func_t code;
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ ATF_CHECK(!prog_validate(insns, insn_count));
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(NULL, insns, insn_count);
+ rump_unschedule();
+ ATF_CHECK(code == NULL);
+}
+
+ATF_TC(bpfjit_copx_ret_A);
+ATF_TC_HEAD(bpfjit_copx_ret_A, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns a content of the A register");
+}
+
+ATF_TC_BODY(bpfjit_copx_ret_A, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
+ BPF_STMT(BPF_MISC+BPF_COPX, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 13);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_copx_ret_buflen);
+ATF_TC_HEAD(bpfjit_copx_ret_buflen, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns the buflen argument");
+}
+
+ATF_TC_BODY(bpfjit_copx_ret_buflen, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
+ BPF_STMT(BPF_MISC+BPF_COPX, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt)
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_copx_ret_wirelen);
+ATF_TC_HEAD(bpfjit_copx_ret_wirelen, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns the wirelen argument");
+}
+
+ATF_TC_BODY(bpfjit_copx_ret_wirelen, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_MISC+BPF_COPX, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt)
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_copx_ret_nfuncs);
+ATF_TC_HEAD(bpfjit_copx_ret_nfuncs, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns nfuncs member of the context argument");
+}
+
+ATF_TC_BODY(bpfjit_copx_ret_nfuncs, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
+ BPF_STMT(BPF_MISC+BPF_COPX, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt)
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_copx_side_effect);
+ATF_TC_HEAD(bpfjit_copx_side_effect, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test that ABC optimization doesn't skip BPF_COPX call");
+}
+
+ATF_TC_BODY(bpfjit_copx_side_effect, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
+ BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
+ BPF_STMT(BPF_MISC+BPF_COPX, 0),
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ bool arg = false;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ .mem = NULL,
+ .arg = &arg
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 0);
+ ATF_CHECK(arg == true);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_copx_cop);
+ATF_TC_HEAD(bpfjit_copx_cop, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test BPF_COPX call followed by BPF_COP call");
+}
+
+ATF_TC_BODY(bpfjit_copx_cop, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_IMM, 2), /* X <- 2 */
+ BPF_STMT(BPF_MISC+BPF_COPX, 0), /* retWL */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A = P[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_MISC+BPF_COP, 3), /* retNF */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1), /* A = A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 2 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_copx_invalid_index);
+ATF_TC_HEAD(bpfjit_copx_invalid_index, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test that out-of-range BPF_COPX call fails at runtime");
+}
+
+ATF_TC_BODY(bpfjit_copx_invalid_index, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
+ BPF_STMT(BPF_MISC+BPF_COPX, 0),
+ BPF_STMT(BPF_RET+BPF_K, 27)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt)
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ /*
+ * For every new test please also add a similar test
+ * to ../../lib/libbpfjit/t_cop.c
+ */
+ ATF_TP_ADD_TC(tp, bpfjit_cop_no_ctx);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_ret_A);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_ret_buflen);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_ret_wirelen);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_ret_nfuncs);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_side_effect);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_copx);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_invalid_index);
+
+ ATF_TP_ADD_TC(tp, bpfjit_copx_no_ctx);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_ret_A);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_ret_buflen);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_ret_wirelen);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_ret_nfuncs);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_side_effect);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_cop);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_invalid_index);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/bpfjit/t_extmem.c b/contrib/netbsd-tests/net/bpfjit/t_extmem.c
new file mode 100644
index 0000000..915c436
--- /dev/null
+++ b/contrib/netbsd-tests/net/bpfjit/t_extmem.c
@@ -0,0 +1,506 @@
+/* $NetBSD: t_extmem.c,v 1.1 2014/07/09 13:49:49 alnsn Exp $ */
+
+/*-
+ * Copyright (c) 2014 Alexander Nasonov.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_extmem.c,v 1.1 2014/07/09 13:49:49 alnsn Exp $");
+
+#include <stdint.h>
+#include <string.h>
+
+#define __BPF_PRIVATE
+#include <net/bpf.h>
+#include <net/bpfjit.h>
+
+#include "../../net/bpf/h_bpf.h"
+
+/* XXX: atf-c.h has collisions with mbuf */
+#undef m_type
+#undef m_data
+#include <atf-c.h>
+
+#include "../../h_macros.h"
+
+static uint32_t retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
+
+static const bpf_copfunc_t copfuncs[] = {
+ &retM
+};
+
+static const bpf_ctx_t ctx = {
+ .copfuncs = copfuncs,
+ .nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
+ .extwords = 4,
+ .preinited = BPF_MEMWORD_INIT(0) | BPF_MEMWORD_INIT(3),
+};
+
+static uint32_t
+retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
+{
+
+ return args->mem[(uintptr_t)args->arg];
+}
+
+
+ATF_TC(bpfjit_extmem_load_preinited);
+ATF_TC_HEAD(bpfjit_extmem_load_preinited, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test a load of external "
+ "pre-initialized memory");
+}
+
+ATF_TC_BODY(bpfjit_extmem_load_preinited, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_MEM, 3),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ uint32_t mem[ctx.extwords];
+
+ /* Pre-inited words. */
+ mem[0] = 0;
+ mem[3] = 3;
+
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ .mem = mem,
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 3);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_extmem_invalid_load);
+ATF_TC_HEAD(bpfjit_extmem_invalid_load, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test that out-of-range load "
+ "fails validation");
+}
+
+ATF_TC_BODY(bpfjit_extmem_invalid_load, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_MEM, 4),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_CHECK(code == NULL);
+}
+
+ATF_TC(bpfjit_extmem_store);
+ATF_TC_HEAD(bpfjit_extmem_store, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test stores to external memory");
+}
+
+ATF_TC_BODY(bpfjit_extmem_store, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 1), /* A <- 1 */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2 */
+ BPF_STMT(BPF_ST, 1), /* M[1] <- A */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_STX, 2), /* M[2] <- X */
+ BPF_STMT(BPF_ST, 3), /* M[3] <- A */
+ BPF_STMT(BPF_RET+BPF_A, 0) /* ret A */
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ uint32_t mem[ctx.extwords];
+
+ /* Pre-inited words. */
+ mem[0] = 0;
+ mem[3] = 7;
+
+ mem[1] = mem[2] = 0xdeadbeef;
+
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ .mem = mem,
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 3);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+
+ ATF_CHECK(mem[0] == 0);
+ ATF_CHECK(mem[1] == 1);
+ ATF_CHECK(mem[2] == 2);
+ ATF_CHECK(mem[3] == 3);
+}
+
+ATF_TC(bpfjit_extmem_side_effect);
+ATF_TC_HEAD(bpfjit_extmem_side_effect, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test that ABC optimization doesn\'t "
+ "skip stores to external memory");
+}
+
+ATF_TC_BODY(bpfjit_extmem_side_effect, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A <- P[0] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2 */
+ BPF_STMT(BPF_ST, 1), /* M[1] <- A */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_STX, 2), /* M[2] <- X */
+ BPF_STMT(BPF_ST, 3), /* M[3] <- A */
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99), /* A <- P[99] */
+ BPF_STMT(BPF_RET+BPF_A, 0) /* ret A */
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 1 };
+ uint32_t mem[ctx.extwords];
+
+ /* Pre-inited words. */
+ mem[0] = 0;
+ mem[3] = 7;
+
+ mem[1] = mem[2] = 0xdeadbeef;
+
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ .mem = mem,
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 0);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+
+ ATF_CHECK(mem[0] == 0);
+ ATF_CHECK(mem[1] == 1);
+ ATF_CHECK(mem[2] == 2);
+ ATF_CHECK(mem[3] == 3);
+}
+
+ATF_TC(bpfjit_extmem_invalid_store);
+ATF_TC_HEAD(bpfjit_extmem_invalid_store, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test that out-of-range store "
+ "fails validation");
+}
+
+ATF_TC_BODY(bpfjit_extmem_invalid_store, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_ST, 4),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_CHECK(code == NULL);
+}
+
+ATF_TC(bpfjit_cop_ret_mem);
+ATF_TC_HEAD(bpfjit_cop_ret_mem, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns a content of external memory word");
+}
+
+ATF_TC_BODY(bpfjit_cop_ret_mem, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_ST, 2),
+ BPF_STMT(BPF_LD+BPF_IMM, 137),
+ BPF_STMT(BPF_ST, 1),
+ BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ uint32_t mem[ctx.extwords];
+ void *arg = (void*)(uintptr_t)2;
+
+ /* Pre-inited words. */
+ mem[0] = 0;
+ mem[3] = 3;
+
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ .arg = arg,
+ .mem = mem,
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 13);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_cop_ret_preinited_mem);
+ATF_TC_HEAD(bpfjit_cop_ret_preinited_mem, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
+ "returns a content of external pre-initialized memory word");
+}
+
+ATF_TC_BODY(bpfjit_cop_ret_preinited_mem, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_ST, 2),
+ BPF_STMT(BPF_LD+BPF_IMM, 137),
+ BPF_STMT(BPF_ST, 1),
+ BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ uint32_t mem[ctx.extwords];
+ void *arg = (void*)(uintptr_t)3;
+
+ /* Pre-inited words. */
+ mem[0] = 0;
+ mem[3] = 3;
+
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ .arg = arg,
+ .mem = mem,
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 3);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_copx_ret_mem);
+ATF_TC_HEAD(bpfjit_copx_ret_mem, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
+ "that returns a content of external memory word");
+}
+
+ATF_TC_BODY(bpfjit_copx_ret_mem, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_ST, 2),
+ BPF_STMT(BPF_LD+BPF_IMM, 137),
+ BPF_STMT(BPF_ST, 1),
+ BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
+ BPF_STMT(BPF_MISC+BPF_COPX, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ uint32_t mem[ctx.extwords];
+ void *arg = (void*)(uintptr_t)2;
+
+ /* Pre-inited words. */
+ mem[0] = 0;
+ mem[3] = 3;
+
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ .arg = arg,
+ .mem = mem,
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 13);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TC(bpfjit_copx_ret_preinited_mem);
+ATF_TC_HEAD(bpfjit_copx_ret_preinited_mem, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
+ "returns a content of external pre-initialized memory word");
+}
+
+ATF_TC_BODY(bpfjit_copx_ret_preinited_mem, tc)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 13),
+ BPF_STMT(BPF_ST, 2),
+ BPF_STMT(BPF_LD+BPF_IMM, 137),
+ BPF_STMT(BPF_ST, 1),
+ BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
+ BPF_STMT(BPF_MISC+BPF_COPX, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0)
+ };
+
+ bpfjit_func_t code;
+ uint8_t pkt[1] = { 0 };
+ uint32_t mem[ctx.extwords];
+ void *arg = (void*)(uintptr_t)3;
+
+ /* Pre-inited words. */
+ mem[0] = 0;
+ mem[3] = 3;
+
+ bpf_args_t args = {
+ .pkt = pkt,
+ .buflen = sizeof(pkt),
+ .wirelen = sizeof(pkt),
+ .arg = arg,
+ .mem = mem,
+ };
+
+ size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ RZ(rump_init());
+
+ rump_schedule();
+ code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
+ rump_unschedule();
+ ATF_REQUIRE(code != NULL);
+
+ ATF_CHECK(code(&ctx, &args) == 3);
+
+ rump_schedule();
+ rumpns_bpfjit_free_code(code);
+ rump_unschedule();
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ /*
+ * For every new test please also add a similar test
+ * to ../../lib/libbpfjit/t_extmem.c
+ */
+ //ATF_TP_ADD_TC(tp, bpfjit_extmem_load_default);
+ ATF_TP_ADD_TC(tp, bpfjit_extmem_load_preinited);
+ ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_load);
+ ATF_TP_ADD_TC(tp, bpfjit_extmem_store);
+ ATF_TP_ADD_TC(tp, bpfjit_extmem_side_effect);
+ ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_store);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_ret_mem);
+ ATF_TP_ADD_TC(tp, bpfjit_cop_ret_preinited_mem);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_ret_mem);
+ ATF_TP_ADD_TC(tp, bpfjit_copx_ret_preinited_mem);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/bpfjit/t_mbuf.c b/contrib/netbsd-tests/net/bpfjit/t_mbuf.c
new file mode 100644
index 0000000..489ef80
--- /dev/null
+++ b/contrib/netbsd-tests/net/bpfjit/t_mbuf.c
@@ -0,0 +1,982 @@
+/* $NetBSD: t_mbuf.c,v 1.1 2014/07/08 21:45:55 alnsn Exp $ */
+
+/*-
+ * Copyright (c) 2014 Alexander Nasonov.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_mbuf.c,v 1.1 2014/07/08 21:45:55 alnsn Exp $");
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include <net/bpf.h>
+#include <net/bpfjit.h>
+
+#include <stdint.h>
+#include <string.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include "../../net/bpf/h_bpf.h"
+
+/* XXX: atf-c.h has collisions with mbuf */
+#undef m_type
+#undef m_data
+#include <atf-c.h>
+
+#include "../../h_macros.h"
+
+static bool
+test_ldb_abs(size_t split)
+{
+ /* Return a product of all packet bytes. */
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0), /* A <- P[0] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 1), /* A <- P[1] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 2), /* A <- P[2] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 3), /* A <- P[3] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 4), /* A <- P[4] */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 120;
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldh_abs(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 0), /* A <- P[0:2] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 1), /* A <- P[1:2] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 2), /* A <- P[2:2] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 3), /* A <- P[3:2] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 0x0a0e; /* 10 14 */
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldw_abs(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), /* A <- P[0:4] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_MISC+BPF_TAX, 0), /* X <- A */
+
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 1), /* A <- P[1:4] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 0x03050709;
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldb_ind(size_t split)
+{
+ /* Return a sum of all packet bytes. */
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 0), /* A <- P[0+X] */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1), /* A <- P[1+X] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1), /* A <- P[1+X] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 2), /* A <- P[2+X] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 3), /* A <- P[3+X] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 15;
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldw_ind(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 0), /* A <- P[X+0:4] */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 0), /* A <- P[X+0:4] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 0), /* X <- 0 */
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1), /* A <- P[X+1:4] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 0x05080b0e;
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldh_ind(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 0), /* A <- P[X+0:2] */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1), /* A <- P[X+1:2] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1), /* A <- P[X+1:2] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_ST, 0), /* M[0] <- A */
+
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1), /* X <- 1 */
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 2), /* A <- P[X+2:2] */
+ BPF_STMT(BPF_LDX+BPF_W+BPF_MEM, 0), /* X <- M[0] */
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 0x0a0e; /* 10 14 */
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == res;
+}
+
+static bool
+test_msh(size_t split)
+{
+ /* Return a product of all packet bytes. */
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_IMM, 1), /* A <- 1 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 0), /* X <- 4*(P[0]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 1), /* X <- 4*(P[1]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 2), /* X <- 4*(P[2]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 3), /* X <- 4*(P[3]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 4), /* X <- 4*(P[4]&0xf) */
+ BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), /* A <- A * X */
+ BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 4), /* A <- A / 4 */
+
+ BPF_STMT(BPF_RET+BPF_A, 0), /* ret A */
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const unsigned int res = 120;
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == res;
+}
+
+static bool
+test_ldb_abs_overflow(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 5),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldh_abs_overflow(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldw_abs_overflow(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 2),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldb_ind_overflow1(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 5),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldb_ind_overflow2(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 4),
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldb_ind_overflow3(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldh_ind_overflow1(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 4),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldh_ind_overflow2(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 3),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldh_ind_overflow3(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldw_ind_overflow1(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 2),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldw_ind_overflow2(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 1),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_ldw_ind_overflow3(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, UINT32_MAX),
+ BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+static bool
+test_msh_overflow(size_t split)
+{
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 5),
+ BPF_STMT(BPF_MISC+BPF_TXA, 0),
+ BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 1),
+ BPF_STMT(BPF_RET+BPF_A, 0),
+ };
+
+ static unsigned char P[] = { 1, 2, 3, 4, 5 };
+ const size_t insn_count = sizeof(insns) / sizeof(insns[0]);
+
+ if (!prog_validate(insns, insn_count))
+ return false;
+
+ return exec_prog_mchain2(insns, insn_count, P, sizeof(P), split) == 0;
+}
+
+ATF_TC(bpfjit_mbuf_ldb_abs);
+ATF_TC_HEAD(bpfjit_mbuf_ldb_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_ABS "
+ "loads bytes from mbuf correctly");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldb_abs, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_abs(0));
+ ATF_CHECK(test_ldb_abs(1));
+ ATF_CHECK(test_ldb_abs(2));
+ ATF_CHECK(test_ldb_abs(3));
+ ATF_CHECK(test_ldb_abs(4));
+ ATF_CHECK(test_ldb_abs(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldh_abs);
+ATF_TC_HEAD(bpfjit_mbuf_ldh_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_ABS "
+ "loads halfwords from mbuf correctly");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldh_abs, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_abs(0));
+ ATF_CHECK(test_ldh_abs(1));
+ ATF_CHECK(test_ldh_abs(2));
+ ATF_CHECK(test_ldh_abs(3));
+ ATF_CHECK(test_ldh_abs(4));
+ ATF_CHECK(test_ldh_abs(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldw_abs);
+ATF_TC_HEAD(bpfjit_mbuf_ldw_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_ABS "
+ "loads words from mbuf correctly");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldw_abs, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_abs(0));
+ ATF_CHECK(test_ldw_abs(1));
+ ATF_CHECK(test_ldw_abs(2));
+ ATF_CHECK(test_ldw_abs(3));
+ ATF_CHECK(test_ldw_abs(4));
+ ATF_CHECK(test_ldw_abs(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldb_ind);
+ATF_TC_HEAD(bpfjit_mbuf_ldb_ind, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_IND "
+ "loads bytes from mbuf correctly");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldb_ind, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_ind(0));
+ ATF_CHECK(test_ldb_ind(1));
+ ATF_CHECK(test_ldb_ind(2));
+ ATF_CHECK(test_ldb_ind(3));
+ ATF_CHECK(test_ldb_ind(4));
+ ATF_CHECK(test_ldb_ind(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldh_ind);
+ATF_TC_HEAD(bpfjit_mbuf_ldh_ind, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_IND "
+ "loads halfwords from mbuf correctly");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldh_ind, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_ind(0));
+ ATF_CHECK(test_ldh_ind(1));
+ ATF_CHECK(test_ldh_ind(2));
+ ATF_CHECK(test_ldh_ind(3));
+ ATF_CHECK(test_ldh_ind(4));
+ ATF_CHECK(test_ldh_ind(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldw_ind);
+ATF_TC_HEAD(bpfjit_mbuf_ldw_ind, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_IND "
+ "loads words from mbuf correctly");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldw_ind, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_ind(0));
+ ATF_CHECK(test_ldw_ind(1));
+ ATF_CHECK(test_ldw_ind(2));
+ ATF_CHECK(test_ldw_ind(3));
+ ATF_CHECK(test_ldw_ind(4));
+ ATF_CHECK(test_ldw_ind(5));
+}
+
+ATF_TC(bpfjit_mbuf_msh);
+ATF_TC_HEAD(bpfjit_mbuf_msh, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LDX+BPF_B+BPF_MSH "
+ "loads bytes from mbuf correctly");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_msh, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_msh(0));
+ ATF_CHECK(test_msh(1));
+ ATF_CHECK(test_msh(2));
+ ATF_CHECK(test_msh(3));
+ ATF_CHECK(test_msh(4));
+ ATF_CHECK(test_msh(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldb_abs_overflow);
+ATF_TC_HEAD(bpfjit_mbuf_ldb_abs_overflow, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_ABS "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldb_abs_overflow, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_abs_overflow(0));
+ ATF_CHECK(test_ldb_abs_overflow(1));
+ ATF_CHECK(test_ldb_abs_overflow(2));
+ ATF_CHECK(test_ldb_abs_overflow(3));
+ ATF_CHECK(test_ldb_abs_overflow(4));
+ ATF_CHECK(test_ldb_abs_overflow(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldh_abs_overflow);
+ATF_TC_HEAD(bpfjit_mbuf_ldh_abs_overflow, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_ABS "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldh_abs_overflow, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_abs_overflow(0));
+ ATF_CHECK(test_ldh_abs_overflow(1));
+ ATF_CHECK(test_ldh_abs_overflow(2));
+ ATF_CHECK(test_ldh_abs_overflow(3));
+ ATF_CHECK(test_ldh_abs_overflow(4));
+ ATF_CHECK(test_ldh_abs_overflow(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldw_abs_overflow);
+ATF_TC_HEAD(bpfjit_mbuf_ldw_abs_overflow, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_ABS "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldw_abs_overflow, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_abs_overflow(0));
+ ATF_CHECK(test_ldw_abs_overflow(1));
+ ATF_CHECK(test_ldw_abs_overflow(2));
+ ATF_CHECK(test_ldw_abs_overflow(3));
+ ATF_CHECK(test_ldw_abs_overflow(4));
+ ATF_CHECK(test_ldw_abs_overflow(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldb_ind_overflow1);
+ATF_TC_HEAD(bpfjit_mbuf_ldb_ind_overflow1, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldb_ind_overflow1, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_ind_overflow1(0));
+ ATF_CHECK(test_ldb_ind_overflow1(1));
+ ATF_CHECK(test_ldb_ind_overflow1(2));
+ ATF_CHECK(test_ldb_ind_overflow1(3));
+ ATF_CHECK(test_ldb_ind_overflow1(4));
+ ATF_CHECK(test_ldb_ind_overflow1(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldb_ind_overflow2);
+ATF_TC_HEAD(bpfjit_mbuf_ldb_ind_overflow2, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldb_ind_overflow2, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_ind_overflow2(0));
+ ATF_CHECK(test_ldb_ind_overflow2(1));
+ ATF_CHECK(test_ldb_ind_overflow2(2));
+ ATF_CHECK(test_ldb_ind_overflow2(3));
+ ATF_CHECK(test_ldb_ind_overflow2(4));
+ ATF_CHECK(test_ldb_ind_overflow2(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldb_ind_overflow3);
+ATF_TC_HEAD(bpfjit_mbuf_ldb_ind_overflow3, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_B+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldb_ind_overflow3, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldb_ind_overflow3(0));
+ ATF_CHECK(test_ldb_ind_overflow3(1));
+ ATF_CHECK(test_ldb_ind_overflow3(2));
+ ATF_CHECK(test_ldb_ind_overflow3(3));
+ ATF_CHECK(test_ldb_ind_overflow3(4));
+ ATF_CHECK(test_ldb_ind_overflow3(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldh_ind_overflow1);
+ATF_TC_HEAD(bpfjit_mbuf_ldh_ind_overflow1, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldh_ind_overflow1, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_ind_overflow1(0));
+ ATF_CHECK(test_ldh_ind_overflow1(1));
+ ATF_CHECK(test_ldh_ind_overflow1(2));
+ ATF_CHECK(test_ldh_ind_overflow1(3));
+ ATF_CHECK(test_ldh_ind_overflow1(4));
+ ATF_CHECK(test_ldh_ind_overflow1(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldh_ind_overflow2);
+ATF_TC_HEAD(bpfjit_mbuf_ldh_ind_overflow2, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldh_ind_overflow2, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_ind_overflow2(0));
+ ATF_CHECK(test_ldh_ind_overflow2(1));
+ ATF_CHECK(test_ldh_ind_overflow2(2));
+ ATF_CHECK(test_ldh_ind_overflow2(3));
+ ATF_CHECK(test_ldh_ind_overflow2(4));
+ ATF_CHECK(test_ldh_ind_overflow2(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldh_ind_overflow3);
+ATF_TC_HEAD(bpfjit_mbuf_ldh_ind_overflow3, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_H+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldh_ind_overflow3, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldh_ind_overflow3(0));
+ ATF_CHECK(test_ldh_ind_overflow3(1));
+ ATF_CHECK(test_ldh_ind_overflow3(2));
+ ATF_CHECK(test_ldh_ind_overflow3(3));
+ ATF_CHECK(test_ldh_ind_overflow3(4));
+ ATF_CHECK(test_ldh_ind_overflow3(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldw_ind_overflow1);
+ATF_TC_HEAD(bpfjit_mbuf_ldw_ind_overflow1, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldw_ind_overflow1, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_ind_overflow1(0));
+ ATF_CHECK(test_ldw_ind_overflow1(1));
+ ATF_CHECK(test_ldw_ind_overflow1(2));
+ ATF_CHECK(test_ldw_ind_overflow1(3));
+ ATF_CHECK(test_ldw_ind_overflow1(4));
+ ATF_CHECK(test_ldw_ind_overflow1(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldw_ind_overflow2);
+ATF_TC_HEAD(bpfjit_mbuf_ldw_ind_overflow2, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldw_ind_overflow2, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_ind_overflow2(0));
+ ATF_CHECK(test_ldw_ind_overflow2(1));
+ ATF_CHECK(test_ldw_ind_overflow2(2));
+ ATF_CHECK(test_ldw_ind_overflow2(3));
+ ATF_CHECK(test_ldw_ind_overflow2(4));
+ ATF_CHECK(test_ldw_ind_overflow2(5));
+}
+
+ATF_TC(bpfjit_mbuf_ldw_ind_overflow3);
+ATF_TC_HEAD(bpfjit_mbuf_ldw_ind_overflow3, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LD+BPF_W+BPF_IND "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_ldw_ind_overflow3, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_ldw_ind_overflow3(0));
+ ATF_CHECK(test_ldw_ind_overflow3(1));
+ ATF_CHECK(test_ldw_ind_overflow3(2));
+ ATF_CHECK(test_ldw_ind_overflow3(3));
+ ATF_CHECK(test_ldw_ind_overflow3(4));
+ ATF_CHECK(test_ldw_ind_overflow3(5));
+}
+
+ATF_TC(bpfjit_mbuf_msh_overflow);
+ATF_TC_HEAD(bpfjit_mbuf_msh_overflow, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that BPF_LDX+BPF_B+BPF_MSH "
+ "with out-of-bounds index aborts a filter program");
+}
+
+ATF_TC_BODY(bpfjit_mbuf_msh_overflow, tc)
+{
+
+ RZ(rump_init());
+
+ ATF_CHECK(test_msh_overflow(0));
+ ATF_CHECK(test_msh_overflow(1));
+ ATF_CHECK(test_msh_overflow(2));
+ ATF_CHECK(test_msh_overflow(3));
+ ATF_CHECK(test_msh_overflow(4));
+ ATF_CHECK(test_msh_overflow(5));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ /*
+ * For every new test please also add a similar test
+ * to ../../net/bpf/t_mbuf.c
+ */
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldb_abs);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldh_abs);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldw_abs);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldb_ind);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldh_ind);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldw_ind);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_msh);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldb_abs_overflow);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldh_abs_overflow);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldw_abs_overflow);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldb_ind_overflow1);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldb_ind_overflow2);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldb_ind_overflow3);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldh_ind_overflow1);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldh_ind_overflow2);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldh_ind_overflow3);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldw_ind_overflow1);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldw_ind_overflow2);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_ldw_ind_overflow3);
+ ATF_TP_ADD_TC(tp, bpfjit_mbuf_msh_overflow);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/carp/t_basic.c b/contrib/netbsd-tests/net/carp/t_basic.c
new file mode 100644
index 0000000..fe2e6b5
--- /dev/null
+++ b/contrib/netbsd-tests/net/carp/t_basic.c
@@ -0,0 +1,221 @@
+/* $NetBSD: t_basic.c,v 1.5 2011/06/26 13:13:31 christos Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: t_basic.c,v 1.5 2011/06/26 13:13:31 christos Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_carp.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include <atf-c.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "../config/netconfig.c"
+#include "../../h_macros.h"
+
+static bool oknow = false;
+
+static void
+sighnd(int sig)
+{
+
+ ATF_REQUIRE_EQ(sig, SIGCHLD);
+ if (oknow)
+ return;
+
+ atf_tc_fail("child died unexpectedly");
+}
+
+ATF_TC(handover);
+ATF_TC_HEAD(handover, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "check that carp handover works if "
+ "the master dies");
+}
+
+#define THEBUS "buuuuuuus,etherbus"
+
+static void
+child(bool master)
+{
+ char ifname[IFNAMSIZ];
+ struct carpreq cr;
+ struct ifreq ifr;
+ const char *carpif;
+ int s;
+
+ /* helps reading carp debug output */
+ if (master)
+ carpif = "carp0";
+ else
+ carpif = "carp1";
+
+ /*
+ * Should use sysctl, bug debug is dabug.
+ */
+ {
+ //extern int rumpns_carp_opts[]; /* XXX */
+ //rumpns_carp_opts[CARPCTL_LOG] = 1;
+ }
+
+
+ rump_init();
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, carpif, sizeof(ifr.ifr_name));
+
+ RL(s = rump_sys_socket(PF_INET, SOCK_DGRAM, 0));
+ RL(rump_sys_ioctl(s, SIOCIFCREATE, &ifr));
+
+ netcfg_rump_makeshmif(THEBUS, ifname);
+
+ if (master)
+ netcfg_rump_if(ifname, "10.1.1.1", "255.255.255.0");
+ else
+ netcfg_rump_if(ifname, "10.1.1.2", "255.255.255.0");
+
+ /* configure the carp interface */
+ ifr.ifr_data = &cr;
+ RL(rump_sys_ioctl(s, SIOCGVH, &ifr));
+
+ strlcpy(cr.carpr_carpdev, ifname, sizeof(cr.carpr_carpdev));
+ cr.carpr_vhid = 175;
+ if (master)
+ cr.carpr_advskew = 0;
+ else
+ cr.carpr_advskew = 200;
+ cr.carpr_advbase = 1;
+ strcpy((char *)cr.carpr_key, "s3cret");
+
+ RL(rump_sys_ioctl(s, SIOCSVH, &ifr));
+ netcfg_rump_if(carpif, "10.1.1.100", "255.255.255.0");
+
+ /* tassa pause()en enka muuta voi */
+ pause();
+}
+
+ATF_TC_BODY(handover, tc)
+{
+ char ifname[IFNAMSIZ];
+ pid_t mpid, cpid;
+ int i, status;
+
+ signal(SIGCHLD, sighnd);
+
+ /* fork master */
+ switch (mpid = fork()) {
+ case -1:
+ atf_tc_fail_errno("fork failed");
+ /*NOTREACHED*/
+ case 0:
+ child(true);
+ /*NOTREACHED*/
+ default:
+ break;
+ }
+
+ usleep(500000);
+
+ /* fork backup */
+ switch (cpid = fork()) {
+ case -1:
+ kill(mpid, SIGKILL);
+ atf_tc_fail_errno("fork failed");
+ /*NOTREACHED*/
+ case 0:
+ child(false);
+ /*NOTREACHED*/
+ default:
+ break;
+ }
+
+ usleep(500000);
+
+ rump_init();
+ netcfg_rump_makeshmif(THEBUS, ifname);
+ netcfg_rump_if(ifname, "10.1.1.240", "255.255.255.0");
+
+ /* check that the primary addresses are up */
+ ATF_REQUIRE_EQ(netcfg_rump_pingtest("10.1.1.1", 1000), true);
+ ATF_REQUIRE_EQ(netcfg_rump_pingtest("10.1.1.2", 1000), true);
+
+ /* give carp a while to croak */
+ sleep(4);
+
+ /* check that the shared IP works */
+ ATF_REQUIRE_EQ(netcfg_rump_pingtest("10.1.1.100", 500), true);
+
+ /* KILLING SPREE */
+ oknow = true;
+ kill(mpid, SIGKILL);
+ wait(&status);
+ usleep(10000); /* just in case */
+ oknow = false;
+
+ /* check that primary is now dead */
+ ATF_REQUIRE_EQ(netcfg_rump_pingtest("10.1.1.1", 100), false);
+
+ /* do it in installments. carp will cluck meanwhile */
+ for (i = 0; i < 5; i++) {
+ if (netcfg_rump_pingtest("10.1.1.100", 1000) == true)
+ break;
+ }
+ if (i == 5)
+ atf_tc_fail("failed to failover");
+
+ /* to kill the child */
+ oknow = true;
+ kill(cpid, SIGKILL);
+
+ /* clean & done */
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, handover);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/config/netconfig.c b/contrib/netbsd-tests/net/config/netconfig.c
new file mode 100644
index 0000000..c2f9dd4
--- /dev/null
+++ b/contrib/netbsd-tests/net/config/netconfig.c
@@ -0,0 +1,231 @@
+/* $NetBSD: netconfig.c,v 1.8 2013/07/03 19:13:33 pooka Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: netconfig.c,v 1.8 2013/07/03 19:13:33 pooka Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <arpa/inet.h>
+
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+#include <atf-c.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include "../../h_macros.h"
+
+int noatf;
+
+static void __unused
+netcfg_rump_makeshmif(const char *busname, char *ifname)
+{
+ int rv, ifnum;
+
+ if ((rv = rump_pub_shmif_create(busname, &ifnum)) != 0) {
+ if (noatf)
+ err(1, "makeshmif: rump_pub_shmif_create %d", rv);
+ else
+ atf_tc_fail("makeshmif: rump_pub_shmif_create %d", rv);
+ }
+ sprintf(ifname, "shmif%d", ifnum);
+}
+
+static void __unused
+netcfg_rump_if(const char *ifname, const char *addr, const char *mask)
+{
+ struct ifaliasreq ia;
+ struct sockaddr_in *sin;
+ in_addr_t inaddr, inmask;
+ int s, rv;
+
+ s = -1;
+ if ((s = rump_sys_socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+ if (noatf)
+ err(1, "if config socket");
+ else
+ atf_tc_fail_errno("if config socket");
+ }
+
+ inaddr = inet_addr(addr);
+ inmask = inet_addr(mask);
+
+ /* Address */
+ memset(&ia, 0, sizeof(ia));
+ strcpy(ia.ifra_name, ifname);
+ sin = (struct sockaddr_in *)&ia.ifra_addr;
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(struct sockaddr_in);
+ sin->sin_addr.s_addr = inaddr;
+
+ /* Netmask */
+ sin = (struct sockaddr_in *)&ia.ifra_mask;
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(struct sockaddr_in);
+ sin->sin_addr.s_addr = inmask;
+
+ /* Broadcast address */
+ sin = (struct sockaddr_in *)&ia.ifra_broadaddr;
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(struct sockaddr_in);
+ sin->sin_addr.s_addr = inaddr | ~inmask;
+
+ rv = rump_sys_ioctl(s, SIOCAIFADDR, &ia);
+ if (rv == -1) {
+ if (noatf)
+ err(1, "SIOCAIFADDR");
+ else
+ atf_tc_fail_errno("SIOCAIFADDR");
+ }
+ rump_sys_close(s);
+}
+
+static void __unused
+netcfg_rump_route(const char *dst, const char *mask, const char *gw)
+{
+ size_t len;
+ struct {
+ struct rt_msghdr m_rtm;
+ uint8_t m_space[512];
+ } m_rtmsg;
+#define rtm m_rtmsg.m_rtm
+ uint8_t *bp = m_rtmsg.m_space;
+ struct sockaddr_in sinstore;
+ int s, rv;
+
+ s = rump_sys_socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s == -1) {
+ if (noatf)
+ err(1, "routing socket");
+ else
+ atf_tc_fail_errno("routing socket");
+ }
+
+ memset(&m_rtmsg, 0, sizeof(m_rtmsg));
+ rtm.rtm_type = RTM_ADD;
+ rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_seq = 2;
+ rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+
+ /* dst */
+ memset(&sinstore, 0, sizeof(sinstore));
+ sinstore.sin_family = AF_INET;
+ sinstore.sin_len = sizeof(sinstore);
+ sinstore.sin_addr.s_addr = inet_addr(dst);
+ memcpy(bp, &sinstore, sizeof(sinstore));
+ bp += sizeof(sinstore);
+
+ /* gw */
+ memset(&sinstore, 0, sizeof(sinstore));
+ sinstore.sin_family = AF_INET;
+ sinstore.sin_len = sizeof(sinstore);
+ sinstore.sin_addr.s_addr = inet_addr(gw);
+ memcpy(bp, &sinstore, sizeof(sinstore));
+ bp += sizeof(sinstore);
+
+ /* netmask */
+ memset(&sinstore, 0, sizeof(sinstore));
+ sinstore.sin_family = AF_INET;
+ sinstore.sin_len = sizeof(sinstore);
+ sinstore.sin_addr.s_addr = inet_addr(mask);
+ memcpy(bp, &sinstore, sizeof(sinstore));
+ bp += sizeof(sinstore);
+
+ len = bp - (uint8_t *)&m_rtmsg;
+ rtm.rtm_msglen = len;
+
+ rv = rump_sys_write(s, &m_rtmsg, len);
+ if (rv != (int)len) {
+ if (noatf)
+ err(1, "write routing message");
+ else
+ atf_tc_fail_errno("write routing message");
+ }
+ rump_sys_close(s);
+}
+
+static bool __unused
+netcfg_rump_pingtest(const char *dst, int ms_timo)
+{
+ struct timeval tv;
+ struct sockaddr_in sin;
+ struct icmp icmp;
+ socklen_t slen;
+ int s;
+ bool rv = false;
+
+ s = rump_sys_socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (s == -1)
+ return false;
+ tv.tv_sec = ms_timo / 1000;
+ tv.tv_usec = 1000 * (ms_timo % 1000);
+ if (rump_sys_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO,
+ &tv, sizeof(tv)) == -1)
+ goto out;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(dst);
+
+ memset(&icmp, 0, sizeof(icmp));
+ icmp.icmp_type = ICMP_ECHO;
+ icmp.icmp_id = htons(37);
+ icmp.icmp_cksum = htons(0xf7da); /* precalc */
+
+ slen = sizeof(sin);
+ if (rump_sys_sendto(s, &icmp, sizeof(icmp), 0,
+ (struct sockaddr *)&sin, slen) == -1) {
+ goto out;
+ }
+
+ if (rump_sys_recvfrom(s, &icmp, sizeof(icmp), 0,
+ (struct sockaddr *)&sin, &slen) == -1)
+ goto out;
+
+ rv = true;
+ out:
+ rump_sys_close(s);
+ return rv;
+}
diff --git a/contrib/netbsd-tests/net/fdpass/fdpass.c b/contrib/netbsd-tests/net/fdpass/fdpass.c
new file mode 100644
index 0000000..17b0a1d
--- /dev/null
+++ b/contrib/netbsd-tests/net/fdpass/fdpass.c
@@ -0,0 +1,231 @@
+/* $NetBSD: fdpass.c,v 1.1 2012/08/13 11:15:05 christos Exp $ */
+/* $OpenBSD: monitor_fdpass.c,v 1.19 2010/01/12 00:58:25 djm Exp $ */
+/*
+ * Copyright 2001 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: fdpass.c,v 1.1 2012/08/13 11:15:05 christos Exp $");
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <err.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <string.h>
+
+static int debug;
+
+static int
+send_fd(int sock, int fd)
+{
+ struct msghdr msg;
+ union {
+ struct cmsghdr hdr;
+ char buf[1024];
+ } cmsgbuf;
+ struct cmsghdr *cmsg;
+ struct iovec vec;
+ char ch = '\0';
+ ssize_t n;
+ struct pollfd pfd;
+
+ if (sizeof(cmsgbuf.buf) < CMSG_SPACE(sizeof(int)))
+ errx(1, "%s: %zu < %zu, recompile", __func__,
+ sizeof(cmsgbuf.buf), CMSG_SPACE(sizeof(int)));
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_control = &cmsgbuf.buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(int));
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ *(int *)CMSG_DATA(cmsg) = fd;
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ vec.iov_base = &ch;
+ vec.iov_len = 1;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+
+ pfd.fd = sock;
+ pfd.events = POLLOUT;
+ while ((n = sendmsg(sock, &msg, 0)) == -1 &&
+ (errno == EAGAIN || errno == EINTR)) {
+ (void)poll(&pfd, 1, -1);
+ }
+ switch (n) {
+ case -1:
+ err(1, "%s: sendmsg(%d)", __func__, fd);
+ case 1:
+ if (debug)
+ fprintf(stderr, "%d: send fd %d\n", getpid(), fd);
+ return 0;
+ default:
+ errx(1, "%s: sendmsg: expected sent 1 got %ld",
+ __func__, (long)n);
+ }
+}
+
+static int
+recv_fd(int sock)
+{
+ struct msghdr msg;
+ union {
+ struct cmsghdr hdr;
+ char buf[1024];
+ } cmsgbuf;
+ struct cmsghdr *cmsg;
+ struct iovec vec;
+ ssize_t n;
+ char ch;
+ int fd;
+ struct pollfd pfd;
+
+ if (sizeof(cmsgbuf.buf) < CMSG_SPACE(sizeof(int)))
+ errx(1, "%s: %zu < %zu, recompile", __func__,
+ sizeof(cmsgbuf.buf), CMSG_SPACE(sizeof(int)));
+
+ memset(&msg, 0, sizeof(msg));
+ vec.iov_base = &ch;
+ vec.iov_len = 1;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &cmsgbuf.buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(int));
+
+ pfd.fd = sock;
+ pfd.events = POLLIN;
+ while ((n = recvmsg(sock, &msg, 0)) == -1 &&
+ (errno == EAGAIN || errno == EINTR)) {
+ (void)poll(&pfd, 1, -1);
+ }
+ switch (n) {
+ case -1:
+ err(1, "%s: recvmsg", __func__);
+ case 1:
+ break;
+ default:
+ errx(1, "%s: recvmsg: expected received 1 got %ld",
+ __func__, (long)n);
+ }
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg == NULL)
+ errx(1, "%s: no message header", __func__);
+
+ if (cmsg->cmsg_type != SCM_RIGHTS)
+ err(1, "%s: expected type %d got %d", __func__,
+ SCM_RIGHTS, cmsg->cmsg_type);
+ fd = (*(int *)CMSG_DATA(cmsg));
+ if (debug)
+ fprintf(stderr, "%d: recv fd %d\n", getpid(), fd);
+ return fd;
+}
+
+static void usage(void) __attribute__((__noreturn__));
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: %s [-vd] -i <input> -o <output>\n"
+ "\t %s [-v] -p <progname>\n", getprogname(), getprogname());
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int s[2], fd, status, c, verbose;
+ char buf[1024], *prog;
+
+ prog = NULL;
+ s[0] = s[1] = -1;
+ verbose = 0;
+
+ while ((c = getopt(argc, argv, "di:o:p:")) != -1)
+ switch (c) {
+ case 'd':
+ debug++;
+ break;
+ case 'i':
+ s[0] = atoi(optarg);
+ break;
+ case 'o':
+ s[1] = atoi(optarg);
+ break;
+ case 'p':
+ prog = optarg;
+ break;
+ default:
+ usage();
+ }
+
+ if ((s[0] == -1 && s[1] != -1) || (s[0] != -1 && s[1] == -1))
+ usage();
+
+ if (s[0] == -1) {
+ if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, s) == -1)
+ err(1, "socketpair");
+ } else
+ goto recv;
+
+ switch (fork()) {
+ case -1:
+ err(1, "fork");
+ default:
+ fd = open("foo", O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fd == -1)
+ err(1, "open");
+ send_fd(s[0], fd);
+ wait(&status);
+ return 0;
+ case 0:
+ if (prog != NULL) {
+ char i[64], o[64];
+ snprintf(i, sizeof(i), "%d", s[0]);
+ snprintf(o, sizeof(o), "%d", s[1]);
+ execlp(prog, prog, "-i", i, "-o", o, NULL);
+ err(1, "execlp");
+ }
+ recv:
+ fd = recv_fd(s[1]);
+ if (verbose) {
+ snprintf(buf, sizeof(buf), "ls -l /proc/%d/fd",
+ getpid());
+ system(buf);
+ }
+ if (write(fd, "foo\n", 4) == -1)
+ err(1, "write");
+ close(fd);
+ return 0;
+ }
+}
diff --git a/contrib/netbsd-tests/net/fdpass/t_fdpass.sh b/contrib/netbsd-tests/net/fdpass/t_fdpass.sh
new file mode 100755
index 0000000..4e4ac04
--- /dev/null
+++ b/contrib/netbsd-tests/net/fdpass/t_fdpass.sh
@@ -0,0 +1,99 @@
+# $NetBSD: t_fdpass.sh,v 1.2 2012/08/16 08:39:43 martin Exp $
+#
+# Copyright (c) 2012 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Christos Zoulas
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+have32() {
+ local src="$(atf_get_srcdir)"
+ if cmp "${src}/fdpass64" "${src}/fdpass32" > /dev/null
+ then
+ # echo "no -m32 support"
+ return 1
+ else
+ return 0
+ fi
+}
+
+atf_test_case fdpass_normal
+
+fdpass_normal_head() {
+ atf_set "descr" "Test file descriptor passing (default)"
+}
+
+fdpass_normal_body() {
+ local src="$(atf_get_srcdir)"
+ atf_check "${src}/fdpass64"
+}
+
+
+atf_test_case fdpass_compat
+
+fdpass_compat_head() {
+ atf_set "descr" "Test file descriptor passing (compat)"
+}
+
+fdpass_compat_body() {
+ local src="$(atf_get_srcdir)"
+ have32 && atf_check "${src}/fdpass32"
+}
+
+
+atf_test_case fdpass_normal_compat
+
+fdpass_normal_compat_head() {
+ atf_set "descr" "Test file descriptor passing (normal->compat)"
+}
+
+fdpass_normal_compat_body() {
+ local src="$(atf_get_srcdir)"
+ have32 && atf_check "${src}/fdpass64" -p "${src}/fdpass32"
+}
+
+
+atf_test_case fdpass_compat_normal
+
+fdpass_compat_normal_head() {
+ atf_set "descr" "Test file descriptor passing (normal->compat)"
+}
+
+fdpass_compat_normal_body() {
+ local src="$(atf_get_srcdir)"
+ have32 && atf_check "${src}/fdpass32" -p "${src}/fdpass64"
+}
+
+
+atf_init_test_cases()
+{
+ atf_add_test_case fdpass_normal
+ if have32
+ then
+ atf_add_test_case fdpass_compat
+ atf_add_test_case fdpass_compat_normal
+ atf_add_test_case fdpass_normal_compat
+ fi
+}
diff --git a/contrib/netbsd-tests/net/icmp/t_forward.c b/contrib/netbsd-tests/net/icmp/t_forward.c
new file mode 100644
index 0000000..d0c23cc
--- /dev/null
+++ b/contrib/netbsd-tests/net/icmp/t_forward.c
@@ -0,0 +1,169 @@
+/* $NetBSD: t_forward.c,v 1.8 2012/03/18 09:46:50 jruoho Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: t_forward.c,v 1.8 2012/03/18 09:46:50 jruoho Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <net/route.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include <atf-c.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../../h_macros.h"
+#include "../config/netconfig.c"
+
+/*
+ * Since our maxttl is in our private namespace, we don't need raw packet
+ * construction like traceroute(8) -- we can just use the global maxttl.
+ */
+static void
+sendttl(void)
+{
+ struct sockaddr_in sin;
+ char payload[1024];
+ char ifname[IFNAMSIZ];
+ int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
+ int nv;
+ int s;
+
+ netcfg_rump_makeshmif("bus1", ifname);
+ netcfg_rump_if(ifname, "1.0.0.1", "255.255.255.0");
+ netcfg_rump_route("0.0.0.0", "0.0.0.0", "1.0.0.2"); /* default router */
+
+ /* set global ttl to 1 */
+ nv = 1;
+ if (rump_sys___sysctl(mib, 4, NULL, NULL, &nv, sizeof(nv)) == -1)
+ atf_tc_fail_errno("set ttl");
+
+ s = rump_sys_socket(PF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ atf_tc_fail_errno("create send socket");
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(33434);
+ sin.sin_addr.s_addr = inet_addr("9.9.9.9");
+
+ /* send udp datagram with ttl == 1 */
+ if (rump_sys_sendto(s, payload, sizeof(payload), 0,
+ (struct sockaddr *)&sin, sizeof(sin)) == -1)
+ atf_tc_fail_errno("sendto");
+}
+
+static void
+router(void)
+{
+ int mib[4] = { CTL_NET, PF_INET, IPPROTO_ICMP,
+ ICMPCTL_RETURNDATABYTES };
+ char ifname[IFNAMSIZ];
+ int nv;
+
+ /* set returndatabytes to 200 */
+ nv = 200;
+ if (rump_sys___sysctl(mib, 4, NULL, NULL, &nv, sizeof(nv)) == -1)
+ atf_tc_fail_errno("sysctl returndatabytes");
+
+ netcfg_rump_makeshmif("bus1", ifname);
+ netcfg_rump_if(ifname, "1.0.0.2", "255.255.255.0");
+
+ /*
+ * Wait for parent to send us the data and for us to have
+ * a chance to process it.
+ */
+ sleep(1);
+ exit(0);
+}
+
+ATF_TC(returndatabytes);
+ATF_TC_HEAD(returndatabytes, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "icmp.returndatabytes with certain "
+ "packets can cause kernel panic (PR kern/43548)");
+ atf_tc_set_md_var(tc, "timeout", "4"); /* just in case */
+}
+
+ATF_TC_BODY(returndatabytes, tc)
+{
+ pid_t cpid;
+ int status;
+
+ cpid = fork();
+ rump_init();
+
+ switch (cpid) {
+ case -1:
+ atf_tc_fail_errno("fork failed");
+ case 0:
+ router();
+ break;
+ default:
+ sendttl();
+ if (wait(&status) == -1)
+ atf_tc_fail_errno("wait");
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status))
+ atf_tc_fail("child exited with status %d",
+ WEXITSTATUS(status));
+ } else {
+ atf_tc_fail("child died");
+ }
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, returndatabytes);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/icmp/t_ping.c b/contrib/netbsd-tests/net/icmp/t_ping.c
new file mode 100644
index 0000000..fd8067c
--- /dev/null
+++ b/contrib/netbsd-tests/net/icmp/t_ping.c
@@ -0,0 +1,438 @@
+/* $NetBSD: t_ping.c,v 1.15 2012/09/04 22:31:58 alnsn Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: t_ping.c,v 1.15 2012/09/04 22:31:58 alnsn Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+
+#include <atf-c.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <netinet/in.h>
+#include <netinet/ip_var.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include "../../h_macros.h"
+#include "../config/netconfig.c"
+
+ATF_TC(simpleping);
+ATF_TC_HEAD(simpleping, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "check that kernel responds to ping");
+ atf_tc_set_md_var(tc, "timeout", "2");
+}
+
+ATF_TC_BODY(simpleping, tc)
+{
+ char ifname[IFNAMSIZ];
+ pid_t cpid;
+ bool win, win2;
+ char token;
+ int channel[2];
+
+ RL(pipe(channel));
+
+ cpid = fork();
+ rump_init();
+ netcfg_rump_makeshmif("but-can-i-buy-your-ether-bus", ifname);
+
+ switch (cpid) {
+ case -1:
+ atf_tc_fail_errno("fork failed");
+ case 0:
+ netcfg_rump_if(ifname, "1.1.1.10", "255.255.255.0");
+ close(channel[0]);
+ ATF_CHECK(write(channel[1], "U", 1) == 1);
+ close(channel[1]);
+ pause();
+ break;
+ default:
+ break;
+ }
+
+ close(channel[1]);
+ ATF_CHECK(read(channel[0], &token, 1) == 1 && token == 'U');
+ close(channel[0]);
+
+ netcfg_rump_if(ifname, "1.1.1.20", "255.255.255.0");
+
+ /*
+ * The beauty of shmif is that we don't have races here.
+ */
+ win = netcfg_rump_pingtest("1.1.1.10", 500);
+ win2 = netcfg_rump_pingtest("1.1.1.30", 500);
+
+ kill(cpid, SIGKILL);
+
+ if (!win)
+ atf_tc_fail("ping failed");
+ if (win2)
+ atf_tc_fail("non-existent host responded");
+}
+
+ATF_TC(floodping);
+ATF_TC_HEAD(floodping, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "see how kernel responds to floodping");
+}
+
+/* why the hell isn't this available in userspace??? */
+static uint16_t
+in_cksum(void *data, size_t len)
+{
+ uint16_t *buf = data;
+ unsigned sum;
+
+ for (sum = 0; len > 1; len -= 2)
+ sum += *buf++;
+ if (len)
+ sum += *(uint8_t *)buf;
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+
+ return ~sum;
+}
+
+static int
+doping(const char *target, int loops, u_int pktsize)
+{
+ union {
+ char buf[IP_MAXPACKET - sizeof(struct ip)];
+ struct icmp i; /* ensure proper alignment */
+ } sndbuf;
+ char recvbuf[IP_MAXPACKET];
+ struct sockaddr_in dst, pingee;
+ struct icmp *icmp;
+ socklen_t slen;
+ ssize_t n;
+ int loop, succ;
+ int x, xnon, s;
+
+ RL(s = rump_sys_socket(PF_INET, SOCK_RAW, IPPROTO_ICMP));
+ RL(x = rump_sys_fcntl(s, F_GETFL, 0));
+ xnon = x | O_NONBLOCK;
+
+ memset(&dst, 0, sizeof(dst));
+ dst.sin_len = sizeof(dst);
+ dst.sin_family = AF_INET;
+ dst.sin_addr.s_addr = inet_addr(target);
+
+ icmp = (struct icmp *)&sndbuf;
+ memset(icmp, 0, sizeof(*icmp));
+ icmp->icmp_type = ICMP_ECHO;
+ icmp->icmp_id = htons(37);
+
+ if (pktsize < sizeof(*icmp))
+ pktsize = sizeof(*icmp);
+ if (pktsize > sizeof(sndbuf.buf))
+ pktsize = sizeof(sndbuf.buf);
+
+ RL(rump_sys_setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+ &pktsize, sizeof(pktsize)));
+ RL(rump_sys_setsockopt(s, SOL_SOCKET, SO_RCVBUF,
+ &pktsize, sizeof(pktsize)));
+
+ slen = sizeof(pingee);
+ succ = 0;
+ for (loop = 0; loop < loops; loop++) {
+ RL(rump_sys_fcntl(s, F_SETFL, x));
+ icmp->icmp_seq = htons(loop);
+ icmp->icmp_cksum = 0;
+ icmp->icmp_cksum = in_cksum(icmp, pktsize);
+ RL(rump_sys_sendto(s, icmp, pktsize, 0,
+ (struct sockaddr *)&dst, sizeof(dst)));
+
+ RL(rump_sys_fcntl(s, F_SETFL, xnon));
+ while ((n = rump_sys_recvfrom(s, recvbuf, sizeof(recvbuf), 0,
+ (struct sockaddr *)&pingee, &slen)) > 0) {
+ succ++;
+ }
+ if (n == -1 && errno == EAGAIN)
+ continue;
+ atf_tc_fail_errno("recv failed");
+ }
+
+ rump_sys_close(s);
+ return succ;
+}
+
+#define LOOPS 10000
+
+ATF_TC_BODY(floodping, tc)
+{
+ char ifname[IFNAMSIZ];
+ pid_t cpid;
+ int succ;
+
+ cpid = fork();
+ rump_init();
+ netcfg_rump_makeshmif("thank-you-driver-for-getting-me-here", ifname);
+
+ switch (cpid) {
+ case -1:
+ atf_tc_fail_errno("fork failed");
+ case 0:
+ netcfg_rump_if(ifname, "1.1.1.10", "255.255.255.0");
+ pause();
+ break;
+ default:
+ break;
+ }
+
+ netcfg_rump_if(ifname, "1.1.1.20", "255.255.255.0");
+
+ succ = doping("1.1.1.10", LOOPS, 56);
+ printf("got %d/%d\n", succ, LOOPS);
+
+ kill(cpid, SIGKILL);
+}
+
+ATF_TC(floodping2);
+ATF_TC_HEAD(floodping2, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "two hosts floodpinging each other");
+}
+
+ATF_TC_BODY(floodping2, tc)
+{
+ char ifname[IFNAMSIZ];
+ pid_t cpid;
+ int succ;
+
+ cpid = fork();
+ rump_init();
+ netcfg_rump_makeshmif("floodping2", ifname);
+
+ switch (cpid) {
+ case -1:
+ atf_tc_fail_errno("fork failed");
+ case 0:
+ netcfg_rump_if(ifname, "1.1.1.10", "255.255.255.0");
+ succ = doping("1.1.1.20", LOOPS, 56);
+ break;
+ default:
+ netcfg_rump_if(ifname, "1.1.1.20", "255.255.255.0");
+ succ = doping("1.1.1.10", LOOPS, 56);
+ break;
+ }
+
+ printf("got %d/%d\n", succ, LOOPS);
+}
+
+ATF_TC(pingsize);
+ATF_TC_HEAD(pingsize, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "ping with packets min <= size <= max");
+}
+
+ATF_TC_BODY(pingsize, tc)
+{
+ char ifname[IFNAMSIZ];
+ pid_t cpid;
+ int succ, i;
+
+ cpid = fork();
+ rump_init();
+ netcfg_rump_makeshmif("jippikaiee", ifname);
+
+ switch (cpid) {
+ case -1:
+ atf_tc_fail_errno("fork failed");
+ case 0:
+ netcfg_rump_if(ifname, "1.1.1.10", "255.255.255.0");
+ pause();
+ break;
+ default:
+ break;
+ }
+
+ netcfg_rump_if(ifname, "1.1.1.20", "255.255.255.0");
+
+ succ = 0;
+
+ /* small sizes */
+ for (i = 0 ; i < IP_MAXPACKET - 60000; i++)
+ succ += doping("1.1.1.10", 1, i);
+
+ /* medium sizes */
+ for (i = IP_MAXPACKET - 60000; i < IP_MAXPACKET - 100; i += 1000)
+ succ += doping("1.1.1.10", 1, i);
+
+ /* big sizes */
+ for (i = IP_MAXPACKET - 100; i < IP_MAXPACKET; i += 10)
+ succ += doping("1.1.1.10", 1, i);
+
+ printf("got %d/%d\n", succ, IP_MAXPACKET);
+ kill(cpid, SIGKILL);
+}
+
+ATF_TC(ping_of_death);
+ATF_TC_HEAD(ping_of_death, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "send a \"ping of death\"");
+ atf_tc_set_md_var(tc, "timeout", "2");
+}
+
+ATF_TC_BODY(ping_of_death, tc)
+{
+ char data[1500];
+ struct sockaddr_in dst;
+ struct ip *ip;
+ struct icmp *icmp;
+ char ifname[IFNAMSIZ];
+ pid_t cpid;
+ size_t tot, frag;
+ int s, x, loop;
+
+ cpid = fork();
+ rump_init();
+ netcfg_rump_makeshmif("jippikaiee", ifname);
+
+ switch (cpid) {
+ case -1:
+ atf_tc_fail_errno("fork failed");
+ case 0:
+ /* wait until we receive a too long IP packet */
+ for (loop = 0;; loop++) {
+ uint64_t ipstat[IP_NSTATS];
+ size_t arglen;
+ int mib[4];
+
+ if (loop == 1)
+ netcfg_rump_if(ifname,
+ "1.1.1.10", "255.255.255.0");
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET;
+ mib[2] = IPPROTO_IP;
+ mib[3] = IPCTL_STATS;
+
+ arglen = sizeof(ipstat);
+ RL(rump_sys___sysctl(mib, 4, &ipstat, &arglen,
+ NULL, 0));
+ if (loop == 0 && ipstat[IP_STAT_TOOLONG] != 0)
+ _exit(1);
+ if (ipstat[IP_STAT_TOOLONG])
+ break;
+ usleep(10000);
+ }
+
+ _exit(0);
+ break;
+ default:
+ break;
+ }
+
+ netcfg_rump_if(ifname, "1.1.1.20", "255.255.255.0");
+
+ RL(s = rump_sys_socket(PF_INET, SOCK_RAW, 0));
+ x = 1;
+ RL(rump_sys_setsockopt(s, IPPROTO_IP, IP_HDRINCL, &x, sizeof(x)));
+
+ memset(&dst, 0, sizeof(dst));
+ dst.sin_len = sizeof(dst);
+ dst.sin_family = AF_INET;
+ dst.sin_addr.s_addr = inet_addr("1.1.1.10");
+
+ /* construct packet */
+ memset(data, 0, sizeof(data));
+ ip = (struct ip *)data;
+ ip->ip_v = 4;
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_ttl = IPDEFTTL;
+ ip->ip_dst = dst.sin_addr;
+ ip->ip_id = 1234;
+
+ icmp = (struct icmp *)(ip + 1);
+ icmp->icmp_type = ICMP_ECHO;
+ icmp->icmp_cksum = in_cksum(icmp, sizeof(*icmp));
+
+ for (;;) {
+ int status;
+
+ /* resolve arp before sending raw stuff */
+ netcfg_rump_pingtest("1.1.1.10", 1);
+
+ for (tot = 0;
+ tot < 65538 - sizeof(*ip);
+ tot += (frag - sizeof(*ip))) {
+ frag = MIN(65538 - tot, sizeof(data));
+ ip->ip_off = tot >> 3;
+ assert((size_t)ip->ip_off << 3 == tot);
+ ip->ip_len = frag;
+
+ if (frag == sizeof(data)) {
+ ip->ip_off |= IP_MF;
+ }
+
+ RL(rump_sys_sendto(s, data, frag, 0,
+ (struct sockaddr *)&dst, sizeof(dst)));
+ }
+ if (waitpid(-1, &status, WNOHANG) > 0) {
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+ break;
+ atf_tc_fail("child did not exit clean");
+ }
+
+ usleep(10000);
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, simpleping);
+ ATF_TP_ADD_TC(tp, floodping);
+ ATF_TP_ADD_TC(tp, floodping2);
+ ATF_TP_ADD_TC(tp, pingsize);
+ ATF_TP_ADD_TC(tp, ping_of_death);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/icmp/t_ping2.sh b/contrib/netbsd-tests/net/icmp/t_ping2.sh
new file mode 100755
index 0000000..30ff73b
--- /dev/null
+++ b/contrib/netbsd-tests/net/icmp/t_ping2.sh
@@ -0,0 +1,78 @@
+# $NetBSD: t_ping2.sh,v 1.4 2010/12/30 16:58:07 pooka Exp $
+#
+# Copyright (c) 2010 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+netserver=\
+"rump_server -lrumpnet -lrumpnet_net -lrumpnet_netinet -lrumpnet_shmif"
+
+atf_test_case basic cleanup
+basic_head()
+{
+
+ atf_set "descr" "Checks that a simple ping works"
+}
+
+docfg ()
+{
+
+ sock=${1}
+ addr=${2}
+
+ atf_check -s exit:0 \
+ env RUMP_SERVER=${sock} rump.ifconfig shmif0 create
+ atf_check -s exit:0 \
+ env RUMP_SERVER=${sock} rump.ifconfig shmif0 linkstr bus
+ atf_check -s exit:0 \
+ env RUMP_SERVER=${sock} rump.ifconfig shmif0 inet ${addr}
+}
+
+basic_body()
+{
+
+ atf_check -s exit:0 ${netserver} unix://commsock1
+ atf_check -s exit:0 ${netserver} unix://commsock2
+
+ docfg unix://commsock1 1.2.3.4
+ docfg unix://commsock2 1.2.3.5
+
+ atf_check -s exit:0 -o ignore \
+ env RUMP_SERVER=unix://commsock1 rump.ping -n -c 1 1.2.3.5
+ atf_check -s exit:0 -o ignore \
+ env RUMP_SERVER=unix://commsock2 rump.ping -n -c 1 1.2.3.5
+}
+
+basic_cleanup()
+{
+
+ env RUMP_SERVER=unix://commsock1 rump.halt
+ env RUMP_SERVER=unix://commsock2 rump.halt
+}
+
+atf_init_test_cases()
+{
+
+ atf_add_test_case basic
+}
diff --git a/contrib/netbsd-tests/net/if/t_compat.c b/contrib/netbsd-tests/net/if/t_compat.c
new file mode 100644
index 0000000..4798034
--- /dev/null
+++ b/contrib/netbsd-tests/net/if/t_compat.c
@@ -0,0 +1,83 @@
+/* $NetBSD: t_compat.c,v 1.1 2010/11/07 19:53:42 pooka Exp $ */
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include "../config/netconfig.c"
+
+/*
+ * Test for stack smashing in compat ioctl handling. Adapted as an
+ * atf test from code provided by Onno van der Linden in PR kern/44054
+ */
+
+struct oifreq {
+ char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ short ifru_flags;
+ int ifru_metric;
+ int ifru_mtu;
+ int ifru_dlt;
+ u_int ifru_value;
+ void * ifru_data;
+ struct {
+ uint32_t b_buflen;
+ void *b_buf;
+ } ifru_b;
+ } ifr_ifru;
+};
+#define OOSIOCGIFBRDADDR _IOWR('i', 18, struct oifreq)
+
+ATF_TC(OOSIOCGIFBRDADDR);
+ATF_TC_HEAD(OOSIOCGIFBRDADDR, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Checks that OOSIOCGIFBRDADDR works "
+ "(PR kern/44054)");
+}
+
+ATF_TC_BODY(OOSIOCGIFBRDADDR, tc)
+{
+ int fd, ifnum;
+ struct oifreq ifreq;
+ struct sockaddr_in *sin;
+ int rv;
+
+ memset(&ifreq,'\0',sizeof ifreq);
+
+ rump_init();
+
+ /* create an interface and give it netmask 0xffff0000 */
+ rv = rump_pub_shmif_create("bus", &ifnum);
+ if (rv)
+ atf_tc_fail("failed to create shmif: %s", strerror(rv));
+ sprintf(ifreq.ifr_name, "shmif%d", ifnum);
+ netcfg_rump_if(ifreq.ifr_name, "1.7.64.10", "255.255.0.0");
+
+ /* query kernel for iface bcast */
+ RL(fd = rump_sys_socket(AF_INET, SOCK_DGRAM, 0));
+ RL(rump_sys_ioctl(fd, OOSIOCGIFBRDADDR, &ifreq));
+
+ /* make sure we got what we deserve */
+ sin = (struct sockaddr_in *)&ifreq.ifr_broadaddr;
+ ATF_REQUIRE_EQ(sin->sin_addr.s_addr, htonl(0x0107ffff));
+ rump_sys_close(fd);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, OOSIOCGIFBRDADDR);
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/if_bridge/t_bridge.sh b/contrib/netbsd-tests/net/if_bridge/t_bridge.sh
new file mode 100755
index 0000000..5fbafc7
--- /dev/null
+++ b/contrib/netbsd-tests/net/if_bridge/t_bridge.sh
@@ -0,0 +1,312 @@
+#! /usr/bin/atf-sh
+# $NetBSD: t_bridge.sh,v 1.1 2014/09/18 15:13:27 ozaki-r Exp $
+#
+# Copyright (c) 2014 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+inetserver="rump_server -lrumpnet -lrumpnet_net -lrumpnet_netinet -lrumpnet_bridge -lrumpnet_shmif"
+inet6server="rump_server -lrumpnet -lrumpnet_net -lrumpnet_netinet -lrumpnet_netinet6 -lrumpnet_bridge -lrumpnet_shmif"
+
+SOCK1=unix://commsock1
+SOCK2=unix://commsock2
+SOCK3=unix://commsock3
+IP1=10.0.0.1
+IP2=10.0.0.2
+IP61=fc00::1
+IP62=fc00::2
+
+atf_test_case basic cleanup
+atf_test_case basic6 cleanup
+
+basic_head()
+{
+ atf_set "descr" "Does simple if_bridge tests"
+ atf_set "require.progs" "rump_server"
+}
+
+basic6_head()
+{
+ atf_set "descr" "Does simple if_bridge tests (IPv6)"
+ atf_set "require.progs" "rump_server"
+}
+
+setup_endpoint()
+{
+ sock=${1}
+ addr=${2}
+ bus=${3}
+ mode=${4}
+
+ export RUMP_SERVER=${sock}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ${bus}
+ if [ $mode = "ipv6" ]; then
+ atf_check -s exit:0 rump.ifconfig shmif0 inet6 ${addr}
+ else
+ atf_check -s exit:0 rump.ifconfig shmif0 inet ${addr} netmask 0xffffff00
+ fi
+
+ atf_check -s exit:0 rump.ifconfig shmif0 up
+ rump.ifconfig shmif0
+}
+
+test_endpoint()
+{
+ sock=${1}
+ addr=${2}
+ bus=${3}
+ mode=${4}
+
+ export RUMP_SERVER=${sock}
+ atf_check -s exit:0 -o match:shmif0 rump.ifconfig
+ if [ $mode = "ipv6" ]; then
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ atf_check -s exit:0 -o ignore ping6 -n -c 1 ${addr}
+ unset LD_PRELOAD
+ else
+ atf_check -s exit:0 -o ignore rump.ping -n -w 1 -c 1 ${addr}
+ fi
+}
+
+show_endpoint()
+{
+ sock=${1}
+
+ export RUMP_SERVER=${sock}
+ rump.ifconfig -v shmif0
+}
+
+test_setup()
+{
+ test_endpoint $SOCK1 $IP1 bus1 ipv4
+ test_endpoint $SOCK3 $IP2 bus2 ipv4
+
+ export RUMP_SERVER=$SOCK2
+ atf_check -s exit:0 -o match:shmif0 rump.ifconfig
+ atf_check -s exit:0 -o match:shmif1 rump.ifconfig
+}
+
+test_setup6()
+{
+ test_endpoint $SOCK1 $IP61 bus1 ipv6
+ test_endpoint $SOCK3 $IP62 bus2 ipv6
+
+ export RUMP_SERVER=$SOCK2
+ atf_check -s exit:0 -o match:shmif0 rump.ifconfig
+ atf_check -s exit:0 -o match:shmif1 rump.ifconfig
+}
+
+setup_bridge_server()
+{
+ export RUMP_SERVER=$SOCK2
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr bus1
+ atf_check -s exit:0 rump.ifconfig shmif0 up
+
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr bus2
+ atf_check -s exit:0 rump.ifconfig shmif1 up
+}
+
+setup()
+{
+ atf_check -s exit:0 ${inetserver} $SOCK1
+ atf_check -s exit:0 ${inetserver} $SOCK2
+ atf_check -s exit:0 ${inetserver} $SOCK3
+
+ setup_endpoint $SOCK1 $IP1 bus1 ipv4
+ setup_endpoint $SOCK3 $IP2 bus2 ipv4
+ setup_bridge_server
+}
+
+setup6()
+{
+ atf_check -s exit:0 ${inet6server} $SOCK1
+ atf_check -s exit:0 ${inet6server} $SOCK2
+ atf_check -s exit:0 ${inet6server} $SOCK3
+
+ setup_endpoint $SOCK1 $IP61 bus1 ipv6
+ setup_endpoint $SOCK3 $IP62 bus2 ipv6
+ setup_bridge_server
+}
+
+setup_bridge()
+{
+ export RUMP_SERVER=$SOCK2
+ atf_check -s exit:0 rump.ifconfig bridge0 create
+ atf_check -s exit:0 rump.ifconfig bridge0 up
+
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ atf_check -s exit:0 /sbin/brconfig bridge0 add shmif0
+ atf_check -s exit:0 /sbin/brconfig bridge0 add shmif1
+ /sbin/brconfig bridge0
+ unset LD_PRELOAD
+ rump.ifconfig shmif0
+ rump.ifconfig shmif1
+}
+
+teardown_bridge()
+{
+ export RUMP_SERVER=$SOCK2
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ /sbin/brconfig bridge0
+ atf_check -s exit:0 /sbin/brconfig bridge0 delete shmif0
+ atf_check -s exit:0 /sbin/brconfig bridge0 delete shmif1
+ /sbin/brconfig bridge0
+ unset LD_PRELOAD
+ rump.ifconfig shmif0
+ rump.ifconfig shmif1
+}
+
+test_setup_bridge()
+{
+ export RUMP_SERVER=$SOCK2
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ atf_check -s exit:0 -o match:shmif0 /sbin/brconfig bridge0
+ atf_check -s exit:0 -o match:shmif1 /sbin/brconfig bridge0
+ /sbin/brconfig bridge0
+ unset LD_PRELOAD
+}
+
+cleanup()
+{
+ env RUMP_SERVER=$SOCK1 rump.halt
+ env RUMP_SERVER=$SOCK2 rump.halt
+ env RUMP_SERVER=$SOCK3 rump.halt
+}
+
+dump_bus()
+{
+ /usr/bin/shmif_dumpbus -p - bus1 2>/dev/null| /usr/sbin/tcpdump -n -e -r -
+ /usr/bin/shmif_dumpbus -p - bus2 2>/dev/null| /usr/sbin/tcpdump -n -e -r -
+}
+
+down_up_interfaces()
+{
+ export RUMP_SERVER=$SOCK1
+ rump.ifconfig shmif0 down
+ rump.ifconfig shmif0 up
+ export RUMP_SERVER=$SOCK3
+ rump.ifconfig shmif0 down
+ rump.ifconfig shmif0 up
+}
+
+test_ping_failure()
+{
+ export RUMP_SERVER=$SOCK1
+ atf_check -s not-exit:0 -o ignore rump.ping -q -n -w 1 -c 1 $IP2
+ export RUMP_SERVER=$SOCK3
+ atf_check -s not-exit:0 -o ignore rump.ping -q -n -w 1 -c 1 $IP1
+}
+
+test_ping_success()
+{
+ export RUMP_SERVER=$SOCK1
+ rump.ifconfig -v shmif0
+ atf_check -s exit:0 -o ignore rump.ping -q -n -w 1 -c 1 $IP2
+ rump.ifconfig -v shmif0
+
+ export RUMP_SERVER=$SOCK3
+ rump.ifconfig -v shmif0
+ atf_check -s exit:0 -o ignore rump.ping -q -n -w 1 -c 1 $IP1
+ rump.ifconfig -v shmif0
+}
+
+test_ping6_failure()
+{
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ export RUMP_SERVER=$SOCK1
+ atf_check -s not-exit:0 -o ignore ping6 -q -n -c 1 $IP62
+ export RUMP_SERVER=$SOCK3
+ atf_check -s not-exit:0 -o ignore ping6 -q -n -c 1 $IP61
+ unset LD_PRELOAD
+}
+
+test_ping6_success()
+{
+ export RUMP_SERVER=$SOCK1
+ rump.ifconfig -v shmif0
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ atf_check -s exit:0 -o ignore ping6 -q -n -c 1 $IP62
+ unset LD_PRELOAD
+ rump.ifconfig -v shmif0
+
+ export RUMP_SERVER=$SOCK3
+ rump.ifconfig -v shmif0
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+ atf_check -s exit:0 -o ignore ping6 -q -n -c 1 $IP61
+ unset LD_PRELOAD
+ rump.ifconfig -v shmif0
+}
+
+basic_body()
+{
+ setup
+ test_setup
+
+ setup_bridge
+ test_setup_bridge
+
+ test_ping_success
+
+ teardown_bridge
+ test_ping_failure
+}
+
+basic6_body()
+{
+ setup6
+ test_setup6
+
+ # TODO: enable once ping6 implements timeout feature
+ #test_ping6_failure
+
+ setup_bridge
+ test_setup_bridge
+
+ test_ping6_success
+
+ teardown_bridge
+ # TODO: enable once ping6 implements timeout feature
+ #test_ping6_failure
+}
+
+basic_cleanup()
+{
+ dump_bus
+ cleanup
+}
+
+basic6_cleanup()
+{
+ dump_bus
+ cleanup
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case basic
+ atf_add_test_case basic6
+}
diff --git a/contrib/netbsd-tests/net/if_loop/t_pr.c b/contrib/netbsd-tests/net/if_loop/t_pr.c
new file mode 100644
index 0000000..a22953f
--- /dev/null
+++ b/contrib/netbsd-tests/net/if_loop/t_pr.c
@@ -0,0 +1,229 @@
+/* $NetBSD: t_pr.c,v 1.7 2012/03/18 09:46:50 jruoho Exp $ */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: t_pr.c,v 1.7 2012/03/18 09:46:50 jruoho Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <net/route.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include <atf-c.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../config/netconfig.c"
+#include "../../h_macros.h"
+
+/*
+ * Prepare rump, configure interface and route to cause fragmentation
+ */
+static void
+setup(void)
+{
+ char ifname[IFNAMSIZ];
+ struct {
+ struct rt_msghdr m_rtm;
+ struct sockaddr_in m_sin;
+ } m_rtmsg;
+#define rtm m_rtmsg.m_rtm
+#define rsin m_rtmsg.m_sin
+ struct ifreq ifr;
+ int s;
+
+ rump_init();
+
+ /* first, config lo0 & route */
+ strcpy(ifname, "lo0");
+ netcfg_rump_if(ifname, "127.0.0.1", "255.0.0.0");
+ netcfg_rump_route("127.0.0.1", "255.0.0.0", "127.0.0.1");
+
+ if ((s = rump_sys_socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
+ atf_tc_fail_errno("routing socket");
+
+ /*
+ * set MTU for interface so that route MTU doesn't
+ * get overridden by it.
+ */
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, "lo0");
+ ifr.ifr_mtu = 1300;
+ if (rump_sys_ioctl(s, SIOCSIFMTU, &ifr) == -1)
+ atf_tc_fail_errno("set mtu");
+
+ /* change route MTU to 100 */
+ memset(&m_rtmsg, 0, sizeof(m_rtmsg));
+ rtm.rtm_type = RTM_CHANGE;
+ rtm.rtm_flags = RTF_STATIC;
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_seq = 3;
+ rtm.rtm_inits = RTV_MTU;
+ rtm.rtm_addrs = RTA_DST;
+ rtm.rtm_rmx.rmx_mtu = 100;
+ rtm.rtm_msglen = sizeof(m_rtmsg);
+
+ memset(&rsin, 0, sizeof(rsin));
+ rsin.sin_family = AF_INET;
+ rsin.sin_len = sizeof(rsin);
+ rsin.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ if (rump_sys_write(s, &m_rtmsg, sizeof(m_rtmsg)) != sizeof(m_rtmsg))
+ atf_tc_fail_errno("set route mtu");
+ rump_sys_close(s);
+}
+
+/*
+ * Turn on checksums on loopback interfaces
+ */
+static int
+enable_locsums(void)
+{
+ struct sysctlnode q, ans[256];
+ int mib[5], enable;
+ size_t alen;
+ unsigned i;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET;
+ mib[2] = IPPROTO_IP;
+ mib[3] = CTL_QUERY;
+ alen = sizeof(ans);
+
+ memset(&q, 0, sizeof(q));
+ q.sysctl_flags = SYSCTL_VERSION;
+
+ if (rump_sys___sysctl(mib, 4, ans, &alen, &q, sizeof(q)) == -1)
+ return -1;
+
+ for (i = 0; i < __arraycount(ans); i++)
+ if (strcmp("do_loopback_cksum", ans[i].sysctl_name) == 0)
+ break;
+ if (i == __arraycount(ans)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ mib[3] = ans[i].sysctl_num;
+
+ enable = 1;
+ if (rump_sys___sysctl(mib, 4, NULL, NULL, &enable,
+ sizeof(enable)) == -1)
+ return errno;
+
+ return 0;
+}
+
+ATF_TC(loopmtu);
+ATF_TC_HEAD(loopmtu, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "test lo0 fragmentation (PR kern/43664)");
+}
+
+ATF_TC_BODY(loopmtu, tc)
+{
+ struct sockaddr_in sin;
+ char data[2000];
+ int s;
+
+ setup();
+
+ /* open raw socket */
+ s = rump_sys_socket(PF_INET, SOCK_RAW, 0);
+ if (s == -1)
+ atf_tc_fail_errno("raw socket");
+
+ /* then, send data */
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(sin);
+ sin.sin_port = htons(12345);
+ sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ if (rump_sys_sendto(s, data, sizeof(data), 0,
+ (struct sockaddr *)&sin, sizeof(sin)) == -1)
+ atf_tc_fail_errno("sendto failed");
+}
+
+ATF_TC(loopmtu_csum);
+ATF_TC_HEAD(loopmtu_csum, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "test lo0 fragmentation with checksums (PR kern/43664)");
+}
+
+ATF_TC_BODY(loopmtu_csum, tc)
+{
+ struct sockaddr_in sin;
+ char data[2000];
+ int s;
+
+ setup();
+
+ ATF_CHECK(enable_locsums() == 0);
+
+ /* open raw socket */
+ s = rump_sys_socket(PF_INET, SOCK_RAW, 0);
+ if (s == -1)
+ atf_tc_fail_errno("raw socket");
+
+ /* then, send data */
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(sin);
+ sin.sin_port = htons(12345);
+ sin.sin_addr.s_addr = inet_addr("127.0.0.1");
+
+ if (rump_sys_sendto(s, data, sizeof(data), 0,
+ (struct sockaddr *)&sin, sizeof(sin)) == -1)
+ atf_tc_fail_errno("sendto failed");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, loopmtu);
+ ATF_TP_ADD_TC(tp, loopmtu_csum);
+
+ return atf_no_error();
+}
+
diff --git a/contrib/netbsd-tests/net/mpls/t_ldp_regen.sh b/contrib/netbsd-tests/net/mpls/t_ldp_regen.sh
new file mode 100755
index 0000000..65fc29f
--- /dev/null
+++ b/contrib/netbsd-tests/net/mpls/t_ldp_regen.sh
@@ -0,0 +1,178 @@
+# $NetBSD: t_ldp_regen.sh,v 1.4 2014/09/01 06:38:35 gson Exp $
+#
+# Copyright (c) 2013 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# IP/MPLS & LDP label reallocation test
+# Create 4 routers connected like this: R1--R2--R3--R4--
+# The goal is to push packets from R1 to the R4 shmif1 (the right one) interface
+# Enable MPLS forwarding on R2
+# Disable IP forwarding and enable MPLS forwarding on R3
+# Start ldpd and wait for adjancencies to come up
+# Add an alias on shmif1 on R4 for which we already have a route on R3
+# Now: * R4 should install label IMPLNULL for that prefix
+# * R3 should realloc the target label from IMPLNULL to something else
+
+
+RUMP_SERVER1=unix://./r1
+RUMP_SERVER2=unix://./r2
+RUMP_SERVER3=unix://./r3
+RUMP_SERVER4=unix://./r4
+
+RUMP_LIBS="-lrumpnet -lrumpnet_net -lrumpnet_netmpls -lrumpnet_netinet -lrumpnet_netinet6 -lrumpnet_shmif"
+LDP_FLAGS=""
+
+atf_test_case ldp_regen cleanup
+ldp_regen_head() {
+
+ atf_set "descr" "IP/MPLS and LDP label regeneration test"
+ atf_set "require.progs" "rump_server"
+ atf_set "use.fs" "true"
+}
+
+newaddr_and_ping() {
+
+ # Add new address on R4
+ RUMP_SERVER=${RUMP_SERVER4} atf_check -s exit:0 \
+ rump.ifconfig shmif1 10.0.5.1/24 alias
+
+ # Now ldpd on R5 should take notice of the new route and announce it
+ # to R4's ldpd. ldpd on R4 should verify that the next hop
+ # corresponds to its routing table and change its tag entry
+ RUMP_SERVER=${RUMP_SERVER1} atf_check -s exit:0 -o ignore -e ignore \
+ rump.ping -n -o -w 5 10.0.5.1
+}
+
+create_servers() {
+
+ # allows us to run as normal user
+ ulimit -r 400
+
+ atf_check -s exit:0 rump_server ${RUMP_LIBS} ${RUMP_SERVER1}
+ atf_check -s exit:0 rump_server ${RUMP_LIBS} ${RUMP_SERVER2}
+ atf_check -s exit:0 rump_server ${RUMP_LIBS} ${RUMP_SERVER3}
+ atf_check -s exit:0 rump_server ${RUMP_LIBS} ${RUMP_SERVER4}
+
+ # LDP HIJACK
+ export RUMPHIJACK=path=/rump,socket=all,sysctl=yes
+ export LD_PRELOAD=/usr/lib/librumphijack.so
+
+ # Setup first server
+ export RUMP_SERVER=${RUMP_SERVER1}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom1
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.1.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add 10.0.4.0/24 10.0.1.2
+ atf_check -s exit:0 rump.route -q add 10.0.5.0/24 10.0.1.2
+ atf_check -s exit:0 /usr/sbin/ldpd ${LDP_FLAGS}
+
+ # Setup second server
+ export RUMP_SERVER=${RUMP_SERVER2}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom1
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.1.2/24
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr ./shdom2
+ atf_check -s exit:0 rump.ifconfig shmif1 10.0.2.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.forwarding=1
+ # This one should still do ip forwarding because it announces IMPLNULL
+ # for the 10.0.1.0/24 subnet
+ atf_check -s exit:0 rump.route -q add 10.0.4.0/24 10.0.2.2
+ atf_check -s exit:0 rump.route -q add 10.0.5.0/24 10.0.2.2
+ atf_check -s exit:0 /usr/sbin/ldpd ${LDP_FLAGS}
+
+ # Setup third server
+ export RUMP_SERVER=${RUMP_SERVER3}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom2
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.2.2/24
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr ./shdom3
+ atf_check -s exit:0 rump.ifconfig shmif1 10.0.3.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.forwarding=1
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add 10.0.1.0/24 10.0.2.1
+ atf_check -s exit:0 rump.route -q add 10.0.4.0/24 10.0.3.2
+ atf_check -s exit:0 rump.route -q add 10.0.5.0/24 10.0.3.2
+ atf_check -s exit:0 /usr/sbin/ldpd ${LDP_FLAGS}
+
+ # Setup fourth server
+ export RUMP_SERVER=${RUMP_SERVER4}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom3
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.3.2/24
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr ./shdom4
+ atf_check -s exit:0 rump.ifconfig shmif1 10.0.4.1/24
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.route -q add 10.0.1.0/24 10.0.3.1
+ atf_check -s exit:0 /usr/sbin/ldpd ${LDP_FLAGS}
+
+ unset RUMP_SERVER
+ unset LD_PRELOAD
+ unset RUMPHIJACK
+}
+
+wait_ldp_ok() {
+
+ RUMP_SERVER=${RUMP_SERVER1} atf_check -s exit:0 -o ignore -e ignore \
+ rump.ping -o -w 60 10.0.4.1
+}
+
+docleanup() {
+
+ RUMP_SERVER=${RUMP_SERVER1} rump.halt
+ RUMP_SERVER=${RUMP_SERVER2} rump.halt
+ RUMP_SERVER=${RUMP_SERVER3} rump.halt
+ RUMP_SERVER=${RUMP_SERVER4} rump.halt
+}
+
+ldp_regen_body() {
+
+ if sysctl machdep.cpu_brand | grep QEMU >/dev/null 2>&1
+ then
+ atf_skip "unreliable under qemu, skip until PR kern/43997 fixed"
+ fi
+ create_servers
+ wait_ldp_ok
+ newaddr_and_ping
+}
+
+ldp_regen_cleanup() {
+
+ docleanup
+}
+
+atf_init_test_cases() {
+
+ atf_add_test_case ldp_regen
+}
diff --git a/contrib/netbsd-tests/net/mpls/t_mpls_fw.sh b/contrib/netbsd-tests/net/mpls/t_mpls_fw.sh
new file mode 100755
index 0000000..ddd42df
--- /dev/null
+++ b/contrib/netbsd-tests/net/mpls/t_mpls_fw.sh
@@ -0,0 +1,188 @@
+# $NetBSD: t_mpls_fw.sh,v 1.4 2014/03/18 18:20:44 riastradh Exp $
+#
+# Copyright (c) 2013 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# TEST MPLS encap/decap and forwarding using INET as encapsulated protocol
+# Setup four routers connected like this: R1---R2---R3---R4--
+# Goal is to be able to ping from R1 the outermost interface of R4
+# Disable net.inet.ip.forwarding, enable net.mpls.forwarding
+# Add route on R1 in order to encapsulate into MPLS the IP packets with
+# destination equal to R4 right hand side interface
+# Add MPLS routes on R2 in order to forward frames belonging to that FEC to R3
+# Add MPLS "POP" route on R3 for that FEC, pointing to R4
+# Do the same for the reverse direction (R4 to R1)
+# ping from R1 to R4 right hand side interface
+
+
+RUMP_SERVER1=unix://./r1
+RUMP_SERVER2=unix://./r2
+RUMP_SERVER3=unix://./r3
+RUMP_SERVER4=unix://./r4
+
+RUMP_FLAGS=\
+"-lrumpnet -lrumpnet_net -lrumpnet_netmpls -lrumpnet_netinet -lrumpnet_shmif"
+
+atf_test_case mplsfw4 cleanup
+mplsfw4_head()
+{
+
+ atf_set "descr" "IP/MPLS forwarding test using PHP"
+ atf_set "require.progs" "rump_server"
+}
+
+startservers()
+{
+
+ ulimit -r 300
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${RUMP_SERVER1}
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${RUMP_SERVER2}
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${RUMP_SERVER3}
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${RUMP_SERVER4}
+}
+
+configservers()
+{
+
+ # Setup the first server
+ export RUMP_SERVER=${RUMP_SERVER1}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom1
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.1.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add 10.0.4.0/24 -ifa 10.0.1.1 \
+ -ifp mpls0 -tag 25 -inet 10.0.1.2
+
+ # Setup the second server
+ export RUMP_SERVER=${RUMP_SERVER2}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom1
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.1.2/24
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr ./shdom2
+ atf_check -s exit:0 rump.ifconfig shmif1 10.0.2.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.forwarding=1
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add -mpls 25 -tag 30 -inet 10.0.2.2
+ atf_check -s exit:0 rump.route -q add -mpls 27 -tag ${1} -inet 10.0.1.1
+
+ # Setup the third server
+ export RUMP_SERVER=${RUMP_SERVER3}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom2
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.2.2/24
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr ./shdom3
+ atf_check -s exit:0 rump.ifconfig shmif1 10.0.3.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.forwarding=1
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add -mpls 30 -tag ${1} -inet 10.0.3.2
+ atf_check -s exit:0 rump.route -q add -mpls 26 -tag 27 -inet 10.0.2.1
+
+ # Setup the fourth server
+ export RUMP_SERVER=${RUMP_SERVER4}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom3
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.3.2/24
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr ./shdom4
+ atf_check -s exit:0 rump.ifconfig shmif1 10.0.4.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add 10.0.1.0/24 -ifa 10.0.3.2 \
+ -ifp mpls0 -tag 26 -inet 10.0.3.1
+
+ unset RUMP_SERVER
+}
+
+doping()
+{
+
+ export RUMP_SERVER=${RUMP_SERVER1}
+ atf_check -s exit:0 -o match:"64 bytes from 10.0.4.1: icmp_seq=" \
+ rump.ping -n -o -w 5 10.0.4.1
+ unset RUMP_SERVER
+}
+
+docleanup()
+{
+
+ RUMP_SERVER=${RUMP_SERVER1} rump.halt
+ RUMP_SERVER=${RUMP_SERVER2} rump.halt
+ RUMP_SERVER=${RUMP_SERVER3} rump.halt
+ RUMP_SERVER=${RUMP_SERVER4} rump.halt
+}
+
+mplsfw4_body()
+{
+
+ startservers
+ configservers 3
+ doping
+}
+
+mplsfw4_cleanup()
+{
+
+ docleanup
+}
+
+
+atf_test_case mplsfw4_expl cleanup
+mplsfw4_expl_head()
+{
+
+ atf_set "descr" "IP/MPLS forwarding test using explicit NULL labels"
+ atf_set "require.progs" "rump_server"
+}
+
+mplsfw4_expl_body()
+{
+
+ startservers
+ configservers 0
+ doping
+}
+
+mplsfw4_expl_cleanup()
+{
+
+ docleanup
+}
+
+
+atf_init_test_cases()
+{
+
+ atf_add_test_case mplsfw4
+ atf_add_test_case mplsfw4_expl
+}
diff --git a/contrib/netbsd-tests/net/mpls/t_rfc4182.sh b/contrib/netbsd-tests/net/mpls/t_rfc4182.sh
new file mode 100755
index 0000000..8c166f9
--- /dev/null
+++ b/contrib/netbsd-tests/net/mpls/t_rfc4182.sh
@@ -0,0 +1,165 @@
+# $NetBSD: t_rfc4182.sh,v 1.3 2014/03/18 18:20:44 riastradh Exp $
+#
+# Copyright (c) 2013 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# TEST RFC 4182
+# Setup four routers connected like this: R1---R2---R3---R4--
+# Goal is to be able to ping from R1 the outermost interface of R4
+# Disable net.inet.ip.forwarding, enable net.mpls.forwarding
+# Add route on R1 in order to encapsulate into MPLS the IP packets with
+# destination equal to R4 right hand side interface. Use two labels here:
+# 25 and IPv6 Explicit NULL
+# Add a double tagged MPLS route on R2 in order to forward frames belonging to
+# that FEC to R3, with IPv4 NULL being the most outermost one
+# Add MPLS "POP" route on R3 for that FEC, pointing to R4
+# Do the same for the reverse direction (R4 to R1)
+# ping from R1 to R4 right hand side interface
+
+
+RUMP_SERVER1=unix://./r1
+RUMP_SERVER2=unix://./r2
+RUMP_SERVER3=unix://./r3
+RUMP_SERVER4=unix://./r4
+
+RUMP_FLAGS=\
+"-lrumpnet -lrumpnet_net -lrumpnet_netmpls -lrumpnet_netinet -lrumpnet_shmif"
+
+atf_test_case rfc4182 cleanup
+rfc4182_head()
+{
+
+ atf_set "descr" "RFC 4182 conformance test"
+ atf_set "require.progs" "rump_server"
+}
+
+startservers()
+{
+
+ ulimit -r 300
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${RUMP_SERVER1}
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${RUMP_SERVER2}
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${RUMP_SERVER3}
+ atf_check -s exit:0 rump_server ${RUMP_FLAGS} ${RUMP_SERVER4}
+}
+
+configservers()
+{
+
+ # Setup the first server
+ export RUMP_SERVER=${RUMP_SERVER1}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom1
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.1.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add 10.0.4.0/24 -ifa 10.0.1.1 \
+ -ifp mpls0 -tag 25,2 -inet 10.0.1.2
+
+ # Setup the second server
+ export RUMP_SERVER=${RUMP_SERVER2}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom1
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.1.2/24
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr ./shdom2
+ atf_check -s exit:0 rump.ifconfig shmif1 10.0.2.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.forwarding=1
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add -mpls 25 -tag 30,0 -inet 10.0.2.2
+ atf_check -s exit:0 rump.route -q add -mpls 27 -tag 3 -inet 10.0.1.1
+
+ # Setup the third server
+ export RUMP_SERVER=${RUMP_SERVER3}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom2
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.2.2/24
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr ./shdom3
+ atf_check -s exit:0 rump.ifconfig shmif1 10.0.3.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.forwarding=1
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add -mpls 30 -tag 3 -inet 10.0.3.2
+ atf_check -s exit:0 rump.route -q add -mpls 26 -tag 27,0 -inet 10.0.2.1
+
+ # Setup the fourth server
+ export RUMP_SERVER=${RUMP_SERVER4}
+ atf_check -s exit:0 rump.ifconfig shmif0 create
+ atf_check -s exit:0 rump.ifconfig shmif0 linkstr ./shdom3
+ atf_check -s exit:0 rump.ifconfig shmif0 10.0.3.2/24
+ atf_check -s exit:0 rump.ifconfig shmif1 create
+ atf_check -s exit:0 rump.ifconfig shmif1 linkstr ./shdom4
+ atf_check -s exit:0 rump.ifconfig shmif1 10.0.4.1/24
+ atf_check -s exit:0 rump.ifconfig mpls0 create up
+ atf_check -s exit:0 rump.sysctl -q -w net.mpls.accept=1
+ atf_check -s exit:0 rump.sysctl -q -w net.inet.ip.forwarding=0
+ atf_check -s exit:0 rump.route -q add 10.0.1.0/24 -ifa 10.0.3.2 \
+ -ifp mpls0 -tag 26 -inet 10.0.3.1
+
+ unset RUMP_SERVER
+}
+
+doping()
+{
+
+ export RUMP_SERVER=${RUMP_SERVER1}
+ atf_check -s exit:0 -o match:"64 bytes from 10.0.4.1: icmp_seq=" \
+ rump.ping -n -o -w 5 10.0.4.1
+ unset RUMP_SERVER
+}
+
+docleanup()
+{
+
+ RUMP_SERVER=${RUMP_SERVER1} rump.halt
+ RUMP_SERVER=${RUMP_SERVER2} rump.halt
+ RUMP_SERVER=${RUMP_SERVER3} rump.halt
+ RUMP_SERVER=${RUMP_SERVER4} rump.halt
+}
+
+rfc4182_body()
+{
+
+ startservers
+ configservers
+ doping
+}
+
+rfc4182_cleanup()
+{
+
+ docleanup
+}
+
+atf_init_test_cases()
+{
+
+ atf_add_test_case rfc4182
+}
diff --git a/contrib/netbsd-tests/net/net/t_pktinfo.c b/contrib/netbsd-tests/net/net/t_pktinfo.c
new file mode 100644
index 0000000..326f9f6
--- /dev/null
+++ b/contrib/netbsd-tests/net/net/t_pktinfo.c
@@ -0,0 +1,194 @@
+/* $NetBSD: t_pktinfo.c,v 1.2 2013/10/19 17:45:01 christos Exp $ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_pktinfo.c,v 1.2 2013/10/19 17:45:01 christos Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+static const char traffic[] = "foo";
+
+#ifdef TEST
+#include <err.h>
+#define ERR(msg) err(EXIT_FAILURE, msg)
+#define ERRX(msg, a) errx(EXIT_FAILURE, msg, a)
+#define ERRX2(msg, a1, a2) errx(EXIT_FAILURE, msg, a1, a2)
+#else
+#include <atf-c.h>
+#define ERR(msg) ATF_REQUIRE_MSG(0, "%s: %s", msg, strerror(errno))
+#define ERRX(msg, a) ATF_REQUIRE_MSG(0, msg, a)
+#define ERRX2(msg, a1, a2) ATF_REQUIRE_MSG(0, msg, a1, a2)
+#endif
+
+static int
+server(struct sockaddr_in *sin) {
+ int s, one;
+ socklen_t len = sizeof(*sin);
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ ERR("socket");
+
+ memset(sin, 0, len);
+ sin->sin_family = AF_INET;
+ sin->sin_len = len;
+ sin->sin_port = 0;
+ sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ if (bind(s, (const struct sockaddr *)sin, len) == -1)
+ ERR("bind");
+
+ if (getsockname(s, (struct sockaddr *)sin, &len) == -1)
+ ERR("getsockname");
+
+ one = 1;
+ if (setsockopt(s, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)) == -1)
+ ERR("setsockopt");
+ if (setsockopt(s, IPPROTO_IP, IP_RECVPKTINFO, &one, sizeof(one)) == -1)
+ ERR("setsockopt");
+
+ return s;
+}
+
+static int
+client(struct sockaddr_in *sin) {
+ int s;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
+ ERR("socket");
+ if (sendto(s, traffic, sizeof(traffic), 0,
+ (const struct sockaddr *)sin, sizeof(*sin)) == -1)
+ ERR("sendto");
+ return s;
+}
+
+static void
+receive(int s) {
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ char buf[sizeof(traffic)];
+ struct in_pktinfo *ipi;
+ char control[CMSG_SPACE(sizeof(*ipi)) * 2];
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ memset(&iov, 0, sizeof(iov));
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+ msg.msg_iovlen = 1;
+ msg.msg_control = control;
+ msg.msg_controllen = sizeof(control);
+ msg.msg_flags = 0;
+
+ if (recvmsg(s, &msg, 0) == -1)
+ ERR("recvmsg");
+
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != IPPROTO_IP)
+ ERRX("bad level %d", cmsg->cmsg_level);
+ const char *m;
+ switch (cmsg->cmsg_type) {
+ case IP_PKTINFO:
+ m = "pktinfo";
+ break;
+ case IP_RECVPKTINFO:
+ m = "recvpktinfo";
+ break;
+ default:
+ m = NULL;
+ ERRX("bad type %d", cmsg->cmsg_type);
+ }
+ ipi = (void *)CMSG_DATA(cmsg);
+#ifdef TEST
+ printf("%s message received on address %s at interface %d\n",
+ m, inet_ntoa(ipi->ipi_addr), ipi->ipi_ifindex);
+#else
+ __USE(m);
+ ATF_REQUIRE_MSG(ipi->ipi_addr.s_addr == htonl(INADDR_LOOPBACK),
+ "address 0x%x != 0x%x", ipi->ipi_addr.s_addr,
+ htonl(INADDR_LOOPBACK));
+#endif
+ }
+
+ if (strcmp(traffic, buf) != 0)
+ ERRX2("Bad message '%s' != '%s'", buf, traffic);
+}
+
+static void
+doit(void)
+{
+ struct sockaddr_in sin;
+ int s, c;
+ s = server(&sin);
+ c = client(&sin);
+ receive(s);
+ close(s);
+ close(c);
+}
+
+#ifndef TEST
+ATF_TC(pktinfo);
+ATF_TC_HEAD(pktinfo, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that IP_PKTINFO and "
+ "IP_RECVPKTINFO work");
+}
+
+ATF_TC_BODY(pktinfo, tc)
+{
+ doit();
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, pktinfo);
+ return atf_no_error();
+}
+#else
+
+int
+main(int argc, char *argv[]) {
+ doit();
+ return 0;
+}
+#endif
diff --git a/contrib/netbsd-tests/net/net/t_raw.c b/contrib/netbsd-tests/net/net/t_raw.c
new file mode 100644
index 0000000..ef3262d
--- /dev/null
+++ b/contrib/netbsd-tests/net/net/t_raw.c
@@ -0,0 +1,41 @@
+/* $NetBSD: t_raw.c,v 1.1 2011/01/11 10:51:45 pooka Exp $ */
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include <atf-c.h>
+
+#include "../../h_macros.h"
+
+ATF_TC(PRU_SENSE);
+ATF_TC_HEAD(PRU_SENSE, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Biglock leak with PRU_SENSE on "
+ "raw sockets (PR kern/44369)");
+}
+
+ATF_TC_BODY(PRU_SENSE, tc)
+{
+ struct stat sb;
+ int s;
+
+ rump_init();
+ RL(s = rump_sys_socket(PF_ROUTE, SOCK_RAW, 0));
+ /* call PRU_SENSE. unfixed bug causes panic in rump_unschedule() */
+ RL(rump_sys_fstat(s, &sb));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, PRU_SENSE);
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/net/t_tcp.c b/contrib/netbsd-tests/net/net/t_tcp.c
new file mode 100644
index 0000000..8972a0f
--- /dev/null
+++ b/contrib/netbsd-tests/net/net/t_tcp.c
@@ -0,0 +1,220 @@
+/* $NetBSD: t_tcp.c,v 1.3 2013/10/17 12:53:28 christos Exp $ */
+
+/*-
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __RCSID
+__RCSID("$Id: t_tcp.c,v 1.3 2013/10/17 12:53:28 christos Exp $");
+#endif
+
+/* Example code. Should block; does with accept not paccept. */
+/* Original by: Justin Cormack <justin@specialbusrvrervice.com> */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <err.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#ifdef TEST
+#define FAIL(msg, ...) err(EXIT_FAILURE, msg, ## __VA_ARGS__)
+#else
+#include <atf-c.h>
+#define FAIL(msg, ...) ATF_CHECK_MSG(0, msg, ## __VA_ARGS__); goto fail
+#endif
+
+static void
+ding(int al)
+{
+}
+
+static void
+paccept_block(bool pacceptblock, bool fcntlblock)
+{
+ int srvr = -1, clnt = -1, as = -1;
+ int ok, fl, n;
+ char buf[10];
+ struct sockaddr_in sin, ba;
+ struct sigaction sa;
+
+ srvr = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+ if (srvr == -1)
+ FAIL("socket");
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+#ifdef BSD4_4
+ sin.sin_len = sizeof(sin);
+#endif
+ sin.sin_port = htons(0);
+ sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ ok = bind(srvr, (const struct sockaddr *)&sin, (socklen_t)sizeof(sin));
+ if (ok == -1)
+ FAIL("bind");
+
+ socklen_t addrlen = sizeof(struct sockaddr_in);
+ ok = getsockname(srvr, (struct sockaddr *)&ba, &addrlen);
+ if (ok == -1)
+ FAIL("getsockname");
+
+ ok = listen(srvr, SOMAXCONN);
+ if (ok == -1)
+ FAIL("listen");
+
+ clnt = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
+ if (clnt == -1)
+ FAIL("socket");
+
+ /* may not connect first time */
+ ok = connect(clnt, (struct sockaddr *) &ba, addrlen);
+ as = paccept(srvr, NULL, NULL, NULL, pacceptblock ? 0 : SOCK_NONBLOCK);
+ ok = connect(clnt, (struct sockaddr *) &ba, addrlen);
+ if (ok == -1 && errno != EISCONN)
+ FAIL("both connects failed");
+
+#if 0
+ fl = fcntl(srvr, F_GETFL, 0);
+ if (fl == -1)
+ FAIL("fnctl getfl");
+
+ ok = fcntl(srvr, F_SETFL, fl & ~O_NONBLOCK);
+ if (ok == -1)
+ FAIL("fnctl setfl");
+#endif
+
+ if (as == -1) { /* not true under NetBSD */
+ as = paccept(srvr, NULL, NULL, NULL, pacceptblock ? 0 : SOCK_NONBLOCK);
+ if (as == -1)
+ FAIL("paccept");
+ }
+ if (fcntlblock) {
+ fl = fcntl(as, F_GETFL, 0);
+ if (fl == -1)
+ FAIL("fnctl");
+ if (fl != (O_RDWR|O_NONBLOCK))
+ FAIL("fl 0x%x != 0x%x\n", fl, O_RDWR|O_NONBLOCK);
+ ok = fcntl(as, F_SETFL, fl & ~O_NONBLOCK);
+ if (ok == -1)
+ FAIL("fnctl setfl");
+
+ fl = fcntl(as, F_GETFL, 0);
+ if (fl & O_NONBLOCK)
+ FAIL("fl non blocking after reset");
+ }
+ sa.sa_handler = ding;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGALRM, &sa, NULL);
+ alarm(1);
+ n = read(as, buf, 10);
+
+ if (pacceptblock || fcntlblock) {
+ if (n == -1 && errno != EINTR)
+ FAIL("read");
+ } else {
+ if (n != -1 || errno != EWOULDBLOCK)
+ FAIL("read");
+ }
+ return;
+fail:
+ close(srvr);
+ close(clnt);
+ close(as);
+}
+
+#ifndef TEST
+
+ATF_TC(paccept_reset_nonblock);
+ATF_TC_HEAD(paccept_reset_nonblock, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that paccept(2) resets "
+ "the non-blocking flag on non-blocking sockets");
+}
+
+ATF_TC_BODY(paccept_reset_nonblock, tc)
+{
+ paccept_block(true, false);
+}
+
+ATF_TC(fcntl_reset_nonblock);
+ATF_TC_HEAD(fcntl_reset_nonblock, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that fcntl(2) resets "
+ "the non-blocking flag on non-blocking sockets");
+}
+
+ATF_TC_BODY(fcntl_reset_nonblock, tc)
+{
+ paccept_block(false, true);
+}
+
+ATF_TC(paccept_nonblock);
+ATF_TC_HEAD(paccept_nonblock, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that fcntl(2) resets "
+ "the non-blocking flag on non-blocking sockets");
+}
+
+ATF_TC_BODY(paccept_nonblock, tc)
+{
+ paccept_block(false, false);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, paccept_reset_nonblock);
+ ATF_TP_ADD_TC(tp, fcntl_reset_nonblock);
+ ATF_TP_ADD_TC(tp, paccept_nonblock);
+ return atf_no_error();
+}
+#else
+int
+main(int argc, char *argv[])
+{
+ paccept_block(false);
+ paccept_block(true);
+ return 0;
+}
+#endif
diff --git a/contrib/netbsd-tests/net/net/t_udp.c b/contrib/netbsd-tests/net/net/t_udp.c
new file mode 100644
index 0000000..db59342
--- /dev/null
+++ b/contrib/netbsd-tests/net/net/t_udp.c
@@ -0,0 +1,110 @@
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_udp.c,v 1.2 2013/01/06 02:22:50 christos Exp $");
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <netdb.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static const char msg[] = "sendto test";
+
+static void
+sendit(int family)
+{
+ struct addrinfo hints;
+ struct addrinfo *res;
+ int S, s;
+ int e;
+
+ /* lookup localhost addr, depending on argv[1] */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_flags = 0;
+
+ e = getaddrinfo("localhost", "9999", &hints, &res);
+ ATF_REQUIRE_MSG(e == 0, "getaddrinfo AF=%d: %s", family,
+ gai_strerror(e));
+
+ /* server socket */
+ S = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ ATF_REQUIRE_MSG(S >= 0, "server-socket AF=%d: %s", family,
+ strerror(errno));
+
+ e = bind(S, res->ai_addr, res->ai_addrlen);
+ ATF_REQUIRE_MSG(e == 0, "bind AF=%d: %s", family,
+ strerror(errno));
+
+ /* client socket */
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ ATF_REQUIRE_MSG(s >= 0, "client-socket AF=%d: %s", family,
+ strerror(errno));
+
+ /* sendto */
+ e = sendto(s, msg, sizeof(msg), 0, res->ai_addr, res->ai_addrlen);
+ ATF_REQUIRE_MSG(e == sizeof(msg), "sendto(1) AF=%d: %s", family,
+ strerror(errno));
+
+ e = sendto(s, msg, sizeof(msg), 0, res->ai_addr, res->ai_addrlen);
+ ATF_REQUIRE_MSG(e == sizeof(msg), "sendto(2) AF=%d: %s", family,
+ strerror(errno));
+
+ /* connect + send */
+ e = connect(s, res->ai_addr, res->ai_addrlen);
+ ATF_REQUIRE_MSG(e == 0, "connect(1) AF=%d: %s", family,
+ strerror(errno));
+
+ e = send(s, msg, sizeof(msg), 0);
+ ATF_REQUIRE_MSG(e == sizeof(msg), "send(1) AF=%d: %s", family,
+ strerror(errno));
+
+ e = connect(s, res->ai_addr, res->ai_addrlen);
+ ATF_REQUIRE_MSG(e == 0, "connect(2) AF=%d: %s", family,
+ strerror(errno));
+
+ e = send(s, msg, sizeof(msg), 0);
+ ATF_REQUIRE_MSG(e == sizeof(msg), "send(2) AF=%d: %s", family,
+ strerror(errno));
+
+ close(s);
+}
+
+ATF_TC(udp4_send);
+ATF_TC_HEAD(udp4_send, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that inet4 udp send works both"
+ " for connected and unconnected sockets");
+}
+
+ATF_TC_BODY(udp4_send, tc)
+{
+ sendit(AF_INET);
+}
+
+ATF_TC(udp6_send);
+ATF_TC_HEAD(udp6_send, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that inet6 udp send works both"
+ " for connected and unconnected sockets");
+}
+
+ATF_TC_BODY(udp6_send, tc)
+{
+ sendit(AF_INET6);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, udp4_send);
+ ATF_TP_ADD_TC(tp, udp6_send);
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/net/net/t_unix.c b/contrib/netbsd-tests/net/net/t_unix.c
new file mode 100644
index 0000000..30759f1
--- /dev/null
+++ b/contrib/netbsd-tests/net/net/t_unix.c
@@ -0,0 +1,328 @@
+/* $NetBSD: t_unix.c,v 1.11 2013/11/13 21:41:23 christos Exp $ */
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __RCSID
+__RCSID("$Id: t_unix.c,v 1.11 2013/11/13 21:41:23 christos Exp $");
+#else
+#define getprogname() argv[0]
+#endif
+
+#ifdef __linux__
+#define LX -1
+#else
+#define LX
+#endif
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdio.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#ifdef TEST
+#define FAIL(msg, ...) err(EXIT_FAILURE, msg, ## __VA_ARGS__)
+#else
+
+#include <atf-c.h>
+#define FAIL(msg, ...) \
+ do { \
+ ATF_CHECK_MSG(0, msg, ## __VA_ARGS__); \
+ goto fail; \
+ } while (/*CONSTCOND*/0)
+
+#endif
+
+#define OF offsetof(struct sockaddr_un, sun_path)
+
+static void
+print(const char *msg, struct sockaddr_un *addr, socklen_t len)
+{
+ size_t i;
+
+ printf("%s: client socket length: %zu\n", msg, (size_t)len);
+ printf("%s: client family %d\n", msg, addr->sun_family);
+#ifdef BSD4_4
+ printf("%s: client len %d\n", msg, addr->sun_len);
+#endif
+ printf("%s: socket name: ", msg);
+ for (i = 0; i < len - OF; i++) {
+ int ch = addr->sun_path[i];
+ if (ch < ' ' || '~' < ch)
+ printf("\\x%02x", ch);
+ else
+ printf("%c", ch);
+ }
+ printf("\n");
+}
+
+static int
+acc(int s)
+{
+ char guard1;
+ struct sockaddr_un sun;
+ char guard2;
+ socklen_t len;
+
+ guard1 = guard2 = 's';
+
+ memset(&sun, 0, sizeof(sun));
+ len = sizeof(sun);
+ if ((s = accept(s, (struct sockaddr *)&sun, &len)) == -1)
+ FAIL("accept");
+ if (guard1 != 's')
+ FAIL("guard1 = '%c'", guard1);
+ if (guard2 != 's')
+ FAIL("guard2 = '%c'", guard2);
+#ifdef DEBUG
+ print("accept", &sun, len);
+#endif
+ if (len != 2)
+ FAIL("len %d != 2", len);
+ if (sun.sun_family != AF_UNIX)
+ FAIL("sun->sun_family %d != AF_UNIX", sun.sun_family);
+#ifdef BSD4_4
+ if (sun.sun_len != 2)
+ FAIL("sun->sun_len %d != 2", sun.sun_len);
+#endif
+ for (size_t i = 0; i < sizeof(sun.sun_path); i++)
+ if (sun.sun_path[i])
+ FAIL("sun.sun_path[%zu] %d != NULL", i,
+ sun.sun_path[i]);
+ return s;
+fail:
+ if (s != -1)
+ close(s);
+ return -1;
+}
+
+static int
+test(bool closeit, size_t len)
+{
+ size_t slen;
+ socklen_t sl;
+ int srvr = -1, clnt = -1, acpt = -1;
+ struct sockaddr_un *sock_addr = NULL, *sun = NULL;
+ socklen_t sock_addrlen;
+
+ srvr = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (srvr == -1)
+ FAIL("socket(srvrer)");
+
+ slen = len + OF + 1;
+
+ if ((sun = calloc(1, slen)) == NULL)
+ FAIL("calloc");
+
+ srvr = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (srvr == -1)
+ FAIL("socket");
+
+ memset(sun->sun_path, 'a', len);
+ sun->sun_path[len] = '\0';
+ (void)unlink(sun->sun_path);
+
+ sl = SUN_LEN(sun);
+#ifdef BSD4_4
+ sun->sun_len = sl;
+#endif
+ sun->sun_family = AF_UNIX;
+
+ if (bind(srvr, (struct sockaddr *)sun, sl) == -1) {
+ if (errno == EINVAL && sl >= 256) {
+ close(srvr);
+ return -1;
+ }
+ FAIL("bind");
+ }
+
+ if (listen(srvr, SOMAXCONN) == -1)
+ FAIL("listen");
+
+ clnt = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (clnt == -1)
+ FAIL("socket(client)");
+
+ if (connect(clnt, (const struct sockaddr *)sun, sl) == -1)
+ FAIL("connect");
+
+ if (closeit) {
+ if (close(clnt) == -1)
+ FAIL("close");
+ clnt = -1;
+ }
+
+ acpt = acc(srvr);
+#if 0
+ /*
+ * Both linux and NetBSD return ENOTCONN, why?
+ */
+ if (!closeit) {
+ socklen_t peer_addrlen;
+ sockaddr_un peer_addr;
+
+ peer_addrlen = sizeof(peer_addr);
+ memset(&peer_addr, 0, sizeof(peer_addr));
+ if (getpeername(srvr, (struct sockaddr *)&peer_addr,
+ &peer_addrlen) == -1)
+ FAIL("getpeername");
+ print("peer", &peer_addr, peer_addrlen);
+ }
+#endif
+
+ if ((sock_addr = calloc(1, slen)) == NULL)
+ FAIL("calloc");
+ sock_addrlen = slen;
+ if (getsockname(srvr, (struct sockaddr *)sock_addr, &sock_addrlen)
+ == -1)
+ FAIL("getsockname");
+ print("sock", sock_addr, sock_addrlen);
+
+ if (sock_addr->sun_family != AF_UNIX)
+ FAIL("sock_addr->sun_family %d != AF_UNIX",
+ sock_addr->sun_family);
+
+ len += OF;
+ if (sock_addrlen LX != len)
+ FAIL("sock_addr_len %zu != %zu", (size_t)sock_addrlen, len);
+#ifdef BSD4_4
+ if (sock_addr->sun_len != sl)
+ FAIL("sock_addr.sun_len %d != %zu", sock_addr->sun_len,
+ (size_t)sl);
+#endif
+ for (size_t i = 0; i < slen - OF; i++)
+ if (sock_addr->sun_path[i] != sun->sun_path[i])
+ FAIL("sock_addr.sun_path[%zu] %d != "
+ "sun->sun_path[%zu] %d\n", i,
+ sock_addr->sun_path[i], i, sun->sun_path[i]);
+
+ if (acpt != -1)
+ (void)close(acpt);
+ if (srvr != -1)
+ (void)close(srvr);
+ if (clnt != -1 && !closeit)
+ (void)close(clnt);
+
+ free(sock_addr);
+ free(sun);
+ return 0;
+fail:
+ if (acpt != -1)
+ (void)close(acpt);
+ if (srvr != -1)
+ (void)close(srvr);
+ if (clnt != -1 && !closeit)
+ (void)close(clnt);
+ free(sock_addr);
+ free(sun);
+ return -1;
+}
+
+#ifndef TEST
+
+ATF_TC(sockaddr_un_len_exceed);
+ATF_TC_HEAD(sockaddr_un_len_exceed, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that exceeding the size of "
+ "unix domain sockets does not trash memory or kernel when "
+ "exceeding the size of the fixed sun_path");
+}
+
+ATF_TC_BODY(sockaddr_un_len_exceed, tc)
+{
+ ATF_REQUIRE_MSG(test(false, 254) == -1, "test(false, 254): %s",
+ strerror(errno));
+}
+
+ATF_TC(sockaddr_un_len_max);
+ATF_TC_HEAD(sockaddr_un_len_max, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that we can use the maximum "
+ "unix domain socket pathlen (253): 255 - sizeof(sun_len) - "
+ "sizeof(sun_family)");
+}
+
+ATF_TC_BODY(sockaddr_un_len_max, tc)
+{
+ ATF_REQUIRE_MSG(test(false, 253) == 0, "test(false, 253): %s",
+ strerror(errno));
+}
+
+ATF_TC(sockaddr_un_closed);
+ATF_TC_HEAD(sockaddr_un_closed, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Check that we can use the accepted "
+ "address of unix domain socket when closed");
+}
+
+ATF_TC_BODY(sockaddr_un_closed, tc)
+{
+ ATF_REQUIRE_MSG(test(true, 100) == 0, "test(true, 100): %s",
+ strerror(errno));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, sockaddr_un_len_exceed);
+ ATF_TP_ADD_TC(tp, sockaddr_un_len_max);
+ ATF_TP_ADD_TC(tp, sockaddr_un_closed);
+ return atf_no_error();
+}
+#else
+int
+main(int argc, char *argv[])
+{
+ size_t len;
+
+ if (argc == 1) {
+ fprintf(stderr, "Usage: %s <len>\n", getprogname());
+ return EXIT_FAILURE;
+ }
+ test(false, atoi(argv[1]));
+ test(true, atoi(argv[1]));
+}
+#endif
diff --git a/contrib/netbsd-tests/net/npf/t_npf.sh b/contrib/netbsd-tests/net/npf/t_npf.sh
new file mode 100755
index 0000000..bf247fc
--- /dev/null
+++ b/contrib/netbsd-tests/net/npf/t_npf.sh
@@ -0,0 +1,63 @@
+# $NetBSD: t_npf.sh,v 1.2 2012/09/18 08:28:15 martin Exp $
+#
+# Copyright (c) 2008, 2010 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+run_test()
+{
+ local name="${1}"
+
+ atf_check -o ignore -e ignore npfctl debug "$(atf_get_srcdir)/npftest.conf" ./npf.plist
+ atf_check -o ignore npftest -c npf.plist -T "${name}"
+}
+
+add_test()
+{
+ local name="${1}"; shift
+ local desc="${*}";
+
+ atf_test_case "npf_${name}"
+ eval "npf_${name}_head() { \
+ atf_set \"descr\" \"${desc}\"; \
+ atf_set \"require.progs\" \"npfctl npftest\"; \
+ }; \
+ npf_${name}_body() { \
+ run_test \"${name}\"; \
+ }"
+ atf_add_test_case "npf_${name}"
+}
+
+atf_init_test_cases()
+{
+ LIST=/tmp/t_npf.$$
+ trap "rm -f $LIST" EXIT
+
+ sh -ec 'npftest -L || printf "dummy\tnone\n"' > $LIST 2>/dev/null
+
+ while read tag desc
+ do
+ add_test "${tag}" "${desc}"
+ done < $LIST
+}
diff --git a/contrib/netbsd-tests/net/route/t_change.sh b/contrib/netbsd-tests/net/route/t_change.sh
new file mode 100755
index 0000000..3618aee
--- /dev/null
+++ b/contrib/netbsd-tests/net/route/t_change.sh
@@ -0,0 +1,65 @@
+# $NetBSD: t_change.sh,v 1.4 2013/02/19 21:08:25 joerg Exp $
+#
+# Copyright (c) 2011 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+netserver=\
+"rump_server -lrumpnet -lrumpnet_net -lrumpnet_netinet"
+export RUMP_SERVER=unix://commsock
+
+atf_test_case reject2blackhole cleanup
+reject2blackhole_head()
+{
+
+ atf_set "descr" "Change a reject route to blackhole"
+ atf_set "require.progs" "rump_server"
+}
+
+reject2blackhole_body()
+{
+
+ atf_check -s exit:0 ${netserver} ${RUMP_SERVER}
+
+ atf_check -s exit:0 -o ignore \
+ rump.route add 207.46.197.32 127.0.0.1 -reject
+ atf_check -s exit:0 -o match:UGHR -x \
+ "rump.route -n show -inet | grep ^207.46"
+ atf_check -s exit:0 -o ignore \
+ rump.route change 207.46.197.32 127.0.0.1 -blackhole
+ atf_check -s exit:0 -o match:' UGHBS ' -e ignore -x \
+ "rump.netstat -rn -f inet | grep ^207.46| grep ^207.46"
+}
+
+reject2blackhole_cleanup()
+{
+
+ env RUMP_SERVER=unix://commsock rump.halt
+}
+
+atf_init_test_cases()
+{
+
+ atf_add_test_case reject2blackhole
+}
diff --git a/contrib/netbsd-tests/net/sys/t_rfc6056.c b/contrib/netbsd-tests/net/sys/t_rfc6056.c
new file mode 100644
index 0000000..944521b
--- /dev/null
+++ b/contrib/netbsd-tests/net/sys/t_rfc6056.c
@@ -0,0 +1,152 @@
+/* $NetBSD: t_rfc6056.c,v 1.3 2012/06/22 14:54:35 christos Exp $ */
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: t_rfc6056.c,v 1.3 2012/06/22 14:54:35 christos Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/udp.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <err.h>
+
+#include <atf-c.h>
+
+static void
+test(const char *hostname, const char *service, int family, int al)
+{
+ static const char hello[] = "hello\n";
+ int s, error, proto, option;
+ struct sockaddr_storage ss;
+ struct addrinfo hints, *res;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ switch (family) {
+ case AF_INET:
+ proto = IPPROTO_IP;
+ option = IP_PORTALGO;
+ break;
+ case AF_INET6:
+ proto = IPPROTO_IPV6;
+ option = IPV6_PORTALGO;
+ break;
+ default:
+ abort();
+ }
+
+ error = getaddrinfo(hostname, service, &hints, &res);
+ if (error)
+ errx(EXIT_FAILURE, "Cannot get address for %s (%s)",
+ hostname, gai_strerror(error));
+
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s == -1)
+ err(EXIT_FAILURE, "socket");
+
+ if (setsockopt(s, proto, option, &al, sizeof(al)) == -1)
+ err(EXIT_FAILURE, "setsockopt");
+
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_len = res->ai_addrlen;
+ ss.ss_family = res->ai_family;
+
+ if (bind(s, (struct sockaddr *)&ss, ss.ss_len) == -1)
+ err(EXIT_FAILURE, "bind");
+
+ if (sendto(s, hello, sizeof(hello) - 1, 0,
+ res->ai_addr, res->ai_addrlen) == -1)
+ err(EXIT_FAILURE, "sendto");
+
+ if (close(s) == -1)
+ err(EXIT_FAILURE, "close");
+
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s == -1)
+ err(EXIT_FAILURE, "socket");
+
+ if (setsockopt(s, proto, option, &al, sizeof(al)) == -1)
+ err(EXIT_FAILURE, "setsockopt");
+
+ if (connect(s, res->ai_addr, res->ai_addrlen) == -1)
+ err(EXIT_FAILURE, "connect");
+
+ if (send(s, hello, sizeof(hello) - 1, 0) == -1)
+ err(EXIT_FAILURE, "send");
+
+ if (close(s) == -1)
+ err(EXIT_FAILURE, "close");
+
+ freeaddrinfo(res);
+}
+
+ATF_TC(inet4);
+ATF_TC_HEAD(inet4, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Checks random port allocation "
+ "for ipv4");
+}
+
+ATF_TC_BODY(inet4, tc)
+{
+ for (int i = 0; i < 6; i++)
+ test("localhost", "http", AF_INET, i);
+}
+
+ATF_TC(inet6);
+ATF_TC_HEAD(inet6, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Checks random port allocation "
+ "for ipv6");
+}
+
+ATF_TC_BODY(inet6, tc)
+{
+ for (int i = 0; i < 6; i++)
+ test("localhost", "http", AF_INET6, i);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, inet4);
+ ATF_TP_ADD_TC(tp, inet6);
+
+ return atf_no_error();
+}
OpenPOWER on IntegriCloud