summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>2004-12-06 13:15:24 +0000
committercvs2svn <cvs2svn@FreeBSD.org>2004-12-06 13:15:24 +0000
commit6be06e7cb35e62a025c7f01392edaa6aeeb46f2c (patch)
treeac647dbc906e80319f1b795bc7558b54389420a7
parent2ad78170c8780ad27800da05407d8926962d9b61 (diff)
Notes
-rw-r--r--etc/periodic/security/520.pfdenied53
-rw-r--r--share/man/man4/hptmv.482
-rw-r--r--share/man/man4/snd_ich.491
-rw-r--r--tools/regression/aio/aiotest/aiotest.c697
-rw-r--r--tools/regression/netinet/ipsockopt/ipsockopt.c839
-rw-r--r--tools/regression/sockets/kqueue/kqueue.c368
-rw-r--r--tools/tools/nanobsd/Customize/NET480127
-rw-r--r--tools/tools/nanobsd/Customize/default64
-rw-r--r--tools/tools/nanobsd/Customize/nobeastie25
9 files changed, 2246 insertions, 0 deletions
diff --git a/etc/periodic/security/520.pfdenied b/etc/periodic/security/520.pfdenied
new file mode 100644
index 0000000000000..5e51393630280
--- /dev/null
+++ b/etc/periodic/security/520.pfdenied
@@ -0,0 +1,53 @@
+#!/bin/sh -
+#
+# Copyright (c) 2004 The FreeBSD Project
+# 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 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 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.
+#
+# $FreeBSD$
+#
+
+# If there is a global system configuration file, suck it in.
+#
+if [ -r /etc/defaults/periodic.conf ]
+then
+ . /etc/defaults/periodic.conf
+ source_periodic_confs
+fi
+
+. /etc/periodic/security/security.functions
+
+rc=0
+
+case "$daily_status_security_pfdenied_enable" in
+ [Yy][Ee][Ss])
+ TMP=`mktemp -t security`
+ if pfctl -sr -v 2>/dev/null | nawk '{if (/^block/) {buf=$0; getline; gsub(" +"," ",$0); print buf$0;} }' > ${TMP}; then
+ check_diff new_only pf ${TMP} "${host} pf denied packets:"
+ fi
+ rc=$?
+ rm -f ${TMP};;
+ *) rc=0;;
+esac
+
+exit $rc
diff --git a/share/man/man4/hptmv.4 b/share/man/man4/hptmv.4
new file mode 100644
index 0000000000000..2380e204b0b57
--- /dev/null
+++ b/share/man/man4/hptmv.4
@@ -0,0 +1,82 @@
+.\"
+.\" Copyright (c) 2004 David E. O'Brien
+.\" 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 DEVELOPERS ``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 DEVELOPERS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 19, 2004
+.Dt HPTMV 4
+.Os
+.Sh NAME
+.Nm hptmv
+.Nd "HighPoint RocketRAID 182x device driver"
+.Sh SYNOPSIS
+.Cd "device hptmv"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for HighPoint's RocketRAID 182x based RAID controller.
+.Pp
+These devices support ATA disk drives
+and provide RAID0 (striping), RAID1 (mirroring), and RAID5 functionality.
+.Sh HARDWARE
+The
+.Nm
+driver supports the following ATA RAID
+controllers:
+.Pp
+.Bl -bullet -compact
+.It
+HighPoint's RocketRAID 182x series
+.El
+.Sh NOTES
+The
+.Nm
+driver only works on the 'i386' platform as it requires a binary blob object
+from the manufacturer which they only supply for the 'i386' platform.
+.Sh BUGS
+The
+.Nm
+driver does not support manipulating the RAID from the OS, RAIDs need
+to be set up from the on-board BIOS.
+.Sh SEE ALSO
+.Xr kld 4 ,
+.Xr kldload 8 ,
+.Xr loader 8
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+device driver was written by
+.An HighPoint Technologies, Inc. ,
+and ported to
+.Fx
+by
+.An Scott Long .
+This manual page was written by
+.An David E. O'Brien .
diff --git a/share/man/man4/snd_ich.4 b/share/man/man4/snd_ich.4
new file mode 100644
index 0000000000000..443a5ab064758
--- /dev/null
+++ b/share/man/man4/snd_ich.4
@@ -0,0 +1,91 @@
+.\" Copyright (c) 2004 Jorge Mario G. Mazo
+.\" 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 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 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 27, 2004
+.Dt SND_ICH 4
+.Os
+.Sh NAME
+.Nm snd_ich
+.Nd "Intel ICH PCI and compatible bridge device driver"
+.Sh SYNOPSIS
+.Cd "device sound"
+.Cd "device snd_ich"
+.Pp
+.Sh DESCRIPTION
+The
+.Nm
+bridge driver allows the generic audio drivers including
+.Xr sound 4
+to attach to Intel ICH and compatible audio devices.
+.Sh HARDWARE
+The
+.Nm
+driver supports the following audio devices:
+.Pp
+.Bl -bullet -compact
+.It
+AMD 768
+.It
+AMD 8111
+.It
+Intel 443MX
+.It
+Intel ICH
+.It
+Intel ICH revision 1
+.It
+Intel ICH2
+.It
+Intel ICH3
+.It
+Intel ICH4
+.It
+Intel ICH5
+.It
+Intel ICH6
+.It
+NVIDIA nForce
+.It
+NVIDIA nForce2
+.It
+NVIDIA nForce2 400
+.It
+NVIDIA nForce3
+.It
+NVIDIA nForce3 250
+.It
+SiS 7012
+.El
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 4.2 .
+.Sh SEE ALSO
+.Xr sound 4
+.Sh AUTHORS
+This manual page was written by
+.An Jorge Mario G. Mazo Aq jgutie11@eafit.edu.co .
diff --git a/tools/regression/aio/aiotest/aiotest.c b/tools/regression/aio/aiotest/aiotest.c
new file mode 100644
index 0000000000000..8769dc1a93d22
--- /dev/null
+++ b/tools/regression/aio/aiotest/aiotest.c
@@ -0,0 +1,697 @@
+/*-
+ * Copyright (c) 2004 Robert N. M. Watson
+ * 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 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 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Regression test to do some very basic AIO exercising on several types of
+ * file descriptors. Currently, the tests consist of initializing a fixed
+ * size buffer with pseudo-random data, writing it to one fd using AIO, then
+ * reading it from a second descriptor using AIO. For some targets, the same
+ * fd is used for write and read (i.e., file, md device), but for others the
+ * operation is performed on a peer (pty, socket, fifo, etc). A timeout is
+ * initiated to detect undo blocking. This test does not attempt to exercise
+ * error cases or more subtle asynchronous behavior, just make sure that the
+ * basic operations work on some basic object types.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mdioctl.h>
+
+#include <aio.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#define PATH_TEMPLATE "/tmp/aio.XXXXXXXXXX"
+
+/*
+ * GLOBAL_MAX sets the largest usable buffer size to be read and written, as
+ * it sizes ac_buffer in the aio_context structure. It is also the default
+ * size for file I/O. For other types, we use smaller blocks or we risk
+ * blocking (and we run in a single process/thread so that would be bad).
+ */
+#define GLOBAL_MAX 16384
+
+#define BUFFER_MAX GLOBAL_MAX
+struct aio_context {
+ const char *ac_test;
+ int ac_read_fd, ac_write_fd;
+ long ac_seed;
+ char ac_buffer[GLOBAL_MAX];
+ int ac_buflen;
+ int ac_seconds;
+ void (*ac_cleanup)(void *arg);
+ void *ac_cleanup_arg;
+};
+
+static int aio_timedout;
+static int aio_notpresent;
+
+/*
+ * Attempt to provide a cleaner failure mode in the event AIO support is not
+ * present by catching and reporting SIGSYS.
+ */
+static void
+aio_sigsys(int sig)
+{
+
+ aio_notpresent = 1;
+}
+
+static void
+aio_sigsys_setup(void)
+{
+
+ if (signal(SIGSYS, aio_sigsys) == SIG_ERR)
+ errx(-1, "FAIL: signal(SIGSYS): %s", strerror(errno));
+}
+
+/*
+ * Each test run specifies a timeout in seconds. Use the somewhat obsoleted
+ * signal(3) and alarm(3) APIs to set this up.
+ */
+static void
+aio_timeout_signal(int sig)
+{
+
+ aio_timedout = 1;
+}
+
+static void
+aio_timeout_start(const char *string1, const char *string2, int seconds)
+{
+
+ aio_timedout = 0;
+ if (signal(SIGALRM, aio_timeout_signal) == SIG_ERR)
+ errx(-1, "FAIL: %s: %s: aio_timeout_set: signal(SIGALRM): %s",
+ string1, string2, strerror(errno));
+ alarm(seconds);
+}
+
+static void
+aio_timeout_stop(const char *string1, const char *string2)
+{
+
+ if (signal(SIGALRM, NULL) == SIG_ERR)
+ errx(-1, "FAIL: %s: %s: aio_timeout_stop: signal(NULL): %s",
+ string1, string2, strerror(errno));
+ alarm(0);
+}
+
+/*
+ * Fill a buffer given a seed that can be fed into srandom() to initialize
+ * the PRNG in a repeatable manner.
+ */
+static void
+aio_fill_buffer(char *buffer, int len, long seed)
+{
+ char ch;
+ int i;
+
+ srandom(seed);
+ for (i = 0; i < len; i++) {
+ ch = random() & 0xff;
+ buffer[i] = ch;
+ }
+}
+
+/*
+ * Test that a buffer matches a given seed. See aio_fill_buffer(). Return
+ * (1) on a match, (0) on a mismatch.
+ */
+static int
+aio_test_buffer(char *buffer, int len, long seed)
+{
+ char ch;
+ int i;
+
+ srandom(seed);
+ for (i = 0; i < len; i++) {
+ ch = random() & 0xff;
+ if (buffer[i] != ch)
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Initialize a testing context given the file descriptors provided by the
+ * test setup.
+ */
+static void
+aio_context_init(struct aio_context *ac, const char *test, int read_fd,
+ int write_fd, int buflen, int seconds, void (*cleanup)(void *),
+ void *cleanup_arg)
+{
+
+ if (buflen > BUFFER_MAX)
+ errx(-1, "FAIL: %s: aio_context_init: buffer too large",
+ test);
+ bzero(ac, sizeof(*ac));
+ ac->ac_test = test;
+ ac->ac_read_fd = read_fd;
+ ac->ac_write_fd = write_fd;
+ ac->ac_buflen = buflen;
+ srandomdev();
+ ac->ac_seed = random();
+ aio_fill_buffer(ac->ac_buffer, buflen, ac->ac_seed);
+ if (aio_test_buffer(ac->ac_buffer, buflen, ac->ac_seed) == 0)
+ errx(-1, "%s: aio_context_init: aio_test_buffer: internal "
+ "error", test);
+ ac->ac_seconds = seconds;
+ ac->ac_cleanup = cleanup;
+ ac->ac_cleanup_arg = cleanup_arg;
+}
+
+/*
+ * Each tester can register a callback to clean up in the event the test
+ * fails. Preserve the value of errno so that subsequent calls to errx()
+ * work properly.
+ */
+static void
+aio_cleanup(struct aio_context *ac)
+{
+ int error;
+
+ if (ac->ac_cleanup == NULL)
+ return;
+ error = errno;
+ (ac->ac_cleanup)(ac->ac_cleanup_arg);
+ errno = error;
+}
+
+/*
+ * Perform a simple write test of our initialized data buffer to the provided
+ * file descriptor.
+ */
+static void
+aio_write_test(struct aio_context *ac)
+{
+ struct aiocb aio, *aiop;
+ ssize_t len;
+ int error;
+
+ bzero(&aio, sizeof(aio));
+ aio.aio_buf = ac->ac_buffer;
+ aio.aio_nbytes = ac->ac_buflen;
+ aio.aio_fildes = ac->ac_write_fd;
+ aio.aio_offset = 0;
+
+ aio_timeout_start(ac->ac_test, "aio_write_test", ac->ac_seconds);
+
+ if (aio_write(&aio) < 0) {
+ if (errno == EINTR) {
+ if (aio_notpresent)
+ errno = EOPNOTSUPP;
+ if (aio_timedout) {
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_write_test: "
+ "aio_write: timed out", ac->ac_test);
+ }
+ }
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_write_test: aio_write: %s",
+ ac->ac_test, strerror(errno));
+ }
+
+ len = aio_waitcomplete(&aiop, NULL);
+ if (len < 0) {
+ if (errno == EINTR) {
+ if (aio_notpresent)
+ errno = EOPNOTSUPP;
+ if (aio_timedout) {
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_write_test: "
+ "aio_waitcomplete: timed out",
+ ac->ac_test);
+ }
+ }
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_write_test: aio_waitcomplete: %s",
+ ac->ac_test, strerror(errno));
+ }
+
+ aio_timeout_stop(ac->ac_test, "aio_write_test");
+
+ if (len != ac->ac_buflen) {
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_write_test: aio_waitcomplete: short "
+ "write (%d)", ac->ac_test, len);
+ }
+}
+
+/*
+ * Perform a simple read test of our initialized data buffer from the
+ * provided file descriptor.
+ */
+static void
+aio_read_test(struct aio_context *ac)
+{
+ struct aiocb aio, *aiop;
+ ssize_t len;
+
+ bzero(ac->ac_buffer, ac->ac_buflen);
+ bzero(&aio, sizeof(aio));
+ aio.aio_buf = ac->ac_buffer;
+ aio.aio_nbytes = ac->ac_buflen;
+ aio.aio_fildes = ac->ac_read_fd;
+ aio.aio_offset = 0;
+
+ aio_timeout_start(ac->ac_test, "aio_read_test", ac->ac_seconds);
+
+ if (aio_read(&aio) < 0) {
+ if (errno == EINTR) {
+ if (aio_notpresent)
+ errno = EOPNOTSUPP;
+ if (aio_timedout) {
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_read_test: "
+ "aio_read: timed out", ac->ac_test);
+ }
+ }
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_read_test: aio_read %s", ac->ac_test,
+ strerror(errno));
+ }
+
+ len = aio_waitcomplete(&aiop, NULL);
+ if (len < 0) {
+ if (errno == EINTR) {
+ if (aio_notpresent)
+ errno = EOPNOTSUPP;
+ if (aio_timedout) {
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_read_test: "
+ "aio_waitcomplete: timed out",
+ ac->ac_test);
+ }
+ }
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_read_test: aio_waitcomplete: %s",
+ ac->ac_test, strerror(errno));
+ }
+
+ aio_timeout_stop(ac->ac_test, "aio_read_test");
+
+ if (len != ac->ac_buflen) {
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_read_test: aio_waitcomplete: short "
+ "read (%d)", ac->ac_test, len);
+ }
+
+ if (aio_test_buffer(ac->ac_buffer, ac->ac_buflen, ac->ac_seed) == 0) {
+ aio_cleanup(ac);
+ errx(-1, "FAIL: %s: aio_read_test: buffer mismatch",
+ ac->ac_test);
+ }
+}
+
+/*
+ * Series of type-specific tests for AIO. For now, we just make sure we can
+ * issue a write and then a read to each type. We assume that once a write
+ * is issued, a read can follow.
+ */
+
+/*
+ * Test with a classic file. Assumes we can create a moderate size temporary
+ * file.
+ */
+struct aio_file_arg {
+ int afa_fd;
+ char *afa_pathname;
+};
+
+static void
+aio_file_cleanup(void *arg)
+{
+ struct aio_file_arg *afa;
+
+ afa = arg;
+ close(afa->afa_fd);
+ unlink(afa->afa_pathname);
+}
+
+#define FILE_LEN GLOBAL_MAX
+#define FILE_TIMEOUT 30
+static int
+aio_file_test(void)
+{
+ char pathname[PATH_MAX];
+ struct aio_file_arg arg;
+ struct aio_context ac;
+ int fd;
+
+ strcpy(pathname, PATH_TEMPLATE);
+ fd = mkstemp(pathname);
+ if (fd == -1)
+ errx(-1, "FAIL: aio_file_test: mkstemp: %s",
+ strerror(errno));
+
+ arg.afa_fd = fd;
+ arg.afa_pathname = pathname;
+
+ aio_context_init(&ac, "aio_file_test", fd, fd, FILE_LEN,
+ FILE_TIMEOUT, aio_file_cleanup, &arg);
+ aio_write_test(&ac);
+ aio_read_test(&ac);
+
+ aio_file_cleanup(&arg);
+
+ fprintf(stderr, "PASS: aio_file_test\n");
+}
+
+struct aio_fifo_arg {
+ int afa_read_fd;
+ int afa_write_fd;
+ char *afa_pathname;
+};
+
+static void
+aio_fifo_cleanup(void *arg)
+{
+ struct aio_fifo_arg *afa;
+
+ afa = arg;
+ if (afa->afa_read_fd != -1)
+ close(afa->afa_read_fd);
+ if (afa->afa_write_fd != -1)
+ close(afa->afa_write_fd);
+ unlink(afa->afa_pathname);
+}
+
+#define FIFO_LEN 256
+#define FIFO_TIMEOUT 30
+static int
+aio_fifo_test(void)
+{
+ int error, read_fd = -1, write_fd = -1;
+ struct aio_fifo_arg arg;
+ char pathname[PATH_MAX];
+ struct aio_context ac;
+
+ /*
+ * In theory, mktemp() can return a name that is then collided with.
+ * Because this is a regression test, we treat that as a test failure
+ * rather than retrying.
+ */
+ strcpy(pathname, PATH_TEMPLATE);
+ mktemp(pathname);
+ if (mkfifo(pathname, 0600) == -1)
+ errx(-1, "FAIL: aio_fifo_test: mkfifo: %s", strerror(errno));
+ arg.afa_pathname = pathname;
+ arg.afa_read_fd = -1;
+ arg.afa_write_fd = -1;
+
+ read_fd = open(pathname, O_RDONLY | O_NONBLOCK);
+ if (read_fd == -1) {
+ error = errno;
+ aio_fifo_cleanup(&arg);
+ errno = error;
+ errx(-1, "FAIL: aio_fifo_test: read_fd open: %s",
+ strerror(errno));
+ }
+ arg.afa_read_fd = read_fd;
+
+ write_fd = open(pathname, O_WRONLY);
+ if (write_fd == -1) {
+ error = errno;
+ aio_fifo_cleanup(&arg);
+ errno = error;
+ errx(-1, "FAIL: aio_fifo_test: write_fd open: %s",
+ strerror(errno));
+ }
+ arg.afa_write_fd = write_fd;
+
+ aio_context_init(&ac, "aio_fifo_test", read_fd, write_fd, FIFO_LEN,
+ FIFO_TIMEOUT, aio_fifo_cleanup, &arg);
+ aio_write_test(&ac);
+ aio_read_test(&ac);
+
+ aio_fifo_cleanup(&arg);
+
+ fprintf(stderr, "PASS: aio_fifo_test\n");
+}
+
+struct aio_unix_socketpair_arg {
+ int asa_sockets[2];
+};
+
+static void
+aio_unix_socketpair_cleanup(void *arg)
+{
+ struct aio_unix_socketpair_arg *asa;
+
+ asa = arg;
+ close(asa->asa_sockets[0]);
+ close(asa->asa_sockets[1]);
+}
+
+#define UNIX_SOCKETPAIR_LEN 256
+#define UNIX_SOCKETPAIR_TIMEOUT 30
+static int
+aio_unix_socketpair_test(void)
+{
+ struct aio_unix_socketpair_arg arg;
+ struct aio_context ac;
+ int sockets[2];
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) < 0)
+ errx(-1, "FAIL: aio_socketpair_test: socketpair: %s",
+ strerror(errno));
+
+ arg.asa_sockets[0] = sockets[0];
+ arg.asa_sockets[1] = sockets[1];
+ aio_context_init(&ac, "aio_unix_socketpair_test", sockets[0],
+ sockets[1], UNIX_SOCKETPAIR_LEN, UNIX_SOCKETPAIR_TIMEOUT,
+ aio_unix_socketpair_cleanup, &arg);
+ aio_write_test(&ac);
+ aio_read_test(&ac);
+
+ aio_unix_socketpair_cleanup(&arg);
+
+ fprintf(stderr, "PASS: aio_unix_socketpair_test\n");
+}
+
+struct aio_pty_arg {
+ int apa_read_fd;
+ int apa_write_fd;
+};
+
+static void
+aio_pty_cleanup(void *arg)
+{
+ struct aio_pty_arg *apa;
+
+ close(apa->apa_read_fd);
+ close(apa->apa_write_fd);
+};
+
+#define PTY_LEN 256
+#define PTY_TIMEOUT 30
+static int
+aio_pty_test(void)
+{
+ struct aio_pty_arg arg;
+ struct aio_context ac;
+ int read_fd, write_fd;
+ struct termios ts;
+ int error;
+
+ if (openpty(&read_fd, &write_fd, NULL, NULL, NULL) < 0)
+ errx(-1, "FAIL: aio_pty_test: openpty: %s", strerror(errno));
+
+ arg.apa_read_fd = read_fd;
+ arg.apa_write_fd = write_fd;
+
+ if (tcgetattr(write_fd, &ts) < 0) {
+ error = errno;
+ aio_pty_cleanup(&arg);
+ errno = error;
+ errx(-1, "FAIL: aio_pty_test: tcgetattr: %s",
+ strerror(errno));
+ }
+ cfmakeraw(&ts);
+ if (tcsetattr(write_fd, TCSANOW, &ts) < 0) {
+ error = errno;
+ aio_pty_cleanup(&arg);
+ errno = error;
+ errx(-1, "FAIL: aio_pty_test: tcsetattr: %s",
+ strerror(errno));
+ }
+
+ aio_context_init(&ac, "aio_pty_test", read_fd, write_fd, PTY_LEN,
+ PTY_TIMEOUT, aio_pty_cleanup, &arg);
+ aio_write_test(&ac);
+ aio_read_test(&ac);
+
+ aio_pty_cleanup(&arg);
+
+ fprintf(stderr, "PASS: aio_pty_test\n");
+}
+
+static void
+aio_pipe_cleanup(void *arg)
+{
+ int *pipes = arg;
+
+ close(pipes[0]);
+ close(pipes[1]);
+}
+
+#define PIPE_LEN 256
+#define PIPE_TIMEOUT 30
+static int
+aio_pipe_test(void)
+{
+ struct aio_context ac;
+ int pipes[2];
+
+ if (pipe(pipes) < 0)
+ errx(-1, "FAIL: aio_pipe_test: pipe: %s", strerror(errno));
+
+ aio_context_init(&ac, "aio_file_test", pipes[0], pipes[1], PIPE_LEN,
+ PIPE_TIMEOUT, aio_pipe_cleanup, pipes);
+ aio_write_test(&ac);
+ aio_read_test(&ac);
+
+ aio_pipe_cleanup(pipes);
+
+ fprintf(stderr, "PASS: aio_pipe_test\n");
+}
+
+struct aio_md_arg {
+ int ama_mdctl_fd;
+ int ama_unit;
+ int ama_fd;
+};
+
+static void
+aio_md_cleanup(void *arg)
+{
+ struct aio_md_arg *ama;
+ struct md_ioctl mdio;
+ int error;
+
+ ama = arg;
+
+ if (ama->ama_fd != -1)
+ close(ama->ama_fd);
+
+ if (ama->ama_unit != -1) {
+ bzero(&mdio, sizeof(mdio));
+ mdio.md_version = MDIOVERSION;
+ mdio.md_unit = ama->ama_unit;
+ if (ioctl(ama->ama_mdctl_fd, MDIOCDETACH, &mdio) < 0) {
+ error = errno;
+ close(ama->ama_mdctl_fd);
+ errno = error;
+ warnx("FAIL: aio_md_test: MDIOCDETACH: %s",
+ strerror(errno));
+ }
+ }
+
+ close(ama->ama_mdctl_fd);
+}
+
+#define MD_LEN GLOBAL_MAX
+#define MD_TIMEOUT 30
+static int
+aio_md_test(void)
+{
+ int error, fd, i, mdctl_fd, unit;
+ char pathname[PATH_MAX];
+ struct aio_md_arg arg;
+ struct aio_context ac;
+ struct md_ioctl mdio;
+
+ mdctl_fd = open("/dev/" MDCTL_NAME, O_RDWR, 0);
+ if (mdctl_fd < 0)
+ errx(-1, "FAIL: aio_md_test: open(/dev/%s): %s", MDCTL_NAME,
+ strerror(errno));
+
+ bzero(&mdio, sizeof(mdio));
+ mdio.md_version = MDIOVERSION;
+ mdio.md_type = MD_MALLOC;
+ mdio.md_options = MD_AUTOUNIT | MD_COMPRESS;
+ mdio.md_mediasize = GLOBAL_MAX;
+ mdio.md_sectorsize = 512;
+
+ arg.ama_mdctl_fd = mdctl_fd;
+ arg.ama_unit = -1;
+ arg.ama_fd = -1;
+ if (ioctl(mdctl_fd, MDIOCATTACH, &mdio) < 0) {
+ error = errno;
+ aio_md_cleanup(&arg);
+ errno = error;
+ errx(-1, "FAIL: aio_md_test: MDIOCATTACH: %s",
+ strerror(errno));
+ }
+
+ arg.ama_unit = unit = mdio.md_unit;
+ snprintf(pathname, PATH_MAX, "/dev/md%d", unit);
+ fd = open(pathname, O_RDWR);
+ if (fd < 0) {
+ error = errno;
+ aio_md_cleanup(&arg);
+ errno = error;
+ errx(-1, "FAIL: aio_md_test: open(%s): %s", pathname,
+ strerror(errno));
+ }
+ arg.ama_fd = fd;
+
+ aio_context_init(&ac, "aio_md_test", fd, fd, MD_LEN, MD_TIMEOUT,
+ aio_md_cleanup, &arg);
+ aio_write_test(&ac);
+ aio_read_test(&ac);
+
+ aio_md_cleanup(&arg);
+
+ fprintf(stderr, "PASS: aio_md_test\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ aio_sigsys_setup();
+ aio_file_test();
+ aio_fifo_test();
+ aio_unix_socketpair_test();
+ aio_pty_test();
+ aio_pipe_test();
+ if (geteuid() == 0)
+ aio_md_test();
+ else
+ fprintf(stderr, "WARNING: aio_md_test: skipped as euid "
+ "!= 0\n");
+}
diff --git a/tools/regression/netinet/ipsockopt/ipsockopt.c b/tools/regression/netinet/ipsockopt/ipsockopt.c
new file mode 100644
index 0000000000000..1df6b0d3e537b
--- /dev/null
+++ b/tools/regression/netinet/ipsockopt/ipsockopt.c
@@ -0,0 +1,839 @@
+/*-
+ * Copyright (c) 2004 Robert N. M. Watson
+ * 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 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * The test tool exercises IP-level socket options by interrogating the
+ * getsockopt()/setsockopt() APIs. It does not currently test that the
+ * intended semantics of each option are implemented (i.e., that setting IP
+ * options on the socket results in packets with the desired IP options in
+ * it).
+ */
+
+/*
+ * get_socket() is a wrapper function that returns a socket of the specified
+ * type, and created with or without restored root privilege (if running
+ * with a real uid of root and an effective uid of some other user). This
+ * us to test whether the same rights are granted using a socket with a
+ * privileged cached credential vs. a socket with a regular credential.
+ */
+#define PRIV_ASIS 0
+#define PRIV_GETROOT 1
+static int
+get_socket_unpriv(int type)
+{
+
+ return (socket(PF_INET, type, 0));
+}
+
+static int
+get_socket_priv(int type)
+{
+ uid_t olduid;
+ int sock;
+
+ if (getuid() != 0)
+ errx(-1, "get_sock_priv: running without real uid 0");
+
+ olduid = geteuid();
+ if (seteuid(0) < 0)
+ err(-1, "get_sock_priv: seteuid(0)");
+
+ sock = socket(PF_INET, type, 0);
+
+ if (seteuid(olduid) < 0)
+ err(-1, "get_sock_priv: seteuid(%d)", olduid);
+
+ return (sock);
+}
+
+static int
+get_socket(int type, int priv)
+{
+
+ if (priv)
+ return (get_socket_priv(type));
+ else
+ return (get_socket_unpriv(type));
+}
+
+/*
+ * Exercise the IP_OPTIONS socket option. Confirm the following properties:
+ *
+ * - That there is no initial set of options (length returned is 0).
+ * - That if we set a specific set of options, we can read it back.
+ * - That if we then reset the options, they go away.
+ *
+ * Use a UDP socket for this.
+ */
+static void
+test_ip_options(int sock, const char *socktypename)
+{
+ u_int32_t new_options, test_options[2];
+ socklen_t len;
+
+ /*
+ * Start off by confirming the default IP options on a socket are to
+ * have no options set.
+ */
+ len = sizeof(test_options);
+ if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
+ err(-1, "test_ip_options(%s): initial getsockopt()",
+ socktypename);
+
+ if (len != 0)
+ errx(-1, "test_ip_options(%s): initial getsockopt() returned "
+ "%d bytes", socktypename, len);
+
+#define TEST_MAGIC 0xc34e4212
+#define NEW_OPTIONS htonl(IPOPT_EOL | (IPOPT_NOP << 8) | (IPOPT_NOP << 16) \
+ | (IPOPT_NOP << 24))
+
+ /*
+ * Write some new options into the socket.
+ */
+ new_options = NEW_OPTIONS;
+ if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, &new_options,
+ sizeof(new_options)) < 0)
+ err(-1, "test_ip_options(%s): setsockopt(NOP|NOP|NOP|EOL)",
+ socktypename);
+
+ /*
+ * Store some random cruft in a local variable and retrieve the
+ * options to make sure they set. Note that we pass in an array
+ * of u_int32_t's so that if whatever ended up in the option was
+ * larger than what we put in, we find out about it here.
+ */
+ test_options[0] = TEST_MAGIC;
+ test_options[1] = TEST_MAGIC;
+ len = sizeof(test_options);
+ if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
+ err(-1, "test_ip_options(%s): getsockopt() after set",
+ socktypename);
+
+ /*
+ * Getting the right amount back is important.
+ */
+ if (len != sizeof(new_options))
+ errx(-1, "test_ip_options(%s): getsockopt() after set "
+ "returned %d bytes of data", socktypename, len);
+
+ /*
+ * One posible failure mode is that the call succeeds but neglects to
+ * copy out the data.
+ */
+ if (test_options[0] == TEST_MAGIC)
+ errx(-1, "test_ip_options(%s): getsockopt() after set didn't "
+ "return data", socktypename);
+
+ /*
+ * Make sure we get back what we wrote on.
+ */
+ if (new_options != test_options[0])
+ errx(-1, "test_ip_options(%s): getsockopt() after set "
+ "returned wrong options (%08x, %08x)", socktypename,
+ new_options, test_options[0]);
+
+ /*
+ * Now we reset the value to make sure clearing works.
+ */
+ if (setsockopt(sock, IPPROTO_IP, IP_OPTIONS, NULL, 0) < 0)
+ err(-1, "test_ip_options(%s): setsockopt() to reset",
+ socktypename);
+
+ /*
+ * Make sure it was really cleared.
+ */
+ test_options[0] = TEST_MAGIC;
+ test_options[1] = TEST_MAGIC;
+ len = sizeof(test_options);
+ if (getsockopt(sock, IPPROTO_IP, IP_OPTIONS, test_options, &len) < 0)
+ err(-1, "test_ip_options(%s): getsockopt() after reset",
+ socktypename);
+
+ if (len != 0)
+ errx(-1, "test_ip_options(%s): getsockopt() after reset "
+ "returned %d bytes", socktypename, len);
+}
+
+/*
+ * This test checks the behavior of the IP_HDRINCL socket option, which
+ * allows users with privilege to specify the full header on an IP raw
+ * socket. We test that the option can only be used with raw IP sockets, not
+ * with UDP or TCP sockets. We also confirm that the raw socket is only
+ * available to a privileged user (subject to the UID when called). We
+ * confirm that it defaults to off
+ *
+ * Unlike other tests, doesn't use caller-provided socket. Probably should
+ * be fixed.
+ */
+static void
+test_ip_hdrincl(void)
+{
+ int flag[2], sock;
+ socklen_t len;
+
+ /*
+ * Try to receive or set the IP_HDRINCL flag on a TCP socket.
+ */
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock == -1)
+ err(-1, "test_ip_hdrincl(): socket(SOCK_STREAM)");
+
+ flag[0] = -1;
+ len = sizeof(flag[0]);
+ if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
+ err(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINCL)");
+
+ if (errno != ENOPROTOOPT)
+ errx(-1, "test_ip_hdrincl(): initial getsockopt(IP_HDRINC) "
+ "returned %d (%s) not ENOPROTOOPT", errno,
+ strerror(errno));
+
+ flag[0] = 1;
+ if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
+ == 0)
+ err(-1,"test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
+ "succeeded\n");
+
+ if (errno != ENOPROTOOPT)
+ errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on TCP "
+ "returned %d (%s) not ENOPROTOOPT\n", errno,
+ strerror(errno));
+
+ close(sock);
+
+ /*
+ * Try to receive or set the IP_HDRINCL flag on a UDP socket.
+ */
+ sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (sock == -1)
+ err(-1, "test_ip_hdrincl(): socket(SOCK_DGRAM");
+
+ flag[0] = -1;
+ len = sizeof(flag[0]);
+ if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) == 0)
+ err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
+ "succeeded\n");
+
+ if (errno != ENOPROTOOPT)
+ errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on UDP "
+ "returned %d (%s) not ENOPROTOOPT\n", errno,
+ strerror(errno));
+
+ if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
+ == 0)
+ err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
+ "succeeded\n");
+
+ if (errno != ENOPROTOOPT)
+ errx(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL) on UDP "
+ "returned %d (%s) not ENOPROTOOPT\n", errno,
+ strerror(errno));
+
+ close(sock);
+
+ /*
+ * Now try on a raw socket. Access ontrol should prevent non-root
+ * users from creating the raw socket, so check that here based on
+ * geteuid(). If we're non-root, we just return assuming the socket
+ * create fails since the remainder of the tests apply only on a raw
+ * socket.
+ */
+ sock = socket(PF_INET, SOCK_RAW, 0);
+ if (geteuid() != 0) {
+ if (sock != -1)
+ errx(-1, "test_ip_hdrincl: created raw socket as "
+ "uid %d", geteuid());
+ return;
+ }
+ if (sock == -1)
+ err(-1, "test_ip_hdrincl(): socket(PF_INET, SOCK_RAW)");
+
+ /*
+ * Make sure the initial value of the flag is 0 (disabled).
+ */
+ flag[0] = -1;
+ flag[1] = -1;
+ len = sizeof(flag);
+ if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
+ err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) on raw "
+ "socket");
+
+ if (len != sizeof(flag[0]))
+ errx(-1, "test_ip_hdrincl(): %d bytes returned on "
+ "initial get\n", len);
+
+ if (flag[0] != 0)
+ errx(-1, "test_ip_hdrincl(): initial flag value of %d\n",
+ flag[0]);
+
+ /*
+ * Enable the IP_HDRINCL flag.
+ */
+ flag[0] = 1;
+ if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
+ < 0)
+ err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 1)");
+
+ /*
+ * Check that the IP_HDRINCL flag was set.
+ */
+ flag[0] = -1;
+ flag[1] = -1;
+ len = sizeof(flag);
+ if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
+ err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
+ "set");
+
+ if (flag[0] == 0)
+ errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
+ "after set had flag of %d\n", flag[0]);
+
+#define HISTORICAL_INP_HDRINCL 8
+ if (flag[0] != HISTORICAL_INP_HDRINCL)
+ warnx("test_ip_hdrincl(): WARNING: getsockopt(IP_H"
+ "DRINCL) after set had non-historical value of %d\n",
+ flag[0]);
+
+ /*
+ * Reset the IP_HDRINCL flag to 0.
+ */
+ flag[0] = 0;
+ if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, sizeof(flag[0]))
+ < 0)
+ err(-1, "test_ip_hdrincl(): setsockopt(IP_HDRINCL, 0)");
+
+ /*
+ * Check that the IP_HDRINCL flag was reset to 0.
+ */
+ flag[0] = -1;
+ flag[1] = -1;
+ len = sizeof(flag);
+ if (getsockopt(sock, IPPROTO_IP, IP_HDRINCL, flag, &len) < 0)
+ err(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) after "
+ "reset");
+
+ if (flag[0] != 0)
+ errx(-1, "test_ip_hdrincl(): getsockopt(IP_HDRINCL) "
+ "after set had flag of %d\n", flag[0]);
+
+ close(sock);
+}
+
+/*
+ * As with other non-int or larger sized socket options, the IP_TOS and
+ * IP_TTL fields in kernel is stored as an 8-bit value, reflecting the IP
+ * header fields, but useful I/O to the field occurs using 32-bit integers.
+ * The FreeBSD kernel will permit writes from variables at least an int in
+ * size (and ignore additional bytes), and will permit a read to buffers 1
+ * byte or larger (but depending on endianness, may truncate out useful
+ * values if the caller provides less room).
+ *
+ * Given the limitations of the API, use a UDP socket to confirm that the
+ * following are true:
+ *
+ * - We can read the IP_TOS/IP_TTL options.
+ * - The initial value of the TOS option is 0, TTL is 64.
+ * - That if we provide more than 32 bits of storage, we get back only 32
+ * bits of data.
+ * - When we set it to a non-zero value expressible with a u_char, we can
+ * read that value back.
+ * - When we reset it back to zero, we can read it as 0.
+ * - When we set it to a value >255, the value is truncated to something less
+ * than 255.
+ */
+static void
+test_ip_uchar(int sock, const char *socktypename, int option,
+ const char *optionname, int initial)
+{
+ int val[2];
+ socklen_t len;
+
+ /*
+ * Check that the initial value is 0, and that the size is one
+ * u_char;
+ */
+ val[0] = -1;
+ val[1] = -1;
+ len = sizeof(val);
+ if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
+ err(-1, "test_ip_uchar(%s, %s): initial getsockopt()",
+ socktypename, optionname);
+
+ if (len != sizeof(val[0]))
+ errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
+ "returned %d bytes", socktypename, optionname, len);
+
+ if (val[0] == -1)
+ errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() didn't "
+ "return data", socktypename, optionname);
+
+ if (val[0] != initial)
+ errx(-1, "test_ip_uchar(%s, %s): initial getsockopt() "
+ "returned value of %d, not %d", socktypename, optionname,
+ val[0], initial);
+
+ /*
+ * Set the field to a valid value.
+ */
+ val[0] = 128;
+ val[1] = -1;
+ if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
+ err(-1, "test_ip_uchar(%s, %s): setsockopt(128)",
+ socktypename, optionname);
+
+ /*
+ * Check that when we read back the field, we get the same value.
+ */
+ val[0] = -1;
+ val[1] = -1;
+ len = sizeof(val);
+ if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
+ err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
+ "128", socktypename, optionname);
+
+ if (len != sizeof(val[0]))
+ errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
+ "128 returned %d bytes", socktypename, optionname, len);
+
+ if (val[0] == -1)
+ errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
+ "128 didn't return data", socktypename, optionname);
+
+ if (val[0] != 128)
+ errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
+ "128 returned %d", socktypename, optionname, val[0]);
+
+ /*
+ * Reset the value to 0, check that it was reset.
+ */
+ val[0] = 0;
+ val[1] = 0;
+ if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0)
+ err(-1, "test_ip_uchar(%s, %s): setsockopt() to reset from "
+ "128", socktypename, optionname);
+
+ if (len != sizeof(val[0]))
+ errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
+ "from 128 returned %d bytes", socktypename, optionname,
+ len);
+
+ if (val[0] == -1)
+ errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
+ "from 128 didn't return data", socktypename, optionname);
+
+ if (val[0] != 0)
+ errx(-1, "test_ip_uchar(%s, %s): getsockopt() after reset "
+ "from 128 returned %d", socktypename, optionname,
+ val[0]);
+
+ /*
+ * Set the value to something out of range and check that it comes
+ * back truncated, or that we get EINVAL back. Traditional u_char
+ * IP socket options truncate, but newer ones (such as multicast
+ * socket options) will return EINVAL.
+ */
+ val[0] = 32000;
+ val[1] = -1;
+ if (setsockopt(sock, IPPROTO_IP, option, val, sizeof(val[0])) < 0) {
+ /*
+ * EINVAL is a fine outcome, no need to run the truncation
+ * tests.
+ */
+ if (errno == EINVAL)
+ return;
+ err(-1, "test_ip_uchar(%s, %s): getsockopt(32000)",
+ socktypename, optionname);
+ }
+
+ val[0] = -1;
+ val[1] = -1;
+ len = sizeof(val);
+ if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
+ err(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
+ "32000", socktypename, optionname);
+
+ if (len != sizeof(val[0]))
+ errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
+ "32000 returned %d bytes", socktypename, optionname,
+ len);
+
+ if (val[0] == -1)
+ errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
+ "32000 didn't return data", socktypename, optionname);
+
+ if (val[0] == 32000)
+ errx(-1, "test_ip_uchar(%s, %s): getsockopt() after set to "
+ "32000 returned 32000: failed to truncate", socktypename,
+ optionname);
+}
+
+/*
+ * Generic test for a boolean socket option. Caller provides the option
+ * number, string name, expected default (initial) value, and whether or not
+ * the option is root-only. For each option, test:
+ *
+ * - That we can read the option.
+ * - That the initial value is as expected.
+ * - That we can modify the value.
+ * - That on modification, the new value can be read back.
+ * - That we can reset the value.
+ * - that on reset, the new value can be read back.
+ */
+#define BOOLEAN_ANYONE 1
+#define BOOLEAN_ROOTONLY 1
+static void
+test_ip_boolean(int sock, const char *socktypename, int option,
+ char *optionname, int initial, int rootonly)
+{
+ int newvalue, val[2];
+ socklen_t len;
+
+ /*
+ * The default for a boolean might be true or false. If it's false,
+ * we will try setting it to true (but using a non-1 value of true).
+ * If it's true, we'll set it to false.
+ */
+ if (initial == 0)
+ newvalue = 0xff;
+ else
+ newvalue = 0;
+
+ val[0] = -1;
+ val[1] = -1;
+ len = sizeof(val);
+ if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
+ err(-1, "test_ip_boolean: initial getsockopt()");
+
+ if (len != sizeof(val[0]))
+ errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
+ "returned %d bytes", socktypename, optionname, len);
+
+ if (val[0] == -1)
+ errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
+ "didn't return data", socktypename, optionname);
+
+ if (val[0] != initial)
+ errx(-1, "test_ip_boolean(%s, %s): initial getsockopt() "
+ "returned %d (expected %d)", socktypename, optionname,
+ val[0], initial);
+
+ /*
+ * Set the socket option to a new non-default value.
+ */
+ if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
+ < 0)
+ err(-1, "test_ip_boolean(%s, %s): setsockopt() to %d",
+ socktypename, optionname, newvalue);
+
+ /*
+ * Read the value back and see if it is not the default (note: will
+ * not be what we set it to, as we set it to 0xff above).
+ */
+ val[0] = -1;
+ val[1] = -1;
+ len = sizeof(val);
+ if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
+ err(-1, "test_ip_boolean(%s, %s): getsockopt() after set to "
+ "%d", socktypename, optionname, newvalue);
+
+ if (len != sizeof(val[0]))
+ errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
+ "to %d returned %d bytes", socktypename, optionname,
+ newvalue, len);
+
+ if (val[0] == -1)
+ errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
+ "to %d didn't return data", socktypename, optionname,
+ newvalue);
+
+ /*
+ * If we set it to true, check for '1', otherwise '0.
+ */
+ if (val[0] != (newvalue ? 1 : 0))
+ errx(-1, "test_ip_boolean(%s, %s): getsockopt() after set "
+ "to %d returned %d", socktypename, optionname, newvalue,
+ val[0]);
+
+ /*
+ * Reset to initial value.
+ */
+ newvalue = initial;
+ if (setsockopt(sock, IPPROTO_IP, option, &newvalue, sizeof(newvalue))
+ < 0)
+ err(-1, "test_ip_boolean(%s, %s): setsockopt() to reset",
+ socktypename, optionname);
+
+ /*
+ * Check reset version.
+ */
+ val[0] = -1;
+ val[1] = -1;
+ len = sizeof(val);
+ if (getsockopt(sock, IPPROTO_IP, option, val, &len) < 0)
+ err(-1, "test_ip_boolean(%s, %s): getsockopt() after reset",
+ socktypename, optionname);
+
+ if (len != sizeof(val[0]))
+ errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
+ "returned %d bytes", socktypename, optionname, len);
+
+ if (val[0] == -1)
+ errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
+ "didn't return data", socktypename, optionname);
+
+ if (val[0] != newvalue)
+ errx(-1, "test_ip_boolean(%s, %s): getsockopt() after reset "
+ "returned %d", socktypename, optionname, newvalue);
+}
+
+/*
+ * XXX: For now, nothing here.
+ */
+static void
+test_ip_multicast_if(int sock, const char *socktypename)
+{
+
+ /*
+ * It's probably worth trying INADDR_ANY and INADDR_LOOPBACK here
+ * to see what happens.
+ */
+}
+
+/*
+ * XXX: For now, nothing here.
+ */
+static void
+test_ip_multicast_vif(int sock, const char *socktypename)
+{
+
+ /*
+ * This requires some knowledge of the number of virtual interfaces,
+ * and what is valid.
+ */
+}
+
+/*
+ * XXX: For now, nothing here.
+ */
+static void
+test_ip_multicast_membership(int sock, const char *socktypename)
+{
+
+}
+
+static void
+testsuite(int priv)
+{
+ const char *socktypenameset[] = {"SOCK_DGRAM", "SOCK_STREAM",
+ "SOCK_RAW"};
+ int socktypeset[] = {SOCK_DGRAM, SOCK_STREAM, SOCK_RAW};
+ const char *socktypename;
+ int i, sock, socktype;
+
+ test_ip_hdrincl();
+
+ for (i = 0; i < sizeof(socktypeset)/sizeof(int); i++) {
+ socktype = socktypeset[i];
+ socktypename = socktypenameset[i];
+
+ /*
+ * If we can't acquire root privilege, we can't open raw
+ * sockets, so don't actually try.
+ */
+ if (getuid() != 0 && socktype == SOCK_RAW)
+ continue;
+ if (geteuid() != 0 && !priv && socktype == SOCK_RAW)
+ continue;
+
+ /*
+ * XXXRW: On 5.3, this seems not to work for SOCK_RAW.
+ */
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for test_ip_uchar(IP_TOS)",
+ socktypename, priv);
+ test_ip_uchar(sock, socktypename, IP_TOS, "IP_TOS", 0);
+ close(sock);
+
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s %d) for test_ip_uchar(IP_TTL)",
+ socktypename, priv);
+ test_ip_uchar(sock, socktypename, IP_TTL, "IP_TTL", 64);
+ close(sock);
+
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for test_ip_boolean"
+ "(IP_RECVOPTS)", socktypename, priv);
+ test_ip_boolean(sock, socktypename, IP_RECVOPTS,
+ "IP_RECVOPTS", 0, BOOLEAN_ANYONE);
+ close(sock);
+
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for test_ip_boolean"
+ "(IP_RECVRETOPTS)", socktypename, priv);
+ test_ip_boolean(sock, socktypename, IP_RECVRETOPTS,
+ "IP_RECVRETOPTS", 0, BOOLEAN_ANYONE);
+ close(sock);
+
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for test_ip_boolean"
+ "(IP_RECVDSTADDR)", socktypename, priv);
+ test_ip_boolean(sock, socktypename, IP_RECVDSTADDR,
+ "IP_RECVDSTADDR", 0, BOOLEAN_ANYONE);
+ close(sock);
+
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for test_ip_boolean"
+ "(IP_RECVTTL)", socktypename, priv);
+ test_ip_boolean(sock, socktypename, IP_RECVTTL, "IP_RECVTTL",
+ 0, BOOLEAN_ANYONE);
+ close(sock);
+
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for test_ip_boolean"
+ "(IP_RECVIF)", socktypename, priv);
+ test_ip_boolean(sock, socktypename, IP_RECVIF, "IP_RECVIF",
+ 0, BOOLEAN_ANYONE);
+ close(sock);
+
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for test_ip_boolean"
+ "(IP_FAITH)", socktypename, priv);
+ test_ip_boolean(sock, socktypename, IP_FAITH, "IP_FAITH", 0,
+ BOOLEAN_ANYONE);
+ close(sock);
+
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for test_ip_boolean"
+ "(IP_ONESBCAST)", socktypename, priv);
+ test_ip_boolean(sock, socktypename, IP_ONESBCAST,
+ "IP_ONESBCAST", 0, BOOLEAN_ANYONE);
+ close(sock);
+
+ /*
+ * Test the multicast TTL exactly as we would the regular
+ * TTL, only expect a different default.
+ */
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for IP_MULTICAST_TTL",
+ socktypename, priv);
+ test_ip_uchar(sock, socktypename, IP_MULTICAST_TTL,
+ "IP_MULTICAST_TTL", 1);
+ close(sock);
+
+ /*
+ * The multicast loopback flag can be tested using our
+ * boolean tester, but only because the FreeBSD API is a bit
+ * more flexible than earlir APIs and will accept an int as
+ * well as a u_char. Loopback is enabled by default.
+ */
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for IP_MULTICAST_LOOP",
+ socktypename, priv);
+ test_ip_boolean(sock, socktypename, IP_MULTICAST_LOOP,
+ "IP_MULTICAST_LOOP", 1, BOOLEAN_ANYONE);
+ close(sock);
+
+ sock = get_socket(socktype, priv);
+ if (sock == -1)
+ err(-1, "get_socket(%s, %d) for test_ip_options",
+ socktypename, priv);
+ //test_ip_options(sock, socktypename);
+ close(sock);
+
+ test_ip_multicast_if(0, NULL);
+ test_ip_multicast_vif(0, NULL);
+ test_ip_multicast_membership(0, NULL);
+ /*
+ * XXX: Still need to test:
+ * IP_PORTRANGE
+ * IP_IPSEC_POLICY?
+ */
+ }
+}
+
+/*
+ * Very simply exercise that we can get and set each option. If we're running
+ * as root, run it also as nobody. If not as root, complain about that.
+ */
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..1\n");
+ if (geteuid() != 0) {
+ warnx("Not running as root, can't run tests as root");
+ fprintf(stderr, "\n");
+ fprintf(stderr,
+ "Running tests with uid %d sock uid %d\n", geteuid(),
+ geteuid());
+ testsuite(PRIV_ASIS);
+ } else {
+ fprintf(stderr,
+ "Running tests with ruid %d euid %d sock uid 0\n",
+ getuid(), geteuid());
+ testsuite(PRIV_ASIS);
+ if (seteuid(65534) != 0)
+ err(-1, "seteuid(65534)");
+ fprintf(stderr,
+ "Running tests with ruid %d euid %d sock uid 65534\n",
+ getuid(), geteuid());
+ testsuite(PRIV_ASIS);
+ fprintf(stderr,
+ "Running tests with ruid %d euid %d sock uid 0\n",
+ getuid(), geteuid());
+ testsuite(PRIV_GETROOT);
+ }
+ printf("ok 1 - ipsockopt\n");
+ exit(0);
+}
diff --git a/tools/regression/sockets/kqueue/kqueue.c b/tools/regression/sockets/kqueue/kqueue.c
new file mode 100644
index 0000000000000..d46db96ad4ee8
--- /dev/null
+++ b/tools/regression/sockets/kqueue/kqueue.c
@@ -0,0 +1,368 @@
+/*-
+ * Copyright (c) 2004 Robert N. M. Watson
+ * 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 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int curtest = 1;
+
+/*-
+ * This test uses UNIX domain socket pairs to perform some basic exercising
+ * of kqueue functionality on sockets. In particular, testing that for read
+ * and write filters, we see the correct detection of whether reads and
+ * writes should actually be able to occur.
+ *
+ * TODO:
+ * - Test read/write filters for listen/accept sockets.
+ * - Handle the XXXRW below regarding datagram sockets.
+ * - Test that watermark/buffer size "data" fields returned by kqueue are
+ * correct.
+ * - Check that kqueue does something sensible when the remote endpoing is
+ * closed.
+ */
+
+#define OK(testname) printf("ok %d - %s\n", curtest, testname); \
+ curtest++;
+
+static void
+fail(int error, const char *func, const char *socktype, const char *rest)
+{
+
+ printf("not ok %d\n", curtest);
+
+ if (socktype == NULL)
+ printf("# %s(): %s\n", func, strerror(error));
+ else if (rest == NULL)
+ printf("# %s(%s): %s\n", func, socktype,
+ strerror(error));
+ else
+ printf("# %s(%s, %s): %s\n", func, socktype, rest,
+ strerror(error));
+ exit(-1);
+}
+
+static void
+fail_assertion(const char *func, const char *socktype, const char *rest,
+ const char *assertion)
+{
+
+ printf("not ok %d - %s\n", curtest, assertion);
+
+ if (socktype == NULL)
+ printf("# %s(): assertion %s failed\n", func,
+ assertion);
+ else if (rest == NULL)
+ printf("# %s(%s): assertion %s failed\n", func,
+ socktype, assertion);
+ else
+ printf("# %s(%s, %s): assertion %s failed\n", func,
+ socktype, rest, assertion);
+ exit(-1);
+}
+
+/*
+ * Test read kevent on a socket pair: check to make sure endpoint 0 isn't
+ * readable when we start, then write to endpoint 1 and confirm that endpoint
+ * 0 is now readable. Drain the write, then check that it's not readable
+ * again. Use non-blocking kqueue operations and socket operations.
+ */
+static void
+test_evfilt_read(int kq, int fd[2], const char *socktype)
+{
+ struct timespec ts;
+ struct kevent ke;
+ ssize_t len;
+ char ch;
+ int i;
+
+ EV_SET(&ke, fd[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
+ if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)
+ fail(errno, "kevent", socktype, "EVFILT_READ, EV_ADD");
+ OK("EVFILT_READ, EV_ADD");
+
+ /*
+ * Confirm not readable to begin with, no I/O yet.
+ */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ i = kevent(kq, NULL, 0, &ke, 1, &ts);
+ if (i == -1)
+ fail(errno, "kevent", socktype, "EVFILT_READ");
+ OK("EVFILT_READ");
+ if (i != 0)
+ fail_assertion("kevent", socktype, "EVFILT_READ",
+ "empty socket unreadable");
+ OK("empty socket unreadable");
+
+ /*
+ * Write a byte to one end.
+ */
+ ch = 'a';
+ len = write(fd[1], &ch, sizeof(ch));
+ if (len == -1)
+ fail(errno, "write", socktype, NULL);
+ OK("write one byte");
+ if (len != sizeof(ch))
+ fail_assertion("write", socktype, NULL, "write length");
+ OK("write one byte length");
+
+ /*
+ * Other end should now be readable.
+ */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ i = kevent(kq, NULL, 0, &ke, 1, &ts);
+ if (i == -1)
+ fail(errno, "kevent", socktype, "EVFILT_READ");
+ OK("EVFILT_READ");
+ if (i != 1)
+ fail_assertion("kevent", socktype, "EVFILT_READ",
+ "non-empty socket unreadable");
+ OK("non-empty socket unreadable");
+
+ /*
+ * Read a byte to clear the readable state.
+ */
+ len = read(fd[0], &ch, sizeof(ch));
+ if (len == -1)
+ fail(errno, "read", socktype, NULL);
+ OK("read one byte");
+ if (len != sizeof(ch))
+ fail_assertion("read", socktype, NULL, "read length");
+ OK("read one byte length");
+
+ /*
+ * Now re-check for readability.
+ */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ i = kevent(kq, NULL, 0, &ke, 1, &ts);
+ if (i == -1)
+ fail(errno, "kevent", socktype, "EVFILT_READ");
+ OK("EVFILT_READ");
+ if (i != 0)
+ fail_assertion("kevent", socktype, "EVFILT_READ",
+ "empty socket unreadable");
+ OK("empty socket unreadable");
+
+ EV_SET(&ke, fd[0], EVFILT_READ, EV_DELETE, 0, 0, NULL);
+ if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)
+ fail(errno, "kevent", socktype, "EVFILT_READ, EV_DELETE");
+ OK("EVFILT_READ, EV_DELETE");
+}
+
+static void
+test_evfilt_write(int kq, int fd[2], const char *socktype)
+{
+ struct timespec ts;
+ struct kevent ke;
+ ssize_t len;
+ char ch;
+ int i;
+
+ EV_SET(&ke, fd[0], EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+ if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)
+ fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_ADD");
+ OK("EVFILE_WRITE, EV_ADD");
+
+ /*
+ * Confirm writable to begin with, no I/O yet.
+ */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ i = kevent(kq, NULL, 0, &ke, 1, &ts);
+ if (i == -1)
+ fail(errno, "kevent", socktype, "EVFILT_WRITE");
+ OK("EVFILE_WRITE");
+ if (i != 1)
+ fail_assertion("kevent", socktype, "EVFILT_WRITE",
+ "empty socket unwritable");
+ OK("empty socket unwritable");
+
+ /*
+ * Write bytes into the socket until we can't write anymore.
+ */
+ ch = 'a';
+ while ((len = write(fd[0], &ch, sizeof(ch))) == sizeof(ch)) {};
+ if (len == -1 && errno != EAGAIN && errno != ENOBUFS)
+ fail(errno, "write", socktype, NULL);
+ OK("write");
+ if (len != -1 && len != sizeof(ch))
+ fail_assertion("write", socktype, NULL, "write length");
+ OK("write length");
+
+ /*
+ * Check to make sure the socket is no longer writable.
+ */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ i = kevent(kq, NULL, 0, &ke, 1, &ts);
+ if (i == -1)
+ fail(errno, "kevent", socktype, "EVFILT_WRITE");
+ OK("EVFILT_WRITE");
+ if (i != 0)
+ fail_assertion("kevent", socktype, "EVFILT_WRITE",
+ "full socket writable");
+ OK("full socket writable");
+
+ EV_SET(&ke, fd[0], EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
+ if (kevent(kq, &ke, 1, NULL, 0, NULL) == -1)
+ fail(errno, "kevent", socktype, "EVFILT_WRITE, EV_DELETE");
+ OK("EVFILT_WRITE, EV_DELETE");
+}
+
+/*
+ * Basic registration exercise for kqueue(2). Create several types/brands of
+ * sockets, and confirm that we can register for various events on them.
+ */
+int
+main(int argc, char *argv[])
+{
+ int i, kq, sv[2];
+
+ printf("1..49\n");
+
+ kq = kqueue();
+ if (kq == -1)
+ fail(errno, "kqueue", NULL, NULL);
+ OK("kqueue()");
+
+ /*
+ * Create a UNIX domain datagram socket, and attach/test/detach a
+ * read filter on it.
+ */
+ if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)
+ fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL);
+ OK("socketpair() 1");
+
+ if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)
+ fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");
+ OK("fcntl() 1");
+ if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
+ fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");
+ OK("fnctl() 2");
+
+ test_evfilt_read(kq, sv, "PF_UNIX, SOCK_DGRAM");
+
+ if (close(sv[0]) == -1)
+ fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]");
+ OK("close() 1");
+ if (close(sv[1]) == -1)
+ fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]");
+ OK("close() 2");
+
+#if 0
+ /*
+ * XXXRW: We disable the write test in the case of datagram sockets,
+ * as kqueue can't tell when the remote socket receive buffer is
+ * full, whereas the UNIX domain socket implementation can tell and
+ * returns ENOBUFS.
+ */
+ /*
+ * Create a UNIX domain datagram socket, and attach/test/detach a
+ * write filter on it.
+ */
+ if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1)
+ fail(errno, "socketpair", "PF_UNIX, SOCK_DGRAM", NULL);
+
+ if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)
+ fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");
+ if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
+ fail(errno, "fcntl", "PF_UNIX, SOCK_DGRAM", "O_NONBLOCK");
+
+ test_evfilt_write(kq, sv, "PF_UNIX, SOCK_DGRAM");
+
+ if (close(sv[0]) == -1)
+ fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[0]");
+ if (close(sv[1]) == -1)
+ fail(errno, "close", "PF_UNIX/SOCK_DGRAM", "sv[1]");
+#endif
+
+ /*
+ * Create a UNIX domain stream socket, and attach/test/detach a
+ * read filter on it.
+ */
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1)
+ fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL);
+ OK("socketpair() 2");
+
+ if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)
+ fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");
+ OK("fcntl() 3");
+ if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
+ fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");
+ OK("fcntl() 4");
+
+ test_evfilt_read(kq, sv, "PF_UNIX, SOCK_STREAM");
+
+ if (close(sv[0]) == -1)
+ fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]");
+ OK("close() 3");
+ if (close(sv[1]) == -1)
+ fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]");
+ OK("close() 4");
+
+ /*
+ * Create a UNIX domain stream socket, and attach/test/detach a
+ * write filter on it.
+ */
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1)
+ fail(errno, "socketpair", "PF_UNIX, SOCK_STREAM", NULL);
+ OK("socketpair() 3");
+
+ if (fcntl(sv[0], F_SETFL, O_NONBLOCK) != 0)
+ fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");
+ OK("fcntl() 5");
+ if (fcntl(sv[1], F_SETFL, O_NONBLOCK) != 0)
+ fail(errno, "fcntl", "PF_UNIX, SOCK_STREAM", "O_NONBLOCK");
+ OK("fcntl() 6");
+
+ test_evfilt_write(kq, sv, "PF_UNIX, SOCK_STREAM");
+
+ if (close(sv[0]) == -1)
+ fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[0]");
+ OK("close() 5");
+ if (close(sv[1]) == -1)
+ fail(errno, "close", "PF_UNIX/SOCK_STREAM", "sv[1]");
+ OK("close() 6");
+
+ if (close(kq) == -1)
+ fail(errno, "close", "kq", NULL);
+ OK("close() 7");
+
+ return (0);
+}
diff --git a/tools/tools/nanobsd/Customize/NET4801 b/tools/tools/nanobsd/Customize/NET4801
new file mode 100644
index 0000000000000..8715f7f0d62a1
--- /dev/null
+++ b/tools/tools/nanobsd/Customize/NET4801
@@ -0,0 +1,27 @@
+#! /bin/sh
+#
+# Customize a nanoBSD flash image for Soekris NET4801
+#
+# Copyright (c) 2004 Poul-Henning Kamp
+#
+# See /usr/share/examples/etc/bsd-style-copyright for license terms.
+#
+# $FreeBSD$
+#
+# Usage:
+#
+# ${CUSTOMIZE} ${WD} ${WORLDDIR} ${.CURDIR} [ ${LOCAL_FILES_LIST} ]
+
+
+WD=$1
+WORLDDIR=$2
+CURDIR=$3
+LOCAL_FILES_LIST=$4
+
+# Older NET4801s do not have the necessary wires on the PCB to run DMA
+# mode against the CF card. Disable ata_dma so we can boot.
+
+touch ${WD}/boot/loader.conf
+sed -i "" -e '/hw.ata.ata_dma/d' ${WD}/boot/loader.conf
+echo 'hw.ata.ata_dma="0"' >> ${WD}/boot/loader.conf
+
diff --git a/tools/tools/nanobsd/Customize/default b/tools/tools/nanobsd/Customize/default
new file mode 100644
index 0000000000000..c017f9570e0a5
--- /dev/null
+++ b/tools/tools/nanobsd/Customize/default
@@ -0,0 +1,64 @@
+#! /bin/sh
+#
+# Customize a nanoBSD flash image
+#
+# Copyright (c) 2004 Thomas Quinot
+#
+# See /usr/share/examples/etc/bsd-style-copyright for license terms.
+#
+# $FreeBSD$
+#
+# Usage:
+#
+# ${CUSTOMIZE} ${WD} ${WORLDDIR} ${.CURDIR} [ ${LOCAL_FILES_LIST} ]
+
+WD=$1
+WORLDDIR=$2
+CURDIR=$3
+LOCAL_FILES_LIST=$4
+
+PKG_DBDIR=${WD}/var/db/pkg
+export PKG_DBDIR
+
+add_CURDIR() {
+ case "$1" in
+ /*) echo "$1" ;;
+ *) echo "${CURDIR}/$1" ;;
+ esac
+}
+
+pkg_relocate() {
+ sed -e "1,/^@cwd/s#^@cwd #&${WD}#"
+}
+
+installlocalfiles() {
+ if [ -n "${LOCAL_FILES_LIST}" ]; then
+ while read src dest;
+ do
+ case "x${src}" in
+ x#*|x)
+ ;;
+ x@*)
+ eval "for pkg in `add_CURDIR \"\`echo ${src} | sed 's/^@//'\`\"`;
+ do pkg_add -M \${pkg} | pkg_relocate | pkg_add -S;
+ done"
+ ;;
+ *)
+ dest="${dest:-${src}}"
+ mkdir -p ${WD}/`dirname "${dest}x"`
+ eval cp -fp `add_CURDIR ${src}` "${WD}/${dest}"
+ ;;
+ esac
+ done < ${LOCAL_FILES_LIST}
+ fi
+}
+
+movelocaletc() {
+ if [ ! -d ${WD}/etc/local -a -d ${WD}/usr/local/etc ]; then
+ mv ${WD}/usr/local/etc ${WD}/etc/local
+ ln -s ../../etc/local ${WD}/usr/local/etc
+ fi
+}
+
+installlocalfiles
+movelocaletc
diff --git a/tools/tools/nanobsd/Customize/nobeastie b/tools/tools/nanobsd/Customize/nobeastie
new file mode 100644
index 0000000000000..4e8d1e1b6db49
--- /dev/null
+++ b/tools/tools/nanobsd/Customize/nobeastie
@@ -0,0 +1,25 @@
+#! /bin/sh
+#
+# Customize a nanoBSD flash image to disable the loaders ascii-art beastie
+#
+# Copyright (c) 2004 Poul-Henning Kamp
+#
+# See /usr/share/examples/etc/bsd-style-copyright for license terms.
+#
+# $FreeBSD$
+#
+# Usage:
+#
+# ${CUSTOMIZE} ${WD} ${WORLDDIR} ${.CURDIR} [ ${LOCAL_FILES_LIST} ]
+
+WD=$1
+WORLDDIR=$2
+CURDIR=$3
+LOCAL_FILES_LIST=$4
+
+PKG_DBDIR=${WD}/var/db/pkg
+export PKG_DBDIR
+
+touch ${WD}/boot/loader.conf
+sed -i "" -e '/beastie_disable/d' ${WD}/boot/loader.conf
+echo 'beastie_disable="YES"' >> ${WD}/boot/loader.conf