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/netinet | |
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/netinet')
-rw-r--r-- | sys/netinet/if_atm.c | 3 | ||||
-rw-r--r-- | sys/netinet/in_gif.c | 311 | ||||
-rw-r--r-- | sys/netinet/in_gif.h | 42 | ||||
-rw-r--r-- | sys/netinet/in_pcb.c | 114 | ||||
-rw-r--r-- | sys/netinet/in_pcb.h | 3 | ||||
-rw-r--r-- | sys/netinet/in_proto.c | 22 | ||||
-rw-r--r-- | sys/netinet/ip_fw.c | 12 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 9 | ||||
-rw-r--r-- | sys/netinet/tcp_reass.c | 9 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 4 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 4 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 6 | ||||
-rw-r--r-- | sys/netinet/udp_usrreq.c | 232 | ||||
-rw-r--r-- | sys/netinet/udp_var.h | 2 |
14 files changed, 707 insertions, 66 deletions
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)); |