diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 2000-07-10 19:20:09 +0000 |
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 2000-07-10 19:20:09 +0000 |
| commit | 209a6f5a68b2827a91a4e30803330408299dd4dd (patch) | |
| tree | 127744ac436b55c0f3c1ef9fa500ca066db4daec | |
| parent | f8c4dd457f2274102e0c9f779c4390e8d189089b (diff) | |
Notes
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 *)⁡ + +#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 *)); |
