summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>2000-07-10 19:20:09 +0000
committercvs2svn <cvs2svn@FreeBSD.org>2000-07-10 19:20:09 +0000
commit209a6f5a68b2827a91a4e30803330408299dd4dd (patch)
tree127744ac436b55c0f3c1ef9fa500ca066db4daec
parentf8c4dd457f2274102e0c9f779c4390e8d189089b (diff)
Notes
-rw-r--r--contrib/binutils/FREEBSD-deletelist99
-rw-r--r--etc/defaults/periodic.conf172
-rw-r--r--include/ifaddrs.h56
-rw-r--r--include/search.h56
-rw-r--r--lib/libc/net/getifaddrs.3163
-rw-r--r--lib/libc/net/getifaddrs.c379
-rw-r--r--lib/libipsec/libpfkey.h77
-rw-r--r--libexec/rtld-elf/alpha/lockdflt.c158
-rw-r--r--libexec/rtld-elf/i386/lockdflt.c253
-rw-r--r--share/man/man5/periodic.conf.5443
-rw-r--r--share/man/man9/accept_filter.9134
-rw-r--r--sys/modules/sound/Makefile7
-rw-r--r--sys/modules/sound/Makefile.inc3
-rw-r--r--sys/modules/sound/driver/Makefile.inc3
-rw-r--r--sys/modules/sound/driver/ad1816/Makefile8
-rw-r--r--sys/modules/sound/driver/csa/Makefile8
-rw-r--r--sys/modules/sound/driver/csapcm/Makefile8
-rw-r--r--sys/modules/sound/driver/ds1/Makefile8
-rw-r--r--sys/modules/sound/driver/emu10k1/Makefile8
-rw-r--r--sys/modules/sound/driver/es137x/Makefile8
-rw-r--r--sys/modules/sound/driver/es1888/Makefile8
-rw-r--r--sys/modules/sound/driver/ess/Makefile8
-rw-r--r--sys/modules/sound/driver/gusc/Makefile8
-rw-r--r--sys/modules/sound/driver/mss/Makefile8
-rw-r--r--sys/modules/sound/driver/neomagic/Makefile8
-rw-r--r--sys/modules/sound/driver/sb/Makefile8
-rw-r--r--sys/modules/sound/driver/sbc/Makefile8
-rw-r--r--sys/modules/sound/driver/t4dwave/Makefile8
-rw-r--r--sys/net/if_stf.c662
-rw-r--r--sys/net/if_stf.h38
-rw-r--r--sys/netgraph/ng_ether.c639
-rw-r--r--sys/netinet/ip_encap.c534
-rw-r--r--sys/netinet/ip_encap.h64
-rw-r--r--sys/netinet6/README81
-rw-r--r--sys/netinet6/in6_src.c550
-rw-r--r--sys/netinet6/ipcomp.h67
-rw-r--r--sys/netinet6/ipcomp6.h46
-rw-r--r--sys/netinet6/ipcomp_core.c314
-rw-r--r--sys/netinet6/ipcomp_input.c407
-rw-r--r--sys/netinet6/ipcomp_output.c430
-rw-r--r--sys/netinet6/scope6.c302
-rw-r--r--sys/netinet6/scope6_var.h46
-rw-r--r--sys/netinet6/udp6_output.c285
-rw-r--r--sys/netkey/keydb.c217
-rw-r--r--usr.bin/kenv/Makefile5
-rw-r--r--usr.bin/kenv/kenv.150
-rw-r--r--usr.bin/kenv/kenv.c131
-rw-r--r--usr.bin/netstat/ipsec.c316
-rw-r--r--usr.sbin/mld6query/Makefile22
-rw-r--r--usr.sbin/mld6query/mld6.c267
-rw-r--r--usr.sbin/mld6query/mld6query.887
-rw-r--r--usr.sbin/rtadvd/dump.c215
-rw-r--r--usr.sbin/rtadvd/dump.h34
53 files changed, 7924 insertions, 0 deletions
diff --git a/contrib/binutils/FREEBSD-deletelist b/contrib/binutils/FREEBSD-deletelist
new file mode 100644
index 0000000000000..d2e09d375c1fd
--- /dev/null
+++ b/contrib/binutils/FREEBSD-deletelist
@@ -0,0 +1,99 @@
+$FreeBSD$
+CVS
+testsuite
+.cvsignore
+config.if
+mkdep
+*COPYING*
+etc
+*-hp*
+*-macos*
+*-ncr*
+*.bat
+*.com
+*.info*
+arlex.c
+arparse.[ch]
+deflex.c
+gprof
+itbl-lex.c
+itbl-parse.[ch]
+ldgram.[ch]
+ldlex.c
+sysinfo.[ch]
+syslex.c
+testsuite
+texinfo
+*10[23]00*
+*532*
+*[a-z]29k*
+*[a-z][89]60*
+*_be*
+*a68*
+*adobe*
+*aix*
+*apollo*
+*beos*
+*bout*
+*cisco*
+*d10v*
+*delt88*
+*delta*
+*dgux*
+*djgpp*
+*dos*
+*dpx2*
+*dynix*
+*epoc*
+*go32*
+*h8[35]00*
+*hp300*
+*hp[-.]*
+*hppa*
+*hpux*
+*interix*
+*irix*
+*lynx*
+*m32r*
+*m[68]8k*
+*mac-*
+*mach*
+*mcore*
+*mpw*
+*netware*
+*news*
+*nlm*
+*ns32*
+*oasys*
+*os9*
+*pei*
+*pmac*
+*psos*
+*pyr*
+*riscix*
+*riscos*
+*rs6000*
+*sa29200*
+*shpe*
+*som*
+*st2000*
+*sun*
+*symmetry*
+*tahoe*
+*u68k*
+*vax*
+*vms*
+*vxworks*
+*w65*
+*we32k*
+*win*
+*xcoff*
+*i370*
+*avr*
+*tic54x*
+*tic80*
+*d30v*
+*fr30*
+*-sh.*
+*pj*
+*ver.texi
diff --git a/etc/defaults/periodic.conf b/etc/defaults/periodic.conf
new file mode 100644
index 0000000000000..2ad0e504cc61b
--- /dev/null
+++ b/etc/defaults/periodic.conf
@@ -0,0 +1,172 @@
+#!/bin/sh
+#
+# This is defaults/periodic.conf - a file full of useful variables that
+# you can set to change the default behaviour of periodic jobs on your
+# system. You should not edit this file! Put any overrides into one of the
+# $periodic_conf_files instead and you will be able to update these defaults
+# later without spamming your local configuration information.
+#
+# The $periodic_conf_files files should only contain values which override
+# values set in this file. This eases the upgrade path when defaults
+# are changed and new features are added.
+#
+# $FreeBSD$
+#
+
+# What files override these defaults ?
+periodic_conf_files="/etc/periodic.conf /etc/periodic.conf.local"
+
+# periodic script dirs
+local_periodic="/usr/local/etc/periodic /usr/X11R6/etc/periodic"
+
+
+# Daily options
+
+# 100.clean-disks
+daily_clean_disks_enable="NO" # Delete files daily
+daily_clean_disks_files="[#,]* .#* a.out *.core *.CKP .emacs_[0-9]*"
+daily_clean_disks_days=3 # If older than this
+daily_clean_disks_verbose="YES" # Mention files deleted
+
+# 110.clean-tmps
+daily_clean_tmps_enable="NO" # Delete stuff daily
+daily_clean_tmps_dirs="/tmp" # Delete under here
+daily_clean_tmps_days="3" # If not accessed for
+daily_clean_tmps_ignore=".X*-lock quota.user quota.group" # Don't delete these
+daily_clean_tmps_verbose="YES" # Mention files deleted
+
+# 120.clean-preserve
+daily_clean_preserve_enable="YES" # Delete files daily
+daily_clean_preserve_days=7 # If not modified for
+daily_clean_preserve_verbose="YES" # Mention files deleted
+
+# 130.clean-msgs
+daily_clean_msgs_enable="YES" # Delete msgs daily
+daily_clean_msgs_days= # If not modified for
+
+# 140.clean-rwho
+daily_clean_rwho_enable="YES" # Delete rwho daily
+daily_clean_rwho_days=7 # If not modified for
+daily_clean_rwho_verbose="YES" # Mention files deleted
+
+# 150.clean-hoststat
+daily_clean_hoststat_enable="YES" # Delete .hoststat daily
+daily_clean_hoststat_days=3 # If not modified for
+daily_clean_hoststat_verbose="YES" # Mention files deleted
+
+# 200.backup-passwd
+daily_backup_passwd_enable="YES" # Backup passwd & group
+
+# 210.backup-aliases
+daily_backup_aliases_enable="YES" # Backup mail aliases
+
+# 220.backup-distfile
+daily_backup_distfile_enable="YES" # Backup distfile
+
+# 300.calendar
+daily_calendar_enable="NO" # Run calendar -a
+
+# 310.accounting
+daily_accounting_enable="YES" # Rotate acct files
+daily_accounting_compress="NO" # Gzip rotated files
+
+# 320.distfile
+daily_distfile_enable="YES" # Run rdist daily
+
+# 330.news
+daily_news_expire_enable="YES" # Run news.expire
+
+# 340.uucp
+daily_uuclean_enable="YES" # Run uuclean.daily
+
+# 400.status-disks
+daily_status_disks_enable="YES" # Check disk status
+daily_status_disks_df_flags="-k -t nonfs" # df(1) flags for check
+
+# 410.status-uucp
+daily_status_uucp_enable="YES" # Check uucp status
+
+# 420.status-network
+daily_status_network_enable="YES" # Check network status
+daily_status_network_usedns="YES" # DNS lookups are ok
+
+# 430.status-rwho
+daily_status_rwho_enable="YES" # Check system status
+
+# 440.status-mailq
+daily_status_mailq_enable="YES" # Check mail status
+daily_status_mailq_shorten="NO" # Shorten output
+
+# 450.status-security
+daily_status_security_enable="YES" # Security check
+daily_status_security_inline="NO" # Run inline ?
+daily_status_security_noamd="NO" # Don't check amd mounts
+daily_status_security_nomfs="NO" # Don't check mfs mounts
+
+# 460.status-mail-rejects
+daily_status_mail_rejects_enable="YES" # Check mail rejects
+daily_status_mail_rejects_logs=3 # How many logs to check
+
+# 999.local
+daily_local="/etc/daily.local" # Local scripts
+
+
+# Weekly options
+
+# 120.clean-kvmdb
+weekly_clean_kvmdb_enable="YES" # Clean kvmdb weekly
+weekly_clean_kvmdb_days=7 # If not accessed for
+weekly_clean_kvmdb_verbose="YES" # Mention files deleted
+
+# 300.uucp
+weekly_uucp_enable="YES" # Clean uucp weekly
+
+# 310.locate
+weekly_locate_enable="YES" # Update locate weekly
+
+# 320.whatis
+weekly_whatis_enable="YES" # Update whatis weekly
+
+# 330.catman
+weekly_catman_enable="NO" # Preformat man pages
+
+# 340.noid
+weekly_noid_enable="NO" # Find unowned files
+weekly_noid_dirs="/" # Look here
+
+# 400.status-pkg
+weekly_status_pkg_enable="NO" # Find out-of-date pkgs
+
+# 999.local
+weekly_local="/etc/weekly.local" # Local scripts
+
+
+# Monthly options
+
+# 200.accounting
+monthly_accounting_enable="YES" # Login accounting
+
+# 999.local
+monthly_local="/etc/monthly.local" # Local scripts
+
+
+# Define source_periodic_confs, the mechanism used by /etc/periodic/*/*
+# scripts to source defaults/periodic.conf overrides safely.
+
+if [ -z "${source_periodic_confs_defined}" ]; then
+ source_periodic_confs_defined=yes
+ source_periodic_confs () {
+ local i sourced_files
+
+ for i in ${periodic_conf_files}; do
+ case ${sourced_files} in
+ *:$i:*)
+ ;;
+ *)
+ sourced_files="${sourced_files}:$i:"
+ [ -r $i ] && . $i
+ ;;
+ esac
+ done
+ }
+fi
diff --git a/include/ifaddrs.h b/include/ifaddrs.h
new file mode 100644
index 0000000000000..6ebf288c2733a
--- /dev/null
+++ b/include/ifaddrs.h
@@ -0,0 +1,56 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 1995, 1999
+ * Berkeley Software Design, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
+ *
+ * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
+ */
+
+#ifndef _IFADDRS_H_
+#define _IFADDRS_H_
+
+struct ifaddrs {
+ struct ifaddrs *ifa_next;
+ char *ifa_name;
+ u_int ifa_flags;
+ struct sockaddr *ifa_addr;
+ struct sockaddr *ifa_netmask;
+ struct sockaddr *ifa_dstaddr;
+ void *ifa_data;
+};
+
+/*
+ * This may have been defined in <net/if.h>. Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
+#endif
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int getifaddrs __P((struct ifaddrs **));
+extern void freeifaddrs __P((struct ifaddrs *));
+__END_DECLS
+
+#endif
diff --git a/include/search.h b/include/search.h
new file mode 100644
index 0000000000000..370654a446d79
--- /dev/null
+++ b/include/search.h
@@ -0,0 +1,56 @@
+/* $NetBSD: search.h,v 1.12 1999/02/22 10:34:28 christos Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Written by J.T. Conklin <jtc@netbsd.org>
+ * Public domain.
+ */
+
+#ifndef _SEARCH_H_
+#define _SEARCH_H_
+
+#include <sys/cdefs.h>
+#include <machine/ansi.h>
+
+#ifdef _BSD_SIZE_T_
+typedef _BSD_SIZE_T_ size_t;
+#undef _BSD_SIZE_T_
+#endif
+
+typedef struct entry {
+ char *key;
+ void *data;
+} ENTRY;
+
+typedef enum {
+ FIND, ENTER
+} ACTION;
+
+typedef enum {
+ preorder,
+ postorder,
+ endorder,
+ leaf
+} VISIT;
+
+#ifdef _SEARCH_PRIVATE
+typedef struct node {
+ char *key;
+ struct node *llink, *rlink;
+} node_t;
+#endif
+
+__BEGIN_DECLS
+int hcreate __P((size_t));
+void hdestroy __P((void));
+ENTRY *hsearch __P((ENTRY, ACTION));
+void *tdelete __P((const void *, void **,
+ int (*)(const void *, const void *)));
+void *tfind __P((const void *, void **,
+ int (*)(const void *, const void *)));
+void *tsearch __P((const void *, void **,
+ int (*)(const void *, const void *)));
+void twalk __P((const void *, void (*)(const void *, VISIT, int)));
+__END_DECLS
+
+#endif /* !_SEARCH_H_ */
diff --git a/lib/libc/net/getifaddrs.3 b/lib/libc/net/getifaddrs.3
new file mode 100644
index 0000000000000..f2fa749029608
--- /dev/null
+++ b/lib/libc/net/getifaddrs.3
@@ -0,0 +1,163 @@
+.\" $FreeBSD$
+.\" $KAME: getifaddrs.3,v 1.4 2000/05/17 14:13:14 itojun Exp $
+.\" BSDI getifaddrs.3,v 2.5 2000/02/23 14:51:59 dab Exp
+.\"
+.\" Copyright (c) 1995, 1999
+.\" Berkeley Software Design, 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
+.Dd "October 12, 1995"
+.Dt GETIFADDRS 3
+.Sh NAME
+.Nm getifaddrs
+.Nd get interface addresses
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <ifaddrs.h>
+.Ft int
+.Fn getifaddrs "struct ifaddrs **ifap"
+.Ft void
+.Fn freeifaddrs "struct ifaddrs *ifp"
+.Sh DESCRIPTION
+The
+.Fn getifaddrs
+function stores a reference to a linked list of the network interfaces
+on the local machine in the memory referenced by
+.Fa ifap .
+The list consists of
+.Nm ifaddrs
+structures, as defined in the include file
+.Aq Pa ifaddrs.h .
+The
+.Nm ifaddrs
+structure contains at least the following entries:
+.Bd -literal
+ struct ifaddrs *ifa_next; /* Pointer to next struct */
+ char *ifa_name; /* Interface name */
+ u_int ifa_flags; /* Interface flags */
+ struct sockaddr *ifa_addr; /* Interface address */
+ struct sockaddr *ifa_netmask; /* Interface netmask */
+ struct sockaddr *ifa_broadaddr; /* Interface broadcast address */
+ struct sockaddr *ifa_dstaddr; /* P2P interface destination */
+ void *ifa_data; /* Address specific data */
+.Ed
+.Pp
+The
+.Li ifa_next
+field contains a pointer to the next structure on the list.
+This field is
+.Dv NULL
+in last structure on the list.
+.Pp
+The
+.Li ifa_name
+field contains the interface name.
+.Pp
+The
+.Li ifa_flags
+field contains the interface flags, as set by
+.Xr ifconfig 8
+utility.
+.Pp
+The
+.Li ifa_addr
+field references either the address of the interface or the link level
+address of the interface, if one exists, otherwise it is NULL.
+(The
+.Li sa_family
+field of the
+.Li ifa_addr
+field should be consulted to determine the format of the
+.Li ifa_addr
+address.)
+.Pp
+The
+.Li ifa_netmask
+field references the netmask associated with
+.Li ifa_addr ,
+if one is set, otherwise it is NULL.
+.Pp
+The
+.Li ifa_broadaddr
+field,
+which should only be referenced for non-P2P interfaces,
+references the broadcast address associated with
+.Li ifa_addr ,
+if one exists, otherwise it is NULL.
+.Pp
+The
+.Li ifa_dstaddr
+field references the destination address on a P2P interface,
+if one exists, otherwise it is NULL.
+.Pp
+The
+.Li ifa_data
+field references address family specific data. For
+.Dv AF_LINK
+addresses it contains a pointer to the
+.Fa struct if_data
+.Pq as defined in include file Aq Pa net/if.h
+which contains various interface attributes and statistics.
+For all other address families, it contains a pointer to the
+.Fa struct ifa_data
+.Pq as defined in include file Aq Pa net/if.h
+which contains per-address interface statistics.
+.Pp
+The data returned by
+.Fn getifaddrs
+is dynamically allocated and should be freed using
+.Fn freeifaddrs
+when no longer needed.
+.Sh RETURN VALUES
+Upon successful completion, a value of 0 is returned.
+Otherwise, a value of -1 is returned and
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+The
+.Fn getifaddrs
+may fail and set
+.Va errno
+for any of the errors specified for the library routines
+.Xr ioctl 2 ,
+.Xr socket 2 ,
+.Xr malloc 3
+or
+.Xr sysctl 3 .
+.Sh BUGS
+If both
+.Aq Pa net/if.h
+and
+.Aq Pa ifaddrs.h
+are being included,
+.Aq Pa net/if.h
+.Em must
+be included before
+.Aq Pa ifaddrs.h .
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr socket 2 ,
+.Xr sysctl 3 ,
+.Xr networking 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+implementation first appeared in BSDI BSD/OS.
diff --git a/lib/libc/net/getifaddrs.c b/lib/libc/net/getifaddrs.c
new file mode 100644
index 0000000000000..573aadad189b7
--- /dev/null
+++ b/lib/libc/net/getifaddrs.c
@@ -0,0 +1,379 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 1995, 1999
+ * Berkeley Software Design, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
+ *
+ * BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
+ */
+/*
+ * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
+ * try-and-error for region size.
+ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#ifdef NET_RT_IFLIST
+#include <sys/param.h>
+#include <net/route.h>
+#include <sys/sysctl.h>
+#include <net/if_dl.h>
+#endif
+
+#include <errno.h>
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(AF_LINK)
+#define SA_LEN(sa) sizeof(struct sockaddr)
+#endif
+
+#if !defined(SA_LEN)
+#define SA_LEN(sa) (sa)->sa_len
+#endif
+
+#define SALIGN (sizeof(long) - 1)
+#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
+
+#ifndef ALIGNBYTES
+/*
+ * On systems with a routing socket, ALIGNBYTES should match the value
+ * that the kernel uses when building the messages.
+ */
+#define ALIGNBYTES XXX
+#endif
+#ifndef ALIGN
+#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+#endif
+
+#if _BSDI_VERSION >= 199701
+#define HAVE_IFM_DATA
+#endif
+
+#if _BSDI_VERSION >= 199802
+#define HAVE_IFAM_DATA
+#endif
+
+int
+getifaddrs(struct ifaddrs **pif)
+{
+ int icnt = 1;
+ int dcnt = 0;
+ int ncnt = 0;
+#ifdef NET_RT_IFLIST
+ int mib[6];
+ size_t needed;
+ char *buf;
+ char *next;
+ struct ifaddrs *cif = 0;
+ char *p, *p0;
+ struct rt_msghdr *rtm;
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr_dl *dl;
+ struct sockaddr *sa;
+ struct ifaddrs *ifa, *ift;
+ u_short index = 0;
+#else /* NET_RT_IFLIST */
+ char buf[1024];
+ int m, sock;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct ifreq *lifr;
+#endif /* NET_RT_IFLIST */
+ int i;
+ size_t len, alen;
+ char *data;
+ char *names;
+
+#ifdef NET_RT_IFLIST
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ return (-1);
+ if ((buf = malloc(needed)) == NULL)
+ return (-1);
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ free(buf);
+ return (-1);
+ }
+
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+ switch (rtm->rtm_type) {
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *)rtm;
+ if (ifm->ifm_addrs & RTA_IFP) {
+ index = ifm->ifm_index;
+ ++icnt;
+ dl = (struct sockaddr_dl *)(ifm + 1);
+ dcnt += SA_RLEN((struct sockaddr *)dl) +
+ ALIGNBYTES;
+#ifdef HAVE_IFM_DATA
+ dcnt += sizeof(ifm->ifm_data);
+#endif /* HAVE_IFM_DATA */
+ ncnt += dl->sdl_nlen + 1;
+ } else
+ index = 0;
+ break;
+
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+ if (index && ifam->ifam_index != index)
+ abort(); /* this cannot happen */
+
+#define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
+ if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
+ break;
+ p = (char *)(ifam + 1);
+ ++icnt;
+#ifdef HAVE_IFAM_DATA
+ dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES;
+#endif /* HAVE_IFAM_DATA */
+ /* Scan to look for length of address */
+ alen = 0;
+ for (p0 = p, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)p;
+ len = SA_RLEN(sa);
+ if (i == RTAX_IFA) {
+ alen = len;
+ break;
+ }
+ p += len;
+ }
+ for (p = p0, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)p;
+ len = SA_RLEN(sa);
+ if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
+ dcnt += alen;
+ else
+ dcnt += len;
+ p += len;
+ }
+ break;
+ }
+ }
+#else /* NET_RT_IFLIST */
+ ifc.ifc_buf = buf;
+ ifc.ifc_len = sizeof(buf);
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ return (-1);
+ i = ioctl(sock, SIOCGIFCONF, (char *)&ifc);
+ close(sock);
+ if (i < 0)
+ return (-1);
+
+ ifr = ifc.ifc_req;
+ lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
+
+ while (ifr < lifr) {
+ struct sockaddr *sa;
+
+ sa = &ifr->ifr_addr;
+ ++icnt;
+ dcnt += SA_RLEN(sa);
+ ncnt += sizeof(ifr->ifr_name) + 1;
+
+ ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
+ }
+#endif /* NET_RT_IFLIST */
+
+ if (icnt + dcnt + ncnt == 1) {
+ *pif = NULL;
+ free(buf);
+ return (0);
+ }
+ data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
+ if (data == NULL) {
+ free(buf);
+ return(-1);
+ }
+
+ ifa = (struct ifaddrs *)data;
+ data += sizeof(struct ifaddrs) * icnt;
+ names = data + dcnt;
+
+ memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
+ ift = ifa;
+
+#ifdef NET_RT_IFLIST
+ index = 0;
+ for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ if (rtm->rtm_version != RTM_VERSION)
+ continue;
+ switch (rtm->rtm_type) {
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *)rtm;
+ if (ifm->ifm_addrs & RTA_IFP) {
+ index = ifm->ifm_index;
+ dl = (struct sockaddr_dl *)(ifm + 1);
+
+ cif = ift;
+ ift->ifa_name = names;
+ ift->ifa_flags = (int)ifm->ifm_flags;
+ memcpy(names, dl->sdl_data, dl->sdl_nlen);
+ names[dl->sdl_nlen] = 0;
+ names += dl->sdl_nlen + 1;
+
+ ift->ifa_addr = (struct sockaddr *)data;
+ memcpy(data, dl, SA_LEN((struct sockaddr *)dl));
+ data += SA_RLEN((struct sockaddr *)dl);
+
+#ifdef HAVE_IFM_DATA
+ /* ifm_data needs to be aligned */
+ ift->ifa_data = data = (void *)ALIGN(data);
+ memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data));
+ data += sizeof(ifm->ifm_data);
+#else /* HAVE_IFM_DATA */
+ ift->ifa_data = NULL;
+#endif /* HAVE_IFM_DATA */
+
+ ift = (ift->ifa_next = ift + 1);
+ } else
+ index = 0;
+ break;
+
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+ if (index && ifam->ifam_index != index)
+ abort(); /* this cannot happen */
+
+ if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
+ break;
+ ift->ifa_name = cif->ifa_name;
+ ift->ifa_flags = cif->ifa_flags;
+ ift->ifa_data = NULL;
+ p = (char *)(ifam + 1);
+ /* Scan to look for length of address */
+ alen = 0;
+ for (p0 = p, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)p;
+ len = SA_RLEN(sa);
+ if (i == RTAX_IFA) {
+ alen = len;
+ break;
+ }
+ p += len;
+ }
+ for (p = p0, i = 0; i < RTAX_MAX; i++) {
+ if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
+ == 0)
+ continue;
+ sa = (struct sockaddr *)p;
+ len = SA_RLEN(sa);
+ switch (i) {
+ case RTAX_IFA:
+ ift->ifa_addr = (struct sockaddr *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_NETMASK:
+ ift->ifa_netmask =
+ (struct sockaddr *)data;
+ if (SA_LEN(sa) == 0) {
+ memset(data, 0, alen);
+ data += alen;
+ break;
+ }
+ memcpy(data, p, len);
+ data += len;
+ break;
+
+ case RTAX_BRD:
+ ift->ifa_broadaddr =
+ (struct sockaddr *)data;
+ memcpy(data, p, len);
+ data += len;
+ break;
+ }
+ p += len;
+ }
+
+#ifdef HAVE_IFAM_DATA
+ /* ifam_data needs to be aligned */
+ ift->ifa_data = data = (void *)ALIGN(data);
+ memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data));
+ data += sizeof(ifam->ifam_data);
+#endif /* HAVE_IFAM_DATA */
+
+ ift = (ift->ifa_next = ift + 1);
+ break;
+ }
+ }
+
+ free(buf);
+#else /* NET_RT_IFLIST */
+ ifr = ifc.ifc_req;
+ lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
+
+ while (ifr < lifr) {
+ struct sockaddr *sa;
+
+ ift->ifa_name = names;
+ names[sizeof(ifr->ifr_name)] = 0;
+ strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name));
+ while (*names++)
+ ;
+
+ ift->ifa_addr = (struct sockaddr *)data;
+ sa = &ifr->ifr_addr;
+ memcpy(data, sa, SA_LEN(sa));
+ data += SA_RLEN(sa);
+
+ ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa));
+ ift = (ift->ifa_next = ift + 1);
+ }
+#endif /* NET_RT_IFLIST */
+ if (--ift >= ifa) {
+ ift->ifa_next = NULL;
+ *pif = ifa;
+ } else {
+ *pif = NULL;
+ free(ifa);
+ }
+ return (0);
+}
+
+void
+freeifaddrs(struct ifaddrs *ifp)
+{
+ free(ifp);
+}
diff --git a/lib/libipsec/libpfkey.h b/lib/libipsec/libpfkey.h
new file mode 100644
index 0000000000000..ad87700a13015
--- /dev/null
+++ b/lib/libipsec/libpfkey.h
@@ -0,0 +1,77 @@
+/* $FreeBSD$ */
+/* $KAME: libpfkey.h,v 1.1 2000/06/08 21:28:32 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+extern void pfkey_sadump __P((struct sadb_msg *));
+extern void pfkey_spdump __P((struct sadb_msg *));
+
+struct sockaddr;
+int ipsec_check_keylen __P((u_int, u_int, u_int));
+u_int pfkey_set_softrate __P((u_int, u_int));
+u_int pfkey_get_softrate __P((u_int));
+int pfkey_send_getspi __P((int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int32_t, u_int32_t));
+int pfkey_send_update __P((int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int,
+ caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+ u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_add __P((int, u_int, u_int, struct sockaddr *,
+ struct sockaddr *, u_int32_t, u_int32_t, u_int,
+ caddr_t, u_int, u_int, u_int, u_int, u_int, u_int32_t, u_int64_t,
+ u_int64_t, u_int64_t, u_int32_t));
+int pfkey_send_delete __P((int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_get __P((int, u_int, u_int,
+ struct sockaddr *, struct sockaddr *, u_int32_t));
+int pfkey_send_register __P((int, u_int));
+int pfkey_recv_register __P((int));
+int pfkey_send_flush __P((int, u_int));
+int pfkey_send_dump __P((int, u_int));
+int pfkey_send_promisc_toggle __P((int, int));
+int pfkey_send_spdadd __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdupdate __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spddelete __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spddelete2 __P((int, u_int32_t));
+int pfkey_send_spdget __P((int, u_int32_t));
+int pfkey_send_spdsetidx __P((int, struct sockaddr *, u_int,
+ struct sockaddr *, u_int, u_int, caddr_t, int, u_int32_t));
+int pfkey_send_spdflush __P((int));
+int pfkey_send_spddump __P((int));
+
+int pfkey_open __P((void));
+void pfkey_close __P((int));
+struct sadb_msg *pfkey_recv __P((int));
+int pfkey_send __P((int, struct sadb_msg *, int));
+int pfkey_align __P((struct sadb_msg *, caddr_t *));
+int pfkey_check __P((caddr_t *));
diff --git a/libexec/rtld-elf/alpha/lockdflt.c b/libexec/rtld-elf/alpha/lockdflt.c
new file mode 100644
index 0000000000000..65900a63dc250
--- /dev/null
+++ b/libexec/rtld-elf/alpha/lockdflt.c
@@ -0,0 +1,158 @@
+/*-
+ * Copyright 1999, 2000 John D. Polstra.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Thread locking implementation for the dynamic linker.
+ *
+ * We use the "simple, non-scalable reader-preference lock" from:
+ *
+ * J. M. Mellor-Crummey and M. L. Scott. "Scalable Reader-Writer
+ * Synchronization for Shared-Memory Multiprocessors." 3rd ACM Symp. on
+ * Principles and Practice of Parallel Programming, April 1991.
+ *
+ * In this algorithm the lock is a single word. Its low-order bit is
+ * set when a writer holds the lock. The remaining high-order bits
+ * contain a count of readers desiring the lock. The algorithm requires
+ * atomic "compare_and_store" and "add" operations, which we implement
+ * using assembly language sequences in "rtld_start.S".
+ *
+ * These are spinlocks. When spinning we call nanosleep() for 1
+ * microsecond each time around the loop. This will most likely yield
+ * the CPU to other threads (including, we hope, the lockholder) allowing
+ * them to make some progress.
+ */
+
+#include <stdlib.h>
+#include <time.h>
+
+#include "debug.h"
+#include "rtld.h"
+
+/*
+ * This value of CACHE_LINE_SIZE is conservative. The actual size
+ * is 32 on the 21064, 21064A, 21066, 21066A, and 21164. It is 64
+ * on the 21264. Compaq recommends sequestering each lock in its own
+ * 128-byte block to allow for future implementations with larger
+ * cache lines.
+ */
+#define CACHE_LINE_SIZE 128
+
+#define WAFLAG 0x1 /* A writer holds the lock */
+#define RC_INCR 0x2 /* Adjusts count of readers desiring lock */
+
+typedef struct Struct_Lock {
+ volatile int lock;
+ void *base;
+} Lock;
+
+static const struct timespec usec = { 0, 1000 }; /* 1 usec. */
+
+static void *
+lock_create(void *context)
+{
+ void *base;
+ char *p;
+ uintptr_t r;
+ Lock *l;
+
+ /*
+ * Arrange for the lock to occupy its own cache line. First, we
+ * optimistically allocate just a cache line, hoping that malloc
+ * will give us a well-aligned block of memory. If that doesn't
+ * work, we allocate a larger block and take a well-aligned cache
+ * line from it.
+ */
+ base = xmalloc(CACHE_LINE_SIZE);
+ p = (char *)base;
+ if ((uintptr_t)p % CACHE_LINE_SIZE != 0) {
+ free(base);
+ base = xmalloc(2 * CACHE_LINE_SIZE);
+ p = (char *)base;
+ if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0)
+ p += CACHE_LINE_SIZE - r;
+ }
+ l = (Lock *)p;
+ l->base = base;
+ l->lock = 0;
+ return l;
+}
+
+static void
+lock_destroy(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ free(l->base);
+}
+
+static void
+rlock_acquire(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ atomic_add_int(&l->lock, RC_INCR);
+ while (l->lock & WAFLAG)
+ nanosleep(&usec, NULL);
+}
+
+static void
+wlock_acquire(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ while (cmp0_and_store_int(&l->lock, WAFLAG) != 0)
+ nanosleep(&usec, NULL);
+}
+
+static void
+rlock_release(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ atomic_add_int(&l->lock, -RC_INCR);
+}
+
+static void
+wlock_release(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ atomic_add_int(&l->lock, -WAFLAG);
+}
+
+void
+lockdflt_init(LockInfo *li)
+{
+ li->context = NULL;
+ li->lock_create = lock_create;
+ li->rlock_acquire = rlock_acquire;
+ li->wlock_acquire = wlock_acquire;
+ li->rlock_release = rlock_release;
+ li->wlock_release = wlock_release;
+ li->lock_destroy = lock_destroy;
+ li->context_destroy = NULL;
+}
diff --git a/libexec/rtld-elf/i386/lockdflt.c b/libexec/rtld-elf/i386/lockdflt.c
new file mode 100644
index 0000000000000..b2ca9a5005ebb
--- /dev/null
+++ b/libexec/rtld-elf/i386/lockdflt.c
@@ -0,0 +1,253 @@
+/*-
+ * Copyright 1999, 2000 John D. Polstra.
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Thread locking implementation for the dynamic linker.
+ *
+ * On 80486 and later CPUs we use the "simple, non-scalable
+ * reader-preference lock" from:
+ *
+ * J. M. Mellor-Crummey and M. L. Scott. "Scalable Reader-Writer
+ * Synchronization for Shared-Memory Multiprocessors." 3rd ACM Symp. on
+ * Principles and Practice of Parallel Programming, April 1991.
+ *
+ * In this algorithm the lock is a single word. Its low-order bit is
+ * set when a writer holds the lock. The remaining high-order bits
+ * contain a count of readers desiring the lock. The algorithm requires
+ * atomic "compare_and_store" and "add" operations.
+ *
+ * The "compare_and_store" operation requires the "cmpxchg" instruction
+ * on the x86. Unfortunately, the 80386 CPU does not support that
+ * instruction -- only the 80486 and later models support it. So on the
+ * 80386 we must use simple test-and-set exclusive locks instead. We
+ * determine which kind of lock to use by trying to execute a "cmpxchg"
+ * instruction and catching the SIGILL which results on the 80386.
+ *
+ * These are spinlocks. When spinning we call nanosleep() for 1
+ * microsecond each time around the loop. This will most likely yield
+ * the CPU to other threads (including, we hope, the lockholder) allowing
+ * them to make some progress.
+ */
+
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "debug.h"
+#include "rtld.h"
+
+#define CACHE_LINE_SIZE 32
+
+#define WAFLAG 0x1 /* A writer holds the lock */
+#define RC_INCR 0x2 /* Adjusts count of readers desiring lock */
+
+typedef struct Struct_Lock {
+ volatile int lock;
+ void *base;
+} Lock;
+
+static const struct timespec usec = { 0, 1000 }; /* 1 usec. */
+
+static inline int
+cmpxchgl(int old, int new, volatile int *m)
+{
+ int result;
+
+ __asm __volatile ("lock; cmpxchgl %2, %0"
+ : "=m"(*m), "=a"(result)
+ : "r"(new), "0"(*m), "1"(old)
+ : "cc");
+
+ return result;
+}
+
+static inline int
+xchgl(int v, volatile int *m)
+{
+ int result;
+
+ __asm __volatile ("xchgl %0, %1"
+ : "=r"(result), "=m"(*m)
+ : "0"(v), "1"(*m));
+
+ return result;
+}
+
+static void *
+lock_create(void *context)
+{
+ void *base;
+ char *p;
+ uintptr_t r;
+ Lock *l;
+
+ /*
+ * Arrange for the lock to occupy its own cache line. First, we
+ * optimistically allocate just a cache line, hoping that malloc
+ * will give us a well-aligned block of memory. If that doesn't
+ * work, we allocate a larger block and take a well-aligned cache
+ * line from it.
+ */
+ base = xmalloc(CACHE_LINE_SIZE);
+ p = (char *)base;
+ if ((uintptr_t)p % CACHE_LINE_SIZE != 0) {
+ free(base);
+ base = xmalloc(2 * CACHE_LINE_SIZE);
+ p = (char *)base;
+ if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0)
+ p += CACHE_LINE_SIZE - r;
+ }
+ l = (Lock *)p;
+ l->base = base;
+ l->lock = 0;
+ return l;
+}
+
+static void
+lock_destroy(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ free(l->base);
+}
+
+/*
+ * Crude exclusive locks for the 80386, which does not support the
+ * cmpxchg instruction.
+ */
+static void
+lock80386_acquire(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ while (xchgl(1, &l->lock) != 0)
+ while (l->lock != 0)
+ nanosleep(&usec, NULL);
+}
+
+static void
+lock80386_release(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ l->lock = 0;
+}
+
+/*
+ * Better reader/writer locks for the 80486 and later CPUs.
+ */
+static void
+rlock_acquire(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ atomic_add_int(&l->lock, RC_INCR);
+ while (l->lock & WAFLAG)
+ nanosleep(&usec, NULL);
+}
+
+static void
+wlock_acquire(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ while (cmpxchgl(0, WAFLAG, &l->lock) != 0)
+ nanosleep(&usec, NULL);
+}
+
+static void
+rlock_release(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ atomic_add_int(&l->lock, -RC_INCR);
+}
+
+static void
+wlock_release(void *lock)
+{
+ Lock *l = (Lock *)lock;
+
+ atomic_add_int(&l->lock, -WAFLAG);
+}
+
+/*
+ * Code to determine at runtime whether the CPU supports the cmpxchg
+ * instruction. This instruction allows us to use locks that are more
+ * efficient, but it didn't exist on the 80386.
+ */
+static jmp_buf sigill_env;
+
+static void
+sigill(int sig)
+{
+ longjmp(sigill_env, 1);
+}
+
+static int
+cpu_supports_cmpxchg(void)
+{
+ struct sigaction act, oact;
+ int result;
+ volatile int lock;
+
+ memset(&act, 0, sizeof act);
+ act.sa_handler = sigill;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ sigaction(SIGILL, &act, &oact);
+ if (setjmp(sigill_env) == 0) {
+ lock = 0;
+ cmpxchgl(0, 1, &lock);
+ result = 1;
+ } else
+ result = 0;
+ sigaction(SIGILL, &oact, NULL);
+ return result;
+}
+
+void
+lockdflt_init(LockInfo *li)
+{
+ li->context = NULL;
+ li->context_destroy = NULL;
+ li->lock_create = lock_create;
+ li->lock_destroy = lock_destroy;
+ if (cpu_supports_cmpxchg()) {
+ /* Use fast locks that require an 80486 or later. */
+ li->rlock_acquire = rlock_acquire;
+ li->wlock_acquire = wlock_acquire;
+ li->rlock_release = rlock_release;
+ li->wlock_release = wlock_release;
+ } else {
+ /* It's a cruddy old 80386. */
+ li->rlock_acquire = li->wlock_acquire = lock80386_acquire;
+ li->rlock_release = li->wlock_release = lock80386_release;
+ }
+}
diff --git a/share/man/man5/periodic.conf.5 b/share/man/man5/periodic.conf.5
new file mode 100644
index 0000000000000..3acce7892e1d1
--- /dev/null
+++ b/share/man/man5/periodic.conf.5
@@ -0,0 +1,443 @@
+.\"-
+.\" Copyright (c) 2000 Brian Somers <brian@Awfulhak.org>
+.\" 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 June 22, 2000
+.Dt PERIODIC.CONF 5
+.Os FreeBSD 5.0
+.Sh NAME
+.Nm periodic.conf
+.Nd periodic job configuration information.
+.Sh DESCRIPTION
+The file
+.Nm periodic.conf
+contains a description of how daily, weekly and montly system maintenance
+jobs should run.
+It resides in the
+.Pa /etc/defaults
+directory and parts may be overridden by a file of the same name in
+.Pa /etc ,
+which itself may be overridden by the
+.Pa /etc/periodic.conf.local
+file.
+.Pp
+.Nm
+is actually sourced as a shell script from each of the periodic scripts
+and is intended to simply provide default configuration variables.
+.Pp
+The following list provides a name and short description for each
+variable you can set in the
+.Nm
+file.
+.Bl -tag -offset 4n -width 2n
+.It Ar local_periodic
+(str) List of directories to search for periodic scripts.
+.El
+.B Daily variables
+.Pp
+The following variables are used by the standard scripts that reside in
+.Pa /etc/periodic/daily :
+.Bl -tag -offset 4n -width 2n
+.It Ar daily_clean_disks_enable
+(bool) Set to
+.Dq YES
+if you want to remove all files matching
+.Ar daily_clean_disks_files
+daily.
+.It Ar daily_clean_disks_files
+(str) Set to a list of file names to match.
+Wild cards are permitted.
+.It Ar daily_clean_disks_days
+(int) When
+.Ar daily_clean_disks_enable
+is set to
+.Dq YES ,
+this must also be set to the number of days old that a file's access
+and modification times must be before it's deleted.
+.It Ar daily_clean_disks_verbose
+(bool) Set to
+.Dq YES
+if you want the removed files to be reported in your daily output.
+.It Ar daily_clean_tmps_enable
+(bool) Set to
+.Dq YES
+if you want to clear temporary directories daily.
+.It Ar daily_clean_tmps_dirs
+(str) Set to the list of directories to clear if
+.Ar daily_clean_tmps_enable
+is set to
+.Dq YES .
+.It Ar daily_clean_tmps_days
+(int) When
+.Ar daily_clean_tmps_enable
+is set, this must also be set to the number of days old that a file's access
+and modification times must be before it's deleted.
+.It Ar daily_clean_tmps_ignore
+(str) Set to the list of files that should not be deleted when
+.Ar daily_clean_tmps_enable
+is set to
+.Dq YES .
+Wild card characters are permitted.
+.It Ar daily_clean_tmps_verbose
+(bool) Set to
+.Dq YES
+if you want the removed files to be reported in your daily output.
+.It Ar daily_clean_preserve_enable
+(bool) Set to
+.Dq YES
+if you wish to remove old files from
+.Pa /var/preserve .
+.It Ar daily_clean_preserve_days
+(num) Set to the number of days that files must not have been modified before
+they are deleted.
+.It Ar daily_clean_preserve_verbose
+(bool) Set to
+.Dq YES
+if you want the removed files to be reported in your daily output.
+.It Ar daily_clean_msgs_enable
+(bool) Set to
+.Dq YES
+if you old system messages to be purged.
+.It Ar daily_clean_msgs_days
+(num) Set to the number of days that files must not have been modified before
+they are deleted.
+If this variable is left blank, the
+.Xr msgs 1
+default is used.
+.It Ar daily_clean_rwho_enable
+(bool) Set to
+.Dq YES
+if you wish old files in
+.Pa /var/who
+to be purged.
+.It Ar daily_clean_rwho_days
+(num) Set to the number of days that files must not have been modified before
+they are deleted.
+.It Ar daily_clean_rwho_verbose
+(bool) Set to
+.Dq YES
+if you want the removed files to be reported in your daily output.
+.It Ar daily_clean_hoststat_enable
+(bool) Set to
+.Dq YES
+if you wish old files in
+.Pa /var/spool/.hoststat
+to be purged.
+.It Ar daily_clean_hoststat_days
+(num) Set to the number of days that files must not have been modified before
+they are deleted.
+.It Ar daily_clean_hoststat_verbose
+(bool) Set to
+.Dq YES
+if you want the removed files to be reported in your daily output.
+.It Ar daily_backup_passwd_enable
+(bool) Set to
+.Dq YES
+if you want the
+.Pa /etc/master.passwd
+and
+.Pa /etc/group
+files backed up and reported on.
+Reporting consists of checking both files for modifications and running
+.Xr chkgrp 8
+on the
+.Pa group
+file.
+.It Ar daily_backup_aliases_enable
+(bool) Set to
+.Dq YES
+if you want the
+.Pa /etc/aliases
+file backed up and modifications to be displayed in your daily output.
+.It Ar daily_backup_distfile_enable
+(bool) Set to
+.Dq YES
+if you want the
+.Pa /etc/Distfile
+file backed up and modifications to be displayed in your daily output.
+.It Ar daily_calendar_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Ic calendar -a
+daily.
+.It Ar daily_accounting_enable
+(bool) Set to
+.Dq YES
+if you want to rotate your daily accounting files.
+No rotations are necessary unless
+.Ar accounting_enable
+is enabled in
+.Xr rc.conf 5 .
+.It Ar daily_accounting_compress
+(bool) Set to
+.Dq YES
+if you want your daily accounting files to be compressed using
+.Xr gzip 1 .
+.It Ar daily_distfile_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Xr rdist 1
+daily.
+The
+.Pa /etc/Distfile
+file must also exist.
+.It Pa daily_news_expire_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Pa /etc/news.expire .
+.It Pa daily_uuclean_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Pa /etc/uuclean.daily .
+.It Ar daily_status_disks_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Xr df 1
+.Po
+with the arguments supplied in
+.Ar daily_status_disks_df_flags
+.Pc
+and
+.Ic dump W .
+.It Ar daily_status_disks_df_flags
+(str) Set to the arguments for the
+.Xr df 1
+utility when
+.Ar daily_status_disks_enable
+is set to
+.Dq YES .
+.It Ar daily_status_uucp_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Pa /etc/uuclean.daily .
+.It Ar daily_status_network_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Ic netstat -i .
+.It Ar daily_status_network_usedns
+(bool) Set to
+.Dq YES
+if you want to run
+.Xr netstat 1
+without the
+.Fl n
+option (to do DNS lookups).
+.It Ar daily_status_rwho_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Xr uptime 1
+(or
+.Xr ruptime 1
+if
+.Ar rwhod_enable
+is set to
+.Dq YES
+in
+.Pa /etc/rc.conf ).
+.It Ar daily_status_mailq_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Xr mailq 1 .
+.It Ar daily_status_mailq_shorten
+(bool) Set to
+.Dq YES
+if you want to shorten the
+.Nm mailq
+output when
+.Ar daily_status_mailq_enable
+is set to
+.Dq YES .
+.It Ar daily_status_security_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Pa /etc/security .
+.It Ar daily_status_security_inline
+(bool) Set to
+.Dq YES
+if you want to run
+.Pa /etc/security
+inline.
+The alternative is to run it as a background job, mailing the output to
+.An root .
+.It Ar daily_status_security_noamd
+(bool) Set to
+.Dq YES
+if you want to ignore
+.Xr amd 8
+mounts when comparing against yesterdays filesystem mounts.
+.It Ar daily_status_security_nomfs
+(bool) Set to
+.Dq YES
+if you want to ignore
+.Xr mfs 8
+mounts when comparing against yesterdays filesystem mounts.
+.It Ar daily_status_mail_rejects_enable
+(bool) Set to
+.Dq YES
+if you want to summarise mail rejections logged to
+.Pa /var/log/maillog
+for the previous day.
+.It Ar daily_status_mail_rejects_logs
+(num) Set to the number of maillog files that should be checked
+for yesterday's mail rejects.
+.It Ar daily_local
+(str) Set to a list of extra scripts that should be run after all other
+daily scripts.
+All scripts must be absolute path names.
+.El
+.Pp
+The following variables are used by the standard scripts that reside in
+.Pa /etc/periodic/weekly :
+.Bl -tag -offset 4n -width 2n
+.It Ar weekly_clean_kvmdb_enable
+(bool) Set to
+.Dq YES
+if you want to purge old
+.Pa /var/db/kvm_*.db
+files.
+The kvm file for the current kernel will not be purged.
+.It Ar weekly_clean_kvmdb_days
+(num) Set to the number of days that the file must not have been accessed
+before being deleted.
+.It Ar weekly_clean_kvmdb_verbose
+(bool) Set to
+.Dq YES
+if you want the removed files to be reported in your daily output.
+.It Ar weekly_uucp_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Pa /usr/libexec/uucp/clean.weekly .
+.It Ar weekly_locate_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Pa /usr/libexec/locate.updatedb .
+This script is run using
+.Ic nice -5
+as user
+.An nobody ,
+and generates the table used by the
+.Xr locate 1
+command.
+.It Ar weekly_whatis_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Pa /usr/libexec/makewhatis.local .
+This script regenerates the database used by the
+.Xr apropos 1
+command.
+.It Ar weekly_catman_enable
+(bool) Set to
+.Dq YES
+if you want to run
+.Pa /usr/libexec/catman.local .
+This script processes all out of date man pages, speeding up the
+.Xr man 1
+command at the expense of disk space.
+.It Ar weekly_noid_enable
+(bool) Set to
+.Dq YES
+if you want to locate orphaned files on the system.
+An orphaned file is one with an invalid owner or group.
+.It Ar weekly_noid_dirs
+(str) A list of directories under which orphaned files are searched for.
+This would usually be set to
+.Pa / .
+.It Ar weekly_status_pkg_dirs
+(bool) Set to
+.Dq YES
+if you want to use
+.Xr pkg_version 1
+to list installed packages which are out of date.
+.It Ar weekly_local
+(str) Set to a list of extra scripts that should be run after all other
+weekly scripts.
+All scripts must be absolute path names.
+.El
+.Pp
+The following variables are used by the standard scripts that reside in
+.Pa /etc/periodic/monthly :
+.Bl -tag -offset 4n -width 2n
+.It Ar monthly_accounting_enable
+(bool) Set to
+.Dq YES
+if you want to do login accounting using the
+.Xr ac 8
+command.
+.It Ar monthly_local
+(str) Set to a list of extra scripts that should be run after all other
+monthly scripts.
+All scripts must be absolute path names.
+.El
+.Sh FILES
+.Bl -tag -width /etc/defaults/periodic.conf
+.It Pa /etc/defaults/periodic.conf
+The default configuration file.
+This file contains all default variables and values.
+.It Pa /etc/periodic.conf
+The usual system specific variable override file.
+.It Pa /etc/periodic.conf.local
+An additional override file, useful when
+.Pa /etc/periodic.conf
+is shared or distributed.
+.El
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr calendar 1 ,
+.Xr df 1 ,
+.Xr gzip 1 ,
+.Xr locate 1 ,
+.Xr man 1 ,
+.Xr msgs 1 ,
+.Xr netstat 1 ,
+.Xr nice 1 ,
+.Xr pkg_version 1 ,
+.Xr rdist 1 ,
+.Xr rc.conf 5 ,
+.Xr ac 8 ,
+.Xr chkgrp 8 ,
+.Xr dump 8 ,
+.Xr mfs 8 .
+.Xr periodic 8 .
+.Sh HISTORY
+The
+.Nm
+file appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Brian Somers Aq brian@Awfulhak.org .
diff --git a/share/man/man9/accept_filter.9 b/share/man/man9/accept_filter.9
new file mode 100644
index 0000000000000..94a113cc38863
--- /dev/null
+++ b/share/man/man9/accept_filter.9
@@ -0,0 +1,134 @@
+.\"
+.\" Copyright (c) 2000 Alfred Perlstein
+.\"
+.\" 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 June 25, 2000
+.Os
+.Dt ACCEPT_FILTER 9
+.Sh NAME
+.Nm accept_filter ,
+.Nm accept_filt_add ,
+.Nm accept_filt_del ,
+.Nm accept_filt_generic_mod_event ,
+.Nm accept_filt_get
+.Nd filter incoming connections
+.Sh SYNOPSIS
+.Fd #include <sys/types.h>
+.Fd #include <sys/socket.h>
+.Fd #include <sys/socketvar.h>
+.Ft int
+.Fn accept_filt_add "struct accept_filter *filt"
+.Ft int
+.Fn accept_filt_del "char *name"
+.Ft int
+.Fn accept_filt_generic_mod_event "module_t mod" "int event" "void *data"
+.Ft struct accept_filter *
+.Fn accept_filt_get "char *name"
+.Sh DESCRIPTION
+Accept filters allow an application to request
+that the kernel pre-process incoming connections.
+An accept filter is requested via the
+.Xr setsockopt 2
+system call, passing in an
+.Fa optname
+of
+.Dv SO_ACCEPTFILTER .
+.Sh IMPLEMENTATION NOTES
+A module that wants to be an accept filter
+must provide a struct accept_filter to the system:
+.Bd -literal
+struct accept_filter {
+ char accf_name[16];
+ void (*accf_callback)
+ __P((struct socket *so, void *arg, int waitflag));
+ void * (*accf_create)
+ __P((struct socket *so, char *arg));
+ void (*accf_destroy)
+ __P((struct socket *so));
+ SLIST_ENTRY(accept_filter) accf_next; /* next on the list */
+};
+.Ed
+.Pp
+The module should register it with the function
+.Fn accept_filt_add ,
+passing a pointer to a struct accept_filter, allocated with
+.Xr MALLOC 9
+.Pp
+The fields of
+.Fa struct accept_filter
+are as follows:
+.Bl -tag -width accf_callbackXXX
+.It accf_name
+Name of the filter;
+this is how it will be accessed from userland.
+.It accf_callback
+The callback that the kernel will do
+once the connection is established.
+It is the same as a socket upcall
+and will be called when the connection is established
+and whenever new data arrives on the socket,
+unless the callback modifies the socket's flags.
+.It accf_create
+Called whenever a
+.Xr setsockopt 2
+installs the filter onto
+a listening socket.
+.It accf_destroy
+Called whenever the user removes the accept filter on the socket.
+.El
+.Pp
+.Fn accept_filt_del
+passed the same string used in accept_filter.accf_name during registration
+with
+.Fn accept_filt_add ,
+the kernel will then disallow and further userland use of the filter.
+.Pp
+.Fn accept_filt_get
+is used internally to locate which accept filter to use via the
+.Fn setsocketopt
+syscall.
+.Pp
+.Fn accept_filt_generic_mod_event
+provides a simple way to avoid duplicate
+code for accept filters which don't use
+argument field to load and unload
+themselves. It is a function that can be
+put in the load/unload struct
+for the
+.Fn DECLARE_MODULE
+macro.
+.Sh SEE ALSO
+.Xr setsockopt 2 ,
+.Xr malloc 9
+.Sh HISTORY
+The accept filter mechanism was introduced in
+.Fx 4.0 .
+.Sh AUTHORS
+This manual page has been written by
+.An Alfred Perlstein ,
+Sheldon Hearn and Jeroen Ruigrok van der Werven.
+The accept filter concept was pioneered by engineers at Yahoo.com
+and refined to be a loadable module system by Alfred Perlstein.
diff --git a/sys/modules/sound/Makefile b/sys/modules/sound/Makefile
new file mode 100644
index 0000000000000..41ea856b17e7c
--- /dev/null
+++ b/sys/modules/sound/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+SUBDIR =
+SUBDIR += pcm
+SUBDIR += driver
+
+.include <bsd.subdir.mk>
diff --git a/sys/modules/sound/Makefile.inc b/sys/modules/sound/Makefile.inc
new file mode 100644
index 0000000000000..265f86d1ed55a
--- /dev/null
+++ b/sys/modules/sound/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/sys/modules/sound/driver/Makefile.inc b/sys/modules/sound/driver/Makefile.inc
new file mode 100644
index 0000000000000..265f86d1ed55a
--- /dev/null
+++ b/sys/modules/sound/driver/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/sys/modules/sound/driver/ad1816/Makefile b/sys/modules/sound/driver/ad1816/Makefile
new file mode 100644
index 0000000000000..a506c30edf6a7
--- /dev/null
+++ b/sys/modules/sound/driver/ad1816/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/isa
+KMOD = snd_ad1816
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += ad1816.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/csa/Makefile b/sys/modules/sound/driver/csa/Makefile
new file mode 100644
index 0000000000000..2f6ffe173d175
--- /dev/null
+++ b/sys/modules/sound/driver/csa/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
+KMOD = snd_csa
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += csa.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/csapcm/Makefile b/sys/modules/sound/driver/csapcm/Makefile
new file mode 100644
index 0000000000000..42f12c7aad8c4
--- /dev/null
+++ b/sys/modules/sound/driver/csapcm/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
+KMOD = snd_csapcm
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += csapcm.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/ds1/Makefile b/sys/modules/sound/driver/ds1/Makefile
new file mode 100644
index 0000000000000..a703e1ce81388
--- /dev/null
+++ b/sys/modules/sound/driver/ds1/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
+KMOD = snd_ds1
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += ds1.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/emu10k1/Makefile b/sys/modules/sound/driver/emu10k1/Makefile
new file mode 100644
index 0000000000000..73c6ff3a36f56
--- /dev/null
+++ b/sys/modules/sound/driver/emu10k1/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
+KMOD = snd_emu10k1
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += emu10k1.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/es137x/Makefile b/sys/modules/sound/driver/es137x/Makefile
new file mode 100644
index 0000000000000..b1f7abdf95a27
--- /dev/null
+++ b/sys/modules/sound/driver/es137x/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
+KMOD = snd_es137x
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += es137x.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/es1888/Makefile b/sys/modules/sound/driver/es1888/Makefile
new file mode 100644
index 0000000000000..2a6fc3be1ed35
--- /dev/null
+++ b/sys/modules/sound/driver/es1888/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/isa
+KMOD = snd_es1888
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += es1888.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/ess/Makefile b/sys/modules/sound/driver/ess/Makefile
new file mode 100644
index 0000000000000..3dc1032d1528e
--- /dev/null
+++ b/sys/modules/sound/driver/ess/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/isa
+KMOD = snd_ess
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += ess.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/gusc/Makefile b/sys/modules/sound/driver/gusc/Makefile
new file mode 100644
index 0000000000000..facf8acec9f2b
--- /dev/null
+++ b/sys/modules/sound/driver/gusc/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/isa
+KMOD = snd_gusc
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += gusc.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/mss/Makefile b/sys/modules/sound/driver/mss/Makefile
new file mode 100644
index 0000000000000..46703688df6d1
--- /dev/null
+++ b/sys/modules/sound/driver/mss/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/isa
+KMOD = snd_mss
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += mss.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/neomagic/Makefile b/sys/modules/sound/driver/neomagic/Makefile
new file mode 100644
index 0000000000000..be8016c2ce18a
--- /dev/null
+++ b/sys/modules/sound/driver/neomagic/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
+KMOD = snd_neomagic
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += neomagic.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/sb/Makefile b/sys/modules/sound/driver/sb/Makefile
new file mode 100644
index 0000000000000..47373c8feab07
--- /dev/null
+++ b/sys/modules/sound/driver/sb/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/isa
+KMOD = snd_sb
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += sb.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/sbc/Makefile b/sys/modules/sound/driver/sbc/Makefile
new file mode 100644
index 0000000000000..3974b5a82db74
--- /dev/null
+++ b/sys/modules/sound/driver/sbc/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/isa
+KMOD = snd_sbc
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += sbc.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/sound/driver/t4dwave/Makefile b/sys/modules/sound/driver/t4dwave/Makefile
new file mode 100644
index 0000000000000..6c0bb3fa1dc58
--- /dev/null
+++ b/sys/modules/sound/driver/t4dwave/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../../dev/sound/pci
+KMOD = snd_t4dwave
+SRCS = device_if.h bus_if.h isa_if.h pci_if.h
+SRCS += t4dwave.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c
new file mode 100644
index 0000000000000..c95aaa54ec0ed
--- /dev/null
+++ b/sys/net/if_stf.c
@@ -0,0 +1,662 @@
+/* $FreeBSD$ */
+/* $KAME: if_stf.c,v 1.40 2000/06/20 19:44:42 itojun Exp $ */
+
+/*
+ * Copyright (C) 2000 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * 6to4 interface, based on draft-ietf-ngtrans-6to4-06.txt.
+ *
+ * 6to4 interface is NOT capable of link-layer (I mean, IPv4) multicasting.
+ * There is no address mapping defined from IPv6 multicast address to IPv4
+ * address. Therefore, we do not have IFF_MULTICAST on the interface.
+ *
+ * Due to the lack of address mapping for link-local addresses, we cannot
+ * throw packets toward link-local addresses (fe80::x). Also, we cannot throw
+ * packets to link-local multicast addresses (ff02::x).
+ *
+ * Here are interesting symptoms due to the lack of link-local address:
+ *
+ * Unicast routing exchange:
+ * - RIPng: Impossible. Uses link-local multicast packet toward ff02::9,
+ * and link-local addresses as nexthop.
+ * - OSPFv6: Impossible. OSPFv6 assumes that there's link-local address
+ * assigned to the link, and makes use of them. Also, HELLO packets use
+ * link-local multicast addresses (ff02::5 and ff02::6).
+ * - BGP4+: Maybe. You can only use global address as nexthop, and global
+ * address as TCP endpoint address.
+ *
+ * Multicast routing protocols:
+ * - PIM: Hello packet cannot be used to discover adjacent PIM routers.
+ * Adjacent PIM routers must be configured manually (is it really spec-wise
+ * correct thing to do?).
+ *
+ * ICMPv6:
+ * - Redirects cannot be used due to the lack of link-local address.
+ *
+ * Starting from 04 draft, the specification suggests how to construct
+ * link-local address for 6to4 interface.
+ * However, it seems to have no real use and does not help the above symptom
+ * much. Even if we assign link-locals to interface, we cannot really
+ * use link-local unicast/multicast on top of 6to4 cloud, and the above
+ * analysis does not change.
+ *
+ * 6to4 interface has security issues. Refer to
+ * http://playground.iijlab.net/i-d/draft-itojun-ipv6-transition-abuse-00.txt
+ * for details. The code tries to filter out some of malicious packets.
+ * Note that there is no way to be 100% secure.
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/protosw.h>
+#include <sys/kernel.h>
+#include <machine/cpu.h>
+
+#include <sys/malloc.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/if_types.h>
+#include <net/if_stf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/in_var.h>
+
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/in6_gif.h>
+#include <netinet6/in6_var.h>
+#include <netinet/ip_ecn.h>
+
+#include <netinet/ip_encap.h>
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+#include "bpf.h"
+#define NBPFILTER NBPF
+#include "stf.h"
+#include "gif.h" /*XXX*/
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#if NGIF > 0
+#include <net/if_gif.h>
+#endif
+
+#if NSTF > 0
+#if NSTF != 1
+# error only single stf interface allowed
+#endif
+
+#define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002)
+#define GET_V4(x) ((struct in_addr *)(&(x)->s6_addr16[1]))
+
+struct stf_softc {
+ struct ifnet sc_if; /* common area */
+ union {
+ struct route __sc_ro4;
+ struct route_in6 __sc_ro6; /* just for safety */
+ } __sc_ro46;
+#define sc_ro __sc_ro46.__sc_ro4
+ const struct encaptab *encap_cookie;
+};
+
+static struct stf_softc *stf;
+static int nstf;
+
+#if NGIF > 0
+extern int ip_gif_ttl; /*XXX*/
+#else
+static int ip_gif_ttl = 40; /*XXX*/
+#endif
+
+extern struct protosw in_stf_protosw;
+
+void stfattach __P((void *));
+static int stf_encapcheck __P((const struct mbuf *, int, int, void *));
+static struct in6_ifaddr *stf_getsrcifa6 __P((struct ifnet *));
+static int stf_output __P((struct ifnet *, struct mbuf *, struct sockaddr *,
+ struct rtentry *));
+static int stf_checkaddr4 __P((struct in_addr *, struct ifnet *));
+static int stf_checkaddr6 __P((struct in6_addr *, struct ifnet *));
+static void stf_rtrequest __P((int, struct rtentry *, struct sockaddr *));
+static int stf_ioctl __P((struct ifnet *, u_long, caddr_t));
+
+void
+stfattach(dummy)
+ void *dummy;
+{
+ struct stf_softc *sc;
+ int i;
+ const struct encaptab *p;
+
+ nstf = NSTF;
+ stf = malloc(nstf * sizeof(struct stf_softc), M_DEVBUF, M_WAIT);
+ bzero(stf, nstf * sizeof(struct stf_softc));
+ sc = stf;
+
+ /* XXX just in case... */
+ for (i = 0; i < nstf; i++) {
+ sc = &stf[i];
+ bzero(sc, sizeof(*sc));
+ sc->sc_if.if_name = "stf";
+ sc->sc_if.if_unit = i;
+
+ p = encap_attach_func(AF_INET, IPPROTO_IPV6, stf_encapcheck,
+ &in_stf_protosw, sc);
+ if (p == NULL) {
+ printf("%s: attach failed\n", if_name(&sc->sc_if));
+ continue;
+ }
+ sc->encap_cookie = p;
+
+ sc->sc_if.if_mtu = IPV6_MMTU;
+ sc->sc_if.if_flags = 0;
+ sc->sc_if.if_ioctl = stf_ioctl;
+ sc->sc_if.if_output = stf_output;
+ sc->sc_if.if_type = IFT_STF;
+ sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
+ if_attach(&sc->sc_if);
+#if NBPFILTER > 0
+#ifdef HAVE_OLD_BPF
+ bpfattach(&sc->sc_if, DLT_NULL, sizeof(u_int));
+#else
+ bpfattach(&sc->sc_if.if_bpf, &sc->sc_if, DLT_NULL, sizeof(u_int));
+#endif
+#endif
+ }
+}
+
+PSEUDO_SET(stfattach, if_stf);
+
+static int
+stf_encapcheck(m, off, proto, arg)
+ const struct mbuf *m;
+ int off;
+ int proto;
+ void *arg;
+{
+ struct ip ip;
+ struct in6_ifaddr *ia6;
+ struct stf_softc *sc;
+ struct in_addr a, b;
+
+ sc = (struct stf_softc *)arg;
+ if (sc == NULL)
+ return 0;
+
+ if ((sc->sc_if.if_flags & IFF_UP) == 0)
+ return 0;
+
+ if (proto != IPPROTO_IPV6)
+ return 0;
+
+ /* LINTED const cast */
+ m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
+
+ if (ip.ip_v != 4)
+ return 0;
+
+ ia6 = stf_getsrcifa6(&sc->sc_if);
+ if (ia6 == NULL)
+ return 0;
+
+ /*
+ * check if IPv4 dst matches the IPv4 address derived from the
+ * local 6to4 address.
+ * success on: dst = 10.1.1.1, ia6->ia_addr = 2002:0a01:0101:...
+ */
+ if (bcmp(GET_V4(&ia6->ia_addr.sin6_addr), &ip.ip_dst,
+ sizeof(ip.ip_dst)) != 0)
+ return 0;
+
+ /*
+ * check if IPv4 src matches the IPv4 address derived from the
+ * local 6to4 address masked by prefixmask.
+ * success on: src = 10.1.1.1, ia6->ia_addr = 2002:0a00:.../24
+ * fail on: src = 10.1.1.1, ia6->ia_addr = 2002:0b00:.../24
+ */
+ bzero(&a, sizeof(a));
+ a.s_addr = GET_V4(&ia6->ia_addr.sin6_addr)->s_addr;
+ a.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr;
+ b = ip.ip_src;
+ b.s_addr &= GET_V4(&ia6->ia_prefixmask.sin6_addr)->s_addr;
+ if (a.s_addr != b.s_addr)
+ return 0;
+
+ /* stf interface makes single side match only */
+ return 32;
+}
+
+static struct in6_ifaddr *
+stf_getsrcifa6(ifp)
+ struct ifnet *ifp;
+{
+ struct ifaddr *ia;
+ struct in_ifaddr *ia4;
+ struct sockaddr_in6 *sin6;
+ struct in_addr in;
+
+ for (ia = ifp->if_addrlist.tqh_first;
+ ia;
+ ia = ia->ifa_list.tqe_next)
+ {
+ if (ia->ifa_addr == NULL)
+ continue;
+ if (ia->ifa_addr->sa_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)ia->ifa_addr;
+ if (!IN6_IS_ADDR_6TO4(&sin6->sin6_addr))
+ continue;
+
+ bcopy(GET_V4(&sin6->sin6_addr), &in, sizeof(in));
+ for (ia4 = TAILQ_FIRST(&in_ifaddrhead);
+ ia4;
+ ia4 = TAILQ_NEXT(ia4, ia_link))
+ {
+ if (ia4->ia_addr.sin_addr.s_addr == in.s_addr)
+ break;
+ }
+ if (ia4 == NULL)
+ continue;
+
+ return (struct in6_ifaddr *)ia;
+ }
+
+ return NULL;
+}
+
+#ifndef offsetof
+#define offsetof(s, e) ((int)&((s *)0)->e)
+#endif
+
+static int
+stf_output(ifp, m, dst, rt)
+ struct ifnet *ifp;
+ struct mbuf *m;
+ struct sockaddr *dst;
+ struct rtentry *rt;
+{
+ struct stf_softc *sc;
+ struct sockaddr_in6 *dst6;
+ struct sockaddr_in *dst4;
+ u_int8_t tos;
+ struct ip *ip;
+ struct ip6_hdr *ip6;
+ struct in6_ifaddr *ia6;
+
+ sc = (struct stf_softc*)ifp;
+ dst6 = (struct sockaddr_in6 *)dst;
+
+ /* just in case */
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ m_freem(m);
+ return ENETDOWN;
+ }
+
+ /*
+ * If we don't have an ip4 address that match my inner ip6 address,
+ * we shouldn't generate output. Without this check, we'll end up
+ * using wrong IPv4 source.
+ */
+ ia6 = stf_getsrcifa6(ifp);
+ if (ia6 == NULL) {
+ m_freem(m);
+ return ENETDOWN;
+ }
+
+ if (m->m_len < sizeof(*ip6)) {
+ m = m_pullup(m, sizeof(*ip6));
+ if (!m)
+ return ENOBUFS;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+
+ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
+ if (m && m->m_len < sizeof(struct ip))
+ m = m_pullup(m, sizeof(struct ip));
+ if (m == NULL)
+ return ENOBUFS;
+ ip = mtod(m, struct ip *);
+
+ bzero(ip, sizeof(*ip));
+
+ bcopy(GET_V4(&((struct sockaddr_in6 *)&ia6->ia_addr)->sin6_addr),
+ &ip->ip_src, sizeof(ip->ip_src));
+ bcopy(GET_V4(&dst6->sin6_addr), &ip->ip_dst, sizeof(ip->ip_dst));
+ ip->ip_p = IPPROTO_IPV6;
+ ip->ip_ttl = ip_gif_ttl; /*XXX*/
+ ip->ip_len = m->m_pkthdr.len; /*host order*/
+ if (ifp->if_flags & IFF_LINK1)
+ ip_ecn_ingress(ECN_ALLOWED, &ip->ip_tos, &tos);
+
+ dst4 = (struct sockaddr_in *)&sc->sc_ro.ro_dst;
+ if (dst4->sin_family != AF_INET ||
+ bcmp(&dst4->sin_addr, &ip->ip_dst, sizeof(ip->ip_dst)) != 0) {
+ /* cache route doesn't match */
+ dst4->sin_family = AF_INET;
+ dst4->sin_len = sizeof(struct sockaddr_in);
+ bcopy(&ip->ip_dst, &dst4->sin_addr, sizeof(dst4->sin_addr));
+ if (sc->sc_ro.ro_rt) {
+ RTFREE(sc->sc_ro.ro_rt);
+ sc->sc_ro.ro_rt = NULL;
+ }
+ }
+
+ if (sc->sc_ro.ro_rt == NULL) {
+ rtalloc(&sc->sc_ro);
+ if (sc->sc_ro.ro_rt == NULL) {
+ m_freem(m);
+ return ENETUNREACH;
+ }
+ }
+
+ return ip_output(m, NULL, &sc->sc_ro, 0, NULL);
+}
+
+static int
+stf_checkaddr4(in, ifp)
+ struct in_addr *in;
+ struct ifnet *ifp; /* incoming interface */
+{
+ struct in_ifaddr *ia4;
+
+ /*
+ * reject packets with the following address:
+ * 224.0.0.0/4 0.0.0.0/8 127.0.0.0/8 255.0.0.0/8
+ */
+ if (IN_MULTICAST(in->s_addr))
+ return -1;
+ switch ((ntohl(in->s_addr) & 0xff000000) >> 24) {
+ case 0: case 127: case 255:
+ return -1;
+ }
+
+ /*
+ * reject packets with broadcast
+ */
+ for (ia4 = TAILQ_FIRST(&in_ifaddrhead);
+ ia4;
+ ia4 = TAILQ_NEXT(ia4, ia_link))
+ {
+ if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
+ continue;
+ if (in->s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
+ return -1;
+ }
+
+ /*
+ * perform ingress filter
+ */
+ if (ifp) {
+ struct sockaddr_in sin;
+ struct rtentry *rt;
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ sin.sin_addr = *in;
+ rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
+ if (!rt)
+ return -1;
+ if (rt->rt_ifp != ifp) {
+ rtfree(rt);
+ return -1;
+ }
+ rtfree(rt);
+ }
+
+ return 0;
+}
+
+static int
+stf_checkaddr6(in6, ifp)
+ struct in6_addr *in6;
+ struct ifnet *ifp; /* incoming interface */
+{
+ /*
+ * check 6to4 addresses
+ */
+ if (IN6_IS_ADDR_6TO4(in6))
+ return stf_checkaddr4(GET_V4(in6), ifp);
+
+ /*
+ * reject anything that look suspicious. the test is implemented
+ * in ip6_input too, but we check here as well to
+ * (1) reject bad packets earlier, and
+ * (2) to be safe against future ip6_input change.
+ */
+ if (IN6_IS_ADDR_V4COMPAT(in6) || IN6_IS_ADDR_V4MAPPED(in6))
+ return -1;
+
+ return 0;
+}
+
+void
+#if __STDC__
+in_stf_input(struct mbuf *m, ...)
+#else
+in_stf_input(m, va_alist)
+ register struct mbuf *m;
+#endif
+{
+ int off, proto;
+ struct stf_softc *sc;
+ struct ip *ip;
+ struct ip6_hdr *ip6;
+ u_int8_t otos, itos;
+ int s, isr;
+ struct ifqueue *ifq = NULL;
+ struct ifnet *ifp;
+ va_list ap;
+
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
+
+ if (proto != IPPROTO_IPV6) {
+ m_freem(m);
+ return;
+ }
+
+ ip = mtod(m, struct ip *);
+
+ sc = (struct stf_softc *)encap_getarg(m);
+
+ if (sc == NULL || (sc->sc_if.if_flags & IFF_UP) == 0) {
+ m_freem(m);
+ return;
+ }
+
+ ifp = &sc->sc_if;
+
+ /*
+ * perform sanity check against outer src/dst.
+ * for source, perform ingress filter as well.
+ */
+ if (stf_checkaddr4(&ip->ip_dst, NULL) < 0 ||
+ stf_checkaddr4(&ip->ip_src, m->m_pkthdr.rcvif) < 0) {
+ m_freem(m);
+ return;
+ }
+
+ otos = ip->ip_tos;
+ m_adj(m, off);
+
+ if (m->m_len < sizeof(*ip6)) {
+ m = m_pullup(m, sizeof(*ip6));
+ if (!m)
+ return;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+
+ /*
+ * perform sanity check against inner src/dst.
+ * for source, perform ingress filter as well.
+ */
+ if (stf_checkaddr6(&ip6->ip6_dst, NULL) < 0 ||
+ stf_checkaddr6(&ip6->ip6_src, m->m_pkthdr.rcvif) < 0) {
+ m_freem(m);
+ return;
+ }
+
+ itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
+ if ((ifp->if_flags & IFF_LINK1) != 0)
+ ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
+ ip6->ip6_flow &= ~htonl(0xff << 20);
+ ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
+
+ m->m_pkthdr.rcvif = ifp;
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf) {
+ /*
+ * We need to prepend the address family as
+ * a four byte field. Cons up a dummy header
+ * to pacify bpf. This is safe because bpf
+ * will only read from the mbuf (i.e., it won't
+ * try to free it or keep a pointer a to it).
+ */
+ struct mbuf m0;
+ u_int af = AF_INET6;
+
+ m0.m_next = m;
+ m0.m_len = 4;
+ m0.m_data = (char *)&af;
+
+#ifdef HAVE_OLD_BPF
+ bpf_mtap(ifp, &m0);
+#else
+ bpf_mtap(ifp->if_bpf, &m0);
+#endif
+ }
+#endif /*NBPFILTER > 0*/
+
+ /*
+ * Put the packet to the network layer input queue according to the
+ * specified address family.
+ * See net/if_gif.c for possible issues with packet processing
+ * reorder due to extra queueing.
+ */
+ ifq = &ip6intrq;
+ isr = NETISR_IPV6;
+
+ s = splimp();
+ if (IF_QFULL(ifq)) {
+ IF_DROP(ifq); /* update statistics */
+ m_freem(m);
+ splx(s);
+ return;
+ }
+ IF_ENQUEUE(ifq, m);
+ schednetisr(isr);
+ ifp->if_ipackets++;
+ ifp->if_ibytes += m->m_pkthdr.len;
+ splx(s);
+}
+
+/* ARGSUSED */
+static void
+stf_rtrequest(cmd, rt, sa)
+ int cmd;
+ struct rtentry *rt;
+#if defined(__bsdi__) && _BSDI_VERSION >= 199802
+ struct rt_addrinfo *sa;
+#else
+ struct sockaddr *sa;
+#endif
+{
+
+ if (rt)
+ rt->rt_rmx.rmx_mtu = IPV6_MMTU;
+}
+
+static int
+stf_ioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct ifaddr *ifa;
+ struct ifreq *ifr;
+ struct sockaddr_in6 *sin6;
+ int error;
+
+ error = 0;
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifa = (struct ifaddr *)data;
+ if (ifa == NULL || ifa->ifa_addr->sa_family != AF_INET6) {
+ error = EAFNOSUPPORT;
+ break;
+ }
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (IN6_IS_ADDR_6TO4(&sin6->sin6_addr)) {
+ ifa->ifa_rtrequest = stf_rtrequest;
+ ifp->if_flags |= IFF_UP;
+ } else
+ error = EINVAL;
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ ifr = (struct ifreq *)data;
+ if (ifr && ifr->ifr_addr.sa_family == AF_INET6)
+ ;
+ else
+ error = EAFNOSUPPORT;
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+#endif /* NSTF > 0 */
diff --git a/sys/net/if_stf.h b/sys/net/if_stf.h
new file mode 100644
index 0000000000000..258f3a060aa50
--- /dev/null
+++ b/sys/net/if_stf.h
@@ -0,0 +1,38 @@
+/* $FreeBSD$ */
+/* $KAME: if_stf.h,v 1.3 2000/03/25 07:23:33 sumikawa Exp $ */
+
+/*
+ * Copyright (C) 2000 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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 _NET_IF_STF_H_
+#define _NET_IF_STF_H_
+
+void in_stf_input __P((struct mbuf *, ...));
+
+#endif /* _NET_IF_STF_H_ */
diff --git a/sys/netgraph/ng_ether.c b/sys/netgraph/ng_ether.c
new file mode 100644
index 0000000000000..508b2162fbd7f
--- /dev/null
+++ b/sys/netgraph/ng_ether.c
@@ -0,0 +1,639 @@
+
+/*
+ * ng_ether.c
+ *
+ * Copyright (c) 1996-2000 Whistle Communications, Inc.
+ * All rights reserved.
+ *
+ * Subject to the following obligations and disclaimer of warranty, use and
+ * redistribution of this software, in source or object code forms, with or
+ * without modifications are expressly permitted by Whistle Communications;
+ * provided, however, that:
+ * 1. Any and all reproductions of the source or object code must include the
+ * copyright notice above and the following disclaimer of warranties; and
+ * 2. No rights are granted, in any manner or form, to use Whistle
+ * Communications, Inc. trademarks, including the mark "WHISTLE
+ * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
+ * such appears in the above copyright notice or in the software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
+ * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
+ * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
+ * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
+ * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
+ * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
+ * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
+ * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * Authors: Archie Cobbs <archie@freebsd.org>
+ * Julian Elischer <julian@freebsd.org>
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * ng_ether(4) netgraph node type
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/if_arp.h>
+#include <net/if_var.h>
+#include <net/ethernet.h>
+
+#include <netgraph/ng_message.h>
+#include <netgraph/netgraph.h>
+#include <netgraph/ng_parse.h>
+#include <netgraph/ng_ether.h>
+
+#define IFP2AC(IFP) ((struct arpcom *)IFP)
+#define IFP2NG(ifp) ((struct ng_node *)((struct arpcom *)(ifp))->ac_netgraph)
+
+/* Per-node private data */
+struct private {
+ struct ifnet *ifp; /* associated interface */
+ hook_p upper; /* upper hook connection */
+ hook_p lower; /* lower OR orphan hook connection */
+ u_char lowerOrphan; /* whether lower is lower or orphan */
+};
+typedef struct private *priv_p;
+
+/* Functional hooks called from if_ethersubr.c */
+static void ng_ether_input(struct ifnet *ifp,
+ struct mbuf **mp, struct ether_header *eh);
+static void ng_ether_input_orphan(struct ifnet *ifp,
+ struct mbuf *m, struct ether_header *eh);
+static int ng_ether_output(struct ifnet *ifp, struct mbuf **mp);
+static void ng_ether_attach(struct ifnet *ifp);
+static void ng_ether_detach(struct ifnet *ifp);
+
+/* Other functions */
+static void ng_ether_input2(node_p node,
+ struct mbuf **mp, struct ether_header *eh);
+static int ng_ether_glueback_header(struct mbuf **mp,
+ struct ether_header *eh);
+static int ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta);
+static int ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta);
+
+/* Netgraph node methods */
+static ng_constructor_t ng_ether_constructor;
+static ng_rcvmsg_t ng_ether_rcvmsg;
+static ng_shutdown_t ng_ether_rmnode;
+static ng_newhook_t ng_ether_newhook;
+static ng_rcvdata_t ng_ether_rcvdata;
+static ng_disconnect_t ng_ether_disconnect;
+static int ng_ether_mod_event(module_t mod, int event, void *data);
+
+/* List of commands and how to convert arguments to/from ASCII */
+static const struct ng_cmdlist ng_ether_cmdlist[] = {
+ {
+ NGM_ETHER_COOKIE,
+ NGM_ETHER_GET_IFNAME,
+ "getifname",
+ NULL,
+ &ng_parse_string_type
+ },
+ {
+ NGM_ETHER_COOKIE,
+ NGM_ETHER_GET_IFINDEX,
+ "getifindex",
+ NULL,
+ &ng_parse_int32_type
+ },
+ { 0 }
+};
+
+static struct ng_type ng_ether_typestruct = {
+ NG_VERSION,
+ NG_ETHER_NODE_TYPE,
+ ng_ether_mod_event,
+ ng_ether_constructor,
+ ng_ether_rcvmsg,
+ ng_ether_rmnode,
+ ng_ether_newhook,
+ NULL,
+ NULL,
+ ng_ether_rcvdata,
+ ng_ether_rcvdata,
+ ng_ether_disconnect,
+ ng_ether_cmdlist,
+};
+NETGRAPH_INIT(ether, &ng_ether_typestruct);
+
+/******************************************************************
+ ETHERNET FUNCTION HOOKS
+******************************************************************/
+
+/*
+ * Handle a packet that has come in on an interface. We get to
+ * look at it here before any upper layer protocols do.
+ *
+ * NOTE: this function will get called at splimp()
+ */
+static void
+ng_ether_input(struct ifnet *ifp,
+ struct mbuf **mp, struct ether_header *eh)
+{
+ const node_p node = IFP2NG(ifp);
+ const priv_p priv = node->private;
+
+ /* If "lower" hook not connected, let packet continue */
+ if (priv->lower == NULL || priv->lowerOrphan)
+ return;
+ ng_ether_input2(node, mp, eh);
+}
+
+/*
+ * Handle a packet that has come in on an interface, and which
+ * does not match any of our known protocols (an ``orphan'').
+ *
+ * NOTE: this function will get called at splimp()
+ */
+static void
+ng_ether_input_orphan(struct ifnet *ifp,
+ struct mbuf *m, struct ether_header *eh)
+{
+ const node_p node = IFP2NG(ifp);
+ const priv_p priv = node->private;
+
+ /* If "orphan" hook not connected, let packet continue */
+ if (priv->lower == NULL || !priv->lowerOrphan) {
+ m_freem(m);
+ return;
+ }
+ ng_ether_input2(node, &m, eh);
+ if (m != NULL)
+ m_freem(m);
+}
+
+/*
+ * Handle a packet that has come in on an interface.
+ * The Ethernet header has already been detached from the mbuf,
+ * so we have to put it back.
+ *
+ * NOTE: this function will get called at splimp()
+ */
+static void
+ng_ether_input2(node_p node, struct mbuf **mp, struct ether_header *eh)
+{
+ const priv_p priv = node->private;
+ meta_p meta = NULL;
+ int error;
+
+ /* Glue Ethernet header back on */
+ if ((error = ng_ether_glueback_header(mp, eh)) != 0)
+ return;
+
+ /* Send out lower/orphan hook */
+ NG_SEND_DATAQ(error, priv->lower, *mp, meta);
+
+ /* Any reflected packet must come later due to queuing */
+ *mp = NULL;
+}
+
+/*
+ * Handle a packet that is going out on an interface.
+ * The Ethernet header is already attached to the mbuf.
+ */
+static int
+ng_ether_output(struct ifnet *ifp, struct mbuf **mp)
+{
+ const node_p node = IFP2NG(ifp);
+ const priv_p priv = node->private;
+ meta_p meta = NULL;
+ int error = 0;
+
+ /* If "upper" hook not connected, let packet continue */
+ if (priv->upper == NULL)
+ return (0);
+
+ /* Send it out "upper" hook */
+ NG_SEND_DATA_RET(error, priv->upper, *mp, meta);
+
+ /* If we got a reflected packet back, handle it */
+ if (error == 0 && *mp != NULL) {
+ error = ng_ether_rcv_upper(node, *mp, meta);
+ *mp = NULL;
+ }
+ return (error);
+}
+
+/*
+ * A new Ethernet interface has been attached.
+ * Create a new node for it, etc.
+ */
+static void
+ng_ether_attach(struct ifnet *ifp)
+{
+ char name[IFNAMSIZ + 1];
+ priv_p priv;
+ node_p node;
+
+ /* Create node */
+ KASSERT(!IFP2NG(ifp), ("%s: node already exists?", __FUNCTION__));
+ snprintf(name, sizeof(name), "%s%d", ifp->if_name, ifp->if_unit);
+ if (ng_make_node_common(&ng_ether_typestruct, &node) != 0) {
+ log(LOG_ERR, "%s: can't %s for %s\n",
+ __FUNCTION__, "create node", name);
+ return;
+ }
+
+ /* Allocate private data */
+ MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_NOWAIT);
+ if (priv == NULL) {
+ log(LOG_ERR, "%s: can't %s for %s\n",
+ __FUNCTION__, "allocate memory", name);
+ ng_unref(node);
+ return;
+ }
+ bzero(priv, sizeof(*priv));
+ node->private = priv;
+ priv->ifp = ifp;
+ IFP2NG(ifp) = node;
+
+ /* Try to give the node the same name as the interface */
+ if (ng_name_node(node, name) != 0) {
+ log(LOG_WARNING, "%s: can't name node %s\n",
+ __FUNCTION__, name);
+ }
+}
+
+/*
+ * An Ethernet interface is being detached.
+ * Destroy its node.
+ */
+static void
+ng_ether_detach(struct ifnet *ifp)
+{
+ const node_p node = IFP2NG(ifp);
+ priv_p priv;
+
+ if (node == NULL) /* no node (why not?), ignore */
+ return;
+ ng_rmnode(node); /* break all links to other nodes */
+ IFP2NG(ifp) = NULL; /* detach node from interface */
+ priv = node->private; /* free node private info */
+ bzero(priv, sizeof(*priv));
+ FREE(priv, M_NETGRAPH);
+ node->private = NULL;
+ ng_unref(node); /* free node itself */
+}
+
+/*
+ * Optimization for gluing the Ethernet header back onto
+ * the front of an incoming packet.
+ */
+static int
+ng_ether_glueback_header(struct mbuf **mp, struct ether_header *eh)
+{
+ struct mbuf *m = *mp;
+ uintfptr_t room;
+ int error = 0;
+
+ /*
+ * Possibly the header is already on the front.
+ * If this is the case so just move the markers back
+ * to re-include it. We lucked out.
+ * This allows us to avoid a yucky m_pullup
+ * in later nodes if it works.
+ */
+ if (eh == mtod(m, struct ether_header *) - 1) {
+ m->m_len += sizeof(*eh);
+ m->m_data -= sizeof(*eh);
+ m->m_pkthdr.len += sizeof(*eh);
+ goto done;
+ }
+
+ /*
+ * Alternatively there may be room even though
+ * it is stored somewhere else. If so, copy it in.
+ * This only safe because we KNOW that this packet has
+ * just been generated by an ethernet card, so there are
+ * no aliases to the buffer (not so for outgoing packets).
+ * Nearly all ethernet cards will end up producing mbufs
+ * that fall into these cases. So we are not optimizing
+ * contorted cases.
+ */
+ if ((m->m_flags & M_EXT) != 0) {
+ room = mtod(m, caddr_t) - m->m_ext.ext_buf;
+ if (room > m->m_ext.ext_size) /* garbage, fail immediately */
+ room = 0;
+ } else
+ room = mtod(m, caddr_t) - m->m_pktdat;
+
+ /*
+ * If we have room, just copy it and adjust
+ */
+ if (room >= sizeof(*eh)) {
+ m->m_len += sizeof(*eh);
+ m->m_data -= sizeof(*eh);
+ m->m_pkthdr.len += sizeof(*eh);
+ goto copy;
+ }
+
+ /*
+ * Doing anything more is likely to get more
+ * expensive than it's worth..
+ * it's probable that everything else is in one
+ * big lump. The next node will do an m_pullup()
+ * for exactly the amount of data it needs and
+ * hopefully everything after that will not
+ * need one. So let's just use M_PREPEND.
+ */
+ M_PREPEND(m, sizeof (*eh), M_DONTWAIT);
+ if (m == NULL) {
+ error = ENOBUFS;
+ goto done;
+ }
+
+copy:
+ /* Copy header and return (possibly new) mbuf */
+ bcopy((caddr_t)eh, mtod(m, struct ether_header *), sizeof(*eh));
+done:
+ *mp = m;
+ return error;
+}
+
+/******************************************************************
+ NETGRAPH NODE METHODS
+******************************************************************/
+
+/*
+ * It is not possible or allowable to create a node of this type.
+ * Nodes get created when the interface is attached (or, when
+ * this node type's KLD is loaded).
+ */
+static int
+ng_ether_constructor(node_p *nodep)
+{
+ return (EINVAL);
+}
+
+/*
+ * Check for attaching a new hook.
+ */
+static int
+ng_ether_newhook(node_p node, hook_p hook, const char *name)
+{
+ const priv_p priv = node->private;
+ u_char orphan = priv->lowerOrphan;
+ hook_p *hookptr;
+
+ /* Divert hook is an alias for lower */
+ if (strcmp(name, NG_ETHER_HOOK_DIVERT) == 0)
+ name = NG_ETHER_HOOK_LOWER;
+
+ /* Which hook? */
+ if (strcmp(name, NG_ETHER_HOOK_UPPER) == 0)
+ hookptr = &priv->upper;
+ else if (strcmp(name, NG_ETHER_HOOK_LOWER) == 0) {
+ hookptr = &priv->lower;
+ orphan = 0;
+ } else if (strcmp(name, NG_ETHER_HOOK_ORPHAN) == 0) {
+ hookptr = &priv->lower;
+ orphan = 1;
+ } else
+ return (EINVAL);
+
+ /* Check if already connected (shouldn't be, but doesn't hurt) */
+ if (*hookptr != NULL)
+ return (EISCONN);
+
+ /* OK */
+ *hookptr = hook;
+ priv->lowerOrphan = orphan;
+ return (0);
+}
+
+/*
+ * Receive an incoming control message.
+ */
+static int
+ng_ether_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
+ struct ng_mesg **rptr, hook_p lasthook)
+{
+ const priv_p priv = node->private;
+ struct ng_mesg *resp = NULL;
+ int error = 0;
+
+ switch (msg->header.typecookie) {
+ case NGM_ETHER_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_ETHER_GET_IFNAME:
+ NG_MKRESPONSE(resp, msg, IFNAMSIZ + 1, M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ snprintf(resp->data, IFNAMSIZ + 1,
+ "%s%d", priv->ifp->if_name, priv->ifp->if_unit);
+ break;
+ case NGM_ETHER_GET_IFINDEX:
+ NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
+ if (resp == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ *((u_int32_t *)resp->data) = priv->ifp->if_index;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (rptr)
+ *rptr = resp;
+ else if (resp != NULL)
+ FREE(resp, M_NETGRAPH);
+ FREE(msg, M_NETGRAPH);
+ return (error);
+}
+
+/*
+ * Receive data on a hook.
+ */
+static int
+ng_ether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
+ struct mbuf **ret_m, meta_p *ret_meta)
+{
+ const node_p node = hook->node;
+ const priv_p priv = node->private;
+
+ if (hook == priv->lower)
+ return ng_ether_rcv_lower(node, m, meta);
+ if (hook == priv->upper)
+ return ng_ether_rcv_upper(node, m, meta);
+ panic("%s: weird hook", __FUNCTION__);
+}
+
+/*
+ * Handle an mbuf received on the "lower" hook.
+ */
+static int
+ng_ether_rcv_lower(node_p node, struct mbuf *m, meta_p meta)
+{
+ const priv_p priv = node->private;
+ struct ether_header *eh;
+
+ /* Make sure header is fully pulled up */
+ if (m->m_pkthdr.len < sizeof(struct ether_header)) {
+ NG_FREE_DATA(m, meta);
+ return (EINVAL);
+ }
+ if (m->m_len < sizeof(struct ether_header)
+ && (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
+ NG_FREE_META(meta);
+ return (ENOBUFS);
+ }
+
+ /* drop in the MAC address */
+ eh = mtod(m, struct ether_header *);
+ bcopy((IFP2AC(priv->ifp))->ac_enaddr, eh->ether_shost, 6);
+
+ /* Send it on its way */
+ NG_FREE_META(meta);
+ return ether_output_frame(priv->ifp, m);
+}
+
+/*
+ * Handle an mbuf received on the "upper" hook.
+ */
+static int
+ng_ether_rcv_upper(node_p node, struct mbuf *m, meta_p meta)
+{
+ const priv_p priv = node->private;
+ struct ether_header *eh;
+
+ /* Check length and pull off header */
+ if (m->m_pkthdr.len < sizeof(*eh)) {
+ NG_FREE_DATA(m, meta);
+ return (EINVAL);
+ }
+ if (m->m_len < sizeof(*eh) && (m = m_pullup(m, sizeof(*eh))) == NULL) {
+ NG_FREE_META(meta);
+ return (ENOBUFS);
+ }
+ eh = mtod(m, struct ether_header *);
+ m->m_data += sizeof(*eh);
+ m->m_len -= sizeof(*eh);
+ m->m_pkthdr.len -= sizeof(*eh);
+
+ /* Route packet back in */
+ NG_FREE_META(meta);
+ ether_demux(priv->ifp, eh, m);
+ return (0);
+}
+
+/*
+ * Shutdown node. This resets the node but does not remove it.
+ */
+static int
+ng_ether_rmnode(node_p node)
+{
+ ng_cutlinks(node);
+ node->flags &= ~NG_INVALID; /* bounce back to life */
+ return (0);
+}
+
+/*
+ * Hook disconnection.
+ */
+static int
+ng_ether_disconnect(hook_p hook)
+{
+ const priv_p priv = hook->node->private;
+
+ if (hook == priv->upper)
+ priv->upper = NULL;
+ else if (hook == priv->lower) {
+ priv->lower = NULL;
+ priv->lowerOrphan = 0;
+ } else
+ panic("%s: weird hook", __FUNCTION__);
+ return (0);
+}
+
+/******************************************************************
+ INITIALIZATION
+******************************************************************/
+
+/*
+ * Handle loading and unloading for this node type.
+ */
+static int
+ng_ether_mod_event(module_t mod, int event, void *data)
+{
+ struct ifnet *ifp;
+ int error = 0;
+ int s;
+
+ s = splnet();
+ switch (event) {
+ case MOD_LOAD:
+
+ /* Register function hooks */
+ if (ng_ether_attach_p != NULL) {
+ error = EEXIST;
+ break;
+ }
+ ng_ether_attach_p = ng_ether_attach;
+ ng_ether_detach_p = ng_ether_detach;
+ ng_ether_output_p = ng_ether_output;
+ ng_ether_input_p = ng_ether_input;
+ ng_ether_input_orphan_p = ng_ether_input_orphan;
+
+ /* Create nodes for any already-existing Ethernet interfaces */
+ TAILQ_FOREACH(ifp, &ifnet, if_link) {
+ if (ifp->if_type == IFT_ETHER)
+ ng_ether_attach(ifp);
+ }
+ break;
+
+ case MOD_UNLOAD:
+
+ /*
+ * Note that the base code won't try to unload us until
+ * all nodes have been removed, and that can't happen
+ * until all Ethernet interfaces are removed. In any
+ * case, we know there are no nodes left if the action
+ * is MOD_UNLOAD, so there's no need to detach any nodes.
+ */
+
+ /* Unregister function hooks */
+ ng_ether_attach_p = NULL;
+ ng_ether_detach_p = NULL;
+ ng_ether_output_p = NULL;
+ ng_ether_input_p = NULL;
+ ng_ether_input_orphan_p = NULL;
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ splx(s);
+ return (error);
+}
+
diff --git a/sys/netinet/ip_encap.c b/sys/netinet/ip_encap.c
new file mode 100644
index 0000000000000..de833344f2f46
--- /dev/null
+++ b/sys/netinet/ip_encap.c
@@ -0,0 +1,534 @@
+/* $FreeBSD$ */
+/* $KAME: ip_encap.c,v 1.36 2000/06/17 20:34:24 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+/*
+ * My grandfather said that there's a devil inside tunnelling technology...
+ *
+ * We have surprisingly many protocols that want packets with IP protocol
+ * #4 or #41. Here's a list of protocols that want protocol #41:
+ * RFC1933 configured tunnel
+ * RFC1933 automatic tunnel
+ * RFC2401 IPsec tunnel
+ * RFC2473 IPv6 generic packet tunnelling
+ * RFC2529 6over4 tunnel
+ * mobile-ip6 (uses RFC2473)
+ * 6to4 tunnel
+ * Here's a list of protocol that want protocol #4:
+ * RFC1853 IPv4-in-IPv4 tunnelling
+ * RFC2003 IPv4 encapsulation within IPv4
+ * RFC2344 reverse tunnelling for mobile-ip4
+ * RFC2401 IPsec tunnel
+ * Well, what can I say. They impose different en/decapsulation mechanism
+ * from each other, so they need separate protocol handler. The only one
+ * we can easily determine by protocol # is IPsec, which always has
+ * AH/ESP/IPComp header right after outer IP header.
+ *
+ * So, clearly good old protosw does not work for protocol #4 and #41.
+ * The code will let you match protocol via src/dst address pair.
+ */
+/* XXX is M_NETADDR correct? */
+
+#include "opt_mrouting.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/errno.h>
+#include <sys/protosw.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_encap.h>
+#ifdef MROUTING
+#include <netinet/ip_mroute.h>
+#endif /* MROUTING */
+#include <netinet/ipprotosw.h>
+
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/ip6protosw.h>
+#endif
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
+
+static void encap_add __P((struct encaptab *));
+static int mask_match __P((const struct encaptab *, const struct sockaddr *,
+ const struct sockaddr *));
+static void encap_fillarg __P((struct mbuf *, const struct encaptab *));
+
+/* rely upon BSS initialization */
+LIST_HEAD(, encaptab) encaptab;
+
+void
+encap_init()
+{
+#if 0
+ /*
+ * we cannot use LIST_INIT() here, since drivers may want to call
+ * encap_attach(), on driver attach. encap_init() will be called
+ * on AF_INET{,6} initialization, which happens after driver
+ * initialization - using LIST_INIT() here can nuke encap_attach()
+ * from drivers.
+ */
+ LIST_INIT(&encaptab);
+#endif
+}
+
+void
+#if __STDC__
+encap4_input(struct mbuf *m, ...)
+#else
+encap4_input(m, va_alist)
+ struct mbuf *m;
+ va_dcl
+#endif
+{
+ int off, proto;
+ struct ip *ip;
+ struct sockaddr_in s, d;
+ const struct ipprotosw *psw;
+ struct encaptab *ep, *match;
+ va_list ap;
+ int prio, matchprio;
+
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
+
+ ip = mtod(m, struct ip *);
+
+ bzero(&s, sizeof(s));
+ s.sin_family = AF_INET;
+ s.sin_len = sizeof(struct sockaddr_in);
+ s.sin_addr = ip->ip_src;
+ bzero(&d, sizeof(d));
+ d.sin_family = AF_INET;
+ d.sin_len = sizeof(struct sockaddr_in);
+ d.sin_addr = ip->ip_dst;
+
+ match = NULL;
+ matchprio = 0;
+ for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
+ if (ep->af != AF_INET)
+ continue;
+ if (ep->proto >= 0 && ep->proto != proto)
+ continue;
+ if (ep->func)
+ prio = (*ep->func)(m, off, proto, ep->arg);
+ else {
+ /*
+ * it's inbound traffic, we need to match in reverse
+ * order
+ */
+ prio = mask_match(ep, (struct sockaddr *)&d,
+ (struct sockaddr *)&s);
+ }
+
+ /*
+ * We prioritize the matches by using bit length of the
+ * matches. mask_match() and user-supplied matching function
+ * should return the bit length of the matches (for example,
+ * if both src/dst are matched for IPv4, 64 should be returned).
+ * 0 or negative return value means "it did not match".
+ *
+ * The question is, since we have two "mask" portion, we
+ * cannot really define total order between entries.
+ * For example, which of these should be preferred?
+ * mask_match() returns 48 (32 + 16) for both of them.
+ * src=3ffe::/16, dst=3ffe:501::/32
+ * src=3ffe:501::/32, dst=3ffe::/16
+ *
+ * We need to loop through all the possible candidates
+ * to get the best match - the search takes O(n) for
+ * n attachments (i.e. interfaces).
+ */
+ if (prio <= 0)
+ continue;
+ if (prio > matchprio) {
+ matchprio = prio;
+ match = ep;
+ }
+ }
+
+ if (match) {
+ /* found a match, "match" has the best one */
+ psw = (const struct ipprotosw *)match->psw;
+ if (psw && psw->pr_input) {
+ encap_fillarg(m, match);
+ (*psw->pr_input)(m, off, proto);
+ } else
+ m_freem(m);
+ return;
+ }
+
+ /* for backward compatibility */
+# ifdef MROUTING
+# define COMPATFUNC ipip_input
+# endif /*MROUTING*/
+
+#ifdef COMPATFUNC
+ if (proto == IPPROTO_IPV4) {
+ COMPATFUNC(m, off, proto);
+ return;
+ }
+#endif
+
+ /* last resort: inject to raw socket */
+ rip_input(m, off, proto);
+}
+
+#ifdef INET6
+int
+encap6_input(mp, offp, proto)
+ struct mbuf **mp;
+ int *offp;
+ int proto;
+{
+ struct mbuf *m = *mp;
+ struct ip6_hdr *ip6;
+ struct sockaddr_in6 s, d;
+ const struct ip6protosw *psw;
+ struct encaptab *ep, *match;
+ int prio, matchprio;
+
+ ip6 = mtod(m, struct ip6_hdr *);
+
+ bzero(&s, sizeof(s));
+ s.sin6_family = AF_INET6;
+ s.sin6_len = sizeof(struct sockaddr_in6);
+ s.sin6_addr = ip6->ip6_src;
+ bzero(&d, sizeof(d));
+ d.sin6_family = AF_INET6;
+ d.sin6_len = sizeof(struct sockaddr_in6);
+ d.sin6_addr = ip6->ip6_dst;
+
+ match = NULL;
+ matchprio = 0;
+ for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
+ if (ep->af != AF_INET6)
+ continue;
+ if (ep->proto >= 0 && ep->proto != proto)
+ continue;
+ if (ep->func)
+ prio = (*ep->func)(m, *offp, proto, ep->arg);
+ else {
+ /*
+ * it's inbound traffic, we need to match in reverse
+ * order
+ */
+ prio = mask_match(ep, (struct sockaddr *)&d,
+ (struct sockaddr *)&s);
+ }
+
+ /* see encap4_input() for issues here */
+ if (prio <= 0)
+ continue;
+ if (prio > matchprio) {
+ matchprio = prio;
+ match = ep;
+ }
+ }
+
+ if (match) {
+ /* found a match */
+ psw = (const struct ip6protosw *)match->psw;
+ if (psw && psw->pr_input) {
+ encap_fillarg(m, match);
+ return (*psw->pr_input)(mp, offp, proto);
+ } else {
+ m_freem(m);
+ return IPPROTO_DONE;
+ }
+ }
+
+ /* last resort: inject to raw socket */
+ return rip6_input(mp, offp, proto);
+}
+#endif
+
+static void
+encap_add(ep)
+ struct encaptab *ep;
+{
+
+ LIST_INSERT_HEAD(&encaptab, ep, chain);
+}
+
+/*
+ * sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
+ * length of mask (sm and dm) is assumed to be same as sp/dp.
+ * Return value will be necessary as input (cookie) for encap_detach().
+ */
+const struct encaptab *
+encap_attach(af, proto, sp, sm, dp, dm, psw, arg)
+ int af;
+ int proto;
+ const struct sockaddr *sp, *sm;
+ const struct sockaddr *dp, *dm;
+ const struct protosw *psw;
+ void *arg;
+{
+ struct encaptab *ep;
+ int error;
+ int s;
+
+ s = splnet();
+ /* sanity check on args */
+ if (sp->sa_len > sizeof(ep->src) || dp->sa_len > sizeof(ep->dst)) {
+ error = EINVAL;
+ goto fail;
+ }
+ if (sp->sa_len != dp->sa_len) {
+ error = EINVAL;
+ goto fail;
+ }
+ if (af != sp->sa_family || af != dp->sa_family) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ /* check if anyone have already attached with exactly same config */
+ for (ep = LIST_FIRST(&encaptab); ep; ep = LIST_NEXT(ep, chain)) {
+ if (ep->af != af)
+ continue;
+ if (ep->proto != proto)
+ continue;
+ if (ep->src.ss_len != sp->sa_len ||
+ bcmp(&ep->src, sp, sp->sa_len) != 0 ||
+ bcmp(&ep->srcmask, sm, sp->sa_len) != 0)
+ continue;
+ if (ep->dst.ss_len != dp->sa_len ||
+ bcmp(&ep->dst, dp, dp->sa_len) != 0 ||
+ bcmp(&ep->dstmask, dm, dp->sa_len) != 0)
+ continue;
+
+ error = EEXIST;
+ goto fail;
+ }
+
+ ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
+ if (ep == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ bzero(ep, sizeof(*ep));
+
+ ep->af = af;
+ ep->proto = proto;
+ bcopy(sp, &ep->src, sp->sa_len);
+ bcopy(sm, &ep->srcmask, sp->sa_len);
+ bcopy(dp, &ep->dst, dp->sa_len);
+ bcopy(dm, &ep->dstmask, dp->sa_len);
+ ep->psw = psw;
+ ep->arg = arg;
+
+ encap_add(ep);
+
+ error = 0;
+ splx(s);
+ return ep;
+
+fail:
+ splx(s);
+ return NULL;
+}
+
+const struct encaptab *
+encap_attach_func(af, proto, func, psw, arg)
+ int af;
+ int proto;
+ int (*func) __P((const struct mbuf *, int, int, void *));
+ const struct protosw *psw;
+ void *arg;
+{
+ struct encaptab *ep;
+ int error;
+ int s;
+
+ s = splnet();
+ /* sanity check on args */
+ if (!func) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
+ if (ep == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ bzero(ep, sizeof(*ep));
+
+ ep->af = af;
+ ep->proto = proto;
+ ep->func = func;
+ ep->psw = psw;
+ ep->arg = arg;
+
+ encap_add(ep);
+
+ error = 0;
+ splx(s);
+ return ep;
+
+fail:
+ splx(s);
+ return NULL;
+}
+
+int
+encap_detach(cookie)
+ const struct encaptab *cookie;
+{
+ const struct encaptab *ep = cookie;
+ struct encaptab *p;
+
+ for (p = LIST_FIRST(&encaptab); p; p = LIST_NEXT(p, chain)) {
+ if (p == ep) {
+ LIST_REMOVE(p, chain);
+ free(p, M_NETADDR); /*XXX*/
+ return 0;
+ }
+ }
+
+ return EINVAL;
+}
+
+static int
+mask_match(ep, sp, dp)
+ const struct encaptab *ep;
+ const struct sockaddr *sp;
+ const struct sockaddr *dp;
+{
+ struct sockaddr_storage s;
+ struct sockaddr_storage d;
+ int i;
+ const u_int8_t *p, *q;
+ u_int8_t *r;
+ int matchlen;
+
+ if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
+ return 0;
+ if (sp->sa_family != ep->af || dp->sa_family != ep->af)
+ return 0;
+ if (sp->sa_len != ep->src.ss_len || dp->sa_len != ep->dst.ss_len)
+ return 0;
+
+ matchlen = 0;
+
+ p = (const u_int8_t *)sp;
+ q = (const u_int8_t *)&ep->srcmask;
+ r = (u_int8_t *)&s;
+ for (i = 0 ; i < sp->sa_len; i++) {
+ r[i] = p[i] & q[i];
+ /* XXX estimate */
+ matchlen += (q[i] ? 8 : 0);
+ }
+
+ p = (const u_int8_t *)dp;
+ q = (const u_int8_t *)&ep->dstmask;
+ r = (u_int8_t *)&d;
+ for (i = 0 ; i < dp->sa_len; i++) {
+ r[i] = p[i] & q[i];
+ /* XXX rough estimate */
+ matchlen += (q[i] ? 8 : 0);
+ }
+
+ /* need to overwrite len/family portion as we don't compare them */
+ s.ss_len = sp->sa_len;
+ s.ss_family = sp->sa_family;
+ d.ss_len = dp->sa_len;
+ d.ss_family = dp->sa_family;
+
+ if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 &&
+ bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) {
+ return matchlen;
+ } else
+ return 0;
+}
+
+static void
+encap_fillarg(m, ep)
+ struct mbuf *m;
+ const struct encaptab *ep;
+{
+#if 0
+ m->m_pkthdr.aux = ep->arg;
+#else
+ struct mbuf *n;
+
+ n = m_aux_add(m, AF_INET, IPPROTO_IPV4);
+ if (n) {
+ *mtod(n, void **) = ep->arg;
+ n->m_len = sizeof(void *);
+ }
+#endif
+}
+
+void *
+encap_getarg(m)
+ struct mbuf *m;
+{
+ void *p;
+#if 0
+ p = m->m_pkthdr.aux;
+ m->m_pkthdr.aux = NULL;
+ return p;
+#else
+ struct mbuf *n;
+
+ p = NULL;
+ n = m_aux_find(m, AF_INET, IPPROTO_IPV4);
+ if (n) {
+ if (n->m_len == sizeof(void *))
+ p = *mtod(n, void **);
+ m_aux_delete(m, n);
+ }
+ return p;
+#endif
+}
diff --git a/sys/netinet/ip_encap.h b/sys/netinet/ip_encap.h
new file mode 100644
index 0000000000000..38df6f94784ca
--- /dev/null
+++ b/sys/netinet/ip_encap.h
@@ -0,0 +1,64 @@
+/* $FreeBSD$ */
+/* $KAME: ip_encap.h,v 1.7 2000/03/25 07:23:37 sumikawa Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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 _NETINET_IP_ENCAP_H_
+#define _NETINET_IP_ENCAP_H_
+
+#ifdef _KERNEL
+
+struct encaptab {
+ LIST_ENTRY(encaptab) chain;
+ int af;
+ int proto; /* -1: don't care, I'll check myself */
+ struct sockaddr_storage src; /* my addr */
+ struct sockaddr_storage srcmask;
+ struct sockaddr_storage dst; /* remote addr */
+ struct sockaddr_storage dstmask;
+ int (*func) __P((const struct mbuf *, int, int, void *));
+ const struct protosw *psw; /* only pr_input will be used */
+ void *arg; /* passed via m->m_pkthdr.aux */
+};
+
+void encap_init __P((void));
+void encap4_input __P((struct mbuf *, ...));
+int encap6_input __P((struct mbuf **, int *, int));
+const struct encaptab *encap_attach __P((int, int, const struct sockaddr *,
+ const struct sockaddr *, const struct sockaddr *,
+ const struct sockaddr *, const struct protosw *, void *));
+const struct encaptab *encap_attach_func __P((int, int,
+ int (*) __P((const struct mbuf *, int, int, void *)),
+ const struct protosw *, void *));
+int encap_detach __P((const struct encaptab *));
+void *encap_getarg __P((struct mbuf *));
+#endif
+
+#endif /*_NETINET_IP_ENCAP_H_*/
diff --git a/sys/netinet6/README b/sys/netinet6/README
new file mode 100644
index 0000000000000..70cec5e1c6250
--- /dev/null
+++ b/sys/netinet6/README
@@ -0,0 +1,81 @@
+a note to committers about KAME tree
+$FreeBSD$
+KAME project
+
+
+FreeBSD IPv6/IPsec tree is from KAMEproject (http://www.kame.net/).
+To synchronize KAME tree and FreeBSD better today and in the future,
+please understand the following:
+
+- DO NOT MAKE COSTMETIC CHANGES.
+ "Cosmetic changes" here includes tabify, untabify, removal of space at EOL,
+ minor KNF items, and whatever adds more output lines on "diff freebsd kame".
+ To make future synchronization easier. it is critical to preserve certain
+ statements in the code. Also, as KAME tree supports all 4 BSDs (Free, Open,
+ Net, BSD/OS) in single shared tree, it is not always possible to backport
+ FreeBSD changes into KAME tree. So again, please do not make cosmetic
+ changes. Even if you think it a right thing, that will bite KAME guys badly
+ during upgrade attempts, and prevent us from synchronizing two trees.
+ (you don't usually make cosmetic changes against third-party code, do you?)
+
+- REPORT CHANGES/BUGS TO KAME GUYS.
+ It is not always possible for KAME guys to watch all the freebsd mailing
+ list traffic, as the traffic is HUGE. So if possible, please, inform
+ kame guys of changes you made in IPv6/IPsec related portion. Contact
+ path would be snap-users@kame.net or KAME PR database on www.kame.net.
+ (or to core@kame.net if it is necessary to make it confidential)
+
+Thank you for your cooperation and have a happy IPv6 life!
+
+
+Note: KAME-origin code is in the following locations.
+The above notice applies to corresponding manpages too.
+The list may not be complete. If you see $KAME$ in the code, it is from
+KAME distribution. If you see some file that is IPv6/IPsec related, it is
+highly possible that the file is from KAME distribution.
+
+include/ifaddrs.h
+lib/libc/net
+lib/libc/net/getaddrinfo.c
+lib/libc/net/getifaddrs.c
+lib/libc/net/getnameinfo.c
+lib/libc/net/ifname.c
+lib/libc/net/ip6opt.c
+lib/libc/net/map_v4v6.c
+lib/libc/net/name6.c
+lib/libftpio
+lib/libipsec
+sbin/ip6fw
+sbin/ping6
+sbin/rtsol
+share/doc/IPv6
+share/man/man4/ip6.4
+share/man/man4/inet6.4
+sys/crypto (except sys/crypto/rc4)
+sys/kern/uipc_mbuf2.c
+sys/net/if_faith.[ch]
+sys/net/if_gif.[ch]
+sys/net/if_stf.[ch]
+sys/net/pfkeyv2.h
+sys/netinet/icmp6.h
+sys/netinet/in_gif.[ch]
+sys/netinet/ip6.h
+sys/netinet/ip_encap.[ch]
+sys/netinet6
+sys/netkey
+usr.sbin/faithd
+usr.sbin/gifconfig
+usr.sbin/ifmcstat
+usr.sbin/mld6query
+usr.sbin/ndp
+usr.sbin/pim6dd
+usr.sbin/pim6sd
+usr.sbin/prefix
+usr.sbin/rip6query
+usr.sbin/route6d
+usr.sbin/rrenumd
+usr.sbin/rtadvd
+usr.sbin/rtsold
+usr.sbin/scope6config
+usr.sbin/setkey
+usr.sbin/traceroute6
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
new file mode 100644
index 0000000000000..40b0df4fb5b13
--- /dev/null
+++ b/sys/netinet6/in6_src.c
@@ -0,0 +1,550 @@
+/* $FreeBSD$ */
+/* $KAME: in6_src.c,v 1.27 2000/06/21 08:07:13 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1991, 1993
+ * The Regents of the University of California. 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/in_pcb.h>
+#include <netinet6/in6_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/nd6.h>
+#ifdef ENABLE_DEFAULT_SCOPE
+#include <netinet6/scope6_var.h>
+#endif
+
+#include <net/net_osdep.h>
+
+#include "loop.h"
+
+/*
+ * Return an IPv6 address, which is the most appropriate for given
+ * destination and user specified options.
+ * If necessary, this function lookups the routing table and return
+ * an entry to the caller for later use.
+ */
+struct in6_addr *
+in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp)
+ struct sockaddr_in6 *dstsock;
+ struct ip6_pktopts *opts;
+ struct ip6_moptions *mopts;
+ struct route_in6 *ro;
+ struct in6_addr *laddr;
+ int *errorp;
+{
+ struct in6_addr *dst;
+ struct in6_ifaddr *ia6 = 0;
+ struct in6_pktinfo *pi = NULL;
+
+ dst = &dstsock->sin6_addr;
+ *errorp = 0;
+
+ /*
+ * If the source address is explicitly specified by the caller,
+ * use it.
+ */
+ if (opts && (pi = opts->ip6po_pktinfo) &&
+ !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
+ return(&pi->ipi6_addr);
+
+ /*
+ * If the source address is not specified but the socket(if any)
+ * is already bound, use the bound address.
+ */
+ if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr))
+ return(laddr);
+
+ /*
+ * If the caller doesn't specify the source address but
+ * the outgoing interface, use an address associated with
+ * the interface.
+ */
+ if (pi && pi->ipi6_ifindex) {
+ /* XXX boundary check is assumed to be already done. */
+ ia6 = in6_ifawithscope(ifindex2ifnet[pi->ipi6_ifindex],
+ dst);
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+
+ /*
+ * If the destination address is a link-local unicast address or
+ * a multicast address, and if the outgoing interface is specified
+ * by the sin6_scope_id filed, use an address associated with the
+ * interface.
+ * XXX: We're now trying to define more specific semantics of
+ * sin6_scope_id field, so this part will be rewritten in
+ * the near future.
+ */
+ if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) &&
+ dstsock->sin6_scope_id) {
+ /*
+ * I'm not sure if boundary check for scope_id is done
+ * somewhere...
+ */
+ if (dstsock->sin6_scope_id < 0 ||
+ if_index < dstsock->sin6_scope_id) {
+ *errorp = ENXIO; /* XXX: better error? */
+ return(0);
+ }
+ ia6 = in6_ifawithscope(ifindex2ifnet[dstsock->sin6_scope_id],
+ dst);
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+
+ /*
+ * If the destination address is a multicast address and
+ * the outgoing interface for the address is specified
+ * by the caller, use an address associated with the interface.
+ * There is a sanity check here; if the destination has node-local
+ * scope, the outgoing interfacde should be a loopback address.
+ * Even if the outgoing interface is not specified, we also
+ * choose a loopback interface as the outgoing interface.
+ */
+ if (IN6_IS_ADDR_MULTICAST(dst)) {
+ struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL;
+
+ if (ifp == NULL && IN6_IS_ADDR_MC_NODELOCAL(dst)) {
+ ifp = &loif[0];
+ }
+
+ if (ifp) {
+ ia6 = in6_ifawithscope(ifp, dst);
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+ }
+
+ /*
+ * If the next hop address for the packet is specified
+ * by caller, use an address associated with the route
+ * to the next hop.
+ */
+ {
+ struct sockaddr_in6 *sin6_next;
+ struct rtentry *rt;
+
+ if (opts && opts->ip6po_nexthop) {
+ sin6_next = satosin6(opts->ip6po_nexthop);
+ rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL);
+ if (rt) {
+ ia6 = in6_ifawithscope(rt->rt_ifp, dst);
+ if (ia6 == 0)
+ ia6 = ifatoia6(rt->rt_ifa);
+ }
+ if (ia6 == 0) {
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+ }
+
+ /*
+ * If route is known or can be allocated now,
+ * our src addr is taken from the i/f, else punt.
+ */
+ if (ro) {
+ if (ro->ro_rt &&
+ !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, dst)) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = (struct rtentry *)0;
+ }
+ if (ro->ro_rt == (struct rtentry *)0 ||
+ ro->ro_rt->rt_ifp == (struct ifnet *)0) {
+ /* No route yet, so try to acquire one */
+ bzero(&ro->ro_dst, sizeof(struct sockaddr_in6));
+ ro->ro_dst.sin6_family = AF_INET6;
+ ro->ro_dst.sin6_len = sizeof(struct sockaddr_in6);
+ ro->ro_dst.sin6_addr = *dst;
+ ro->ro_dst.sin6_scope_id = dstsock->sin6_scope_id;
+ if (IN6_IS_ADDR_MULTICAST(dst)) {
+ ro->ro_rt = rtalloc1(&((struct route *)ro)
+ ->ro_dst, 0, 0UL);
+ } else {
+ rtalloc((struct route *)ro);
+ }
+ }
+
+ /*
+ * in_pcbconnect() checks out IFF_LOOPBACK to skip using
+ * the address. But we don't know why it does so.
+ * It is necessary to ensure the scope even for lo0
+ * so doesn't check out IFF_LOOPBACK.
+ */
+
+ if (ro->ro_rt) {
+ ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst);
+ if (ia6 == 0) /* xxx scope error ?*/
+ ia6 = ifatoia6(ro->ro_rt->rt_ifa);
+ }
+#if 0
+ /*
+ * xxx The followings are necessary? (kazu)
+ * I don't think so.
+ * It's for SO_DONTROUTE option in IPv4.(jinmei)
+ */
+ if (ia6 == 0) {
+ struct sockaddr_in6 sin6 = {sizeof(sin6), AF_INET6, 0};
+
+ sin6->sin6_addr = *dst;
+
+ ia6 = ifatoia6(ifa_ifwithdstaddr(sin6tosa(&sin6)));
+ if (ia6 == 0)
+ ia6 = ifatoia6(ifa_ifwithnet(sin6tosa(&sin6)));
+ if (ia6 == 0)
+ return(0);
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+#endif /* 0 */
+ if (ia6 == 0) {
+ *errorp = EHOSTUNREACH; /* no route */
+ return(0);
+ }
+ return(&satosin6(&ia6->ia_addr)->sin6_addr);
+ }
+
+ *errorp = EADDRNOTAVAIL;
+ return(0);
+}
+
+/*
+ * Default hop limit selection. The precedence is as follows:
+ * 1. Hoplimit value specified via ioctl.
+ * 2. (If the outgoing interface is detected) the current
+ * hop limit of the interface specified by router advertisement.
+ * 3. The system default hoplimit.
+*/
+int
+in6_selecthlim(in6p, ifp)
+ struct in6pcb *in6p;
+ struct ifnet *ifp;
+{
+ if (in6p && in6p->in6p_hops >= 0)
+ return(in6p->in6p_hops);
+ else if (ifp)
+ return(nd_ifinfo[ifp->if_index].chlim);
+ else
+ return(ip6_defhlim);
+}
+
+/*
+ * XXX: this is borrowed from in6_pcbbind(). If possible, we should
+ * share this function by all *bsd*...
+ */
+int
+in6_pcbsetport(laddr, inp, p)
+ struct in6_addr *laddr;
+ struct inpcb *inp;
+ struct proc *p;
+{
+ struct socket *so = inp->inp_socket;
+ u_int16_t lport = 0, first, last, *lastport;
+ int count, error = 0, wild = 0;
+ struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
+
+ /* XXX: this is redundant when called from in6_pcbbind */
+ if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
+ wild = INPLOOKUP_WILDCARD;
+
+ inp->inp_flags |= INP_ANONPORT;
+
+ if (inp->inp_flags & INP_HIGHPORT) {
+ first = ipport_hifirstauto; /* sysctl */
+ last = ipport_hilastauto;
+ lastport = &pcbinfo->lasthi;
+ } else if (inp->inp_flags & INP_LOWPORT) {
+ if (p && (error = suser(p)))
+ return error;
+ first = ipport_lowfirstauto; /* 1023 */
+ last = ipport_lowlastauto; /* 600 */
+ lastport = &pcbinfo->lastlow;
+ } else {
+ first = ipport_firstauto; /* sysctl */
+ last = ipport_lastauto;
+ lastport = &pcbinfo->lastport;
+ }
+ /*
+ * Simple check to ensure all ports are not used up causing
+ * a deadlock here.
+ *
+ * We split the two cases (up and down) so that the direction
+ * is not being tested on each round of the loop.
+ */
+ if (first > last) {
+ /*
+ * counting down
+ */
+ count = first - last;
+
+ do {
+ if (count-- < 0) { /* completely used? */
+ /*
+ * Undo any address bind that may have
+ * occurred above.
+ */
+ inp->in6p_laddr = in6addr_any;
+ return (EAGAIN);
+ }
+ --*lastport;
+ if (*lastport > first || *lastport < last)
+ *lastport = first;
+ lport = htons(*lastport);
+ } while (in6_pcblookup_local(pcbinfo,
+ &inp->in6p_laddr, lport, wild));
+ } else {
+ /*
+ * counting up
+ */
+ count = last - first;
+
+ do {
+ if (count-- < 0) { /* completely used? */
+ /*
+ * Undo any address bind that may have
+ * occurred above.
+ */
+ inp->in6p_laddr = in6addr_any;
+ return (EAGAIN);
+ }
+ ++*lastport;
+ if (*lastport < first || *lastport > last)
+ *lastport = first;
+ lport = htons(*lastport);
+ } while (in6_pcblookup_local(pcbinfo,
+ &inp->in6p_laddr, lport, wild));
+ }
+
+ inp->inp_lport = lport;
+ if (in_pcbinshash(inp) != 0) {
+ inp->in6p_laddr = in6addr_any;
+ inp->inp_lport = 0;
+ return (EAGAIN);
+ }
+
+ return(0);
+}
+
+/*
+ * generate kernel-internal form (scopeid embedded into s6_addr16[1]).
+ * If the address scope of is link-local, embed the interface index in the
+ * address. The routine determines our precedence
+ * between advanced API scope/interface specification and basic API
+ * specification.
+ *
+ * this function should be nuked in the future, when we get rid of
+ * embedded scopeid thing.
+ *
+ * XXX actually, it is over-specification to return ifp against sin6_scope_id.
+ * there can be multiple interfaces that belong to a particular scope zone
+ * (in specification, we have 1:N mapping between a scope zone and interfaces).
+ * we may want to change the function to return something other than ifp.
+ */
+int
+in6_embedscope(in6, sin6, in6p, ifpp)
+ struct in6_addr *in6;
+ const struct sockaddr_in6 *sin6;
+#ifdef HAVE_NRL_INPCB
+ struct inpcb *in6p;
+#define in6p_outputopts inp_outputopts6
+#define in6p_moptions inp_moptions6
+#else
+ struct in6pcb *in6p;
+#endif
+ struct ifnet **ifpp;
+{
+ struct ifnet *ifp = NULL;
+ u_int32_t scopeid;
+
+ *in6 = sin6->sin6_addr;
+ scopeid = sin6->sin6_scope_id;
+ if (ifpp)
+ *ifpp = NULL;
+
+ /*
+ * don't try to read sin6->sin6_addr beyond here, since the caller may
+ * ask us to overwrite existing sockaddr_in6
+ */
+
+#ifdef ENABLE_DEFAULT_SCOPE
+ if (scopeid == 0)
+ scopeid = scope6_addr2default(in6);
+#endif
+
+ if (IN6_IS_SCOPE_LINKLOCAL(in6)) {
+ struct in6_pktinfo *pi;
+
+ /*
+ * KAME assumption: link id == interface id
+ */
+
+ if (in6p && in6p->in6p_outputopts &&
+ (pi = in6p->in6p_outputopts->ip6po_pktinfo) &&
+ pi->ipi6_ifindex) {
+ ifp = ifindex2ifnet[pi->ipi6_ifindex];
+ in6->s6_addr16[1] = htons(pi->ipi6_ifindex);
+ } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) &&
+ in6p->in6p_moptions &&
+ in6p->in6p_moptions->im6o_multicast_ifp) {
+ ifp = in6p->in6p_moptions->im6o_multicast_ifp;
+ in6->s6_addr16[1] = htons(ifp->if_index);
+ } else if (scopeid) {
+ /* boundary check */
+ if (scopeid < 0 || if_index < scopeid)
+ return ENXIO; /* XXX EINVAL? */
+ ifp = ifindex2ifnet[scopeid];
+ /*XXX assignment to 16bit from 32bit variable */
+ in6->s6_addr16[1] = htons(scopeid & 0xffff);
+ }
+
+ if (ifpp)
+ *ifpp = ifp;
+ }
+
+ return 0;
+}
+#ifdef HAVE_NRL_INPCB
+#undef in6p_outputopts
+#undef in6p_moptions
+#endif
+
+/*
+ * generate standard sockaddr_in6 from embedded form.
+ * touches sin6_addr and sin6_scope_id only.
+ *
+ * this function should be nuked in the future, when we get rid of
+ * embedded scopeid thing.
+ */
+int
+in6_recoverscope(sin6, in6, ifp)
+ struct sockaddr_in6 *sin6;
+ const struct in6_addr *in6;
+ struct ifnet *ifp;
+{
+ u_int32_t scopeid;
+
+ sin6->sin6_addr = *in6;
+
+ /*
+ * don't try to read *in6 beyond here, since the caller may
+ * ask us to overwrite existing sockaddr_in6
+ */
+
+ sin6->sin6_scope_id = 0;
+ if (IN6_IS_SCOPE_LINKLOCAL(in6)) {
+ /*
+ * KAME assumption: link id == interface id
+ */
+ scopeid = ntohs(sin6->sin6_addr.s6_addr16[1]);
+ if (scopeid) {
+ /* sanity check */
+ if (scopeid < 0 || if_index < scopeid)
+ return ENXIO;
+#ifndef FAKE_LOOPBACK_IF
+ if (ifp && (ifp->if_flags & IFF_LOOPBACK) == 0 &&
+ ifp->if_index != scopeid) {
+ return ENXIO;
+ }
+#else
+ if (ifp && ifp->if_index != scopeid)
+ return ENXIO;
+#endif
+ sin6->sin6_addr.s6_addr16[1] = 0;
+ sin6->sin6_scope_id = scopeid;
+ }
+ }
+
+ return 0;
+}
diff --git a/sys/netinet6/ipcomp.h b/sys/netinet6/ipcomp.h
new file mode 100644
index 0000000000000..dea5ea8e7097e
--- /dev/null
+++ b/sys/netinet6/ipcomp.h
@@ -0,0 +1,67 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp.h,v 1.7 2000/05/18 12:45:13 sumikawa Exp $ */
+
+/*
+ * Copyright (C) 1999 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#ifndef _NETINET6_IPCOMP_H_
+#define _NETINET6_IPCOMP_H_
+
+struct ipcomp {
+ u_int8_t comp_nxt; /* Next Header */
+ u_int8_t comp_flags; /* reserved, must be zero */
+ u_int16_t comp_cpi; /* Compression parameter index */
+};
+
+/* well-known algorithm number (in CPI), from RFC2409 */
+#define IPCOMP_OUI 1 /* vendor specific */
+#define IPCOMP_DEFLATE 2 /* RFC2394 */
+#define IPCOMP_LZS 3 /* RFC2395 */
+#define IPCOMP_MAX 4
+
+#define IPCOMP_CPI_NEGOTIATE_MIN 256
+
+#ifdef _KERNEL
+struct ipcomp_algorithm {
+ int (*compress) __P((struct mbuf *, struct mbuf *, size_t *));
+ int (*decompress) __P((struct mbuf *, struct mbuf *, size_t *));
+ size_t minplen; /* minimum required length for compression */
+};
+
+struct ipsecrequest;
+extern struct ipcomp_algorithm ipcomp_algorithms[];
+extern void ipcomp4_input __P((struct mbuf *, ...));
+extern int ipcomp4_output __P((struct mbuf *, struct ipsecrequest *));
+#endif /*KERNEL*/
+
+#endif /*_NETINET6_IPCOMP_H_*/
diff --git a/sys/netinet6/ipcomp6.h b/sys/netinet6/ipcomp6.h
new file mode 100644
index 0000000000000..553c8df7c4f4d
--- /dev/null
+++ b/sys/netinet6/ipcomp6.h
@@ -0,0 +1,46 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp.h,v 1.7 2000/05/18 12:45:13 sumikawa Exp $ */
+
+/*
+ * Copyright (C) 1999 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#ifndef _NETINET6_IPCOMP6_H_
+#define _NETINET6_IPCOMP6_H_
+
+#ifdef _KERNEL
+extern int ipcomp6_input __P((struct mbuf **, int *, int));
+extern int ipcomp6_output __P((struct mbuf *, u_char *, struct mbuf *,
+ struct ipsecrequest *));
+#endif /*KERNEL*/
+
+#endif /*_NETINET6_IPCOMP6_H_*/
diff --git a/sys/netinet6/ipcomp_core.c b/sys/netinet6/ipcomp_core.c
new file mode 100644
index 0000000000000..1eee2538b9686
--- /dev/null
+++ b/sys/netinet6/ipcomp_core.c
@@ -0,0 +1,314 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp_core.c,v 1.12 2000/05/05 11:01:01 sumikawa Exp $ */
+
+/*
+ * Copyright (C) 1999 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/zlib.h>
+#include <machine/cpu.h>
+
+#include <netinet6/ipcomp.h>
+#ifdef INET6
+#include <netinet6/ipcomp6.h>
+#endif
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+static void *deflate_alloc __P((void *, u_int, u_int));
+static void deflate_free __P((void *, void *));
+static int deflate_common __P((struct mbuf *, struct mbuf *, size_t *, int));
+static int deflate_compress __P((struct mbuf *, struct mbuf *, size_t *));
+static int deflate_decompress __P((struct mbuf *, struct mbuf *, size_t *));
+
+/*
+ * We need to use default window size (2^15 = 32Kbytes as of writing) for
+ * inbound case. Otherwise we get interop problem.
+ * Use negative value to avoid Adler32 checksum. This is an undocumented
+ * feature in zlib (see ipsec wg mailing list archive in January 2000).
+ */
+static int deflate_policy = Z_DEFAULT_COMPRESSION;
+static int deflate_window_out = -12;
+static const int deflate_window_in = -1 * MAX_WBITS; /* don't change it */
+static int deflate_memlevel = MAX_MEM_LEVEL;
+
+struct ipcomp_algorithm ipcomp_algorithms[] = {
+ { NULL, NULL, -1 },
+ { NULL, NULL, -1 },
+ { deflate_compress, deflate_decompress, 90 },
+ { NULL, NULL, 90 },
+};
+
+static void *
+deflate_alloc(aux, items, siz)
+ void *aux;
+ u_int items;
+ u_int siz;
+{
+ void *ptr;
+ MALLOC(ptr, void *, items * siz, M_TEMP, M_NOWAIT);
+ return ptr;
+}
+
+static void
+deflate_free(aux, ptr)
+ void *aux;
+ void *ptr;
+{
+ FREE(ptr, M_TEMP);
+}
+
+static int
+deflate_common(m, md, lenp, mode)
+ struct mbuf *m;
+ struct mbuf *md;
+ size_t *lenp;
+ int mode; /* 0: compress 1: decompress */
+{
+ struct mbuf *mprev;
+ struct mbuf *p;
+ struct mbuf *n, *n0 = NULL, **np;
+ z_stream zs;
+ int error = 0;
+ int zerror;
+ size_t offset;
+ int firsttime, final, flush;
+
+ for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
+ ;
+ if (!mprev)
+ panic("md is not in m in deflate_common");
+
+ bzero(&zs, sizeof(zs));
+ zs.zalloc = deflate_alloc;
+ zs.zfree = deflate_free;
+
+ zerror = mode ? inflateInit2(&zs, deflate_window_in)
+ : deflateInit2(&zs, deflate_policy, Z_DEFLATED,
+ deflate_window_out, deflate_memlevel,
+ Z_DEFAULT_STRATEGY);
+ if (zerror != Z_OK) {
+ error = ENOBUFS;
+ goto fail;
+ }
+
+ n0 = n = NULL;
+ np = &n0;
+ offset = 0;
+ firsttime = 1;
+ final = 0;
+ flush = Z_NO_FLUSH;
+ zerror = 0;
+ p = md;
+ while (1) {
+ /*
+ * first time, we need to setup the buffer before calling
+ * compression function.
+ */
+ if (firsttime)
+ firsttime = 0;
+ else {
+ zerror = mode ? inflate(&zs, flush)
+ : deflate(&zs, flush);
+ }
+
+ /* get input buffer */
+ if (p && zs.avail_in == 0) {
+ zs.next_in = mtod(p, u_int8_t *);
+ zs.avail_in = p->m_len;
+ p = p->m_next;
+ if (!p) {
+ final = 1;
+ flush = Z_PARTIAL_FLUSH;
+ }
+ }
+
+ /* get output buffer */
+ if (zs.next_out == NULL || zs.avail_out == 0) {
+ /* keep the reply buffer into our chain */
+ if (n) {
+ n->m_len = zs.total_out - offset;
+ offset = zs.total_out;
+ *np = n;
+ np = &n->m_next;
+ }
+
+ /* get a fresh reply buffer */
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (n) {
+ MCLGET(n, M_DONTWAIT);
+ }
+ if (!n) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ n->m_len = 0;
+ n->m_len = M_TRAILINGSPACE(n);
+ n->m_next = NULL;
+ /*
+ * if this is the first reply buffer, reserve
+ * region for ipcomp header.
+ */
+ if (*np == NULL) {
+ n->m_len -= sizeof(struct ipcomp);
+ n->m_data += sizeof(struct ipcomp);
+ }
+
+ zs.next_out = mtod(n, u_int8_t *);
+ zs.avail_out = n->m_len;
+ }
+
+ if (zerror == Z_OK) {
+ /*
+ * to terminate deflate/inflate process, we need to
+ * call {in,de}flate() with different flushing methods.
+ *
+ * deflate() needs at least one Z_PARTIAL_FLUSH,
+ * then use Z_FINISH until we get to the end.
+ * (if we use Z_FLUSH without Z_PARTIAL_FLUSH, deflate()
+ * will assume contiguous single output buffer, and that
+ * is not what we want)
+ * inflate() does not care about flushing method, but
+ * needs output buffer until it gets to the end.
+ *
+ * the most outer loop will be terminated with
+ * Z_STREAM_END.
+ */
+ if (final == 1) {
+ /* reached end of mbuf chain */
+ if (mode == 0)
+ final = 2;
+ else
+ final = 3;
+ } else if (final == 2) {
+ /* terminate deflate case */
+ flush = Z_FINISH;
+ } else if (final == 3) {
+ /* terminate inflate case */
+ ;
+ }
+ } else if (zerror == Z_STREAM_END)
+ break;
+ else {
+ ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n",
+ mode ? "de" : "", mode ? "in" : "de",
+ zs.msg ? zs.msg : "unknown error"));
+ error = EINVAL;
+ goto fail;
+ }
+ }
+ zerror = mode ? inflateEnd(&zs) : deflateEnd(&zs);
+ if (zerror != Z_OK) {
+ ipseclog((LOG_ERR, "ipcomp_%scompress: %sflate: %s\n",
+ mode ? "de" : "", mode ? "in" : "de",
+ zs.msg ? zs.msg : "unknown error"));
+ error = EINVAL;
+ goto fail;
+ }
+ /* keep the final reply buffer into our chain */
+ if (n) {
+ n->m_len = zs.total_out - offset;
+ offset = zs.total_out;
+ *np = n;
+ np = &n->m_next;
+ }
+
+ /* switch the mbuf to the new one */
+ mprev->m_next = n0;
+ m_freem(md);
+ *lenp = zs.total_out;
+
+ return 0;
+
+fail:
+ if (m)
+ m_freem(m);
+ if (n0)
+ m_freem(n0);
+ return error;
+}
+
+static int
+deflate_compress(m, md, lenp)
+ struct mbuf *m;
+ struct mbuf *md;
+ size_t *lenp;
+{
+ if (!m)
+ panic("m == NULL in deflate_compress");
+ if (!md)
+ panic("md == NULL in deflate_compress");
+ if (!lenp)
+ panic("lenp == NULL in deflate_compress");
+
+ return deflate_common(m, md, lenp, 0);
+}
+
+static int
+deflate_decompress(m, md, lenp)
+ struct mbuf *m;
+ struct mbuf *md;
+ size_t *lenp;
+{
+ if (!m)
+ panic("m == NULL in deflate_decompress");
+ if (!md)
+ panic("md == NULL in deflate_decompress");
+ if (!lenp)
+ panic("lenp == NULL in deflate_decompress");
+
+ return deflate_common(m, md, lenp, 1);
+}
diff --git a/sys/netinet6/ipcomp_input.c b/sys/netinet6/ipcomp_input.c
new file mode 100644
index 0000000000000..da0184c82c7a5
--- /dev/null
+++ b/sys/netinet6/ipcomp_input.c
@@ -0,0 +1,407 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp_input.c,v 1.15 2000/07/03 13:23:28 itojun Exp $ */
+
+/*
+ * Copyright (C) 1999 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/zlib.h>
+#include <machine/cpu.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_ecn.h>
+
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
+#include <netinet6/ipcomp.h>
+#ifdef INET6
+#include <netinet6/ipcomp6.h>
+#endif
+
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+#include <netkey/key.h>
+#include <netkey/keydb.h>
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+#define IPLEN_FLIPPED
+
+#ifdef INET
+#include <netinet/ipprotosw.h>
+extern struct ipprotosw inetsw[];
+
+void
+#if __STDC__
+ipcomp4_input(struct mbuf *m, ...)
+#else
+ipcomp4_input(m, va_alist)
+ struct mbuf *m;
+ va_dcl
+#endif
+{
+ struct ip *ip;
+ struct ipcomp *ipcomp;
+ struct ipcomp_algorithm *algo;
+ u_int16_t cpi; /* host order */
+ u_int16_t nxt;
+ size_t hlen;
+ int error;
+ size_t newlen, olen;
+ struct secasvar *sav = NULL;
+ int off, proto;
+ va_list ap;
+
+ va_start(ap, m);
+ off = va_arg(ap, int);
+ proto = va_arg(ap, int);
+ va_end(ap);
+
+ if (off + sizeof(struct ipcomp) > MHLEN) {
+ /*XXX the restriction should be relaxed*/
+ ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed "
+ "(header too long)\n"));
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+ if (m->m_len < off + sizeof(struct ipcomp)) {
+ m = m_pullup(m, off + sizeof(struct ipcomp));
+ if (!m) {
+ ipseclog((LOG_DEBUG, "IPv4 IPComp input: can't pullup;"
+ "dropping the packet for simplicity\n"));
+ ipsecstat.in_nomem++;
+ goto fail;
+ }
+ } else if (m->m_len > off + sizeof(struct ipcomp)) {
+ /* chop header part from the packet header chain */
+ struct mbuf *n;
+ MGETHDR(n, M_DONTWAIT, MT_HEADER);
+ if (!n) {
+ ipsecstat.in_nomem++;
+ goto fail;
+ }
+ M_COPY_PKTHDR(n, m);
+ MH_ALIGN(n, off + sizeof(struct ipcomp));
+ n->m_len = off + sizeof(struct ipcomp);
+ bcopy(mtod(m, caddr_t), mtod(n, caddr_t),
+ off + sizeof(struct ipcomp));
+ m_adj(m, off + sizeof(struct ipcomp));
+ m->m_flags &= ~M_PKTHDR;
+ n->m_next = m;
+ m = n;
+ }
+
+ ip = mtod(m, struct ip *);
+ ipcomp = (struct ipcomp *)(((caddr_t)ip) + off);
+ nxt = ipcomp->comp_nxt;
+#ifdef _IP_VHL
+ hlen = IP_VHL_HL(ip->ip_vhl) << 2;
+#else
+ hlen = ip->ip_hl << 2;
+#endif
+
+ cpi = ntohs(ipcomp->comp_cpi);
+
+ if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
+ sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src,
+ (caddr_t)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi));
+ if (sav != NULL
+ && (sav->state == SADB_SASTATE_MATURE
+ || sav->state == SADB_SASTATE_DYING)) {
+ cpi = sav->alg_enc; /*XXX*/
+ /* other parameters to look at? */
+ }
+ }
+ if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL)
+ algo = &ipcomp_algorithms[cpi];
+ else
+ algo = NULL;
+ if (!algo) {
+ ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n",
+ cpi));
+ ipsecstat.in_nosa++;
+ goto fail;
+ }
+
+ /* chop ipcomp header */
+ ipcomp = NULL;
+ m->m_len -= sizeof(struct ipcomp);
+ m->m_pkthdr.len -= sizeof(struct ipcomp);
+#ifdef IPLEN_FLIPPED
+ ip->ip_len -= sizeof(struct ipcomp);
+#else
+ ip->ip_len = htons(ntohs(ip->ip_len) - sizeof(struct ipcomp));
+#endif
+
+ olen = m->m_pkthdr.len;
+ newlen = m->m_pkthdr.len - off;
+ error = (*algo->decompress)(m, m->m_next, &newlen);
+ if (error != 0) {
+ if (error == EINVAL)
+ ipsecstat.in_inval++;
+ else if (error == ENOBUFS)
+ ipsecstat.in_nomem++;
+ m = NULL;
+ goto fail;
+ }
+ ipsecstat.in_comphist[cpi]++;
+
+ /*
+ * returning decompressed packet onto icmp is meaningless.
+ * mark it decrypted to prevent icmp from attaching original packet.
+ */
+ m->m_flags |= M_DECRYPTED;
+
+ m->m_pkthdr.len = off + newlen;
+ ip = mtod(m, struct ip *);
+ {
+ size_t len;
+#ifdef IPLEN_FLIPPED
+ len = ip->ip_len;
+#else
+ len = ntohs(ip->ip_len);
+#endif
+ /*
+ * be careful about underflow. also, do not assign exact value
+ * as ip_len is manipulated differently on *BSDs.
+ */
+ len += m->m_pkthdr.len;
+ len -= olen;
+ if (len & ~0xffff) {
+ /* packet too big after decompress */
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+#ifdef IPLEN_FLIPPED
+ ip->ip_len = len & 0xffff;
+#else
+ ip->ip_len = htons(len & 0xffff);
+#endif
+ ip->ip_p = nxt;
+ }
+
+ if (sav) {
+ key_sa_recordxfer(sav, m);
+ key_freesav(sav);
+ sav = NULL;
+ }
+
+ if (nxt != IPPROTO_DONE)
+ (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt);
+ else
+ m_freem(m);
+ m = NULL;
+
+ ipsecstat.in_success++;
+ return;
+
+fail:
+ if (sav)
+ key_freesav(sav);
+ if (m)
+ m_freem(m);
+ return;
+}
+#endif /* INET */
+
+#ifdef INET6
+int
+ipcomp6_input(mp, offp, proto)
+ struct mbuf **mp;
+ int *offp, proto;
+{
+ struct mbuf *m, *md;
+ int off;
+ struct ip6_hdr *ip6;
+ struct mbuf *ipcompm;
+ struct ipcomp *ipcomp;
+ struct ipcomp_algorithm *algo;
+ u_int16_t cpi; /* host order */
+ u_int16_t nxt;
+ int error;
+ size_t newlen;
+ struct secasvar *sav = NULL;
+
+ m = *mp;
+ off = *offp;
+
+ IP6_EXTHDR_CHECK(m, off, sizeof(struct ipcomp), IPPROTO_DONE);
+
+ {
+ int skip;
+ struct mbuf *n;
+ struct mbuf *p, *q;
+ size_t l;
+
+ skip = off;
+ for (n = m; n && skip > 0; n = n->m_next) {
+ if (n->m_len <= skip) {
+ skip -= n->m_len;
+ continue;
+ }
+ break;
+ }
+ if (!n) {
+ ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n"));
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+ if (n->m_len < skip + sizeof(struct ipcomp)) {
+ ipseclog((LOG_DEBUG, "IPv6 IPComp input: wrong mbuf chain\n"));
+ ipsecstat.in_inval++;
+ goto fail;
+ }
+ ip6 = mtod(m, struct ip6_hdr *);
+ ipcompm = n;
+ ipcomp = (struct ipcomp *)(mtod(n, caddr_t) + skip);
+ if (n->m_len > skip + sizeof(struct ipcomp)) {
+ /* split mbuf to ease the following steps*/
+ l = n->m_len - (skip + sizeof(struct ipcomp));
+ p = m_copym(n, skip + sizeof(struct ipcomp), l , M_DONTWAIT);
+ if (!p) {
+ ipsecstat.in_nomem++;
+ goto fail;
+ }
+ for (q = p; q && q->m_next; q = q->m_next)
+ ;
+ q->m_next = n->m_next;
+ n->m_next = p;
+ n->m_len -= l;
+ md = p;
+ } else
+ md = n->m_next;
+ }
+
+ nxt = ipcomp->comp_nxt;
+ cpi = ntohs(ipcomp->comp_cpi);
+
+ if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) {
+ sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src,
+ (caddr_t)&ip6->ip6_dst, IPPROTO_IPCOMP, htonl(cpi));
+ if (sav != NULL
+ && (sav->state == SADB_SASTATE_MATURE
+ || sav->state == SADB_SASTATE_DYING)) {
+ cpi = sav->alg_enc; /*XXX*/
+ /* other parameters to look at? */
+ }
+ }
+ if (cpi < IPCOMP_MAX && ipcomp_algorithms[cpi].decompress != NULL)
+ algo = &ipcomp_algorithms[cpi];
+ else
+ algo = NULL;
+ if (!algo) {
+ ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; "
+ "dropping the packet for simplicity\n", cpi));
+ ipsec6stat.in_nosa++;
+ goto fail;
+ }
+
+ newlen = m->m_pkthdr.len - off - sizeof(struct ipcomp);
+ error = (*algo->decompress)(m, md, &newlen);
+ if (error != 0) {
+ if (error == EINVAL)
+ ipsec6stat.in_inval++;
+ else if (error == ENOBUFS)
+ ipsec6stat.in_nomem++;
+ m = NULL;
+ goto fail;
+ }
+ ipsec6stat.in_comphist[cpi]++;
+ m->m_pkthdr.len = off + sizeof(struct ipcomp) + newlen;
+
+ /*
+ * returning decompressed packet onto icmp is meaningless.
+ * mark it decrypted to prevent icmp from attaching original packet.
+ */
+ m->m_flags |= M_DECRYPTED;
+
+ {
+ char *prvnxtp;
+
+ /* chop IPComp header */
+ prvnxtp = ip6_get_prevhdr(m, off);
+ *prvnxtp = nxt;
+ ipcompm->m_len -= sizeof(struct ipcomp);
+ ipcompm->m_pkthdr.len -= sizeof(struct ipcomp);
+
+ /* adjust payload length */
+ ip6 = mtod(m, struct ip6_hdr *);
+ if (((m->m_pkthdr.len - sizeof(struct ip6_hdr)) & ~0xffff) != 0)
+ ip6->ip6_plen = 0; /*now a jumbogram*/
+ else
+ ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
+ }
+
+ if (sav) {
+ key_sa_recordxfer(sav, m);
+ key_freesav(sav);
+ sav = NULL;
+ }
+ *offp = off;
+ *mp = m;
+ ipsec6stat.in_success++;
+ return nxt;
+
+fail:
+ if (m)
+ m_freem(m);
+ if (sav)
+ key_freesav(sav);
+ return IPPROTO_DONE;
+}
+#endif /* INET6 */
diff --git a/sys/netinet6/ipcomp_output.c b/sys/netinet6/ipcomp_output.c
new file mode 100644
index 0000000000000..265700ee68af8
--- /dev/null
+++ b/sys/netinet6/ipcomp_output.c
@@ -0,0 +1,430 @@
+/* $FreeBSD$ */
+/* $KAME: ipcomp_output.c,v 1.15 2000/07/03 13:23:28 itojun Exp $ */
+
+/*
+ * Copyright (C) 1999 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * RFC2393 IP payload compression protocol (IPComp).
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/netisr.h>
+#include <net/zlib.h>
+#include <machine/cpu.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_ecn.h>
+
+#ifdef INET6
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#endif
+#include <netinet6/ipcomp.h>
+#ifdef INET6
+#include <netinet6/ipcomp6.h>
+#endif
+
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+#include <netkey/key.h>
+#include <netkey/keydb.h>
+
+#include <machine/stdarg.h>
+
+#include <net/net_osdep.h>
+
+static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *,
+ struct ipsecrequest *, int));
+
+/*
+ * Modify the packet so that the payload is compressed.
+ * The mbuf (m) must start with IPv4 or IPv6 header.
+ * On failure, free the given mbuf and return NULL.
+ *
+ * on invocation:
+ * m nexthdrp md
+ * v v v
+ * IP ......... payload
+ * during the encryption:
+ * m nexthdrp mprev md
+ * v v v v
+ * IP ............... ipcomp payload
+ * <-----><----->
+ * complen plen
+ * <-> hlen
+ * <-----------------> compoff
+ */
+static int
+ipcomp_output(m, nexthdrp, md, isr, af)
+ struct mbuf *m;
+ u_char *nexthdrp;
+ struct mbuf *md;
+ struct ipsecrequest *isr;
+ int af;
+{
+ struct mbuf *n;
+ struct mbuf *md0;
+ struct mbuf *mprev;
+ struct ipcomp *ipcomp;
+ struct secasvar *sav = isr->sav;
+ struct ipcomp_algorithm *algo;
+ u_int16_t cpi; /* host order */
+ size_t plen0, plen; /*payload length to be compressed*/
+ size_t compoff;
+ int afnumber;
+ int error = 0;
+
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ afnumber = 4;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ afnumber = 6;
+ break;
+#endif
+ default:
+ ipseclog((LOG_ERR, "ipcomp_output: unsupported af %d\n", af));
+ return 0; /* no change at all */
+ }
+
+ /* grab parameters */
+ if ((ntohl(sav->spi) & ~0xffff) != 0 || sav->alg_enc >= IPCOMP_MAX
+ || ipcomp_algorithms[sav->alg_enc].compress == NULL) {
+ ipsecstat.out_inval++;
+ m_freem(m);
+ return EINVAL;
+ }
+ if ((sav->flags & SADB_X_EXT_RAWCPI) == 0)
+ cpi = sav->alg_enc;
+ else
+ cpi = ntohl(sav->spi) & 0xffff;
+ algo = &ipcomp_algorithms[sav->alg_enc]; /*XXX*/
+
+ /* compute original payload length */
+ plen = 0;
+ for (n = md; n; n = n->m_next)
+ plen += n->m_len;
+
+ /* if the payload is short enough, we don't need to compress */
+ if (plen < algo->minplen)
+ return 0;
+
+ /*
+ * keep the original data packet, so that we can backout
+ * our changes when compression is not necessary.
+ */
+ md0 = m_copym(md, 0, M_COPYALL, M_NOWAIT);
+ if (md0 == NULL) {
+ error = ENOBUFS;
+ return 0;
+ }
+ plen0 = plen;
+
+ /* make the packet over-writable */
+ for (mprev = m; mprev && mprev->m_next != md; mprev = mprev->m_next)
+ ;
+ if (mprev == NULL || mprev->m_next != md) {
+ ipseclog((LOG_DEBUG, "ipcomp%d_output: md is not in chain\n",
+ afnumber));
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ ipsecstat.out_inval++;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ipsec6stat.out_inval++;
+ break;
+#endif
+ }
+ m_freem(m);
+ m_freem(md0);
+ return EINVAL;
+ }
+ mprev->m_next = NULL;
+ if ((md = ipsec_copypkt(md)) == NULL) {
+ m_freem(m);
+ m_freem(md0);
+ error = ENOBUFS;
+ goto fail;
+ }
+ mprev->m_next = md;
+
+ /* compress data part */
+ if ((*algo->compress)(m, md, &plen) || mprev->m_next == NULL) {
+ ipseclog((LOG_ERR, "packet compression failure\n"));
+ m = NULL;
+ m_freem(md0);
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ ipsecstat.out_inval++;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ipsec6stat.out_inval++;
+ break;
+#endif
+ }
+ error = EINVAL;
+ goto fail;
+ }
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ ipsecstat.out_comphist[sav->alg_enc]++;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ipsec6stat.out_comphist[sav->alg_enc]++;
+ break;
+#endif
+ }
+ md = mprev->m_next;
+
+ /*
+ * if the packet became bigger, meaningless to use IPComp.
+ * we've only wasted our cpu time.
+ */
+ if (plen0 < plen) {
+ m_freem(md);
+ mprev->m_next = md0;
+ return 0;
+ }
+
+ /* no need to backout change beyond here */
+ m_freem(md0);
+ md0 = NULL;
+ m->m_pkthdr.len -= plen0;
+ m->m_pkthdr.len += plen;
+
+ {
+ /*
+ * insert IPComp header.
+ */
+#ifdef INET
+ struct ip *ip = NULL;
+#endif
+#ifdef INET6
+ struct ip6_hdr *ip6 = NULL;
+#endif
+ size_t hlen = 0; /*ip header len*/
+ size_t complen = sizeof(struct ipcomp);
+
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ ip = mtod(m, struct ip *);
+#ifdef _IP_VHL
+ hlen = IP_VHL_HL(ip->ip_vhl) << 2;
+#else
+ hlen = ip->ip_hl << 2;
+#endif
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ip6 = mtod(m, struct ip6_hdr *);
+ hlen = sizeof(*ip6);
+ break;
+#endif
+ }
+
+ compoff = m->m_pkthdr.len - plen;
+
+ /*
+ * grow the mbuf to accomodate ipcomp header.
+ * before: IP ... payload
+ * after: IP ... ipcomp payload
+ */
+ if (M_LEADINGSPACE(md) < complen) {
+ MGET(n, M_DONTWAIT, MT_DATA);
+ if (!n) {
+ m_freem(m);
+ error = ENOBUFS;
+ goto fail;
+ }
+ n->m_len = complen;
+ mprev->m_next = n;
+ n->m_next = md;
+ m->m_pkthdr.len += complen;
+ ipcomp = mtod(n, struct ipcomp *);
+ } else {
+ md->m_len += complen;
+ md->m_data -= complen;
+ m->m_pkthdr.len += complen;
+ ipcomp = mtod(md, struct ipcomp *);
+ }
+
+ bzero(ipcomp, sizeof(*ipcomp));
+ ipcomp->comp_nxt = *nexthdrp;
+ *nexthdrp = IPPROTO_IPCOMP;
+ ipcomp->comp_cpi = htons(cpi);
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ if (compoff + complen + plen < IP_MAXPACKET)
+ ip->ip_len = htons(compoff + complen + plen);
+ else {
+ ipseclog((LOG_ERR,
+ "IPv4 ESP output: size exceeds limit\n"));
+ ipsecstat.out_inval++;
+ m_freem(m);
+ error = EMSGSIZE;
+ goto fail;
+ }
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ /* total packet length will be computed in ip6_output() */
+ break;
+#endif
+ }
+ }
+
+ if (!m) {
+ ipseclog((LOG_DEBUG,
+ "NULL mbuf after compression in ipcomp%d_output",
+ afnumber));
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ ipsecstat.out_inval++;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ipsec6stat.out_inval++;
+ break;
+#endif
+ }
+ } else {
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ ipsecstat.out_success++;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ipsec6stat.out_success++;
+ break;
+#endif
+ }
+ }
+#if 0
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ ipsecstat.out_esphist[sav->alg_enc]++;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ ipsec6stat.out_esphist[sav->alg_enc]++;
+ break;
+#endif
+ }
+#endif
+ key_sa_recordxfer(sav, m);
+ return 0;
+
+fail:
+#if 1
+ return error;
+#else
+ panic("something bad in ipcomp_output");
+#endif
+}
+
+#ifdef INET
+int
+ipcomp4_output(m, isr)
+ struct mbuf *m;
+ struct ipsecrequest *isr;
+{
+ struct ip *ip;
+ if (m->m_len < sizeof(struct ip)) {
+ ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n"));
+ ipsecstat.out_inval++;
+ m_freem(m);
+ return 0;
+ }
+ ip = mtod(m, struct ip *);
+ /* XXX assumes that m->m_next points to payload */
+ return ipcomp_output(m, &ip->ip_p, m->m_next, isr, AF_INET);
+}
+#endif /*INET*/
+
+#ifdef INET6
+int
+ipcomp6_output(m, nexthdrp, md, isr)
+ struct mbuf *m;
+ u_char *nexthdrp;
+ struct mbuf *md;
+ struct ipsecrequest *isr;
+{
+ if (m->m_len < sizeof(struct ip6_hdr)) {
+ ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n"));
+ ipsec6stat.out_inval++;
+ m_freem(m);
+ return 0;
+ }
+ return ipcomp_output(m, nexthdrp, md, isr, AF_INET6);
+}
+#endif /*INET6*/
diff --git a/sys/netinet6/scope6.c b/sys/netinet6/scope6.c
new file mode 100644
index 0000000000000..43a6fb722afa6
--- /dev/null
+++ b/sys/netinet6/scope6.c
@@ -0,0 +1,302 @@
+/* $FreeBSD$ */
+/* $KAME: scope6.c,v 1.9 2000/05/18 15:03:26 jinmei Exp $ */
+
+/*
+ * Copyright (C) 2000 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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/param.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+
+#include <net/route.h>
+#include <net/if.h>
+
+#include <netinet/in.h>
+
+#include <netinet6/in6_var.h>
+#include <netinet6/scope6_var.h>
+
+struct scope6_id {
+ /*
+ * 16 is correspondent to 4bit multicast scope field.
+ * i.e. from node-local to global with some reserved/unassigned types.
+ */
+ u_int32_t s6id_list[16];
+};
+static size_t if_indexlim = 8;
+struct scope6_id *scope6_ids = NULL;
+
+void
+scope6_ifattach(ifp)
+ struct ifnet *ifp;
+{
+ int s = splnet();
+
+ /*
+ * We have some arrays that should be indexed by if_index.
+ * since if_index will grow dynamically, they should grow too.
+ */
+ if (scope6_ids == NULL || if_index >= if_indexlim) {
+ size_t n;
+ caddr_t q;
+
+ while (if_index >= if_indexlim)
+ if_indexlim <<= 1;
+
+ /* grow scope index array */
+ n = if_indexlim * sizeof(struct scope6_id);
+ /* XXX: need new malloc type? */
+ q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
+ bzero(q, n);
+ if (scope6_ids) {
+ bcopy((caddr_t)scope6_ids, q, n/2);
+ free((caddr_t)scope6_ids, M_IFADDR);
+ }
+ scope6_ids = (struct scope6_id *)q;
+ }
+
+#define SID scope6_ids[ifp->if_index]
+
+ /* don't initialize if called twice */
+ if (SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]) {
+ splx(s);
+ return;
+ }
+
+ /*
+ * XXX: IPV6_ADDR_SCOPE_xxx macros are not standard.
+ * Should we rather hardcode here?
+ */
+ SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = ifp->if_index;
+#ifdef MULTI_SCOPE
+ /* by default, we don't care about scope boundary for these scopes. */
+ SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL] = 1;
+ SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL] = 1;
+#endif
+#undef SID
+
+ splx(s);
+}
+
+int
+scope6_set(ifp, idlist)
+ struct ifnet *ifp;
+ u_int32_t *idlist;
+{
+ int i, s;
+ int error = 0;
+
+ if (scope6_ids == NULL) /* paranoid? */
+ return(EINVAL);
+
+ /*
+ * XXX: We need more consistency checks of the relationship among
+ * scopes (e.g. an organization should be larger than a site).
+ */
+
+ /*
+ * TODO(XXX): after setting, we should reflect the changes to
+ * interface addresses, routing table entries, PCB entries...
+ */
+
+ s = splnet();
+
+ for (i = 0; i < 16; i++) {
+ if (idlist[i] &&
+ idlist[i] != scope6_ids[ifp->if_index].s6id_list[i]) {
+ if (i == IPV6_ADDR_SCOPE_LINKLOCAL &&
+ idlist[i] > if_index) {
+ /*
+ * XXX: theoretically, there should be no
+ * relationship between link IDs and interface
+ * IDs, but we check the consistency for
+ * safety in later use.
+ */
+ splx(s);
+ return(EINVAL);
+ }
+
+ /*
+ * XXX: we must need lots of work in this case,
+ * but we simply set the new value in this initial
+ * implementation.
+ */
+ scope6_ids[ifp->if_index].s6id_list[i] = idlist[i];
+ }
+ }
+ splx(s);
+
+ return(error);
+}
+
+int
+scope6_get(ifp, idlist)
+ struct ifnet *ifp;
+ u_int32_t *idlist;
+{
+ if (scope6_ids == NULL) /* paranoid? */
+ return(EINVAL);
+
+ bcopy(scope6_ids[ifp->if_index].s6id_list, idlist,
+ sizeof(scope6_ids[ifp->if_index].s6id_list));
+
+ return(0);
+}
+
+
+/*
+ * Get a scope of the address. Node-local, link-local, site-local or global.
+ */
+int
+in6_addrscope(addr)
+struct in6_addr *addr;
+{
+ int scope;
+
+ if (addr->s6_addr8[0] == 0xfe) {
+ scope = addr->s6_addr8[1] & 0xc0;
+
+ switch (scope) {
+ case 0x80:
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
+ break;
+ case 0xc0:
+ return IPV6_ADDR_SCOPE_SITELOCAL;
+ break;
+ default:
+ return IPV6_ADDR_SCOPE_GLOBAL; /* just in case */
+ break;
+ }
+ }
+
+
+ if (addr->s6_addr8[0] == 0xff) {
+ scope = addr->s6_addr8[1] & 0x0f;
+
+ /*
+ * due to other scope such as reserved,
+ * return scope doesn't work.
+ */
+ switch (scope) {
+ case IPV6_ADDR_SCOPE_NODELOCAL:
+ return IPV6_ADDR_SCOPE_NODELOCAL;
+ break;
+ case IPV6_ADDR_SCOPE_LINKLOCAL:
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
+ break;
+ case IPV6_ADDR_SCOPE_SITELOCAL:
+ return IPV6_ADDR_SCOPE_SITELOCAL;
+ break;
+ default:
+ return IPV6_ADDR_SCOPE_GLOBAL;
+ break;
+ }
+ }
+
+ if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) {
+ if (addr->s6_addr8[15] == 1) /* loopback */
+ return IPV6_ADDR_SCOPE_NODELOCAL;
+ if (addr->s6_addr8[15] == 0) /* unspecified */
+ return IPV6_ADDR_SCOPE_LINKLOCAL;
+ }
+
+ return IPV6_ADDR_SCOPE_GLOBAL;
+}
+
+int
+in6_addr2scopeid(ifp, addr)
+ struct ifnet *ifp; /* must not be NULL */
+ struct in6_addr *addr; /* must not be NULL */
+{
+ int scope = in6_addrscope(addr);
+
+ if (scope6_ids == NULL) /* paranoid? */
+ return(0); /* XXX */
+ if (ifp->if_index >= if_indexlim)
+ return(0); /* XXX */
+
+#define SID scope6_ids[ifp->if_index]
+ switch(scope) {
+ case IPV6_ADDR_SCOPE_NODELOCAL:
+ return(-1); /* XXX: is this an appropriate value? */
+
+ case IPV6_ADDR_SCOPE_LINKLOCAL:
+ return(SID.s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL]);
+
+ case IPV6_ADDR_SCOPE_SITELOCAL:
+ return(SID.s6id_list[IPV6_ADDR_SCOPE_SITELOCAL]);
+
+ case IPV6_ADDR_SCOPE_ORGLOCAL:
+ return(SID.s6id_list[IPV6_ADDR_SCOPE_ORGLOCAL]);
+
+ default:
+ return(0); /* XXX: treat as global. */
+ }
+#undef SID
+}
+
+void
+scope6_setdefault(ifp)
+ struct ifnet *ifp; /* note that this might be NULL */
+{
+ /*
+ * Currently, this function just set the default "link" according to
+ * the given interface.
+ * We might eventually have to separate the notion of "link" from
+ * "interface" and provide a user interface to set the default.
+ */
+ if (ifp) {
+ scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] =
+ ifp->if_index;
+ }
+ else
+ scope6_ids[0].s6id_list[IPV6_ADDR_SCOPE_LINKLOCAL] = 0;
+}
+
+int
+scope6_get_default(idlist)
+ u_int32_t *idlist;
+{
+ if (scope6_ids == NULL) /* paranoid? */
+ return(EINVAL);
+
+ bcopy(scope6_ids[0].s6id_list, idlist,
+ sizeof(scope6_ids[0].s6id_list));
+
+ return(0);
+}
+
+u_int32_t
+scope6_addr2default(addr)
+ struct in6_addr *addr;
+{
+ return(scope6_ids[0].s6id_list[in6_addrscope(addr)]);
+}
diff --git a/sys/netinet6/scope6_var.h b/sys/netinet6/scope6_var.h
new file mode 100644
index 0000000000000..6e107d7c1a7e7
--- /dev/null
+++ b/sys/netinet6/scope6_var.h
@@ -0,0 +1,46 @@
+/* $FreeBSD$ */
+/* $KAME: scope6_var.h,v 1.4 2000/05/18 15:03:27 jinmei Exp $ */
+
+/*
+ * Copyright (C) 2000 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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 _NETINET6_SCOPE6_VAR_H_
+#define _NETINET6_SCOPE6_VAR_H_
+
+#ifdef _KERNEL
+void scope6_ifattach __P((struct ifnet *));
+int scope6_set __P((struct ifnet *, u_int32_t *));
+int scope6_get __P((struct ifnet *, u_int32_t *));
+void scope6_setdefault __P((struct ifnet *));
+int scope6_get_default __P((u_int32_t *));
+u_int32_t scope6_in6_addrscope __P((struct in6_addr *));
+u_int32_t scope6_addr2default __P((struct in6_addr *));
+#endif /* _KERNEL */
+
+#endif /* _NETINET6_SCOPE6_VAR_H_ */
diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c
new file mode 100644
index 0000000000000..c6d831f38f923
--- /dev/null
+++ b/sys/netinet6/udp6_output.c
@@ -0,0 +1,285 @@
+/* $FreeBSD$ */
+/* $KAME: udp6_output.c,v 1.14 2000/06/13 10:31:23 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)udp_var.h 8.1 (Berkeley) 6/10/93
+ */
+
+#include "opt_ipsec.h"
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/syslog.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_types.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/in_pcb.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/udp6_var.h>
+#include <netinet/icmp6.h>
+#include <netinet6/ip6protosw.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#ifdef INET6
+#include <netinet6/ipsec6.h>
+#endif
+#endif /*IPSEC*/
+
+#include "faith.h"
+
+#include <net/net_osdep.h>
+
+/*
+ * UDP protocol inplementation.
+ * Per RFC 768, August, 1980.
+ */
+
+#define in6pcb inpcb
+#define udp6stat udpstat
+#define udp6s_opackets udps_opackets
+
+int
+udp6_output(in6p, m, addr6, control, p)
+ register struct in6pcb *in6p;
+ register struct mbuf *m;
+ struct mbuf *control;
+ struct sockaddr *addr6;
+ struct proc *p;
+{
+ register u_int32_t ulen = m->m_pkthdr.len;
+ u_int32_t plen = sizeof(struct udphdr) + ulen;
+ struct ip6_hdr *ip6;
+ struct udphdr *udp6;
+ struct in6_addr *laddr, *faddr;
+ u_short fport;
+ int error = 0;
+ struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts;
+ int priv;
+ int af, hlen;
+ int flags;
+ struct sockaddr_in6 tmp;
+
+ priv = 0;
+ if (p && !suser(p))
+ priv = 1;
+ if (control) {
+ if ((error = ip6_setpktoptions(control, &opt, priv)) != 0)
+ goto release;
+ in6p->in6p_outputopts = &opt;
+ }
+
+ if (addr6) {
+ /*
+ * IPv4 version of udp_output calls in_pcbconnect in this case,
+ * which needs splnet and affects performance.
+ * Since we saw no essential reason for calling in_pcbconnect,
+ * we get rid of such kind of logic, and call in6_selectsrc
+ * and in6_pcbsetport in order to fill in the local address
+ * and the local port.
+ */
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr6;
+ if (sin6->sin6_port == 0) {
+ error = EADDRNOTAVAIL;
+ goto release;
+ }
+
+ if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+ error = EISCONN;
+ goto release;
+ }
+
+ /* protect *sin6 from overwrites */
+ tmp = *sin6;
+ sin6 = &tmp;
+
+ faddr = &sin6->sin6_addr;
+ fport = sin6->sin6_port; /* allow 0 port */
+
+ /* KAME hack: embed scopeid */
+ if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) {
+ error = EINVAL;
+ goto release;
+ }
+
+ if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
+ laddr = in6_selectsrc(sin6, in6p->in6p_outputopts,
+ in6p->in6p_moptions,
+ &in6p->in6p_route,
+ &in6p->in6p_laddr, &error);
+ } else
+ laddr = &in6p->in6p_laddr; /*XXX*/
+ if (laddr == NULL) {
+ if (error == 0)
+ error = EADDRNOTAVAIL;
+ goto release;
+ }
+ if (in6p->in6p_lport == 0 &&
+ (error = in6_pcbsetport(laddr, in6p, p)) != 0)
+ goto release;
+ } else {
+ if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
+ error = ENOTCONN;
+ goto release;
+ }
+ laddr = &in6p->in6p_laddr;
+ faddr = &in6p->in6p_faddr;
+ fport = in6p->in6p_fport;
+ }
+
+ if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
+ af = AF_INET6;
+ hlen = sizeof(struct ip6_hdr);
+ } else {
+ af = AF_INET;
+ hlen = sizeof(struct ip);
+ }
+
+ /*
+ * Calculate data length and get a mbuf
+ * for UDP and IP6 headers.
+ */
+ M_PREPEND(m, hlen + sizeof(struct udphdr), M_DONTWAIT);
+ if (m == 0) {
+ error = ENOBUFS;
+ goto release;
+ }
+
+ /*
+ * Stuff checksum and output datagram.
+ */
+ udp6 = (struct udphdr *)(mtod(m, caddr_t) + hlen);
+ udp6->uh_sport = in6p->in6p_lport; /* lport is always set in the PCB */
+ udp6->uh_dport = fport;
+ if (plen <= 0xffff)
+ udp6->uh_ulen = htons((u_short)plen);
+ else
+ udp6->uh_ulen = 0;
+ udp6->uh_sum = 0;
+
+ switch (af) {
+ case AF_INET6:
+ ip6 = mtod(m, struct ip6_hdr *);
+ ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
+#if 0 /* ip6_plen will be filled in ip6_output. */
+ ip6->ip6_plen = htons((u_short)plen);
+#endif
+ ip6->ip6_nxt = IPPROTO_UDP;
+ ip6->ip6_hlim = in6_selecthlim(in6p,
+ in6p->in6p_route.ro_rt ?
+ in6p->in6p_route.ro_rt->rt_ifp : NULL);
+ ip6->ip6_src = *laddr;
+ ip6->ip6_dst = *faddr;
+
+ if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP,
+ sizeof(struct ip6_hdr), plen)) == 0) {
+ udp6->uh_sum = 0xffff;
+ }
+
+ flags = 0;
+
+ udp6stat.udp6s_opackets++;
+#ifdef IPSEC
+ ipsec_setsocket(m, in6p->in6p_socket);
+#endif /*IPSEC*/
+ error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route,
+ flags, in6p->in6p_moptions, NULL);
+ break;
+ case AF_INET:
+ error = EAFNOSUPPORT;
+ goto release;
+ }
+ goto releaseopt;
+
+release:
+ m_freem(m);
+
+releaseopt:
+ if (control) {
+ in6p->in6p_outputopts = stickyopt;
+ m_freem(control);
+ }
+ return(error);
+}
diff --git a/sys/netkey/keydb.c b/sys/netkey/keydb.c
new file mode 100644
index 0000000000000..dd1fb17bd5791
--- /dev/null
+++ b/sys/netkey/keydb.c
@@ -0,0 +1,217 @@
+/* $FreeBSD$ */
+/* $KAME: keydb.c,v 1.64 2000/05/11 17:02:30 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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 "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/errno.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+
+#include <net/pfkeyv2.h>
+#include <netkey/keydb.h>
+#include <netinet6/ipsec.h>
+
+#include <net/net_osdep.h>
+
+MALLOC_DEFINE(M_SECA, "key mgmt", "security associations, key management");
+
+static void keydb_delsecasvar __P((struct secasvar *));
+
+/*
+ * secpolicy management
+ */
+struct secpolicy *
+keydb_newsecpolicy()
+{
+ struct secpolicy *p;
+
+ p = (struct secpolicy *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (!p)
+ return p;
+ bzero(p, sizeof(*p));
+ return p;
+}
+
+void
+keydb_delsecpolicy(p)
+ struct secpolicy *p;
+{
+
+ free(p, M_SECA);
+}
+
+/*
+ * secashead management
+ */
+struct secashead *
+keydb_newsecashead()
+{
+ struct secashead *p;
+ int i;
+
+ p = (struct secashead *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (!p)
+ return p;
+ bzero(p, sizeof(*p));
+ for (i = 0; i < sizeof(p->savtree)/sizeof(p->savtree[0]); i++)
+ LIST_INIT(&p->savtree[i]);
+ return p;
+}
+
+void
+keydb_delsecashead(p)
+ struct secashead *p;
+{
+
+ free(p, M_SECA);
+}
+
+/*
+ * secasvar management (reference counted)
+ */
+struct secasvar *
+keydb_newsecasvar()
+{
+ struct secasvar *p;
+
+ p = (struct secasvar *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (!p)
+ return p;
+ bzero(p, sizeof(*p));
+ p->refcnt = 1;
+ return p;
+}
+
+void
+keydb_refsecasvar(p)
+ struct secasvar *p;
+{
+ int s;
+
+ s = splnet();
+ p->refcnt++;
+ splx(s);
+}
+
+void
+keydb_freesecasvar(p)
+ struct secasvar *p;
+{
+ int s;
+
+ s = splnet();
+ p->refcnt--;
+ /* negative refcnt will cause panic intentionally */
+ if (p->refcnt <= 0)
+ keydb_delsecasvar(p);
+ splx(s);
+}
+
+static void
+keydb_delsecasvar(p)
+ struct secasvar *p;
+{
+
+ if (p->refcnt)
+ panic("keydb_delsecasvar called with refcnt != 0");
+
+ free(p, M_SECA);
+}
+
+/*
+ * secreplay management
+ */
+struct secreplay *
+keydb_newsecreplay(wsize)
+ size_t wsize;
+{
+ struct secreplay *p;
+
+ p = (struct secreplay *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (!p)
+ return p;
+
+ bzero(p, sizeof(*p));
+ if (wsize != 0) {
+ p->bitmap = (caddr_t)malloc(wsize, M_SECA, M_NOWAIT);
+ if (!p->bitmap) {
+ free(p, M_SECA);
+ return NULL;
+ }
+ bzero(p->bitmap, wsize);
+ }
+ p->wsize = wsize;
+ return p;
+}
+
+void
+keydb_delsecreplay(p)
+ struct secreplay *p;
+{
+
+ if (p->bitmap)
+ free(p->bitmap, M_SECA);
+ free(p, M_SECA);
+}
+
+/*
+ * secreg management
+ */
+struct secreg *
+keydb_newsecreg()
+{
+ struct secreg *p;
+
+ p = (struct secreg *)malloc(sizeof(*p), M_SECA, M_NOWAIT);
+ if (p)
+ bzero(p, sizeof(*p));
+ return p;
+}
+
+void
+keydb_delsecreg(p)
+ struct secreg *p;
+{
+
+ free(p, M_SECA);
+}
diff --git a/usr.bin/kenv/Makefile b/usr.bin/kenv/Makefile
new file mode 100644
index 0000000000000..33a6dfc3bff5c
--- /dev/null
+++ b/usr.bin/kenv/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+PROG= kenv
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/kenv/kenv.1 b/usr.bin/kenv/kenv.1
new file mode 100644
index 0000000000000..e80b9443270a3
--- /dev/null
+++ b/usr.bin/kenv/kenv.1
@@ -0,0 +1,50 @@
+.\" Copyright (c) 2000 Peter Wemm <peter@freebsd.org>
+.\"
+.\" 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 AUTHORS 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 AUTHORS 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 June 6, 1993
+.Dt KENV 1
+.Os BSD 4
+.Sh NAME
+.Nm kenv
+.Nd dump the kernel environment
+.Sh SYNOPSIS
+.Nm kenv
+.Op Fl h
+.Op variable
+.Sh DESCRIPTION
+.Nm kenv
+will dump the kernel environment.
+If the
+.Fl h
+flag is specified, it will limit the report to kernel probe hints.
+If an optional variable name is specified,
+.Nm
+will only report that value.
+.Sh SEE ALSO
+.Xr loader 8
+.Sh HISTORY
+.Nm kenv
+appeared in
+.Fx 5.0 .
diff --git a/usr.bin/kenv/kenv.c b/usr.bin/kenv/kenv.c
new file mode 100644
index 0000000000000..4e5970a2c8abb
--- /dev/null
+++ b/usr.bin/kenv/kenv.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2000 Peter Wemm <peter@freebsd.org>
+ *
+ * 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 AUTHORS 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 AUTHORS 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/sysctl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+
+static char sbuf[1024];
+
+static void
+usage(void)
+{
+ errx(1, "usage: [-h] [variable]");
+}
+
+int
+main(int argc, char **argv)
+{
+ int name2oid_oid[2];
+ int real_oid[CTL_MAXNAME+4];
+ size_t oidlen;
+ int ch, error, hflag, i, slen;
+ char *env, *eq, *name, *var, *val;
+
+ hflag = 0;
+ env = NULL;
+ while ((ch = getopt(argc, argv, "h")) != -1) {
+ switch (ch) {
+ case 'h':
+ hflag++;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc > 0) {
+ env = argv[0];
+ argv++;
+ argc--;
+ }
+ if (argc > 0)
+ usage();
+ name2oid_oid[0] = 0; /* This is magic & undocumented! */
+ name2oid_oid[1] = 3;
+ oidlen = sizeof(real_oid);
+ name = "kern.environment";
+ error = sysctl(name2oid_oid, 2, real_oid, &oidlen, name, strlen(name));
+ if (error < 0)
+ err(1, "cannot find kern.environment base sysctl OID");
+ oidlen /= sizeof (int);
+ if (oidlen >= CTL_MAXNAME)
+ errx(1, "kern.environment OID is too large!");
+ real_oid[oidlen] = 0;
+ for (i = 0; ; i++) {
+ real_oid[oidlen + 1] = i;
+ slen = sizeof(sbuf) - 1;
+ error = sysctl(real_oid, oidlen + 2, sbuf, &slen, NULL, 0);
+ if (error < 0) {
+ if (errno != ENOENT)
+ err(1, "sysctl kern.environment.%d\n", i);
+ break;
+ }
+ sbuf[sizeof(sbuf) - 1] = '\0';
+ eq = strchr(sbuf, '=');
+ if (eq == NULL)
+ err(1, "malformed environment string: %s\n", sbuf);
+ var = sbuf;
+ *eq = '\0';
+ val = eq + 1;
+ if (env) {
+ if (strcmp(var, env) != 0)
+ continue;
+ printf("%s\n", val);
+ break;
+ }
+ if (hflag) {
+ if (strncmp(var, "hint.", 5) != 0)
+ continue;
+ /* FALLTHROUGH */
+ }
+ printf("%s=\"", var);
+ while (*val) {
+ switch (*val) {
+ case '"':
+ putchar('\\');
+ putchar('"');
+ break;
+ case '\\':
+ putchar('\\');
+ putchar('\\');
+ break;
+ default:
+ putchar(*val);
+ break;
+ }
+ val++;
+ }
+ printf("\"\n");
+ }
+ exit(0);
+}
diff --git a/usr.bin/netstat/ipsec.c b/usr.bin/netstat/ipsec.c
new file mode 100644
index 0000000000000..ce96488557989
--- /dev/null
+++ b/usr.bin/netstat/ipsec.c
@@ -0,0 +1,316 @@
+/* $FreeBSD$ */
+/* $NetBSD: inet.c,v 1.35.2.1 1999/04/29 14:57:08 perry Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. 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 University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 lint
+/*
+static char sccsid[] = "@(#)inet.c 8.5 (Berkeley) 5/24/95";
+*/
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#include <netkey/keysock.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+/*
+ * portability issues:
+ * - bsdi[34] uses PLURAL(), not plural().
+ * - freebsd2 can't print "unsigned long long" properly.
+ */
+/*
+ * XXX see PORTABILITY for the twist
+ */
+#define LLU "%llu"
+#define CAST unsigned long long
+
+#ifdef IPSEC
+static const char *ipsec_ahnames[] = {
+ "none",
+ "hmac MD5",
+ "hmac SHA1",
+ "keyed MD5",
+ "keyed SHA1",
+ "null",
+};
+
+static const char *ipsec_espnames[] = {
+ "none",
+ "DES CBC",
+ "3DES CBC",
+ "simple",
+ "blowfish CBC",
+ "CAST128 CBC",
+ "DES derived IV",
+};
+
+static const char *ipsec_compnames[] = {
+ "none",
+ "OUI",
+ "deflate",
+ "LZS",
+};
+
+static const char *pfkey_msgtypenames[] = {
+ "reserved", "getspi", "update", "add", "delete",
+ "get", "acquire", "register", "expire", "flush",
+ "dump", "x_promisc", "x_pchange", "x_spdupdate", "x_spdadd",
+ "x_spddelete", "x_spdget", "x_spdacquire", "x_spddump", "x_spdflush",
+ "x_spdsetidx", "x_spdexpire", "x_spddelete2"
+};
+
+static struct ipsecstat ipsecstat;
+
+static void print_ipsecstats __P((void));
+static const char *pfkey_msgtype_names __P((int));
+static void ipsec_hist __P((const u_quad_t *, size_t, const char **, size_t,
+ const char *));
+
+/*
+ * Dump IPSEC statistics structure.
+ */
+static void
+ipsec_hist(hist, histmax, name, namemax, title)
+ const u_quad_t *hist;
+ size_t histmax;
+ const char **name;
+ size_t namemax;
+ const char *title;
+{
+ int first;
+ size_t proto;
+
+ for (first = 1, proto = 0; proto < histmax; proto++) {
+ if (hist[proto] <= 0)
+ continue;
+ if (first) {
+ printf("\t%s histogram:\n", title);
+ first = 0;
+ }
+ if (proto < namemax && name[proto]) {
+ printf("\t\t%s: " LLU "\n", name[proto],
+ (CAST)hist[proto]);
+ } else {
+ printf("\t\t#%ld: " LLU "\n", (long)proto,
+ (CAST)hist[proto]);
+ }
+ }
+}
+
+static void
+print_ipsecstats()
+{
+#define p(f, m) if (ipsecstat.f || sflag <= 1) \
+ printf(m, (CAST)ipsecstat.f, plural(ipsecstat.f))
+#define hist(f, n, t) \
+ ipsec_hist((f), sizeof(f)/sizeof(f[0]), (n), sizeof(n)/sizeof(n[0]), (t));
+
+ p(in_success, "\t" LLU " inbound packet%s processed successfully\n");
+ p(in_polvio, "\t" LLU " inbound packet%s violated process security "
+ "policy\n");
+ p(in_nosa, "\t" LLU " inbound packet%s with no SA available\n");
+ p(in_inval, "\t" LLU " invalid inbound packet%s\n");
+ p(in_nomem, "\t" LLU " inbound packet%s failed due to insufficient memory\n");
+ p(in_badspi, "\t" LLU " inbound packet%s failed getting SPI\n");
+ p(in_ahreplay, "\t" LLU " inbound packet%s failed on AH replay check\n");
+ p(in_espreplay, "\t" LLU " inbound packet%s failed on ESP replay check\n");
+ p(in_ahauthsucc, "\t" LLU " inbound packet%s considered authentic\n");
+ p(in_ahauthfail, "\t" LLU " inbound packet%s failed on authentication\n");
+ hist(ipsecstat.in_ahhist, ipsec_ahnames, "AH input");
+ hist(ipsecstat.in_esphist, ipsec_espnames, "ESP input");
+ hist(ipsecstat.in_comphist, ipsec_compnames, "IPComp input");
+
+ p(out_success, "\t" LLU " outbound packet%s processed successfully\n");
+ p(out_polvio, "\t" LLU " outbound packet%s violated process security "
+ "policy\n");
+ p(out_nosa, "\t" LLU " outbound packet%s with no SA available\n");
+ p(out_inval, "\t" LLU " invalid outbound packet%s\n");
+ p(out_nomem, "\t" LLU " outbound packet%s failed due to insufficient memory\n");
+ p(out_noroute, "\t" LLU " outbound packet%s with no route\n");
+ hist(ipsecstat.out_ahhist, ipsec_ahnames, "AH output");
+ hist(ipsecstat.out_esphist, ipsec_espnames, "ESP output");
+ hist(ipsecstat.out_comphist, ipsec_compnames, "IPComp output");
+#undef p
+#undef hist
+}
+
+void
+ipsec_stats(off, name)
+ u_long off;
+ char *name;
+{
+ if (off == 0)
+ return;
+ printf ("%s:\n", name);
+ kread(off, (char *)&ipsecstat, sizeof (ipsecstat));
+
+ print_ipsecstats();
+}
+
+#if defined(__bsdi__) && _BSDI_VERSION >= 199802 /* bsdi4 only */
+void
+ipsec_stats0(name)
+ char *name;
+{
+ printf("%s:\n", name);
+
+ skread(name, &ipsecstat_info);
+
+ print_ipsecstats();
+}
+#endif
+
+static const char *
+pfkey_msgtype_names(x)
+ int x;
+{
+ const int max =
+ sizeof(pfkey_msgtypenames)/sizeof(pfkey_msgtypenames[0]);
+ static char buf[10];
+
+ if (x < max && pfkey_msgtypenames[x])
+ return pfkey_msgtypenames[x];
+ snprintf(buf, sizeof(buf), "#%d", x);
+ return buf;
+}
+
+void
+pfkey_stats(off, name)
+ u_long off;
+ char *name;
+{
+ struct pfkeystat pfkeystat;
+ int first, type;
+
+ if (off == 0)
+ return;
+ printf ("%s:\n", name);
+ kread(off, (char *)&pfkeystat, sizeof(pfkeystat));
+
+#define p(f, m) if (pfkeystat.f || sflag <= 1) \
+ printf(m, (CAST)pfkeystat.f, plural(pfkeystat.f))
+
+ /* kernel -> userland */
+ p(out_total, "\t" LLU " request%s sent to userland\n");
+ p(out_bytes, "\t" LLU " byte%s sent to userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.out_msgtype)/sizeof(pfkeystat.out_msgtype[0]);
+ type++) {
+ if (pfkeystat.out_msgtype[type] <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type),
+ (CAST)pfkeystat.out_msgtype[type]);
+ }
+ p(out_invlen, "\t" LLU " message%s with invalid length field\n");
+ p(out_invver, "\t" LLU " message%s with invalid version field\n");
+ p(out_invmsgtype, "\t" LLU " message%s with invalid message type field\n");
+ p(out_tooshort, "\t" LLU " message%s too short\n");
+ p(out_nomem, "\t" LLU " message%s with memory allocation failure\n");
+ p(out_dupext, "\t" LLU " message%s with duplicate extension\n");
+ p(out_invexttype, "\t" LLU " message%s with invalid extension type\n");
+ p(out_invsatype, "\t" LLU " message%s with invalid sa type\n");
+ p(out_invaddr, "\t" LLU " message%s with invalid address extension\n");
+
+ /* userland -> kernel */
+ p(in_total, "\t" LLU " request%s sent from userland\n");
+ p(in_bytes, "\t" LLU " byte%s sent from userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.in_msgtype)/sizeof(pfkeystat.in_msgtype[0]);
+ type++) {
+ if (pfkeystat.in_msgtype[type] <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type),
+ (CAST)pfkeystat.in_msgtype[type]);
+ }
+ p(in_msgtarget[KEY_SENDUP_ONE],
+ "\t" LLU " message%s toward single socket\n");
+ p(in_msgtarget[KEY_SENDUP_ALL],
+ "\t" LLU " message%s toward all sockets\n");
+ p(in_msgtarget[KEY_SENDUP_REGISTERED],
+ "\t" LLU " message%s toward registered sockets\n");
+ p(in_nomem, "\t" LLU " message%s with memory allocation failure\n");
+#undef p
+}
+#endif /*IPSEC*/
diff --git a/usr.sbin/mld6query/Makefile b/usr.sbin/mld6query/Makefile
new file mode 100644
index 0000000000000..c1cdd8fee4770
--- /dev/null
+++ b/usr.sbin/mld6query/Makefile
@@ -0,0 +1,22 @@
+# Copyright (c) 1996 WIDE Project. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modifications, are permitted provided that the above copyright notice
+# and this paragraph are duplicated in all such forms and that any
+# documentation, advertising materials, and other materials related to
+# such distribution and use acknowledge that the software was developed
+# by the WIDE Project, Japan. The name of the Project may not be used to
+# endorse or promote products derived from this software without
+# specific prior written permission. THIS SOFTWARE IS PROVIDED ``AS IS''
+# AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+# LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE.
+
+PROG= mld6query
+SRCS= mld6.c
+
+MAN8= mld6query.8
+
+CFLAGS+= -DINET6 -DIPSEC
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mld6query/mld6.c b/usr.sbin/mld6query/mld6.c
new file mode 100644
index 0000000000000..473e0f4f00fc8
--- /dev/null
+++ b/usr.sbin/mld6query/mld6.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 1998 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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/param.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <err.h>
+
+struct msghdr m;
+struct sockaddr_in6 dst;
+struct mld6_hdr mldh;
+struct in6_addr maddr = IN6ADDR_ANY_INIT, any = IN6ADDR_ANY_INIT;
+struct ipv6_mreq mreq;
+u_short ifindex;
+int s;
+
+#define QUERY_RESPONSE_INTERVAL 10000
+
+void make_msg(int index, struct in6_addr *addr, u_int type);
+void usage(void);
+void dump(int);
+void quit(int);
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ struct icmp6_filter filt;
+ u_int hlim = 1;
+ fd_set fdset;
+ struct itimerval itimer;
+ u_int type;
+ int ch;
+
+ type = MLD6_LISTENER_QUERY;
+ while ((ch = getopt(argc, argv, "d")) != EOF) {
+ switch (ch) {
+ case 'd':
+ type = MLD6_LISTENER_DONE;
+ break;
+ case 'r':
+ type = MLD6_LISTENER_REPORT;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc != 1 && argc != 2)
+ usage();
+
+ ifindex = (u_short)if_nametoindex(argv[0]);
+ if (ifindex == 0)
+ usage();
+ if (argc == 3 && inet_pton(AF_INET6, argv[1], &maddr) != 1)
+ usage();
+
+ if ((s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
+ err(1, "socket");
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hlim,
+ sizeof(hlim)) == -1)
+ err(1, "setsockopt(IPV6_MULTICAST_HOPS)");
+
+ mreq.ipv6mr_multiaddr = any;
+ mreq.ipv6mr_interface = ifindex;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
+ sizeof(mreq)) == -1)
+ err(1, "setsockopt(IPV6_JOIN_GROUP)");
+
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_QUERY, &filt);
+ ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_REPORT, &filt);
+ ICMP6_FILTER_SETPASS(ICMP6_MEMBERSHIP_REDUCTION, &filt);
+ if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) < 0)
+ err(1, "setsockopt(ICMP6_FILTER)");
+
+ make_msg(ifindex, &maddr, type);
+
+ if (sendmsg(s, &m, 0) < 0)
+ err(1, "sendmsg");
+
+ itimer.it_value.tv_sec = QUERY_RESPONSE_INTERVAL / 1000;
+ itimer.it_interval.tv_sec = 0;
+ itimer.it_interval.tv_usec = 0;
+ itimer.it_value.tv_usec = 0;
+
+ (void)signal(SIGALRM, quit);
+ (void)setitimer(ITIMER_REAL, &itimer, NULL);
+
+ FD_ZERO(&fdset);
+ for (;;) {
+ FD_SET(s, &fdset);
+ if ((i = select(s + 1, &fdset, NULL, NULL, NULL)) < 0)
+ perror("select");
+ if (i == 0)
+ continue;
+ else
+ dump(s);
+ }
+}
+
+void
+make_msg(int index, struct in6_addr *addr, u_int type)
+{
+ static struct iovec iov[2];
+ static u_char *cmsgbuf;
+ int cmsglen, hbhlen = 0;
+ u_int8_t raopt[IP6OPT_RTALERT_LEN];
+ struct in6_pktinfo *pi;
+ struct cmsghdr *cmsgp;
+ u_short rtalert_code = htons(IP6OPT_RTALERT_MLD);
+
+ dst.sin6_len = sizeof(dst);
+ dst.sin6_family = AF_INET6;
+ if (IN6_IS_ADDR_UNSPECIFIED(addr)) {
+ if (inet_pton(AF_INET6, "ff02::1", &dst.sin6_addr) != 1)
+ errx(1, "inet_pton failed");
+ }
+ else
+ dst.sin6_addr = *addr;
+ m.msg_name = (caddr_t)&dst;
+ m.msg_namelen = dst.sin6_len;
+ iov[0].iov_base = (caddr_t)&mldh;
+ iov[0].iov_len = sizeof(mldh);
+ m.msg_iov = iov;
+ m.msg_iovlen = 1;
+
+ bzero(&mldh, sizeof(mldh));
+ mldh.mld6_type = type & 0xff;
+ mldh.mld6_maxdelay = htons(QUERY_RESPONSE_INTERVAL);
+ mldh.mld6_addr = *addr;
+
+ hbhlen = sizeof(raopt);
+ cmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ inet6_option_space(hbhlen);
+
+ if ((cmsgbuf = malloc(cmsglen)) == NULL)
+ errx(1, "can't allocate enough memory for cmsg");
+ cmsgp = (struct cmsghdr *)cmsgbuf;
+ m.msg_control = (caddr_t)cmsgbuf;
+ m.msg_controllen = cmsglen;
+ /* specify the outgoing interface */
+ cmsgp->cmsg_len = CMSG_SPACE(sizeof(struct in6_pktinfo));
+ cmsgp->cmsg_level = IPPROTO_IPV6;
+ cmsgp->cmsg_type = IPV6_PKTINFO;
+ pi = (struct in6_pktinfo *)CMSG_DATA(cmsgp);
+ pi->ipi6_ifindex = index;
+ memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr));
+ /* specifiy to insert router alert option in a hop-by-hop opt hdr. */
+ cmsgp = CMSG_NXTHDR(&m, cmsgp);
+ if (inet6_option_init((void *)cmsgp, &cmsgp, IPV6_HOPOPTS))
+ errx(1, "inet6_option_init failed\n");
+ raopt[0] = IP6OPT_RTALERT;
+ raopt[1] = IP6OPT_RTALERT_LEN - 2;
+ memcpy(&raopt[2], (caddr_t)&rtalert_code, sizeof(u_short));
+ if (inet6_option_append(cmsgp, raopt, 4, 0))
+ errx(1, "inet6_option_append failed\n");
+}
+
+void
+dump(int s)
+{
+ int i;
+ struct mld6_hdr *mld;
+ u_char buf[1024];
+ struct sockaddr_in6 from;
+ int from_len = sizeof(from);
+ char ntop_buf[256];
+
+ if ((i = recvfrom(s, buf, sizeof(buf), 0,
+ (struct sockaddr *)&from,
+ &from_len)) < 0)
+ return;
+
+ if (i < sizeof(struct mld6_hdr)) {
+ printf("too short!\n");
+ return;
+ }
+
+ mld = (struct mld6_hdr *)buf;
+
+ printf("from %s, ", inet_ntop(AF_INET6, &from.sin6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+
+ switch (mld->mld6_type) {
+ case ICMP6_MEMBERSHIP_QUERY:
+ printf("type=Multicast Listener Query, ");
+ break;
+ case ICMP6_MEMBERSHIP_REPORT:
+ printf("type=Multicast Listener Report, ");
+ break;
+ case ICMP6_MEMBERSHIP_REDUCTION:
+ printf("type=Multicast Listener Done, ");
+ break;
+ }
+ printf("addr=%s\n", inet_ntop(AF_INET6, &mld->mld6_addr,
+ ntop_buf, sizeof(ntop_buf)));
+
+ fflush(stdout);
+}
+
+/* ARGSUSED */
+void
+quit(int signum) {
+ mreq.ipv6mr_multiaddr = any;
+ mreq.ipv6mr_interface = ifindex;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq,
+ sizeof(mreq)) == -1)
+ err(1, "setsockopt(IPV6_LEAVE_GROUP)");
+
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: mld6query ifname [addr]\n");
+ exit(1);
+}
diff --git a/usr.sbin/mld6query/mld6query.8 b/usr.sbin/mld6query/mld6query.8
new file mode 100644
index 0000000000000..470e18ae63f7e
--- /dev/null
+++ b/usr.sbin/mld6query/mld6query.8
@@ -0,0 +1,87 @@
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE 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.
+.\" 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+.\"
+.\" $Id: mld6query.8,v 1.3 1999/08/20 10:00:06 itojun Exp $
+.\"
+.Dd May 17, 1998
+.Dt MLD6QUERY 8
+.Os KAME
+.\"
+.Sh NAME
+.Nm mld6query
+.Nd send multicast listener query
+.\"
+.Sh SYNOPSIS
+.Nm
+.Op Fl dr
+.Ar intface
+.Op Ar maddr
+.\"
+.Sh DESCRIPTION
+.Nm
+sends an IPv6 multicast listener discovery (MLD) query packet toward
+the specified multicast address,
+.Ar maddr ,
+toward interface
+.Ar intface .
+If you omit
+.Ar maddr ,
+linklocal all nodes multicast address(ff02::1) is used.
+.Pp
+After sending a query,
+.Nm
+waits for replies for at most 10 seconds.
+If a reply is returned,
+.Nm
+prints it with its type and then waits for another reply.
+.Pp
+This program is provided only for debugging.
+It is not necessary for normal use.
+.Pp
+With
+.Fl d ,
+.Nm
+will transmit MLD done packet instead of MLD query packet.
+With
+.Fl r ,
+similarly, MLD report packet will be transmitted.
+.Fl dr
+options are for debugging purposes only.
+.\"
+.Sh RETURN VALUES
+The program exits with 0 on success, non-zero on failures.
+.\"
+.\" .Sh SEE ALSO
+.\"
+.Sh HISTORY
+The
+.Nm
+command first appeared in WIDE/KAME IPv6 protocol stack kit.
+.Sh BUGS
+.Nm Mld6query
+does not take care of multicast addresses which have non link-local
+scope.
diff --git a/usr.sbin/rtadvd/dump.c b/usr.sbin/rtadvd/dump.c
new file mode 100644
index 0000000000000..8c070f8991cd7
--- /dev/null
+++ b/usr.sbin/rtadvd/dump.c
@@ -0,0 +1,215 @@
+/* $KAME: dump.c,v 1.10 2000/05/23 11:31:25 itojun Exp $ */
+
+/*
+ * Copyright (C) 2000 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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 <net/if.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <net/if_var.h>
+#endif /* __FreeBSD__ >= 3 */
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+
+/* XXX: the following two are non-standard include files */
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <string.h>
+#include <errno.h>
+
+#include "rtadvd.h"
+#include "timer.h"
+#include "if.h"
+#include "dump.h"
+
+static FILE *fp;
+
+extern struct rainfo *ralist;
+
+static char *ether_str __P((struct sockaddr_dl *));
+static void if_dump __P((void));
+
+#ifdef __FreeBSD__ /* XXX: see PORTABILITY */
+#define LONGLONG "%qu"
+#else
+#define LONGLONG "%llu"
+#endif
+
+static char *
+ether_str(sdl)
+ struct sockaddr_dl *sdl;
+{
+ static char ebuf[32];
+ u_char *cp;
+
+ if (sdl->sdl_alen && sdl->sdl_alen > 5) {
+ cp = (u_char *)LLADDR(sdl);
+ sprintf(ebuf, "%x:%x:%x:%x:%x:%x",
+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+ }
+ else {
+ sprintf(ebuf, "NONE");
+ }
+
+ return(ebuf);
+}
+
+static void
+if_dump()
+{
+ struct rainfo *rai;
+ struct prefix *pfx;
+ char prefixbuf[INET6_ADDRSTRLEN];
+ int first;
+
+ for (rai = ralist; rai; rai = rai->next) {
+ fprintf(fp, "%s:\n", rai->ifname);
+
+ fprintf(fp, " Status: %s\n",
+ (iflist[rai->ifindex]->ifm_flags & IFF_UP) ? "UP" :
+ "DOWN");
+
+ /* control information */
+ if (rai->lastsent.tv_sec) {
+ /* note that ctime() appends CR by itself */
+ fprintf(fp, " Last RA sent: %s",
+ ctime((time_t *)&rai->lastsent.tv_sec));
+ }
+ if (rai->timer) {
+ fprintf(fp, " Next RA will be sent: %s",
+ ctime((time_t *)&rai->timer->tm.tv_sec));
+ }
+ else
+ fprintf(fp, " RA timer is stopped");
+ fprintf(fp, " waits: %d, initcount: %d\n",
+ rai->waiting, rai->initcounter);
+
+ /* statistics */
+ fprintf(fp,
+ " statistics: RA(out/in/inconsistent): "
+ LONGLONG "/" LONGLONG "/" LONGLONG ", ",
+ (unsigned long long)rai->raoutput,
+ (unsigned long long)rai->rainput,
+ (unsigned long long)rai->rainconsistent);
+ fprintf(fp, "RS(input): " LONGLONG "\n",
+ (unsigned long long)rai->rsinput);
+
+ /* interface information */
+ if (rai->advlinkopt)
+ fprintf(fp, " Link-layer address: %s\n",
+ ether_str(rai->sdl));
+ fprintf(fp, " MTU: %d\n", rai->phymtu);
+
+ /* Router configuration variables */
+ fprintf(fp,
+ " DefaultLifetime: %d, MaxAdvInterval: %d, "
+ "MinAdvInterval: %d\n",
+ rai->lifetime, rai->maxinterval, rai->mininterval);
+ fprintf(fp, " Flags: %s%s%s MTU: %d\n",
+ rai->managedflg ? "M" : "", rai->otherflg ? "O" : "",
+#ifdef MIP6
+ rai->haflg ? "H" :
+#endif
+ "", rai->linkmtu);
+ fprintf(fp, " ReachableTime: %d, RetransTimer: %d, "
+ "CurHopLimit: %d\n", rai->reachabletime,
+ rai->retranstimer, rai->hoplimit);
+#ifdef MIP6
+ fprintf(fp, " HAPreference: %d, HALifetime: %d\n",
+ rai->hapref, rai->hatime);
+#endif
+
+ for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix;
+ pfx = pfx->next) {
+ if (first) {
+ fprintf(fp, " Prefixes:\n");
+ first = 0;
+ }
+ fprintf(fp, " %s/%d(",
+ inet_ntop(AF_INET6, &pfx->prefix,
+ prefixbuf, sizeof(prefixbuf)),
+ pfx->prefixlen);
+ switch(pfx->origin) {
+ case PREFIX_FROM_KERNEL:
+ fprintf(fp, "KERNEL, ");
+ break;
+ case PREFIX_FROM_CONFIG:
+ fprintf(fp, "CONFIG, ");
+ break;
+ case PREFIX_FROM_DYNAMIC:
+ fprintf(fp, "DYNAMIC, ");
+ break;
+ }
+ if (pfx->validlifetime == ND6_INFINITE_LIFETIME)
+ fprintf(fp, "vltime: infinity, ");
+ else
+ fprintf(fp, "vltime: %ld, ",
+ (long)pfx->validlifetime);
+ if (pfx->preflifetime == ND6_INFINITE_LIFETIME)
+ fprintf(fp, "pltime: infinity, ");
+ else
+ fprintf(fp, "pltime: %ld, ",
+ (long)pfx->preflifetime);
+ fprintf(fp, "flags: %s%s%s",
+ pfx->onlinkflg ? "L" : "",
+ pfx->autoconfflg ? "A" : "",
+#ifdef MIP6
+ pfx->routeraddr ? "R" :
+#endif
+ "");
+ fprintf(fp, ")\n");
+ }
+ }
+}
+
+void
+rtadvd_dump_file(dumpfile)
+ char *dumpfile;
+{
+ if ((fp = fopen(dumpfile, "w")) == NULL) {
+ syslog(LOG_WARNING, "<%s> open a dump file(%s)",
+ __FUNCTION__, dumpfile);
+ return;
+ }
+
+ if_dump();
+
+ fclose(fp);
+}
diff --git a/usr.sbin/rtadvd/dump.h b/usr.sbin/rtadvd/dump.h
new file mode 100644
index 0000000000000..b973d0adbd4be
--- /dev/null
+++ b/usr.sbin/rtadvd/dump.h
@@ -0,0 +1,34 @@
+/* $KAME$ */
+
+/*
+ * Copyright (C) 1998 WIDE 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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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$
+ */
+
+extern void rtadvd_dump_file __P((char *));