diff options
author | shin <shin@FreeBSD.org> | 1999-12-07 17:39:16 +0000 |
---|---|---|
committer | shin <shin@FreeBSD.org> | 1999-12-07 17:39:16 +0000 |
commit | 70f0bdf6818a73c858bc47a23afc1e9d7c56d716 (patch) | |
tree | 446280db4239de7d7d9030c47d2c30515a265a54 /sys | |
parent | 7bdf4b7db0db632bec3b1040d83cdfbdb35e59cd (diff) | |
download | FreeBSD-src-70f0bdf6818a73c858bc47a23afc1e9d7c56d716.zip FreeBSD-src-70f0bdf6818a73c858bc47a23afc1e9d7c56d716.tar.gz |
udp IPv6 support, IPv6/IPv4 tunneling support in kernel,
packet divert at kernel for IPv6/IPv4 translater daemon
This includes queue related patch submitted by jburkhol@home.com.
Submitted by: queue related patch from jburkhol@home.com
Reviewed by: freebsd-arch, cvs-committers
Obtained from: KAME project
Diffstat (limited to 'sys')
52 files changed, 2628 insertions, 314 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES index db2f541..8ec43fc 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -437,6 +437,11 @@ device mn0 # Munich32x/Falc54 Nx64kbit/sec cards. # included for testing purposes. # The `tun' pseudo-device implements (user-)ppp and nos-tun # The `streams' pseudo-device implements SysVR4 STREAMS emulation. +# The `gif' pseudo-device implements IPv6 over IP4 tunneling, +# IPv4 over IPv6 tunneling, IPv4 over IPv4 tunneling and +# IPv6 over IPv6 tunneling. +# The `faith' pseudo-device captures packets sent to it and diverts them +# to the IPv4/IPv6 translation daemon. # # The PPP_BSDCOMP option enables support for compress(1) style entire # packet compression, the PPP_DEFLATE is for zlib/gzip style compression. @@ -459,6 +464,10 @@ options PPP_BSDCOMP #PPP BSD-compress support options PPP_DEFLATE #PPP zlib/deflate/gzip support options PPP_FILTER #enable bpf filtering (needs bpf) +# for IPv6 +pseudo-device gif 4 #IPv6 and IPv4 tunneling +pseudo-device faith 1 #for IPv6 and IPv4 translation + # # Internet family options: # diff --git a/sys/conf/files b/sys/conf/files index dc919b1..62700b5 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -465,7 +465,9 @@ net/if_atmsubr.c optional atm net/if_disc.c optional disc net/if_ethersubr.c optional ether net/if_iso88025subr.c optional token +net/if_faith.c optional faith net/if_fddisubr.c optional fddi +net/if_gif.c optional gif net/if_loop.c optional loop net/if_media.c standard net/if_mib.c standard @@ -474,6 +476,7 @@ net/if_sl.c optional sl net/if_spppsubr.c optional sppp net/if_tun.c optional tun net/if_vlan.c optional vlan +net/net_osdep.c standard net/ppp_deflate.c optional ppp_deflate net/ppp_tty.c optional ppp net/radix.c standard @@ -484,7 +487,6 @@ net/rtsock.c standard net/slcompress.c optional ppp net/slcompress.c optional sl net/zlib.c optional ppp_deflate -net/net_osdep.c standard netatalk/aarp.c optional netatalk netatalk/at_control.c optional netatalk netatalk/at_proto.c optional netatalk @@ -595,6 +597,7 @@ netgraph/ng_vjc.c optional netgraph_vjc net/slcompress.c optional netgraph_vjc netinet/if_atm.c optional atm netinet/if_ether.c optional ether +netinet/in_gif.c optional gif inet netinet/igmp.c optional inet netinet/in.c optional inet #netinet/in_hostcache.c optional inet @@ -617,34 +620,36 @@ netinet/tcp_subr.c optional inet netinet/tcp_timer.c optional inet netinet/tcp_usrreq.c optional inet netinet/udp_usrreq.c optional inet -netinet6/in6.c optional inet6 -netinet6/in6_ifattach.c optional inet6 -netinet6/in6_cksum.c optional inet6 -netinet6/in6_pcb.c optional inet6 -netinet6/in6_proto.c optional inet6 -netinet6/in6_rmx.c optional inet6 -netinet6/in6_prefix.c optional inet6 +netinet/ip_fil.c optional ipfilter inet +netinet/fil.c optional ipfilter inet +netinet/ip_nat.c optional ipfilter inet +netinet/ip_frag.c optional ipfilter inet +netinet/ip_state.c optional ipfilter inet +netinet/ip_auth.c optional ipfilter inet +netinet/ip_proxy.c optional ipfilter inet +netinet/ip_log.c optional ipfilter inet +netinet/mlfk_ipl.c optional ipfilter inet netinet6/dest6.c optional inet6 netinet6/frag6.c optional inet6 netinet6/icmp6.c optional inet6 -netinet6/ip6_input.c optional inet6 +netinet6/in6.c optional inet6 +netinet6/in6_cksum.c optional inet6 +netinet6/in6_gif.c optional gif inet6 netinet6/ip6_forward.c optional inet6 +netinet6/in6_ifattach.c optional inet6 +netinet6/ip6_input.c optional inet6 netinet6/ip6_output.c optional inet6 -netinet6/route6.c optional inet6 +netinet6/in6_pcb.c optional inet6 +netinet6/in6_prefix.c optional inet6 +netinet6/in6_proto.c optional inet6 +netinet6/in6_rmx.c optional inet6 netinet6/mld6.c optional inet6 netinet6/nd6.c optional inet6 netinet6/nd6_nbr.c optional inet6 netinet6/nd6_rtr.c optional inet6 netinet6/raw_ip6.c optional inet6 -netinet/ip_fil.c optional ipfilter inet -netinet/fil.c optional ipfilter inet -netinet/ip_nat.c optional ipfilter inet -netinet/ip_frag.c optional ipfilter inet -netinet/ip_state.c optional ipfilter inet -netinet/ip_auth.c optional ipfilter inet -netinet/ip_proxy.c optional ipfilter inet -netinet/ip_log.c optional ipfilter inet -netinet/mlfk_ipl.c optional ipfilter inet +netinet6/route6.c optional inet6 +netinet6/udp6_usrreq.c optional inet6 netipx/ipx.c optional ipx netipx/ipx_cksum.c optional ipx netipx/ipx_input.c optional ipx diff --git a/sys/conf/options b/sys/conf/options index ed76e00..3c7558b 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -217,7 +217,7 @@ BOOTP_WIRED_TO opt_bootp.h BRIDGE opt_bdg.h MROUTING opt_mrouting.h INET opt_inet.h -INET6 opt_inet.h +INET6 opt_inet6.h IPDIVERT DUMMYNET opt_ipdn.h IPFILTER opt_ipfilter.h diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index db2f541..8ec43fc 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -437,6 +437,11 @@ device mn0 # Munich32x/Falc54 Nx64kbit/sec cards. # included for testing purposes. # The `tun' pseudo-device implements (user-)ppp and nos-tun # The `streams' pseudo-device implements SysVR4 STREAMS emulation. +# The `gif' pseudo-device implements IPv6 over IP4 tunneling, +# IPv4 over IPv6 tunneling, IPv4 over IPv4 tunneling and +# IPv6 over IPv6 tunneling. +# The `faith' pseudo-device captures packets sent to it and diverts them +# to the IPv4/IPv6 translation daemon. # # The PPP_BSDCOMP option enables support for compress(1) style entire # packet compression, the PPP_DEFLATE is for zlib/gzip style compression. @@ -459,6 +464,10 @@ options PPP_BSDCOMP #PPP BSD-compress support options PPP_DEFLATE #PPP zlib/deflate/gzip support options PPP_FILTER #enable bpf filtering (needs bpf) +# for IPv6 +pseudo-device gif 4 #IPv6 and IPv4 tunneling +pseudo-device faith 1 #for IPv6 and IPv4 translation + # # Internet family options: # diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index db2f541..8ec43fc 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -437,6 +437,11 @@ device mn0 # Munich32x/Falc54 Nx64kbit/sec cards. # included for testing purposes. # The `tun' pseudo-device implements (user-)ppp and nos-tun # The `streams' pseudo-device implements SysVR4 STREAMS emulation. +# The `gif' pseudo-device implements IPv6 over IP4 tunneling, +# IPv4 over IPv6 tunneling, IPv4 over IPv4 tunneling and +# IPv6 over IPv6 tunneling. +# The `faith' pseudo-device captures packets sent to it and diverts them +# to the IPv4/IPv6 translation daemon. # # The PPP_BSDCOMP option enables support for compress(1) style entire # packet compression, the PPP_DEFLATE is for zlib/gzip style compression. @@ -459,6 +464,10 @@ options PPP_BSDCOMP #PPP BSD-compress support options PPP_DEFLATE #PPP zlib/deflate/gzip support options PPP_FILTER #enable bpf filtering (needs bpf) +# for IPv6 +pseudo-device gif 4 #IPv6 and IPv4 tunneling +pseudo-device faith 1 #for IPv6 and IPv4 translation + # # Internet family options: # diff --git a/sys/modules/if_disc/Makefile b/sys/modules/if_disc/Makefile index 63b8592..e33555d 100644 --- a/sys/modules/if_disc/Makefile +++ b/sys/modules/if_disc/Makefile @@ -2,7 +2,7 @@ .PATH: ${.CURDIR}/../../net KMOD= if_disc -SRCS= if_disc.c opt_inet.h +SRCS= if_disc.c opt_inet.h opt_inet6.h NOMAN= NBPF?= 1 @@ -12,4 +12,7 @@ CFLAGS+= ${PROTOS} opt_inet.h: echo "#define INET 1" > opt_inet.h +#opt_inet6.h: +# echo "#define INET6 1" > opt_inet6.h + .include <bsd.kmod.mk> diff --git a/sys/net/if.c b/sys/net/if.c index 7c560bc..c0ba5ee 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -35,7 +35,7 @@ */ #include "opt_compat.h" -#include "opt_inet.h" +#include "opt_inet6.h" #include <sys/param.h> #include <sys/malloc.h> diff --git a/sys/net/if_atmsubr.c b/sys/net/if_atmsubr.c index 66cd09d..0a357a6 100644 --- a/sys/net/if_atmsubr.c +++ b/sys/net/if_atmsubr.c @@ -30,6 +30,8 @@ * 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$ */ /* @@ -37,6 +39,7 @@ */ #include "opt_inet.h" +#include "opt_inet6.h" #include "opt_natm.h" #include <sys/param.h> diff --git a/sys/net/if_disc.c b/sys/net/if_disc.c index b90a658..66bd5f8 100644 --- a/sys/net/if_disc.c +++ b/sys/net/if_disc.c @@ -52,6 +52,7 @@ #include <net/bpf.h> #include "opt_inet.h" +#include "opt_inet6.h" #ifdef TINY_DSMTU #define DSMTU (1024+512) @@ -180,6 +181,10 @@ discioctl(ifp, cmd, data) case AF_INET: break; #endif +#ifdef INET6 + case AF_INET6: + break; +#endif default: error = EAFNOSUPPORT; diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index ec0f5cf..bf11e9d 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -36,6 +36,7 @@ #include "opt_atalk.h" #include "opt_inet.h" +#include "opt_inet6.h" #include "opt_ipx.h" #include "opt_bdg.h" #include "opt_netgraph.h" diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c new file mode 100644 index 0000000..0e21af7 --- /dev/null +++ b/sys/net/if_faith.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1982, 1986, 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. + * + * $FreeBSD$ + */ +/* + * derived from + * @(#)if_loop.c 8.1 (Berkeley) 6/10/93 + * Id: if_loop.c,v 1.22 1996/06/19 16:24:10 wollman Exp + */ + +/* + * Loopback interface driver for protocol testing and timing. + */ + +#include "faith.h" +#if NFAITH > 0 + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> +#include <net/bpf.h> + +extern int loioctl __P((struct ifnet *, u_long, caddr_t)); +extern int looutput __P((struct ifnet *ifp, + struct mbuf *m, struct sockaddr *dst, struct rtentry *rt)); + +void faithattach __P((void *)); +PSEUDO_SET(faithattach, if_faith); +static struct ifnet faithif[NFAITH]; + +#define FAITHMTU 1500 + +/* ARGSUSED */ +void +faithattach(faith) + void *faith; +{ + register struct ifnet *ifp; + register int i; + + for (i = 0; i < NFAITH; i++) { + ifp = &faithif[i]; + bzero(ifp, sizeof(faithif[i])); + ifp->if_name = "faith"; + ifp->if_unit = i; + ifp->if_mtu = FAITHMTU; + /* Change to BROADCAST experimentaly to announce its prefix. */ + ifp->if_flags = /* IFF_LOOPBACK */ IFF_BROADCAST | IFF_MULTICAST; + ifp->if_ioctl = loioctl; + ifp->if_output = looutput; + ifp->if_type = IFT_FAITH; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_hdrlen = 0; + ifp->if_addrlen = 0; + if_attach(ifp); + bpfattach(ifp, DLT_NULL, sizeof(u_int)); + } +} +#endif /* NFAITH > 0 */ diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c index eedc822..0b39131 100644 --- a/sys/net/if_fddisubr.c +++ b/sys/net/if_fddisubr.c @@ -38,6 +38,7 @@ #include "opt_atalk.h" #include "opt_inet.h" +#include "opt_inet6.h" #include "opt_ipx.h" #include <sys/param.h> @@ -52,11 +53,14 @@ #include <net/if_dl.h> #include <net/if_types.h> -#ifdef INET +#if defined(INET) || defined(INET6) #include <netinet/in.h> #include <netinet/in_var.h> #include <netinet/if_ether.h> #endif +#ifdef INET6 +#include <netinet6/nd6.h> +#endif #if defined(__FreeBSD__) #include <netinet/if_fddi.h> #else @@ -186,6 +190,16 @@ fddi_output(ifp, m0, dst, rt0) break; } #endif +#ifdef INET6 + case AF_INET6: + if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { + /* this must be impossible, so we bark */ + printf("nd6_storelladdr failed\n"); + return(0); + } + type = htons(ETHERTYPE_IPV6); + break; +#endif #ifdef IPX case AF_IPX: type = htons(ETHERTYPE_IPX); @@ -481,7 +495,7 @@ fddi_input(ifp, fh, m) l = mtod(m, struct llc *); switch (l->llc_dsap) { -#if defined(INET) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK) +#if defined(INET) || defined(INET6) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK) case LLC_SNAP_LSAP: { u_int16_t type; @@ -528,6 +542,12 @@ fddi_input(ifp, fh, m) return; #endif #endif +#ifdef INET6 + case ETHERTYPE_IPV6: + schednetisr(NETISR_IPV6); + inq = &ip6intrq; + break; +#endif #ifdef IPX case ETHERTYPE_IPX: schednetisr(NETISR_IPX); diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c new file mode 100644 index 0000000..3eaa703 --- /dev/null +++ b/sys/net/if_gif.c @@ -0,0 +1,468 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * gif.c + */ + +#include "opt_inet.h" +#include "opt_inet6.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/syslog.h> +#include <machine/cpu.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/netisr.h> +#include <net/route.h> +#include <net/bpf.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/in_gif.h> +#endif /* INET */ + +#ifdef INET6 +#ifndef INET +#include <netinet/in.h> +#endif +#include <netinet6/in6_var.h> +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/in6_gif.h> +#endif /* INET6 */ + +#include <net/if_gif.h> + +#include "gif.h" + +#include <net/net_osdep.h> + +#if NGIF > 0 + +void gifattach __P((void *)); + +/* + * gif global variable definitions + */ +int ngif = NGIF; /* number of interfaces */ +struct gif_softc *gif = 0; + +void +gifattach(dummy) + void *dummy; +{ + register struct gif_softc *sc; + register int i; + + gif = sc = malloc (ngif * sizeof(struct gif_softc), M_DEVBUF, M_WAIT); + bzero(sc, ngif * sizeof(struct gif_softc)); + for (i = 0; i < ngif; sc++, i++) { + sc->gif_if.if_name = "gif"; + sc->gif_if.if_unit = i; + sc->gif_if.if_mtu = GIF_MTU; + sc->gif_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; + sc->gif_if.if_ioctl = gif_ioctl; + sc->gif_if.if_output = gif_output; + sc->gif_if.if_type = IFT_GIF; + sc->gif_if.if_snd.ifq_maxlen = ifqmaxlen; + if_attach(&sc->gif_if); + bpfattach(&sc->gif_if, DLT_NULL, sizeof(u_int)); + } +} + +PSEUDO_SET(gifattach, if_gif); + +int +gif_output(ifp, m, dst, rt) + struct ifnet *ifp; + struct mbuf *m; + struct sockaddr *dst; + struct rtentry *rt; /* added in net2 */ +{ + register struct gif_softc *sc = (struct gif_softc*)ifp; + int error = 0; + static int called = 0; /* XXX: MUTEX */ + int calllimit = 10; /* XXX: adhoc */ + + /* + * gif may cause infinite recursion calls when misconfigured. + * We'll prevent this by introducing upper limit. + * XXX: this mechanism may introduce another problem about + * mutual exclusion of the variable CALLED, especially if we + * use kernel thread. + */ + if (++called >= calllimit) { + log(LOG_NOTICE, + "gif_output: recursively called too many times(%d)\n", + called); + m_freem(m); + error = EIO; /* is there better errno? */ + goto end; + } + getmicrotime(&ifp->if_lastchange); + m->m_flags &= ~(M_BCAST|M_MCAST); + if (!(ifp->if_flags & IFF_UP) || + sc->gif_psrc == NULL || sc->gif_pdst == NULL) { + m_freem(m); + error = ENETDOWN; + goto end; + } + + 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 = dst->sa_family; + + m0.m_next = m; + m0.m_len = 4; + m0.m_data = (char *)⁡ + + bpf_mtap(ifp, &m0); + } + ifp->if_opackets++; + ifp->if_obytes += m->m_pkthdr.len; + + switch (sc->gif_psrc->sa_family) { +#ifdef INET + case AF_INET: + error = in_gif_output(ifp, dst->sa_family, m, rt); + break; +#endif +#ifdef INET6 + case AF_INET6: + error = in6_gif_output(ifp, dst->sa_family, m, rt); + break; +#endif + default: + m_freem(m); + error = ENETDOWN; + } + + end: + called = 0; /* reset recursion counter */ + if (error) ifp->if_oerrors++; + return error; +} + +void +gif_input(m, af, gifp) + struct mbuf *m; + int af; + struct ifnet *gifp; +{ + int s, isr; + register struct ifqueue *ifq = 0; + + if (gifp == NULL) { + /* just in case */ + m_freem(m); + return; + } + + if (m->m_pkthdr.rcvif) + m->m_pkthdr.rcvif = gifp; + + if (gifp->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 *)⁡ + + bpf_mtap(gifp, &m0); + } + + /* + * Put the packet to the network layer input queue according to the + * specified address family. + * Note: older versions of gif_input directly called network layer + * input functions, e.g. ip6_input, here. We changed the policy to + * prevent too many recursive calls of such input functions, which + * might cause kernel panic. But the change may introduce another + * problem; if the input queue is full, packets are discarded. + * We believed it rarely occurs and changed the policy. If we find + * it occurs more times than we thought, we may change the policy + * again. + */ + switch (af) { +#ifdef INET + case AF_INET: + ifq = &ipintrq; + isr = NETISR_IP; + break; +#endif +#ifdef INET6 + case AF_INET6: + ifq = &ip6intrq; + isr = NETISR_IPV6; + break; +#endif + default: + m_freem(m); + return; + } + + s = splimp(); + if (IF_QFULL(ifq)) { + IF_DROP(ifq); /* update statistics */ + m_freem(m); + splx(s); + return; + } + IF_ENQUEUE(ifq, m); + /* we need schednetisr since the address family may change */ + schednetisr(isr); + gifp->if_ipackets++; + gifp->if_ibytes += m->m_pkthdr.len; + splx(s); + + return; +} + + +int +gif_ioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + struct gif_softc *sc = (struct gif_softc*)ifp; + struct ifreq *ifr = (struct ifreq*)data; + int error = 0, size; + struct sockaddr *sa, *dst, *src; + + switch (cmd) { + case SIOCSIFADDR: + break; + + case SIOCSIFDSTADDR: + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + break; + + case SIOCGIFMTU: + break; + case SIOCSIFMTU: + { + u_long mtu; + mtu = ifr->ifr_mtu; + if (mtu < GIF_MTU_MIN || mtu > GIF_MTU_MAX) { + return (EINVAL); + } + ifp->if_mtu = mtu; + } + break; + + case SIOCSIFPHYADDR: +#ifdef INET6 + case SIOCSIFPHYADDR_IN6: +#endif /* INET6 */ + switch (ifr->ifr_addr.sa_family) { +#ifdef INET + case AF_INET: + src = (struct sockaddr *) + &(((struct in_aliasreq *)data)->ifra_addr); + dst = (struct sockaddr *) + &(((struct in_aliasreq *)data)->ifra_dstaddr); + + /* only one gif can have dst = INADDR_ANY */ +#define satosaddr(sa) (((struct sockaddr_in *)(sa))->sin_addr.s_addr) + + if (satosaddr(dst) == INADDR_ANY) { + int i; + struct gif_softc *sc2; + + for (i = 0, sc2 = gif; i < ngif; i++, sc2++) { + if (sc2 == sc) continue; + if (sc2->gif_pdst && + satosaddr(sc2->gif_pdst) + == INADDR_ANY) { + error = EADDRNOTAVAIL; + goto bad; + } + } + } + size = sizeof(struct sockaddr_in); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + src = (struct sockaddr *) + &(((struct in6_aliasreq *)data)->ifra_addr); + dst = (struct sockaddr *) + &(((struct in6_aliasreq *)data)->ifra_dstaddr); + + /* only one gif can have dst = in6addr_any */ +#define satoin6(sa) (&((struct sockaddr_in6 *)(sa))->sin6_addr) + + if (IN6_IS_ADDR_UNSPECIFIED(satoin6(dst))) { + int i; + struct gif_softc *sc2; + + for (i = 0, sc2 = gif; i < ngif; i++, sc2++) { + if (sc2 == sc) continue; + if (sc2->gif_pdst && + IN6_IS_ADDR_UNSPECIFIED( + satoin6(sc2->gif_pdst) + )) { + error = EADDRNOTAVAIL; + goto bad; + } + } + } + size = sizeof(struct sockaddr_in6); + break; +#endif /* INET6 */ + default: + error = EPROTOTYPE; + goto bad; + break; + } + if (sc->gif_psrc != NULL) + free((caddr_t)sc->gif_psrc, M_IFADDR); + if (sc->gif_pdst != NULL) + free((caddr_t)sc->gif_pdst, M_IFADDR); + + sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK); + bzero((caddr_t)sa, size); + bcopy((caddr_t)src, (caddr_t)sa, size); + sc->gif_psrc = sa; + + sa = (struct sockaddr *)malloc(size, M_IFADDR, M_WAITOK); + bzero((caddr_t)sa, size); + bcopy((caddr_t)dst, (caddr_t)sa, size); + sc->gif_pdst = sa; + + ifp->if_flags |= (IFF_UP|IFF_RUNNING); + if_up(ifp); /* send up RTM_IFINFO */ + + break; + + case SIOCGIFPSRCADDR: +#ifdef INET6 + case SIOCGIFPSRCADDR_IN6: +#endif /* INET6 */ + if (sc->gif_psrc == NULL) { + error = EADDRNOTAVAIL; + goto bad; + } + src = sc->gif_psrc; + switch (sc->gif_psrc->sa_family) { +#ifdef INET + case AF_INET: + dst = &ifr->ifr_addr; + size = sizeof(struct sockaddr_in); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + dst = (struct sockaddr *) + &(((struct in6_ifreq *)data)->ifr_addr); + size = sizeof(struct sockaddr_in6); + break; +#endif /* INET6 */ + default: + error = EADDRNOTAVAIL; + goto bad; + } + bcopy((caddr_t)src, (caddr_t)dst, size); + break; + + case SIOCGIFPDSTADDR: +#ifdef INET6 + case SIOCGIFPDSTADDR_IN6: +#endif /* INET6 */ + if (sc->gif_pdst == NULL) { + error = EADDRNOTAVAIL; + goto bad; + } + src = sc->gif_pdst; + switch (sc->gif_pdst->sa_family) { +#ifdef INET + case AF_INET: + dst = &ifr->ifr_addr; + size = sizeof(struct sockaddr_in); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + dst = (struct sockaddr *) + &(((struct in6_ifreq *)data)->ifr_addr); + size = sizeof(struct sockaddr_in6); + break; +#endif /* INET6 */ + default: + error = EADDRNOTAVAIL; + goto bad; + } + bcopy((caddr_t)src, (caddr_t)dst, size); + break; + + case SIOCSIFFLAGS: + break; + + default: + error = EINVAL; + break; + } + bad: + return error; +} +#endif /*NGIF > 0*/ diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h index a402471..cc26938 100644 --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -36,9 +36,6 @@ #ifndef _NET_IF_GIF_H_ #define _NET_IF_GIF_H_ -#include <netinet/in.h> -/* xxx sigh, why route have struct route instead of pointer? */ - struct gif_softc { struct ifnet gif_if; /* common area */ struct sockaddr *gif_psrc; /* Physical src addr */ diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index c57f857..a714bf1 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -42,6 +42,7 @@ #include "opt_atalk.h" #include "opt_inet.h" +#include "opt_inet6.h" #include "opt_ipx.h" #include <sys/param.h> @@ -90,13 +91,13 @@ #include <netatalk/at_var.h> #endif NETATALK -static int loioctl __P((struct ifnet *, u_long, caddr_t)); +int loioctl __P((struct ifnet *, u_long, caddr_t)); static void lortrequest __P((int, struct rtentry *, struct sockaddr *)); static void loopattach __P((void *)); PSEUDO_SET(loopattach, if_loop); -static int looutput __P((struct ifnet *ifp, +int looutput __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt)); #ifdef TINY_LOMTU @@ -131,7 +132,7 @@ loopattach(dummy) } } -static int +int looutput(ifp, m, dst, rt) struct ifnet *ifp; register struct mbuf *m; @@ -341,7 +342,7 @@ lortrequest(cmd, rt, sa) * Process an ioctl request. */ /* ARGSUSED */ -static int +int loioctl(ifp, cmd, data) register struct ifnet *ifp; u_long cmd; diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c index 133af2b..e02ef90 100644 --- a/sys/net/if_spppsubr.c +++ b/sys/net/if_spppsubr.c @@ -24,12 +24,14 @@ #if defined(__FreeBSD__) && __FreeBSD__ >= 3 #include "opt_inet.h" +#include "opt_inet6.h" #include "opt_ipx.h" #endif #ifdef NetBSD1_3 # if NetBSD1_3 > 6 # include "opt_inet.h" +# include "opt_inet6.h" # include "opt_iso.h" # endif #endif @@ -572,6 +574,12 @@ sppp_input(struct ifnet *ifp, struct mbuf *m) inq = &ipintrq; break; #endif +#ifdef INET6 + case ETHERTYPE_IPV6: + schednetisr (NETISR_IPV6); + inq = &ip6intrq; + break; +#endif #ifdef IPX case ETHERTYPE_IPX: schednetisr (NETISR_IPX); @@ -741,6 +749,15 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, } break; #endif +#ifdef INET6 + case AF_INET6: /* Internet Protocol */ + if (sp->pp_mode == IFF_CISCO) + h->protocol = htons (ETHERTYPE_IPV6); + else { + goto nosupport; + } + break; +#endif #ifdef NS case AF_NS: /* Xerox NS Protocol */ h->protocol = htons (sp->pp_mode == IFF_CISCO ? @@ -759,8 +776,8 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, goto nosupport; h->protocol = htons (PPP_ISO); break; -nosupport: #endif +nosupport: default: m_freem (m); ++ifp->if_oerrors; diff --git a/sys/netinet/if_atm.c b/sys/netinet/if_atm.c index 020e5ac..04b49bf 100644 --- a/sys/netinet/if_atm.c +++ b/sys/netinet/if_atm.c @@ -30,6 +30,8 @@ * 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$ */ /* @@ -37,6 +39,7 @@ */ #include "opt_inet.h" +#include "opt_inet6.h" #include "opt_natm.h" #if defined(INET) || defined(INET6) diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c new file mode 100644 index 0000000..fd8317f --- /dev/null +++ b/sys/netinet/in_gif.c @@ -0,0 +1,311 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * in_gif.c + */ + +#include "opt_mrouting.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/kernel.h> +#include <sys/sysctl.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/in_gif.h> + +#ifdef INET6 +#include <netinet/ip6.h> +#endif + +#ifdef MROUTING +#include <netinet/ip_mroute.h> +#endif /* MROUTING */ + +#include <net/if_gif.h> + +#include "gif.h" + +#include <machine/stdarg.h> + +#include <net/net_osdep.h> + +#if NGIF > 0 +int ip_gif_ttl = GIF_TTL; +#else +int ip_gif_ttl = 0; +#endif + +SYSCTL_DECL(_net_inet_ip); +SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, + &ip_gif_ttl, 0, ""); + +int +in_gif_output(ifp, family, m, rt) + struct ifnet *ifp; + int family; + struct mbuf *m; + struct rtentry *rt; +{ + register struct gif_softc *sc = (struct gif_softc*)ifp; + struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; + struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; + struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; + struct ip iphdr; /* capsule IP header, host byte ordered */ + int proto, error; + u_int8_t tos; + + if (sin_src == NULL || sin_dst == NULL || + sin_src->sin_family != AF_INET || + sin_dst->sin_family != AF_INET) { + m_freem(m); + return EAFNOSUPPORT; + } + + switch (family) { + case AF_INET: + { + struct ip *ip; + + proto = IPPROTO_IPV4; + if (m->m_len < sizeof(*ip)) { + m = m_pullup(m, sizeof(*ip)); + if (!m) + return ENOBUFS; + } + ip = mtod(m, struct ip *); + tos = ip->ip_tos; + break; + } +#ifdef INET6 + case AF_INET6: + { + struct ip6_hdr *ip6; + proto = IPPROTO_IPV6; + 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; + break; + } +#endif /*INET6*/ + default: +#ifdef DIAGNOSTIC + printf("in_gif_output: warning: unknown family %d passed\n", + family); +#endif + m_freem(m); + return EAFNOSUPPORT; + } + + bzero(&iphdr, sizeof(iphdr)); + iphdr.ip_src = sin_src->sin_addr; + if (ifp->if_flags & IFF_LINK0) { + /* multi-destination mode */ + if (sin_dst->sin_addr.s_addr != INADDR_ANY) + iphdr.ip_dst = sin_dst->sin_addr; + else if (rt) { + iphdr.ip_dst = ((struct sockaddr_in *) + (rt->rt_gateway))->sin_addr; + } else { + m_freem(m); + return ENETUNREACH; + } + } else { + /* bidirectional configured tunnel mode */ + if (sin_dst->sin_addr.s_addr != INADDR_ANY) + iphdr.ip_dst = sin_dst->sin_addr; + else { + m_freem(m); + return ENETUNREACH; + } + } + iphdr.ip_p = proto; + /* version will be set in ip_output() */ + iphdr.ip_ttl = ip_gif_ttl; + iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); + + /* prepend new IP header */ + 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) { + printf("ENOBUFS in in_gif_output %d\n", __LINE__); + return ENOBUFS; + } + + *(mtod(m, struct ip *)) = iphdr; + + if (dst->sin_family != sin_dst->sin_family || + dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { + /* cache route doesn't match */ + dst->sin_family = sin_dst->sin_family; + dst->sin_len = sizeof(struct sockaddr_in); + dst->sin_addr = sin_dst->sin_addr; + if (sc->gif_ro.ro_rt) { + RTFREE(sc->gif_ro.ro_rt); + sc->gif_ro.ro_rt = NULL; + } + } + + if (sc->gif_ro.ro_rt == NULL) { + rtalloc(&sc->gif_ro); + if (sc->gif_ro.ro_rt == NULL) { + m_freem(m); + return ENETUNREACH; + } + } + +#ifdef IPSEC + m->m_pkthdr.rcvif = NULL; +#endif /*IPSEC*/ + error = ip_output(m, 0, &sc->gif_ro, 0, 0); + return(error); +} + +void +#if __STDC__ +in_gif_input(struct mbuf *m, ...) +#else +in_gif_input(m, va_alist) + struct mbuf *m; + va_dcl +#endif +{ + int off, proto; + struct gif_softc *sc; + struct ifnet *gifp = NULL; + struct ip *ip; + int i, af; + va_list ap; + + va_start(ap, m); + off = va_arg(ap, int); + proto = va_arg(ap, int); + va_end(ap); + + ip = mtod(m, struct ip *); + + /* this code will be soon improved. */ +#define satosin(sa) ((struct sockaddr_in *)(sa)) + for (i = 0, sc = gif; i < ngif; i++, sc++) { + if (sc->gif_psrc == NULL + || sc->gif_pdst == NULL + || sc->gif_psrc->sa_family != AF_INET + || sc->gif_pdst->sa_family != AF_INET) { + continue; + } + + if ((sc->gif_if.if_flags & IFF_UP) == 0) + continue; + + if ((sc->gif_if.if_flags & IFF_LINK0) + && satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr + && satosin(sc->gif_pdst)->sin_addr.s_addr == INADDR_ANY) { + gifp = &sc->gif_if; + continue; + } + + if (satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr + && satosin(sc->gif_pdst)->sin_addr.s_addr == ip->ip_src.s_addr) + { + gifp = &sc->gif_if; + break; + } + } + + if (gifp == NULL) { +#ifdef MROUTING + /* for backward compatibility */ + if (proto == IPPROTO_IPV4) { + ipip_input(m, off, proto); + return; + } +#endif /*MROUTING*/ + m_freem(m); + ipstat.ips_nogif++; + return; + } + + m_adj(m, off); + + switch (proto) { + case IPPROTO_IPV4: + { + struct ip *ip; + af = AF_INET; + if (m->m_len < sizeof(*ip)) { + m = m_pullup(m, sizeof(*ip)); + if (!m) + return; + } + ip = mtod(m, struct ip *); + break; + } +#ifdef INET6 + case IPPROTO_IPV6: + { + struct ip6_hdr *ip6; + af = AF_INET6; + if (m->m_len < sizeof(*ip6)) { + m = m_pullup(m, sizeof(*ip6)); + if (!m) + return; + } + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_flow &= ~htonl(0xff << 20); + break; + } +#endif /* INET6 */ + default: + ipstat.ips_nogif++; + m_freem(m); + return; + } + gif_input(m, af, gifp); + return; +} diff --git a/sys/netinet/in_gif.h b/sys/netinet/in_gif.h new file mode 100644 index 0000000..b874524 --- /dev/null +++ b/sys/netinet/in_gif.h @@ -0,0 +1,42 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NETINET_IN_GIF_H_ +#define _NETINET_IN_GIF_H_ + +#define GIF_TTL 30 + +extern int ip_gif_ttl; + +void in_gif_input __P((struct mbuf *, ...)); +int in_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *)); + +#endif /*_NETINET_IN_GIF_H_*/ diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index d19d449..71d091b 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -34,10 +34,13 @@ * $FreeBSD$ */ +#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/socketvar.h> @@ -51,12 +54,25 @@ #include <vm/vm_zone.h> #include <net/if.h> +#include <net/if_types.h> #include <net/route.h> #include <netinet/in.h> #include <netinet/in_pcb.h> #include <netinet/in_var.h> #include <netinet/ip_var.h> +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet6/ip6_var.h> +#endif /* INET6 */ + +#include "faith.h" + +#ifdef IPSEC +#include <netinet6/ipsec.h> +#include <netkey/key.h> +#include <netkey/key_debug.h> +#endif /* IPSEC */ struct in_addr zeroin_addr; @@ -212,13 +228,34 @@ in_pcbbind(inp, nam, p) (t->inp_socket->so_options & SO_REUSEPORT) == 0) && (so->so_cred->cr_uid != - t->inp_socket->so_cred->cr_uid)) + t->inp_socket->so_cred->cr_uid)) { +#if defined(INET6) + if (ip6_mapped_addr_on == 0 || + ntohl(sin->sin_addr.s_addr) != + INADDR_ANY || + ntohl(t->inp_laddr.s_addr) != + INADDR_ANY || + INP_SOCKAF(so) == + INP_SOCKAF(t->inp_socket)) +#endif /* defined(INET6) */ return (EADDRINUSE); + } } t = in_pcblookup_local(pcbinfo, sin->sin_addr, lport, prison ? 0 : wild); - if (t && (reuseport & t->inp_socket->so_options) == 0) + if (t && + (reuseport & t->inp_socket->so_options) == 0) { +#if defined(INET6) + if (ip6_mapped_addr_on == 0 || + ntohl(sin->sin_addr.s_addr) != + INADDR_ANY || + ntohl(t->inp_laddr.s_addr) != + INADDR_ANY || + INP_SOCKAF(so) == + INP_SOCKAF(t->inp_socket)) +#endif /* defined(INET6) */ return (EADDRINUSE); + } } inp->inp_laddr = sin->sin_addr; } @@ -452,7 +489,7 @@ in_pcbconnect(inp, nam, p) if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, - inp->inp_lport, 0) != NULL) { + inp->inp_lport, 0, NULL) != NULL) { return (EADDRINUSE); } if (inp->inp_laddr.s_addr == INADDR_ANY) { @@ -488,6 +525,9 @@ in_pcbdetach(inp) struct socket *so = inp->inp_socket; struct inpcbinfo *ipi = inp->inp_pcbinfo; +#ifdef IPSEC + ipsec4_delete_pcbpolicy(inp); +#endif /*IPSEC*/ inp->inp_gencnt = ++ipi->ipi_gencnt; in_pcbremlists(inp); so->so_pcb = 0; @@ -497,6 +537,7 @@ in_pcbdetach(inp) if (inp->inp_route.ro_rt) rtfree(inp->inp_route.ro_rt); ip_freemoptions(inp->inp_moptions); + inp->inp_vflag = 0; zfreei(ipi->ipi_zone, inp); } @@ -620,6 +661,12 @@ in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify) errno = inetctlerrmap[cmd]; s = splnet(); for (inp = head->lh_first; inp != NULL;) { +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV4) == NULL) { + inp = LIST_NEXT(inp, inp_list); + continue; + } +#endif if (inp->inp_faddr.s_addr != faddr.s_addr || inp->inp_socket == 0 || (lport && inp->inp_lport != lport) || @@ -711,6 +758,10 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) */ head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV4) == NULL) + continue; +#endif if (inp->inp_faddr.s_addr == INADDR_ANY && inp->inp_laddr.s_addr == laddr.s_addr && inp->inp_lport == lport) { @@ -748,6 +799,10 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) for (inp = phd->phd_pcblist.lh_first; inp != NULL; inp = inp->inp_portlist.le_next) { wildcard = 0; +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV4) == NULL) + continue; +#endif if (inp->inp_faddr.s_addr != INADDR_ANY) wildcard++; if (inp->inp_laddr.s_addr != INADDR_ANY) { @@ -776,11 +831,13 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay) * Lookup PCB in hash list. */ struct inpcb * -in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) +in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, + ifp) struct inpcbinfo *pcbinfo; struct in_addr faddr, laddr; u_int fport_arg, lport_arg; int wildcard; + struct ifnet *ifp; { struct inpcbhead *head; register struct inpcb *inp; @@ -791,6 +848,10 @@ in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) */ head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV4) == NULL) + continue; +#endif if (inp->inp_faddr.s_addr == faddr.s_addr && inp->inp_laddr.s_addr == laddr.s_addr && inp->inp_fport == fport && @@ -803,17 +864,40 @@ in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) } if (wildcard) { struct inpcb *local_wild = NULL; +#if defined(INET6) + struct inpcb *local_wild_mapped = NULL; +#endif /* defined(INET6) */ head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV4) == NULL) + continue; +#endif if (inp->inp_faddr.s_addr == INADDR_ANY && inp->inp_lport == lport) { +#if defined(NFAITH) && NFAITH > 0 + if (ifp && ifp->if_type == IFT_FAITH && + (inp->inp_flags & INP_FAITH) == 0) + continue; +#endif if (inp->inp_laddr.s_addr == laddr.s_addr) return (inp); - else if (inp->inp_laddr.s_addr == INADDR_ANY) + else if (inp->inp_laddr.s_addr == INADDR_ANY) { +#if defined(INET6) + if (INP_CHECK_SOCKAF(inp->inp_socket, + AF_INET6)) + local_wild_mapped = inp; + else +#endif /* defined(INET6) */ local_wild = inp; + } } } +#if defined(INET6) + if (local_wild == NULL) + return (local_wild_mapped); +#endif /* defined(INET6) */ return (local_wild); } @@ -834,8 +918,16 @@ in_pcbinshash(inp) struct inpcbporthead *pcbporthash; struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; struct inpcbport *phd; + u_int32_t hashkey_faddr; - pcbhash = &pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, +#ifdef INET6 + if (inp->inp_vflag & INP_IPV6) + hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; + else +#endif /* INET6 */ + hashkey_faddr = inp->inp_faddr.s_addr; + + pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)]; pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport, @@ -877,8 +969,16 @@ in_pcbrehash(inp) struct inpcb *inp; { struct inpcbhead *head; + u_int32_t hashkey_faddr; + +#ifdef INET6 + if (inp->inp_vflag & INP_IPV6) + hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */; + else +#endif /* INET6 */ + hashkey_faddr = inp->inp_faddr.s_addr; - head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, + head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr, inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; LIST_REMOVE(inp, inp_hash); diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index adfa5fa..5aeb579 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -287,7 +287,8 @@ struct inpcb * struct in_addr, u_int, int)); struct inpcb * in_pcblookup_hash __P((struct inpcbinfo *, - struct in_addr, u_int, struct in_addr, u_int, int)); + struct in_addr, u_int, struct in_addr, u_int, + int, struct ifnet *)); void in_pcbnotify __P((struct inpcbhead *, struct sockaddr *, u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int))); void in_pcbrehash __P((struct inpcb *)); diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 22647d9..b9a9e4a 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -63,6 +63,11 @@ * TCP/IP protocol family: IP, ICMP, UDP, TCP. */ +#include "gif.h" +#if NGIF > 0 +#include <netinet/in_gif.h> +#endif + #ifdef IPXIP #include <netipx/ipx_ip.h> #endif @@ -119,12 +124,29 @@ struct protosw inetsw[] = { 0, 0, 0, 0, &rip_usrreqs }, +#if NGIF > 0 +{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, + in_gif_input, 0, 0, 0, + 0, + 0, 0, 0, 0, + &nousrreqs +}, +# ifdef INET6 +{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, + in_gif_input, 0, 0, 0, + 0, + 0, 0, 0, 0, + &nousrreqs +}, +#endif +#else /*NGIF*/ { SOCK_RAW, &inetdomain, IPPROTO_IPIP, PR_ATOMIC|PR_ADDR, ipip_input, 0, 0, rip_ctloutput, 0, 0, 0, 0, 0, &rip_usrreqs }, +#endif /*NGIF*/ #ifdef IPDIVERT { SOCK_RAW, &inetdomain, IPPROTO_DIVERT, PR_ATOMIC|PR_ADDR, div_input, 0, 0, ip_ctloutput, diff --git a/sys/netinet/ip_fw.c b/sys/netinet/ip_fw.c index a70822e..b897421 100644 --- a/sys/netinet/ip_fw.c +++ b/sys/netinet/ip_fw.c @@ -707,10 +707,12 @@ again: if (oif) P = in_pcblookup_hash(&tcbinfo, ip->ip_dst, - tcp->th_dport, ip->ip_src, tcp->th_sport, 0); + tcp->th_dport, ip->ip_src, tcp->th_sport, 0, + oif); else P = in_pcblookup_hash(&tcbinfo, ip->ip_src, - tcp->th_sport, ip->ip_dst, tcp->th_dport, 0); + tcp->th_sport, ip->ip_dst, tcp->th_dport, 0, + NULL); if (P && P->inp_socket) { if (f->fw_flg & IP_FW_F_UID) { @@ -738,10 +740,12 @@ again: if (oif) P = in_pcblookup_hash(&udbinfo, ip->ip_dst, - udp->uh_dport, ip->ip_src, udp->uh_sport, 1); + udp->uh_dport, ip->ip_src, udp->uh_sport, 1, + oif); else P = in_pcblookup_hash(&udbinfo, ip->ip_src, - udp->uh_sport, ip->ip_dst, udp->uh_dport, 1); + udp->uh_sport, ip->ip_dst, udp->uh_dport, 1, + NULL); if (P && P->inp_socket) { if (f->fw_flg & IP_FW_F_UID) { diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 5f61ff3..909adf9 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -390,7 +390,7 @@ findpcb: * already got one like this? */ inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport, 0); + ti->ti_dst, ti->ti_dport, 0, m->m_pkthdr.rcvif); if (!inp) { /* * No, then it's new. Try find the ambushing socket @@ -398,12 +398,13 @@ findpcb: if (!ip_fw_fwd_addr->sin_port) { inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, ip_fw_fwd_addr->sin_addr, - ti->ti_dport, 1); + ti->ti_dport, 1, m->m_pkthdr.rcvif); } else { inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, ip_fw_fwd_addr->sin_addr, - ntohs(ip_fw_fwd_addr->sin_port), 1); + ntohs(ip_fw_fwd_addr->sin_port), 1, + m->m_pkthdr.rcvif); } } ip_fw_fwd_addr = NULL; @@ -411,7 +412,7 @@ findpcb: #endif /* IPFIREWALL_FORWARD */ inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport, 1); + ti->ti_dst, ti->ti_dport, 1, m->m_pkthdr.rcvif); /* * If the state is CLOSED (i.e., TCB does not exist) then diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 5f61ff3..909adf9 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -390,7 +390,7 @@ findpcb: * already got one like this? */ inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport, 0); + ti->ti_dst, ti->ti_dport, 0, m->m_pkthdr.rcvif); if (!inp) { /* * No, then it's new. Try find the ambushing socket @@ -398,12 +398,13 @@ findpcb: if (!ip_fw_fwd_addr->sin_port) { inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, ip_fw_fwd_addr->sin_addr, - ti->ti_dport, 1); + ti->ti_dport, 1, m->m_pkthdr.rcvif); } else { inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, ip_fw_fwd_addr->sin_addr, - ntohs(ip_fw_fwd_addr->sin_port), 1); + ntohs(ip_fw_fwd_addr->sin_port), 1, + m->m_pkthdr.rcvif); } } ip_fw_fwd_addr = NULL; @@ -411,7 +412,7 @@ findpcb: #endif /* IPFIREWALL_FORWARD */ inp = in_pcblookup_hash(&tcbinfo, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport, 1); + ti->ti_dst, ti->ti_dport, 1, m->m_pkthdr.rcvif); /* * If the state is CLOSED (i.e., TCB does not exist) then diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index b472de5..fd3e435 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -35,7 +35,7 @@ */ #include "opt_compat.h" -#include "opt_inet.h" +#include "opt_inet6.h" #include "opt_tcpdebug.h" #include <sys/param.h> @@ -647,7 +647,7 @@ tcp_getcred SYSCTL_HANDLER_ARGS return (error); s = splnet(); inp = in_pcblookup_hash(&tcbinfo, addrs[1].sin_addr, addrs[1].sin_port, - addrs[0].sin_addr, addrs[0].sin_port, 0); + addrs[0].sin_addr, addrs[0].sin_port, 0, NULL); if (inp == NULL || inp->inp_socket == NULL) { error = ENOENT; goto out; diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index b472de5..fd3e435 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -35,7 +35,7 @@ */ #include "opt_compat.h" -#include "opt_inet.h" +#include "opt_inet6.h" #include "opt_tcpdebug.h" #include <sys/param.h> @@ -647,7 +647,7 @@ tcp_getcred SYSCTL_HANDLER_ARGS return (error); s = splnet(); inp = in_pcblookup_hash(&tcbinfo, addrs[1].sin_addr, addrs[1].sin_port, - addrs[0].sin_addr, addrs[0].sin_port, 0); + addrs[0].sin_addr, addrs[0].sin_port, 0, NULL); if (inp == NULL || inp->inp_socket == NULL) { error = ENOENT; goto out; diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 49fca1e..af43fc3 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -34,6 +34,7 @@ * $FreeBSD$ */ +#include "opt_inet6.h" #include "opt_tcpdebug.h" #include <sys/param.h> @@ -535,7 +536,7 @@ tcp_connect(tp, nam, p) sin->sin_addr, sin->sin_port, inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr : ifaddr->sin_addr, - inp->inp_lport, 0); + inp->inp_lport, 0, NULL); if (oinp) { if (oinp != inp && (otp = intotcpcb(oinp)) != NULL && otp->t_state == TCPS_TIME_WAIT && @@ -731,6 +732,9 @@ tcp_attach(so, p) if (error) return (error); inp = sotoinpcb(so); +#ifdef INET6 + inp->inp_vflag |= INP_IPV4; +#endif tp = tcp_newtcpcb(inp); if (tp == 0) { int nofd = so->so_state & SS_NOFDREF; /* XXX */ diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 2f0cb58..f49a128 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -34,11 +34,14 @@ * $FreeBSD$ */ +#include "opt_inet6.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/mbuf.h> +#include <sys/domain.h> #include <sys/proc.h> #include <sys/protosw.h> #include <sys/socket.h> @@ -54,14 +57,24 @@ #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> +#ifdef INET6 +#include <netinet/ip6.h> +#endif #include <netinet/in_pcb.h> #include <netinet/in_var.h> #include <netinet/ip_var.h> +#ifdef INET6 +#include <netinet6/ip6_var.h> +#endif #include <netinet/ip_icmp.h> #include <netinet/icmp_var.h> #include <netinet/udp.h> #include <netinet/udp_var.h> +#ifdef IPSEC +#include <netinet6/ipsec.h> +#endif /*IPSEC*/ + /* * UDP protocol implementation. * Per RFC 768, August, 1980. @@ -83,6 +96,7 @@ SYSCTL_INT(_net_inet_udp, OID_AUTO, blackhole, CTLFLAG_RW, &blackhole, 0, "Do not send port unreachables for refused connects"); struct inpcbhead udb; /* from udp_var.h */ +#define udb6 udb /* for KAME src sync over BSD*'s */ struct inpcbinfo udbinfo; #ifndef UDBHASHSIZE @@ -94,7 +108,27 @@ SYSCTL_STRUCT(_net_inet_udp, UDPCTL_STATS, stats, CTLFLAG_RD, &udpstat, udpstat, "UDP statistics (struct udpstat, netinet/udp_var.h)"); static struct sockaddr_in udp_in = { sizeof(udp_in), AF_INET }; +#ifdef INET6 +struct udp_in6 { + struct sockaddr_in6 uin6_sin; + u_char uin6_init_done : 1; +} udp_in6 = { + { sizeof(udp_in6.uin6_sin), AF_INET6 }, + 0 +}; +struct udp_ip6 { + struct ip6_hdr uip6_ip6; + u_char uip6_init_done : 1; +} udp_ip6; +#endif /* INET6 */ + +static void udp_append __P((struct inpcb *last, struct ip *ip, + struct mbuf *n, int off)); +#ifdef INET6 +static void ip_2_ip6_hdr __P((struct ip6_hdr *ip6, struct ip *ip)); +#endif +static int udp_detach __P((struct socket *so)); static int udp_output __P((struct inpcb *, struct mbuf *, struct sockaddr *, struct mbuf *, struct proc *)); @@ -111,16 +145,18 @@ udp_init() } void -udp_input(m, iphlen) +udp_input(m, off, proto) register struct mbuf *m; - int iphlen; + int off, proto; { + int iphlen = off; register struct ip *ip; register struct udphdr *uh; register struct inpcb *inp; struct mbuf *opts = 0; int len; struct ip save_ip; + struct sockaddr *append_sa; udpstat.udps_ipackets++; @@ -205,14 +241,19 @@ udp_input(m, iphlen) */ udp_in.sin_port = uh->uh_sport; udp_in.sin_addr = ip->ip_src; - m->m_len -= sizeof (struct udpiphdr); - m->m_data += sizeof (struct udpiphdr); /* * Locate pcb(s) for datagram. * (Algorithm copied from raw_intr().) */ last = NULL; - for (inp = udb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { +#ifdef INET6 + udp_in6.uin6_init_done = udp_ip6.uip6_init_done = 0; +#endif + LIST_FOREACH(inp, &udb, inp_list) { +#ifdef INET6 + if ((inp->inp_vflag & INP_IPV4) == NULL) + continue; +#endif if (inp->inp_lport != uh->uh_dport) continue; if (inp->inp_laddr.s_addr != INADDR_ANY) { @@ -230,21 +271,17 @@ udp_input(m, iphlen) if (last != NULL) { struct mbuf *n; - if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { - if (last->inp_flags & INP_CONTROLOPTS - || last->inp_socket->so_options & SO_TIMESTAMP) - ip_savecontrol(last, &opts, ip, n); - if (sbappendaddr(&last->inp_socket->so_rcv, - (struct sockaddr *)&udp_in, - n, opts) == 0) { - m_freem(n); - if (opts) - m_freem(opts); - udpstat.udps_fullsock++; - } else - sorwakeup(last->inp_socket); - opts = 0; - } +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (ipsec4_in_reject_so(m, last->inp_socket)) + ipsecstat.in_polvio++; + /* do not inject data to pcb */ + else +#endif /*IPSEC*/ + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) + udp_append(last, ip, n, + iphlen + + sizeof(struct udphdr)); } last = inp; /* @@ -268,23 +305,21 @@ udp_input(m, iphlen) udpstat.udps_noportbcast++; goto bad; } - if (last->inp_flags & INP_CONTROLOPTS - || last->inp_socket->so_options & SO_TIMESTAMP) - ip_savecontrol(last, &opts, ip, m); - if (sbappendaddr(&last->inp_socket->so_rcv, - (struct sockaddr *)&udp_in, - m, opts) == 0) { - udpstat.udps_fullsock++; +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (ipsec4_in_reject_so(m, last->inp_socket)) { + ipsecstat.in_polvio++; goto bad; } - sorwakeup(last->inp_socket); +#endif /*IPSEC*/ + udp_append(last, ip, m, iphlen + sizeof(struct udphdr)); return; } /* * Locate pcb for datagram. */ inp = in_pcblookup_hash(&udbinfo, ip->ip_src, uh->uh_sport, - ip->ip_dst, uh->uh_dport, 1); + ip->ip_dst, uh->uh_dport, 1, m->m_pkthdr.rcvif); if (inp == NULL) { if (log_in_vain) { char buf[4*sizeof "123"]; @@ -311,6 +346,12 @@ udp_input(m, iphlen) goto bad; return; } +#ifdef IPSEC + if (ipsec4_in_reject_so(m, inp->inp_socket)) { + ipsecstat.in_polvio++; + goto bad; + } +#endif /*IPSEC*/ /* * Construct sockaddr format source address. @@ -319,14 +360,30 @@ udp_input(m, iphlen) udp_in.sin_port = uh->uh_sport; udp_in.sin_addr = ip->ip_src; if (inp->inp_flags & INP_CONTROLOPTS - || inp->inp_socket->so_options & SO_TIMESTAMP) + || inp->inp_socket->so_options & SO_TIMESTAMP) { +#ifdef INET6 + if (inp->inp_vflag & INP_IPV6) { + int savedflags; + + ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip); + savedflags = inp->inp_flags; + inp->inp_flags &= ~INP_UNMAPPABLEOPTS; + ip6_savecontrol(inp, &opts, &udp_ip6.uip6_ip6, m); + inp->inp_flags = savedflags; + } else +#endif ip_savecontrol(inp, &opts, ip, m); + } iphlen += sizeof(struct udphdr); - m->m_len -= iphlen; - m->m_pkthdr.len -= iphlen; - m->m_data += iphlen; - if (sbappendaddr(&inp->inp_socket->so_rcv, (struct sockaddr *)&udp_in, - m, opts) == 0) { + m_adj(m, iphlen); +#ifdef INET6 + if (inp->inp_vflag & INP_IPV6) { + in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin); + append_sa = (struct sockaddr *)&udp_in6; + } else +#endif + append_sa = (struct sockaddr *)&udp_in; + if (sbappendaddr(&inp->inp_socket->so_rcv, append_sa, m, opts) == 0) { udpstat.udps_fullsock++; goto bad; } @@ -336,6 +393,78 @@ bad: m_freem(m); if (opts) m_freem(opts); + return; +} + +#if defined(INET6) +static void +ip_2_ip6_hdr(ip6, ip) + struct ip6_hdr *ip6; + struct ip *ip; +{ + bzero(ip6, sizeof(*ip6)); + + ip6->ip6_vfc = IPV6_VERSION; + ip6->ip6_plen = ip->ip_len; + ip6->ip6_nxt = ip->ip_p; + ip6->ip6_hlim = ip->ip_ttl; + ip6->ip6_src.s6_addr32[2] = ip6->ip6_dst.s6_addr32[2] = + IPV6_ADDR_INT32_SMP; + ip6->ip6_src.s6_addr32[3] = ip->ip_src.s_addr; + ip6->ip6_dst.s6_addr32[3] = ip->ip_dst.s_addr; +} +#endif + +/* + * subroutine of udp_input(), mainly for source code readability. + * caller must properly init udp_ip6 and udp_in6 beforehand. + */ +static void +udp_append(last, ip, n, off) + struct inpcb *last; + struct ip *ip; + struct mbuf *n; + int off; +{ + struct sockaddr *append_sa; + struct mbuf *opts = 0; + + if (last->inp_flags & INP_CONTROLOPTS || + last->inp_socket->so_options & SO_TIMESTAMP) { +#ifdef INET6 + if (last->inp_vflag & INP_IPV6) { + int savedflags; + + if (udp_ip6.uip6_init_done == 0) { + ip_2_ip6_hdr(&udp_ip6.uip6_ip6, ip); + udp_ip6.uip6_init_done = 1; + } + savedflags = last->inp_flags; + last->inp_flags &= ~INP_UNMAPPABLEOPTS; + ip6_savecontrol(last, &opts, &udp_ip6.uip6_ip6, n); + last->inp_flags = savedflags; + } else +#endif + ip_savecontrol(last, &opts, ip, n); + } +#ifdef INET6 + if (last->inp_vflag & INP_IPV6) { + if (udp_in6.uin6_init_done == 0) { + in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin); + udp_in6.uin6_init_done = 1; + } + append_sa = (struct sockaddr *)&udp_in6.uin6_sin; + } else +#endif + append_sa = (struct sockaddr *)&udp_in; + m_adj(n, off); + if (sbappendaddr(&last->inp_socket->so_rcv, append_sa, n, opts) == 0) { + m_freem(n); + if (opts) + m_freem(opts); + udpstat.udps_fullsock++; + } else + sorwakeup(last->inp_socket); } /* @@ -473,7 +602,7 @@ udp_getcred SYSCTL_HANDLER_ARGS return (error); s = splnet(); inp = in_pcblookup_hash(&udbinfo, addrs[1].sin_addr, addrs[1].sin_port, - addrs[0].sin_addr, addrs[0].sin_port, 1); + addrs[0].sin_addr, addrs[0].sin_port, 1, NULL); if (inp == NULL || inp->inp_socket == NULL) { error = ENOENT; goto out; @@ -570,6 +699,11 @@ udp_output(inp, m, addr, control, p) ((struct ip *)ui)->ip_ttl = inp->inp_ip_ttl; /* XXX */ ((struct ip *)ui)->ip_tos = inp->inp_ip_tos; /* XXX */ udpstat.udps_opackets++; + +#ifdef IPSEC + m->m_pkthdr.rcvif = (struct ifnet *)inp->inp_socket; +#endif /*IPSEC*/ + error = ip_output(m, inp->inp_options, &inp->inp_route, inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST), inp->inp_moptions); @@ -591,7 +725,13 @@ u_long udp_sendspace = 9216; /* really max datagram size */ SYSCTL_INT(_net_inet_udp, UDPCTL_MAXDGRAM, maxdgram, CTLFLAG_RW, &udp_sendspace, 0, "Maximum outgoing UDP datagram size"); -u_long udp_recvspace = 40 * (1024 + sizeof(struct sockaddr_in)); +u_long udp_recvspace = 40 * (1024 + +#ifdef INET6 + sizeof(struct sockaddr_in6) +#else + sizeof(struct sockaddr_in) +#endif + ); SYSCTL_INT(_net_inet_udp, UDPCTL_RECVSPACE, recvspace, CTLFLAG_RW, &udp_recvspace, 0, "Maximum incoming UDP datagram size"); @@ -621,15 +761,27 @@ udp_attach(struct socket *so, int proto, struct proc *p) if (inp != 0) return EINVAL; + error = soreserve(so, udp_sendspace, udp_recvspace); + if (error) + return error; s = splnet(); error = in_pcballoc(so, &udbinfo, p); splx(s); if (error) return error; - error = soreserve(so, udp_sendspace, udp_recvspace); - if (error) + + inp = (struct inpcb *)so->so_pcb; +#ifdef INET6 + inp->inp_vflag |= INP_IPV4; +#endif + inp->inp_ip_ttl = ip_defttl; +#ifdef IPSEC + error = ipsec_init_policy(so, &inp->inp_sp); + if (error != 0) { + in_pcbdetach(inp); return error; - ((struct inpcb *) so->so_pcb)->inp_ip_ttl = ip_defttl; + } +#endif /*IPSEC*/ return 0; } diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h index 0ee8258..491632e 100644 --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -115,7 +115,7 @@ extern int log_in_vain; void udp_ctlinput __P((int, struct sockaddr *, void *)); void udp_init __P((void)); -void udp_input __P((struct mbuf *, int)); +void udp_input __P((struct mbuf *, int, int)); void udp_notify __P((struct inpcb *inp, int errno)); int udp_shutdown __P((struct socket *so)); diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 425a5d5..943ddf7 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -64,7 +64,6 @@ * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 */ -#include "opt_inet.h" #include "opt_key.h" #include <sys/param.h> @@ -97,15 +96,10 @@ #ifdef IPSEC #include <netinet6/ipsec.h> -#ifdef INET6 #include <netinet6/ipsec6.h> -#endif /* INET6 */ #include <netkey/key.h> #ifdef KEY_DEBUG #include <netkey/key_debug.h> -#ifdef INET6 -#include <netkey/key_debug6.h> -#endif /* INET6 */ #else #define DPRINTF(lev,arg) #define DDO(lev, stmt) @@ -113,7 +107,7 @@ #endif /* KEY_DEBUG */ #endif /* IPSEC */ -/* #include "faith.h" */ +#include "faith.h" #include <net/net_osdep.h> @@ -910,8 +904,7 @@ ni6_addrs(ni6, m, ifpp) for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list)) { addrsofif = 0; - for (ifa = ifp->if_addrlist.tqh_first; ifa; - ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -976,8 +969,7 @@ ni6_store_addrs(ni6, nni6, ifp0, resid) for (; ifp; ifp = TAILQ_NEXT(ifp, if_list)) { - for (ifa = ifp->if_addrlist.tqh_first; ifa; - ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { docopy = 0; diff --git a/sys/netinet6/icmp6.h b/sys/netinet6/icmp6.h index 8fd63ff..2fdb28b 100644 --- a/sys/netinet6/icmp6.h +++ b/sys/netinet6/icmp6.h @@ -516,6 +516,9 @@ struct icmp6stat { #define RTF_PROBEMTU RTF_PROTO1 #ifdef _KERNEL +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet6_icmp6); +#endif # ifdef __STDC__ struct rtentry; struct rttimer; diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index e18b14f..a981c79 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -64,8 +64,6 @@ * @(#)in.c 8.2 (Berkeley) 11/15/93 */ -#include "opt_inet.h" - #include <sys/param.h> #include <sys/errno.h> #include <sys/malloc.h> @@ -81,10 +79,8 @@ #include <net/if.h> #include <net/if_types.h> #include <net/route.h> -/* #include "gif.h" */ -#if NGIF > 0 -#include <net/if_gif.h> -#endif +#include "gif.h" + #include <net/if_dl.h> #include <netinet/in.h> @@ -96,6 +92,9 @@ #include <netinet6/ip6_var.h> #include <netinet6/mld6_var.h> #include <netinet6/in6_ifattach.h> +#if NGIF > 0 +#include <net/if_gif.h> +#endif #include <net/net_osdep.h> @@ -348,7 +347,7 @@ in6_ifindex2scopeid(idx) return -1; ifp = ifindex2ifnet[idx]; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1059,9 +1058,7 @@ in6_lifaddr_ioctl(so, cmd, data, ifp, p) } } - for (ifa = ifp->if_addrlist.tqh_first; - ifa; - ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1311,7 +1308,7 @@ in6ifa_ifpforlinklocal(ifp) { register struct ifaddr *ifa; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr == NULL) continue; /* just for safety */ @@ -1335,7 +1332,7 @@ in6ifa_ifpwithaddr(ifp, addr) { register struct ifaddr *ifa; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr == NULL) continue; /* just for safety */ @@ -1575,7 +1572,7 @@ in6_ifawithscope(ifp, dst) * If two or more, return one which matches the dst longest. * If none, return one of global addresses assigned other ifs. */ - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1661,7 +1658,7 @@ in6_ifawithifp(ifp, dst) * If two or more, return one which matches the dst longest. * If none, return one of global addresses assigned other ifs. */ - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1696,7 +1693,7 @@ in6_ifawithifp(ifp, dst) if (besta) return(besta); - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1742,7 +1739,7 @@ in6_if_up(ifp) bzero(&ea, sizeof(ea)); sdl = NULL; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr)) { @@ -1789,7 +1786,7 @@ in6_if_up(ifp) dad: dad_delay = 0; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 1ca678e..b5266ce 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -74,6 +74,7 @@ * Identification of the network protocol stack */ #define __KAME__ +#define __KAME_VERSION "SNAP 19991101" /* * Local port number conventions: @@ -343,13 +344,6 @@ extern const struct in6_addr in6addr_linklocal_allrouters; #endif /* - * Wildcard Socket - */ -#if 0 /*pre-RFC2553*/ -#define IN6_IS_ADDR_ANY(a) IN6_IS_ADDR_UNSPECIFIED(a) -#endif - -/* * KAME Scope */ #ifdef _KERNEL /*nonstandard*/ @@ -522,65 +516,12 @@ struct in6_pktinfo { #define IPV6CTL_AUTO_FLOWLABEL 17 #define IPV6CTL_DEFMCASTHLIM 18 #define IPV6CTL_GIF_HLIM 19 /* default HLIM for gif encap packet */ +#define IPV6CTL_KAME_VERSION 20 #define IPV6CTL_USE_DEPRECATED 21 /* use deprecated addr (RFC2462 5.5.4) */ #define IPV6CTL_RR_PRUNE 22 /* walk timer for router renumbering */ #define IPV6CTL_MAPPED_ADDR 23 /* New entries should be added here from current IPV6CTL_MAXID value. */ #define IPV6CTL_MAXID 24 - -#define IPV6CTL_NAMES { \ - { 0, 0 }, \ - { "forwarding", CTLTYPE_INT }, \ - { "redirect", CTLTYPE_INT }, \ - { "hlim", CTLTYPE_INT }, \ - { "mtu", CTLTYPE_INT }, \ - { "forwsrcrt", CTLTYPE_INT }, \ - { 0, 0 }, \ - { 0, 0 }, \ - { "mrtproto", CTLTYPE_INT }, \ - { "maxfragpackets", CTLTYPE_INT }, \ - { "sourcecheck", CTLTYPE_INT }, \ - { "sourcecheck_logint", CTLTYPE_INT }, \ - { "accept_rtadv", CTLTYPE_INT }, \ - { "keepfaith", CTLTYPE_INT }, \ - { "log_interval", CTLTYPE_INT }, \ - { "hdrnestlimit", CTLTYPE_INT }, \ - { "dad_count", CTLTYPE_INT }, \ - { "auto_flowlabel", CTLTYPE_INT }, \ - { "defmcasthlim", CTLTYPE_INT }, \ - { "gifhlim", CTLTYPE_INT }, \ - { 0, 0 }, \ - { "use_deprecated", CTLTYPE_INT }, \ - { "rr_prune", CTLTYPE_INT }, \ - { "mapped_addr", CTLTYPE_INT }, \ -} - -#define IPV6CTL_VARS { \ - 0, \ - &ip6_forwarding, \ - &ip6_sendredirects, \ - &ip6_defhlim, \ - 0, \ - &ip6_forward_srcrt, \ - 0, \ - 0, \ - 0, \ - &ip6_maxfragpackets, \ - &ip6_sourcecheck, \ - &ip6_sourcecheck_interval, \ - &ip6_accept_rtadv, \ - &ip6_keepfaith, \ - &ip6_log_interval, \ - &ip6_hdrnestlimit, \ - &ip6_dad_count, \ - &ip6_auto_flowlabel, \ - &ip6_defmcasthlim, \ - &ip6_gif_hlim, \ - 0, \ - &ip6_use_deprecated, \ - &ip6_rr_prune, \ - &ip6_mapped_addr_on, \ -} #endif /* !_XOPEN_SOURCE */ /* @@ -633,9 +574,6 @@ extern struct cmsghdr *inet6_rthdr_init __P((void *, int)); extern int inet6_rthdr_add __P((struct cmsghdr *, const struct in6_addr *, u_int)); extern int inet6_rthdr_lasthop __P((struct cmsghdr *, u_int)); -#if 0 /* not implemented yet */ -extern int inet6_rthdr_reverse __P((const struct cmsghdr *, struct cmsghdr *)); -#endif extern int inet6_rthdr_segments __P((const struct cmsghdr *)); extern struct in6_addr *inet6_rthdr_getaddr __P((struct cmsghdr *, int)); extern int inet6_rthdr_getflags __P((const struct cmsghdr *, int)); diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c new file mode 100644 index 0000000..dd7cd2f --- /dev/null +++ b/sys/netinet6/in6_gif.c @@ -0,0 +1,263 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +/* + * in6_gif.c + */ + +#include "opt_inet.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> +#ifdef INET +#include <netinet/ip.h> +#endif +#include <netinet6/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/in6_gif.h> +#include <netinet6/ip6.h> + +#include <net/if_gif.h> + +#include <net/net_osdep.h> + +int +in6_gif_output(ifp, family, m, rt) + struct ifnet *ifp; + int family; /* family of the packet to be encapsulate. */ + struct mbuf *m; + struct rtentry *rt; +{ + struct gif_softc *sc = (struct gif_softc*)ifp; + struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst; + struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc; + struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst; + struct ip6_hdr *ip6; + int proto; + + if (sin6_src == NULL || sin6_dst == NULL || + sin6_src->sin6_family != AF_INET6 || + sin6_dst->sin6_family != AF_INET6) { + m_freem(m); + return EAFNOSUPPORT; + } + + switch (family) { +#ifdef INET + case AF_INET: + { + struct ip *ip; + + proto = IPPROTO_IPV4; + if (m->m_len < sizeof(*ip)) { + m = m_pullup(m, sizeof(*ip)); + if (!m) + return ENOBUFS; + } + ip = mtod(m, struct ip *); + break; + } +#endif + case AF_INET6: + { + struct ip6_hdr *ip6; + proto = IPPROTO_IPV6; + if (m->m_len < sizeof(*ip6)) { + m = m_pullup(m, sizeof(*ip6)); + if (!m) + return ENOBUFS; + } + ip6 = mtod(m, struct ip6_hdr *); + break; + } + default: +#ifdef DIAGNOSTIC + printf("in6_gif_output: warning: unknown family %d passed\n", + family); +#endif + m_freem(m); + return EAFNOSUPPORT; + } + + /* prepend new IP header */ + M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); + if (m && m->m_len < sizeof(struct ip6_hdr)) + m = m_pullup(m, sizeof(struct ip6_hdr)); + if (m == NULL) { + printf("ENOBUFS in in6_gif_output %d\n", __LINE__); + return ENOBUFS; + } + + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_flow = 0; + ip6->ip6_vfc = IPV6_VERSION; + ip6->ip6_plen = htons((u_short)m->m_pkthdr.len); + ip6->ip6_nxt = proto; + ip6->ip6_hlim = ip6_gif_hlim; + ip6->ip6_src = sin6_src->sin6_addr; + if (ifp->if_flags & IFF_LINK0) { + /* multi-destination mode */ + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) + ip6->ip6_dst = sin6_dst->sin6_addr; + else if (rt) { + ip6->ip6_dst = ((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr; + } else { + m_freem(m); + return ENETUNREACH; + } + } else { + /* bidirectional configured tunnel mode */ + if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr)) + ip6->ip6_dst = sin6_dst->sin6_addr; + else { + m_freem(m); + return ENETUNREACH; + } + } + + if (dst->sin6_family != sin6_dst->sin6_family || + !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) { + /* cache route doesn't match */ + bzero(dst, sizeof(*dst)); + dst->sin6_family = sin6_dst->sin6_family; + dst->sin6_len = sizeof(struct sockaddr_in6); + dst->sin6_addr = sin6_dst->sin6_addr; + if (sc->gif_ro6.ro_rt) { + RTFREE(sc->gif_ro6.ro_rt); + sc->gif_ro6.ro_rt = NULL; + } + } + + if (sc->gif_ro6.ro_rt == NULL) { + rtalloc((struct route *)&sc->gif_ro6); + if (sc->gif_ro6.ro_rt == NULL) { + m_freem(m); + return ENETUNREACH; + } + } + +#ifdef IPSEC + m->m_pkthdr.rcvif = NULL; +#endif /*IPSEC*/ + return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL)); +} + +int in6_gif_input(mp, offp, proto) + struct mbuf **mp; + int *offp, proto; +{ + struct mbuf *m = *mp; + struct gif_softc *sc; + struct ifnet *gifp = NULL; + struct ip6_hdr *ip6; + int i; + int af = 0; + + ip6 = mtod(m, struct ip6_hdr *); + +#define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr) + for (i = 0, sc = gif; i < ngif; i++, sc++) { + if (sc->gif_psrc == NULL || + sc->gif_pdst == NULL || + sc->gif_psrc->sa_family != AF_INET6 || + sc->gif_pdst->sa_family != AF_INET6) { + continue; + } + if ((sc->gif_if.if_flags & IFF_UP) == 0) + continue; + if ((sc->gif_if.if_flags & IFF_LINK0) && + IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && + IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc->gif_pdst))) { + gifp = &sc->gif_if; + continue; + } + if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && + IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) { + gifp = &sc->gif_if; + break; + } + } + + if (gifp == NULL) { + m_freem(m); + ip6stat.ip6s_nogif++; + return IPPROTO_DONE; + } + + m_adj(m, *offp); + + switch (proto) { +#ifdef INET + case IPPROTO_IPV4: + { + struct ip *ip; + af = AF_INET; + if (m->m_len < sizeof(*ip)) { + m = m_pullup(m, sizeof(*ip)); + if (!m) + return IPPROTO_DONE; + } + ip = mtod(m, struct ip *); + break; + } +#endif /* INET */ + case IPPROTO_IPV6: + { + struct ip6_hdr *ip6; + af = AF_INET6; + if (m->m_len < sizeof(*ip6)) { + m = m_pullup(m, sizeof(*ip6)); + if (!m) + return IPPROTO_DONE; + } + ip6 = mtod(m, struct ip6_hdr *); + break; + } + default: + ip6stat.ip6s_nogif++; + m_freem(m); + return IPPROTO_DONE; + } + + gif_input(m, af, gifp); + return IPPROTO_DONE; +} diff --git a/sys/netinet6/in6_gif.h b/sys/netinet6/in6_gif.h new file mode 100644 index 0000000..7d06c3c --- /dev/null +++ b/sys/netinet6/in6_gif.h @@ -0,0 +1,40 @@ +/* + * 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. + * + * $FreeBSD$ + */ + +#ifndef _NETINET6_IN6_GIF_H_ +#define _NETINET6_IN6_GIF_H_ + +#define GIF_HLIM 30 + +int in6_gif_input __P((struct mbuf **, int *, int)); +int in6_gif_output __P((struct ifnet *, int, struct mbuf *, struct rtentry *)); + +#endif /*_NETINET6_IN6_GIF_H_*/ diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c index 85ca75f..7d332ed 100644 --- a/sys/netinet6/in6_ifattach.c +++ b/sys/netinet6/in6_ifattach.c @@ -153,13 +153,11 @@ in6_ifattach_getifid(ifp0) if (found_first_ifid) return 0; - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) + TAILQ_FOREACH(ifp, &ifnet, if_list) { if (ifp0 != NULL && ifp0 != ifp) continue; - for (ifa = ifp->if_addrlist.tqh_first; - ifa; - ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_LINK) continue; @@ -239,7 +237,7 @@ in6_ifattach_p2p() if (found_first_ifid == 0) return; - for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) + TAILQ_FOREACH(ifp, &ifnet, if_list) { switch (ifp->if_type) { case IFT_GIF: @@ -645,7 +643,7 @@ in6_ifdetach(ifp) struct rtentry *rt; short rtflags; - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) { diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 8aee5b3..ac5b923 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -65,7 +65,6 @@ * $FreeBSD$ */ -#include "opt_inet.h" #include "opt_key.h" #include <sys/param.h> @@ -96,19 +95,14 @@ #include <netinet/in_pcb.h> #include <netinet6/in6_pcb.h> -/* #include "faith.h" */ +#include "faith.h" #ifdef IPSEC #include <netinet6/ipsec.h> -#ifdef INET6 #include <netinet6/ipsec6.h> -#endif /* INET6 */ #include <netkey/key.h> #ifdef KEY_DEBUG #include <netkey/key_debug.h> -#ifdef INET6 -#include <netkey/key_debug6.h> -#endif /* INET6 */ #else #define DPRINTF(lev,arg) #define DDO(lev, stmt) @@ -1065,7 +1059,7 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) head = &pcbinfo->hashbase[INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, lport, fport, pcbinfo->hashmask)]; - for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { + LIST_FOREACH(inp, head, inp_hash) { if ((inp->inp_vflag & INP_IPV6) == NULL) continue; if (IN6_ARE_ADDR_EQUAL(&inp->in6p_faddr, faddr) && @@ -1083,8 +1077,7 @@ in6_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp) head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; - for (inp = head->lh_first; inp != NULL; - inp = inp->inp_hash.le_next) { + LIST_FOREACH(inp, head, inp_hash) { if ((inp->inp_vflag & INP_IPV6) == NULL) continue; if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) && diff --git a/sys/netinet6/in6_prefix.c b/sys/netinet6/in6_prefix.c index 8da07c4..6799d0d 100644 --- a/sys/netinet6/in6_prefix.c +++ b/sys/netinet6/in6_prefix.c @@ -184,7 +184,7 @@ search_matched_prefix(struct ifnet *ifp, struct in6_prefixreq *ipr) * which matches the addr */ - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -249,7 +249,7 @@ mark_matched_prefixes(u_long cmd, struct ifnet *ifp, struct in6_rrenumreq *irr) * search matched addr, and then search prefixes * which matche the addr */ - for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { struct rr_prefix *rpp; @@ -364,8 +364,7 @@ search_ifidwithprefix(struct rr_prefix *rpp, struct in6_addr *ifid) { struct rp_addr *rap; - for (rap = rpp->rp_addrhead.lh_first; rap != NULL; - rap = rap->ra_entry.le_next) + LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) if (rr_are_ifid_equal(ifid, &rap->ra_ifid, (sizeof(struct in6_addr) << 3) - rpp->rp_plen)) @@ -682,8 +681,7 @@ rrpr_update(struct socket *so, struct rr_prefix *new) * If it existed but not pointing to the prefix yet, * init the prefix pointer. */ - for (rap = rpp->rp_addrhead.lh_first; rap != NULL; - rap = rap->ra_entry.le_next) { + LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) { if (rap->ra_addr != NULL) { if (rap->ra_addr->ia6_ifpr == NULL) rap->ra_addr->ia6_ifpr = rp2ifpr(rpp); @@ -771,8 +769,7 @@ init_newprefix(struct in6_rrenumreq *irr, struct ifprefix *ifpr, irr->irr_u_uselen, min(ifpr->ifpr_plen - irr->irr_u_uselen, irr->irr_u_keeplen)); - for (orap = (ifpr2rp(ifpr)->rp_addrhead).lh_first; orap != NULL; - orap = orap->ra_entry.le_next) { + LIST_FOREACH(orap, &(ifpr2rp(ifpr)->rp_addrhead), ra_entry) { struct rp_addr *rap; int error = 0; @@ -845,8 +842,7 @@ unprefer_prefix(struct rr_prefix *rpp) { struct rp_addr *rap; - for (rap = rpp->rp_addrhead.lh_first; rap != NULL; - rap = rap->ra_entry.le_next) { + LIST_FOREACH(rap, &rpp->rp_addrhead, ra_entry) { if (rap->ra_addr == NULL) continue; rap->ra_addr->ia6_lifetime.ia6t_preferred = time_second; @@ -863,7 +859,7 @@ delete_each_prefix(struct socket *so, struct rr_prefix *rpp, u_char origin) if (rpp->rp_origin > origin) return(EPERM); - while (rpp->rp_addrhead.lh_first != NULL) { + while (!LIST_EMPTY(&rpp->rp_addrhead)) { struct rp_addr *rap; int s; @@ -923,8 +919,7 @@ link_stray_ia6s(struct rr_prefix *rpp) { struct ifaddr *ifa; - for (ifa = rpp->rp_ifp->if_addrlist.tqh_first; ifa; - ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &rpp->rp_ifp->if_addrlist, ifa_list) { struct rp_addr *rap; struct rr_prefix *orpp; diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 1d1c7a3..3f59ec2 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -64,8 +64,6 @@ * @(#)in_proto.c 8.1 (Berkeley) 6/10/93 */ -#include "opt_inet.h" - #include <sys/param.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -104,9 +102,7 @@ #ifdef IPSEC #include <netinet6/ipsec.h> -#ifdef INET6 #include <netinet6/ipsec6.h> -#endif /* INET6 */ #include <netinet6/ah.h> #ifdef IPSEC_ESP #include <netinet6/esp.h> @@ -116,7 +112,7 @@ #include <netinet6/ip6protosw.h> -/* #include "gif.h" */ +#include "gif.h" #if NGIF > 0 #include <netinet6/in6_gif.h> #endif @@ -139,6 +135,12 @@ struct ip6protosw inet6sw[] = { ip6_init, 0, frag6_slowtimo, frag6_drain, &nousrreqs, }, +{ SOCK_DGRAM, &inet6domain, IPPROTO_UDP, PR_ATOMIC | PR_ADDR, + udp6_input, 0, udp6_ctlinput, ip6_ctloutput, + 0, + 0, 0, 0, 0, + &udp6_usrreqs, +}, { SOCK_RAW, &inet6domain, IPPROTO_RAW, PR_ATOMIC | PR_ADDR, rip6_input, rip6_output, 0, rip6_ctloutput, 0, @@ -194,18 +196,16 @@ struct ip6protosw inet6sw[] = { #if NGIF > 0 { SOCK_RAW, &inet6domain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, in6_gif_input,0, 0, 0, - 0, + 0, 0, 0, 0, 0, &nousrreqs }, -#ifdef INET6 { SOCK_RAW, &inet6domain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, in6_gif_input,0, 0, 0, - 0, + 0, 0, 0, 0, 0, &nousrreqs }, -#endif /* INET6 */ #endif /* GIF */ /* raw wildcard */ { SOCK_RAW, &inet6domain, 0, PR_ATOMIC | PR_ADDR, @@ -334,8 +334,8 @@ sysctl_ip6_forwarding SYSCTL_HANDLER_ARGS int s = splnet(); struct nd_prefix *pr, *next; - for (pr = nd_prefix.lh_first; pr; pr = next) { - next = pr->ndpr_next; + for (pr = LIST_FIRST(&nd_prefix); pr; pr = next) { + next = LIST_NEXT(pr, ndpr_entry); if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); prelist_remove(pr); @@ -379,6 +379,8 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_DEFMCASTHLIM, defmcasthlim, CTLFLAG_RW, &ip6_defmcasthlim, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_RW, &ip6_gif_hlim, 0, ""); +SYSCTL_STRING(_net_inet6_ip6, IPV6CTL_KAME_VERSION, + kame_version, CTLFLAG_RD, __KAME_VERSION, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_USE_DEPRECATED, use_deprecated, CTLFLAG_RW, &ip6_use_deprecated, 0, ""); SYSCTL_INT(_net_inet6_ip6, IPV6CTL_RR_PRUNE, diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 4117c20..163c167 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -437,7 +437,7 @@ MALLOC_DECLARE(M_IPMADDR); /* struct in6_ifaddr *ia; */ \ do { \ struct ifaddr *ifa; \ - for (ifa = (ifp)->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) { \ + TAILQ_FOREACH(ifa, &(ifp)->if_addrlist, ifa_list) { \ if (!ifa->ifa_addr) \ continue; \ if (ifa->ifa_addr->sa_family == AF_INET6) \ @@ -467,6 +467,11 @@ struct in6_multi { }; #ifdef _KERNEL + +#ifdef SYSCTL_DECL +SYSCTL_DECL(_net_inet6_ip6); +#endif + extern LIST_HEAD(in6_multihead, in6_multi) in6_multihead; /* @@ -512,14 +517,14 @@ do { \ /* struct in6_multi *in6m; */ \ do { \ if (((in6m) = (step).i_in6m) != NULL) \ - (step).i_in6m = (step).i_in6m->in6m_entry.le_next; \ + (step).i_in6m = LIST_NEXT((step).i_in6m, in6m_entry); \ } while(0) #define IN6_FIRST_MULTI(step, in6m) \ /* struct in6_multistep step; */ \ /* struct in6_multi *in6m */ \ do { \ - (step).i_in6m = in6_multihead.lh_first; \ + (step).i_in6m = LIST_FIRST(&in6_multihead); \ IN6_NEXT_MULTI((step), (in6m)); \ } while(0) diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index a50ba6c..46b3188 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -29,7 +29,6 @@ * $FreeBSD$ */ -#include "opt_inet.h" #include "opt_key.h" #include <sys/param.h> @@ -56,15 +55,10 @@ #ifdef IPSEC_IPV6FWD #include <netinet6/ipsec.h> -#ifdef INET6 #include <netinet6/ipsec6.h> -#endif /* INET6 */ #include <netkey/key.h> #ifdef KEY_DEBUG #include <netkey/key_debug.h> -#ifdef INET6 -#include <netkey/key_debug6.h> -#endif /* INET6 */ #else #define DPRINTF(lev,arg) #define DDO(lev, stmt) diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 097d5a0..105b4bc 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -64,8 +64,6 @@ * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 */ -#include "opt_inet.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -88,10 +86,8 @@ #include <netinet/in.h> #include <netinet/in_systm.h> -#ifdef INET #include <netinet/ip.h> #include <netinet/ip_icmp.h> -#endif /*INET*/ #include <netinet/in_pcb.h> #include <netinet6/in6_var.h> #include <netinet6/ip6.h> @@ -113,9 +109,9 @@ /* we need it for NLOOP. */ #include "loop.h" -/* #include "faith.h" */ -/* #include "gif.h" */ +#include "faith.h" +#include "gif.h" #include <net/net_osdep.h> @@ -793,7 +789,6 @@ ip6_savecontrol(in6p, mp, ip6, m) if (p && !suser(p)) privileged++; -#ifdef SO_TIMESTAMP if (in6p->in6p_socket->so_options & SO_TIMESTAMP) { struct timeval tv; @@ -803,7 +798,6 @@ ip6_savecontrol(in6p, mp, ip6, m) if (*mp) mp = &(*mp)->m_next; } -#endif if (in6p->in6p_flags & IN6P_RECVDSTADDR) { *mp = sbcreatecontrol((caddr_t) &ip6->ip6_dst, sizeof(struct in6_addr), IPV6_RECVDSTADDR, diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index de85510..1524bc3 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -64,7 +64,6 @@ * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 */ -#include "opt_inet.h" #include "opt_key.h" #include <sys/param.h> @@ -91,15 +90,10 @@ #ifdef IPSEC #include <netinet6/ipsec.h> -#ifdef INET6 #include <netinet6/ipsec6.h> -#endif /* INET6 */ #include <netkey/key.h> #ifdef KEY_DEBUG #include <netkey/key_debug.h> -#ifdef INET6 -#include <netkey/key_debug6.h> -#endif /* INET6 */ #else #define DPRINTF(lev,arg) #define DDO(lev, stmt) @@ -1764,8 +1758,7 @@ ip6_setmoptions(optname, im6op, m) /* * See if the membership already exists. */ - for (imm = im6o->im6o_memberships.lh_first; - imm != NULL; imm = imm->i6mm_chain.le_next) + LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain) if (imm->i6mm_maddr->in6m_ifp == ifp && IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, &mreq->ipv6mr_multiaddr)) @@ -1831,8 +1824,7 @@ ip6_setmoptions(optname, im6op, m) /* * Find the membership in the membership list. */ - for (imm = im6o->im6o_memberships.lh_first; - imm != NULL; imm = imm->i6mm_chain.le_next) { + LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain) { if ((ifp == NULL || imm->i6mm_maddr->in6m_ifp == ifp) && IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, @@ -1864,7 +1856,7 @@ ip6_setmoptions(optname, im6op, m) if (im6o->im6o_multicast_ifp == NULL && im6o->im6o_multicast_hlim == ip6_defmcasthlim && im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP && - im6o->im6o_memberships.lh_first == NULL) { + LIST_EMPTY(&im6o->im6o_memberships)) { free(*im6op, M_IPMOPTS); *im6op = NULL; } @@ -1931,7 +1923,7 @@ ip6_freemoptions(im6o) if (im6o == NULL) return; - while ((imm = im6o->im6o_memberships.lh_first) != NULL) { + while ((imm = LIST_FIRST(&im6o->im6o_memberships)) != NULL) { LIST_REMOVE(imm, i6mm_chain); if (imm->i6mm_maddr) in6_delmulti(imm->i6mm_maddr); diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c index 43cb9b7..634f61b 100644 --- a/sys/netinet6/mld6.c +++ b/sys/netinet6/mld6.c @@ -68,8 +68,6 @@ * @(#)igmp.c 8.1 (Berkeley) 7/19/93 */ -#include "opt_inet.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/mbuf.h> diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 87eab9d..74787f2 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -458,17 +458,17 @@ nd6_timer(ignored_arg) } /* expire */ - dr = nd_defrouter.lh_first; + dr = LIST_FIRST(&nd_defrouter); while (dr) { if (dr->expire && dr->expire < time_second) { struct nd_defrouter *t; - t = dr->dr_next; + t = LIST_NEXT(dr, dr_entry); defrtrlist_del(dr); dr = t; } else - dr = dr->dr_next; + dr = LIST_NEXT(dr, dr_entry); } - pr = nd_prefix.lh_first; + pr = LIST_FIRST(&nd_prefix); while (pr) { struct in6_ifaddr *ia6; struct in6_addrlifetime *lt6; @@ -503,7 +503,7 @@ nd6_timer(ignored_arg) if (pr->ndpr_expire && pr->ndpr_expire + NDPR_KEEP_EXPIRED < time_second) { struct nd_prefix *t; - t = pr->ndpr_next; + t = LIST_NEXT(pr, ndpr_entry); /* * address expiration and prefix expiration are @@ -513,7 +513,7 @@ nd6_timer(ignored_arg) prelist_remove(pr); pr = t; } else - pr = pr->ndpr_next; + pr = LIST_NEXT(pr, ndpr_entry); } splx(s); } @@ -627,9 +627,7 @@ nd6_is_addr_neighbor(addr, ifp) * If the address matches one of our addresses, * it should be a neighbor. */ - for (ifa = ifp->if_addrlist.tqh_first; - ifa; - ifa = ifa->ifa_list.tqe_next) + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { if (ifa->ifa_addr->sa_family != AF_INET6) next: continue; @@ -967,7 +965,7 @@ nd6_ioctl(cmd, data, ifp) case SIOCGDRLST_IN6: bzero(drl, sizeof(*drl)); s = splnet(); - dr = nd_defrouter.lh_first; + dr = LIST_FIRST(&nd_defrouter); while (dr && i < DRLSTSIZ) { drl->defrouter[i].rtaddr = dr->rtaddr; if (IN6_IS_ADDR_LINKLOCAL(&drl->defrouter[i].rtaddr)) { @@ -984,14 +982,14 @@ nd6_ioctl(cmd, data, ifp) drl->defrouter[i].expire = dr->expire; drl->defrouter[i].if_index = dr->ifp->if_index; i++; - dr = dr->dr_next; + dr = LIST_NEXT(dr, dr_entry); } splx(s); break; case SIOCGPRLST_IN6: bzero(prl, sizeof(*prl)); s = splnet(); - pr = nd_prefix.lh_first; + pr = LIST_FIRST(&nd_prefix); while (pr && i < PRLSTSIZ) { struct nd_pfxrouter *pfr; int j; @@ -1004,7 +1002,7 @@ nd6_ioctl(cmd, data, ifp) prl->prefix[i].if_index = pr->ndpr_ifp->if_index; prl->prefix[i].expire = pr->ndpr_expire; - pfr = pr->ndpr_advrtrs.lh_first; + pfr = LIST_FIRST(&pr->ndpr_advrtrs); j = 0; while(pfr) { if (j < DRLSTSIZ) { @@ -1022,12 +1020,12 @@ nd6_ioctl(cmd, data, ifp) #undef RTRADDR } j++; - pfr = pfr->pfr_next; + pfr = LIST_NEXT(pfr, pfr_entry); } prl->prefix[i].advrtrs = j; i++; - pr = pr->ndpr_next; + pr = LIST_NEXT(pr, ndpr_entry); } splx(s); { @@ -1069,8 +1067,8 @@ nd6_ioctl(cmd, data, ifp) struct nd_prefix *pr, *next; s = splnet(); - for (pr = nd_prefix.lh_first; pr; pr = next) { - next = pr->ndpr_next; + for (pr = LIST_FIRST(&nd_prefix); pr; pr = next) { + next = LIST_NEXT(pr, ndpr_entry); if (!IN6_IS_ADDR_UNSPECIFIED(&pr->ndpr_addr)) in6_ifdel(pr->ndpr_ifp, &pr->ndpr_addr); prelist_remove(pr); @@ -1084,16 +1082,16 @@ nd6_ioctl(cmd, data, ifp) struct nd_defrouter *dr, *next; s = splnet(); - if ((dr = nd_defrouter.lh_first) != NULL) { + if ((dr = LIST_FIRST(&nd_defrouter)) != NULL) { /* * The first entry of the list may be stored in * the routing table, so we'll delete it later. */ - for (dr = dr->dr_next; dr; dr = next) { - next = dr->dr_next; + for (dr = LIST_NEXT(dr, dr_entry); dr; dr = next) { + next = LIST_NEXT(dr, dr_entry); defrtrlist_del(dr); } - defrtrlist_del(nd_defrouter.lh_first); + defrtrlist_del(LIST_FIRST(&nd_defrouter)); } splx(s); break; diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 2bb4fe4..756f495 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -126,7 +126,6 @@ struct in6_ndireq { struct nd_defrouter { LIST_ENTRY(nd_defrouter) dr_entry; -#define dr_next dr_entry.le_next struct in6_addr rtaddr; u_char flags; u_short rtlifetime; @@ -154,8 +153,6 @@ struct nd_prefix { } ndpr_stateflags; }; -#define ndpr_next ndpr_entry.le_next - #define ndpr_raf ndpr_flags #define ndpr_raf_onlink ndpr_flags.onlink #define ndpr_raf_auto ndpr_flags.autonomous @@ -200,7 +197,6 @@ struct inet6_ndpr_msghdr { struct nd_pfxrouter { LIST_ENTRY(nd_pfxrouter) pfr_entry; -#define pfr_next pfr_entry.le_next struct nd_defrouter *router; }; diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c index de09176..840f074 100644 --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -29,8 +29,6 @@ * $FreeBSD$ */ -#include "opt_inet.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/malloc.h> @@ -818,7 +816,7 @@ nd6_dad_find(ifa) { struct dadq *dp; - for (dp = dadq.tqh_first; dp; dp = dp->dad_list.tqe_next) { + TAILQ_FOREACH(dp, &dadq, dad_list) { if (dp->dad_ifa == ifa) return dp; } diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index d177a66..da92879 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -374,7 +374,7 @@ defrouter_lookup(addr, ifp) { struct nd_defrouter *dr; - for(dr = nd_defrouter.lh_first; dr; dr = dr->dr_next) + LIST_FOREACH(dr, &nd_defrouter, dr_entry) if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr)) return(dr); @@ -405,8 +405,8 @@ defrouter_delreq(dr, dofree) if (dofree) free(dr, M_IP6NDP); - if (nd_defrouter.lh_first) - defrouter_addreq(nd_defrouter.lh_first); + if (!LIST_EMPTY(&nd_defrouter)) + defrouter_addreq(LIST_FIRST(&nd_defrouter)); /* * xxx update the Destination Cache entries for all @@ -430,7 +430,7 @@ defrtrlist_del(dr) rt6_flush(&dr->rtaddr, dr->ifp); } - if (dr == nd_defrouter.lh_first) + if (dr == LIST_FIRST(&nd_defrouter)) deldr = dr; /* The router is primary. */ LIST_REMOVE(dr, dr_entry); @@ -438,7 +438,7 @@ defrtrlist_del(dr) /* * Also delete all the pointers to the router in each prefix lists. */ - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { + LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { struct nd_pfxrouter *pfxrtr; if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL) pfxrtr_del(pfxrtr); @@ -489,11 +489,11 @@ defrtrlist_update(new) } bzero(n, sizeof(*n)); *n = *new; - if (nd_defrouter.lh_first == NULL) { + if (LIST_EMPTY(&nd_defrouter)) { LIST_INSERT_HEAD(&nd_defrouter, n, dr_entry); defrouter_addreq(n); } else { - LIST_INSERT_AFTER(nd_defrouter.lh_first, n, dr_entry); + LIST_INSERT_AFTER(LIST_FIRST(&nd_defrouter), n, dr_entry); defrouter_addreq(n); } splx(s); @@ -507,8 +507,8 @@ pfxrtr_lookup(pr, dr) struct nd_defrouter *dr; { struct nd_pfxrouter *search; - - for (search = pr->ndpr_advrtrs.lh_first; search; search = search->pfr_next) { + + LIST_FOREACH(search, &pr->ndpr_advrtrs, pfr_entry) { if (search->router == dr) break; } @@ -548,7 +548,7 @@ prefix_lookup(pr) { struct nd_prefix *search; - for (search = nd_prefix.lh_first; search; search = search->ndpr_next) { + LIST_FOREACH(search, &nd_prefix, ndpr_entry) { if (pr->ndpr_ifp == search->ndpr_ifp && pr->ndpr_plen == search->ndpr_plen && in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr, @@ -611,8 +611,8 @@ prelist_remove(pr) splx(s); /* free list of routers that adversed the prefix */ - for (pfr = pr->ndpr_advrtrs.lh_first; pfr; pfr = next) { - next = pfr->pfr_next; + for (pfr = LIST_FIRST(&pr->ndpr_advrtrs); pfr; pfr = next) { + next = LIST_NEXT(pfr, pfr_entry); free(pfr, M_IP6NDP); } @@ -809,8 +809,8 @@ pfxlist_onlink_check() { struct nd_prefix *pr; - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) - if (pr->ndpr_advrtrs.lh_first) /* pr has an available router */ + LIST_FOREACH(pr, &nd_prefix, ndpr_entry) + if (!LIST_EMPTY(&pr->ndpr_advrtrs)) /* pr has an available router */ break; if (pr) { @@ -821,21 +821,21 @@ pfxlist_onlink_check() * attached prefix and a detached prefix may have a same * interface route. */ - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (pr->ndpr_advrtrs.lh_first == NULL && + LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { + if (LIST_EMPTY(&pr->ndpr_advrtrs) && pr->ndpr_statef_onlink) { pr->ndpr_statef_onlink = 0; nd6_detach_prefix(pr); } } - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) { - if (pr->ndpr_advrtrs.lh_first && + LIST_FOREACH(pr, &nd_prefix, ndpr_entry) { + if (!LIST_EMPTY(&pr->ndpr_advrtrs) && pr->ndpr_statef_onlink == 0) nd6_attach_prefix(pr); } } else { /* there is no prefix that has a router */ - for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) + LIST_FOREACH(pr, &nd_prefix, ndpr_entry) if (pr->ndpr_statef_onlink == 0) nd6_attach_prefix(pr); } @@ -993,7 +993,7 @@ in6_ifadd(ifp, in6, addr, prefixlen) in6_ifaddr = ia; /* link to if_addrlist */ - if (ifp->if_addrlist.tqh_first != NULL) { + if (!TAILQ_EMPTY(&ifp->if_addrlist)) { TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list); } diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index c54874e..3131e41 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -64,8 +64,6 @@ * @(#)raw_ip.c 8.2 (Berkeley) 1/4/94 */ -#include "opt_inet.h" - #include <stddef.h> #include <sys/param.h> @@ -94,14 +92,12 @@ #ifdef IPSEC #include <netinet6/ipsec.h> -#ifdef INET6 #include <netinet6/ipsec6.h> -#endif /* INET6 */ #endif /*IPSEC*/ #include <machine/stdarg.h> -/* #include "faith.h" */ +#include "faith.h" #define satosin6(sa) ((struct sockaddr_in6 *)(sa)) #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa)) diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c new file mode 100644 index 0000000..c22a719 --- /dev/null +++ b/sys/netinet6/udp6_usrreq.c @@ -0,0 +1,835 @@ +/* + * 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 + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.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/syslog.h> +#include <sys/proc.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/if_types.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/in_var.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet6/ip6.h> +#include <netinet6/ip6_var.h> +#include <netinet6/in6_pcb.h> +#include <netinet6/icmp6.h> +#include <netinet6/udp6_var.h> +#include <netinet6/ip6protosw.h> + +#ifdef IPSEC +#include <netinet6/ipsec.h> +#endif /*IPSEC*/ + +#include "faith.h" + +/* + * UDP protocol inplementation. + * Per RFC 768, August, 1980. + */ + +extern struct protosw inetsw[]; +static int in6_mcmatch __P((struct inpcb *, struct in6_addr *, struct ifnet *)); +static int udp6_detach __P((struct socket *so)); + +static int +in6_mcmatch(in6p, ia6, ifp) + struct inpcb *in6p; + register struct in6_addr *ia6; + struct ifnet *ifp; +{ + struct ip6_moptions *im6o = in6p->in6p_moptions; + struct in6_multi_mship *imm; + + if (im6o == NULL) + return 0; + + for (imm = im6o->im6o_memberships.lh_first; imm != NULL; + imm = imm->i6mm_chain.le_next) { + if ((ifp == NULL || + imm->i6mm_maddr->in6m_ifp == ifp) && + IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, + ia6)) + return 1; + } + return 0; +} + +int +udp6_input(mp, offp, proto) + struct mbuf **mp; + int *offp, proto; +{ + struct mbuf *m = *mp; + register struct ip6_hdr *ip6; + register struct udphdr *uh; + register struct inpcb *in6p; + struct mbuf *opts = 0; + int off = *offp; + int plen, ulen; + struct sockaddr_in6 udp_in6; + +#if defined(NFAITH) && 0 < NFAITH + if (m->m_pkthdr.rcvif) { + if (m->m_pkthdr.rcvif->if_type == IFT_FAITH) { + /* XXX send icmp6 host/port unreach? */ + m_freem(m); + return IPPROTO_DONE; + } + } +#endif + udpstat.udps_ipackets++; + + IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); + + ip6 = mtod(m, struct ip6_hdr *); + plen = ntohs(ip6->ip6_plen) - off + sizeof(*ip6); + uh = (struct udphdr *)((caddr_t)ip6 + off); + ulen = ntohs((u_short)uh->uh_ulen); + + if (plen != ulen) { + udpstat.udps_badlen++; + goto bad; + } + + /* + * Checksum extended UDP header and data. + */ + if (uh->uh_sum == 0) + udpstat.udps_nosum++; + else if (in6_cksum(m, IPPROTO_UDP, off, ulen) != 0) { + udpstat.udps_badsum++; + goto bad; + } + + if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { + struct inpcb *last; + + /* + * Deliver a multicast datagram to all sockets + * for which the local and remote addresses and ports match + * those of the incoming datagram. This allows more than + * one process to receive multicasts on the same port. + * (This really ought to be done for unicast datagrams as + * well, but that would cause problems with existing + * applications that open both address-specific sockets and + * a wildcard socket listening to the same port -- they would + * end up receiving duplicates of every unicast datagram. + * Those applications open the multiple sockets to overcome an + * inadequacy of the UDP socket interface, but for backwards + * compatibility we avoid the problem here rather than + * fixing the interface. Maybe 4.5BSD will remedy this?) + */ + + /* + * In a case that laddr should be set to the link-local + * address (this happens in RIPng), the multicast address + * specified in the received packet does not match with + * laddr. To cure this situation, the matching is relaxed + * if the receiving interface is the same as one specified + * in the socket and if the destination multicast address + * matches one of the multicast groups specified in the socket. + */ + + /* + * Construct sockaddr format source address. + */ + init_sin6(&udp_in6, m); /* general init */ + udp_in6.sin6_port = uh->uh_sport; + /* + * KAME note: usually we drop udphdr from mbuf here. + * We need udphdr for IPsec processing so we do that later. + */ + + /* + * Locate pcb(s) for datagram. + * (Algorithm copied from raw_intr().) + */ + last = NULL; + LIST_FOREACH(in6p, &udb, inp_list) { + if ((in6p->inp_vflag & INP_IPV6) == NULL) + continue; + if (in6p->in6p_lport != uh->uh_dport) + continue; + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { + if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, + &ip6->ip6_dst) && + !in6_mcmatch(in6p, &ip6->ip6_dst, + m->m_pkthdr.rcvif)) + continue; + } + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, + &ip6->ip6_src) || + in6p->in6p_fport != uh->uh_sport) + continue; + } + + if (last != NULL) { + struct mbuf *n; + +#ifdef IPSEC + /* + * Check AH/ESP integrity. + */ + if (last != NULL && + ipsec6_in_reject_so(m, last->inp_socket)) { + ipsec6stat.in_polvio++; + /* do not inject data into pcb */ + } else +#endif /*IPSEC*/ + if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { + /* + * KAME NOTE: do not + * m_copy(m, offset, ...) above. + * sbappendaddr() expects M_PKTHDR, + * and m_copy() will copy M_PKTHDR + * only if offset is 0. + */ + if (last->in6p_flags & IN6P_CONTROLOPTS + || last->in6p_socket->so_options & SO_TIMESTAMP) + ip6_savecontrol(last, &opts, + ip6, n); + m_adj(n, off + sizeof(struct udphdr)); + if (sbappendaddr(&last->in6p_socket->so_rcv, + (struct sockaddr *)&udp_in6, + n, opts) == 0) { + m_freem(n); + if (opts) + m_freem(opts); + udpstat.udps_fullsock++; + } else + sorwakeup(last->in6p_socket); + opts = 0; + } + } + last = in6p; + /* + * Don't look for additional matches if this one does + * not have either the SO_REUSEPORT or SO_REUSEADDR + * socket options set. This heuristic avoids searching + * through all pcbs in the common case of a non-shared + * port. It assumes that an application will never + * clear these options after setting them. + */ + if ((last->in6p_socket->so_options & + (SO_REUSEPORT|SO_REUSEADDR)) == 0) + break; + } + + if (last == NULL) { + /* + * No matching pcb found; discard datagram. + * (No need to send an ICMP Port Unreachable + * for a broadcast or multicast datgram.) + */ + udpstat.udps_noport++; + udpstat.udps_noportmcast++; + goto bad; + } +#ifdef IPSEC + /* + * Check AH/ESP integrity. + */ + if (last != NULL && ipsec6_in_reject_so(m, last->inp_socket)) { + ipsec6stat.in_polvio++; + goto bad; + } +#endif /*IPSEC*/ + if (last->in6p_flags & IN6P_CONTROLOPTS + || last->in6p_socket->so_options & SO_TIMESTAMP) + ip6_savecontrol(last, &opts, ip6, m); + + m_adj(m, off + sizeof(struct udphdr)); + if (sbappendaddr(&last->in6p_socket->so_rcv, + (struct sockaddr *)&udp_in6, + m, opts) == 0) { + udpstat.udps_fullsock++; + goto bad; + } + sorwakeup(last->in6p_socket); + return IPPROTO_DONE; + } + /* + * Locate pcb for datagram. + */ + in6p = in6_pcblookup_hash(&udbinfo, &ip6->ip6_src, uh->uh_sport, + &ip6->ip6_dst, uh->uh_dport, 1, + m->m_pkthdr.rcvif); + if (in6p == 0) { + if (log_in_vain) { + char buf[INET6_ADDRSTRLEN]; + + strcpy(buf, ip6_sprintf(&ip6->ip6_dst)); + log(LOG_INFO, + "Connection attempt to UDP %s:%d from %s:%d\n", + buf, ntohs(uh->uh_dport), + ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport)); + } + udpstat.udps_noport++; + if (m->m_flags & M_MCAST) { + printf("UDP6: M_MCAST is set in a unicast packet.\n"); + udpstat.udps_noportmcast++; + goto bad; + } + icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT, 0); + return IPPROTO_DONE; + } +#ifdef IPSEC + /* + * Check AH/ESP integrity. + */ + if (in6p != NULL && ipsec6_in_reject_so(m, in6p->in6p_socket)) { + ipsec6stat.in_polvio++; + goto bad; + } +#endif /*IPSEC*/ + + /* + * Construct sockaddr format source address. + * Stuff source address and datagram in user buffer. + */ + init_sin6(&udp_in6, m); /* general init */ + udp_in6.sin6_port = uh->uh_sport; + if (in6p->in6p_flags & IN6P_CONTROLOPTS + || in6p->in6p_socket->so_options & SO_TIMESTAMP) + ip6_savecontrol(in6p, &opts, ip6, m); + m_adj(m, off + sizeof(struct udphdr)); + if (sbappendaddr(&in6p->in6p_socket->so_rcv, + (struct sockaddr *)&udp_in6, + m, opts) == 0) { + udpstat.udps_fullsock++; + goto bad; + } + sorwakeup(in6p->in6p_socket); + return IPPROTO_DONE; +bad: + if (m) + m_freem(m); + if (opts) + m_freem(opts); + return IPPROTO_DONE; +} + +void +udp6_ctlinput(cmd, sa, d) + int cmd; + struct sockaddr *sa; + void *d; +{ + register struct udphdr *uhp; + struct udphdr uh; + struct sockaddr_in6 sa6; + struct ip6_hdr *ip6; + struct mbuf *m; + int off; + + if (sa->sa_family != AF_INET6 || + sa->sa_len != sizeof(struct sockaddr_in6)) + return; + + if (!PRC_IS_REDIRECT(cmd) && + ((unsigned)cmd >= PRC_NCMDS || inet6ctlerrmap[cmd] == 0)) + return; + + /* if the parameter is from icmp6, decode it. */ + if (d != NULL) { + struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + m = ip6cp->ip6c_m; + ip6 = ip6cp->ip6c_ip6; + off = ip6cp->ip6c_off; + } else { + m = NULL; + ip6 = NULL; + } + + /* translate addresses into internal form */ + sa6 = *(struct sockaddr_in6 *)sa; + if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr)) + sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + + if (ip6) { + /* + * XXX: We assume that when IPV6 is non NULL, + * M and OFF are valid. + */ + struct in6_addr s; + + /* translate addresses into internal form */ + memcpy(&s, &ip6->ip6_src, sizeof(s)); + if (IN6_IS_ADDR_LINKLOCAL(&s)) + s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); + + if (m->m_len < off + sizeof(uh)) { + /* + * this should be rare case, + * so we compromise on this copy... + */ + m_copydata(m, off, sizeof(uh), (caddr_t)&uh); + uhp = &uh; + } else + uhp = (struct udphdr *)(mtod(m, caddr_t) + off); + (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, + uhp->uh_dport, &s, + uhp->uh_sport, cmd, udp_notify); + } else + (void) in6_pcbnotify(&udb, (struct sockaddr *)&sa6, 0, + &zeroin6_addr, 0, cmd, udp_notify); +} + +static int +udp6_getcred SYSCTL_HANDLER_ARGS +{ + struct sockaddr_in6 addrs[2]; + struct inpcb *inp; + int error, s; + + error = suser(req->p); + if (error) + return (error); + error = SYSCTL_IN(req, addrs, sizeof(addrs)); + if (error) + return (error); + s = splnet(); + inp = in6_pcblookup_hash(&udbinfo, &addrs[1].sin6_addr, + addrs[1].sin6_port, + &addrs[0].sin6_addr, addrs[0].sin6_port, + 1, NULL); + if (!inp || !inp->inp_socket || !inp->inp_socket->so_cred) { + error = ENOENT; + goto out; + } + error = SYSCTL_OUT(req, inp->inp_socket->so_cred, + sizeof(struct ucred)); + +out: + splx(s); + return (error); +} + +SYSCTL_PROC(_net_inet6_udp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW, + 0, 0, + udp6_getcred, "S,ucred", "Get the ucred of a UDP6 connection"); + +int +udp6_output(in6p, m, addr6, control, p) + register struct inpcb *in6p; + register struct mbuf *m; + struct sockaddr *addr6; + struct mbuf *control; + struct proc *p; +{ + register int ulen = m->m_pkthdr.len; + int plen = sizeof(struct udphdr) + ulen; + struct ip6_hdr *ip6; + struct udphdr *udp6; + struct in6_addr laddr6; + int s = 0, error = 0; + struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts; + + if (control) { + if ((error = ip6_setpktoptions(control, &opt, suser(p))) != 0) + goto release; + in6p->in6p_outputopts = &opt; + } + + if (addr6) { + laddr6 = in6p->in6p_laddr; + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + error = EISCONN; + goto release; + } + /* + * Must block input while temporarily connected. + */ + s = splnet(); + /* + * XXX: the user might want to overwrite the local address + * via an ancillary data. + */ + bzero(&in6p->in6p_laddr, sizeof(struct in6_addr)); + error = in6_pcbconnect(in6p, addr6, p); + if (error) { + splx(s); + goto release; + } + } else { + if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + error = ENOTCONN; + goto release; + } + } + /* + * Calculate data length and get a mbuf + * for UDP and IP6 headers. + */ + M_PREPEND(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr), + M_DONTWAIT); + if (m == 0) { + error = ENOBUFS; + if (addr6) + splx(s); + goto release; + } + + /* + * Stuff checksum and output datagram. + */ + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_flow = in6p->in6p_flowinfo & IPV6_FLOWINFO_MASK; + ip6->ip6_vfc = IPV6_VERSION; + /* ip6_plen will be filled in ip6_output. */ + 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 = in6p->in6p_laddr; + ip6->ip6_dst = in6p->in6p_faddr; + + udp6 = (struct udphdr *)(ip6 + 1); + udp6->uh_sport = in6p->in6p_lport; + udp6->uh_dport = in6p->in6p_fport; + udp6->uh_ulen = htons((u_short)plen); + udp6->uh_sum = 0; + + if ((udp6->uh_sum = in6_cksum(m, IPPROTO_UDP, + sizeof(struct ip6_hdr), plen)) == 0) { + udp6->uh_sum = 0xffff; + } + + udpstat.udps_opackets++; + +#ifdef IPSEC + m->m_pkthdr.rcvif = (struct ifnet *)in6p->in6p_socket; +#endif /*IPSEC*/ + error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, + 0, in6p->in6p_moptions, NULL); + + if (addr6) { + in6_pcbdisconnect(in6p); + in6p->in6p_laddr = laddr6; + splx(s); + } + goto releaseopt; + +release: + m_freem(m); + +releaseopt: + if (control) { + in6p->in6p_outputopts = stickyopt; + m_freem(control); + } + return(error); +} + +static int +udp6_abort(struct socket *so) +{ + struct inpcb *inp; + int s; + + inp = sotoinpcb(so); + if (inp == 0) + return EINVAL; /* ??? possible? panic instead? */ + soisdisconnected(so); + s = splnet(); + in6_pcbdetach(inp); + splx(s); + return 0; +} + +static int +udp6_attach(struct socket *so, int proto, struct proc *p) +{ + struct inpcb *inp; + int s, error; + + inp = sotoinpcb(so); + if (inp != 0) + return EINVAL; + + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { + error = soreserve(so, udp_sendspace, udp_recvspace); + if (error) + return error; + } + s = splnet(); + error = in_pcballoc(so, &udbinfo, p); + splx(s); + if (error) + return error; + inp = (struct inpcb *)so->so_pcb; + inp->inp_vflag |= INP_IPV6; + inp->in6p_hops = -1; /* use kernel default */ + inp->in6p_cksum = -1; /* just to be sure */ +#ifdef IPSEC + error = ipsec_init_policy(so, &inp->in6p_sp); + if (error != 0) { + in6_pcbdetach(inp); + return (error); + } +#endif /*IPSEC*/ + return 0; +} + +static int +udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p) +{ + struct inpcb *inp; + int s, error; + + inp = sotoinpcb(so); + if (inp == 0) + return EINVAL; + + inp->inp_vflag &= ~INP_IPV4; + inp->inp_vflag |= INP_IPV6; + if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_BINDV6ONLY) == NULL) { + struct sockaddr_in6 *sin6_p; + + sin6_p = (struct sockaddr_in6 *)nam; + + if (IN6_IS_ADDR_UNSPECIFIED(&sin6_p->sin6_addr)) + inp->inp_vflag |= INP_IPV4; + else if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { + struct sockaddr_in sin; + + in6_sin6_2_sin(&sin, sin6_p); + inp->inp_vflag |= INP_IPV4; + inp->inp_vflag &= ~INP_IPV6; + s = splnet(); + error = in_pcbbind(inp, (struct sockaddr *)&sin, p); + splx(s); + return error; + } + } + + s = splnet(); + error = in6_pcbbind(inp, nam, p); + splx(s); + return error; +} + +static int +udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) +{ + struct inpcb *inp; + int s, error; + + inp = sotoinpcb(so); + if (inp == 0) + return EINVAL; + + if (ip6_mapped_addr_on) { + struct sockaddr_in6 *sin6_p; + + sin6_p = (struct sockaddr_in6 *)nam; + if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) { + struct sockaddr_in sin; + + if (inp->inp_faddr.s_addr != INADDR_ANY) + return EISCONN; + in6_sin6_2_sin(&sin, sin6_p); + s = splnet(); + error = in_pcbconnect(inp, (struct sockaddr *)&sin, p); + splx(s); + if (error == NULL) { + inp->inp_vflag |= INP_IPV4; + inp->inp_vflag &= ~INP_IPV6; + soisconnected(so); + } + return error; + } + } + + if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) + return EISCONN; + s = splnet(); + error = in6_pcbconnect(inp, nam, p); + if (ip6_auto_flowlabel) { + inp->in6p_flowinfo &= ~IPV6_FLOWLABEL_MASK; + inp->in6p_flowinfo |= + (htonl(ip6_flow_seq++) & IPV6_FLOWLABEL_MASK); + } + splx(s); + if (error == NULL) { + if (ip6_mapped_addr_on) { /* should be non mapped addr */ + inp->inp_vflag &= ~INP_IPV4; + inp->inp_vflag |= INP_IPV6; + } + soisconnected(so); + } + return error; +} + +static int +udp6_detach(struct socket *so) +{ + struct inpcb *inp; + int s; + + inp = sotoinpcb(so); + if (inp == 0) + return EINVAL; + s = splnet(); + in6_pcbdetach(inp); + splx(s); + return 0; +} + +static int +udp6_disconnect(struct socket *so) +{ + struct inpcb *inp; + int s; + + inp = sotoinpcb(so); + if (inp == 0) + return EINVAL; + + if (inp->inp_vflag & INP_IPV4) { + struct pr_usrreqs *pru; + + pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; + return ((*pru->pru_disconnect)(so)); + } + + if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) + return ENOTCONN; + + s = splnet(); + in6_pcbdisconnect(inp); + inp->in6p_laddr = in6addr_any; + splx(s); + so->so_state &= ~SS_ISCONNECTED; /* XXX */ + return 0; +} + +static int +udp6_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, + struct mbuf *control, struct proc *p) +{ + struct inpcb *inp; + + inp = sotoinpcb(so); + if (inp == 0) { + m_freem(m); + return EINVAL; + } + + if (ip6_mapped_addr_on) { + int hasv4addr; + struct sockaddr_in6 *sin6 = 0; + + if (addr == 0) + hasv4addr = (inp->inp_vflag & INP_IPV4); + else { + sin6 = (struct sockaddr_in6 *)addr; + hasv4addr = IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) + ? 1 : 0; + } + if (hasv4addr) { + struct pr_usrreqs *pru; + int error; + + if (sin6) + in6_sin6_2_sin_in_sock(addr); + pru = inetsw[ip_protox[IPPROTO_UDP]].pr_usrreqs; + error = ((*pru->pru_send)(so, flags, m, addr, control, + p)); + /* addr will just be freed in sendit(). */ + return error; + } + } + + return udp6_output(inp, m, addr, control, p); +} + +struct pr_usrreqs udp6_usrreqs = { + udp6_abort, pru_accept_notsupp, udp6_attach, udp6_bind, udp6_connect, + pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect, + pru_listen_notsupp, in6_mapped_peeraddr, pru_rcvd_notsupp, + pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp_shutdown, + in6_mapped_sockaddr, sosend, soreceive, sopoll +}; diff --git a/sys/netinet6/udp6_var.h b/sys/netinet6/udp6_var.h index b95bc78..e0ade7a 100644 --- a/sys/netinet6/udp6_var.h +++ b/sys/netinet6/udp6_var.h @@ -68,6 +68,8 @@ #define _NETINET6_UDP6_VAR_H_ #ifdef KERNEL +SYSCTL_DECL(_net_inet6_udp6); + extern struct pr_usrreqs udp6_usrreqs; void udp6_ctlinput __P((int, struct sockaddr *, void *)); |