in_gif.c revision 152242
143543Swollman/*	$FreeBSD: head/sys/netinet/in_gif.c 152242 2005-11-09 13:29:16Z ru $	*/
22742Swollman/*	$KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $	*/
32742Swollman
42742Swollman/*-
52742Swollman * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
62742Swollman * All rights reserved.
72742Swollman *
82742Swollman * Redistribution and use in source and binary forms, with or without
92742Swollman * modification, are permitted provided that the following conditions
102742Swollman * are met:
112742Swollman * 1. Redistributions of source code must retain the above copyright
122742Swollman *    notice, this list of conditions and the following disclaimer.
132742Swollman * 2. Redistributions in binary form must reproduce the above copyright
142742Swollman *    notice, this list of conditions and the following disclaimer in the
152742Swollman *    documentation and/or other materials provided with the distribution.
162742Swollman * 3. Neither the name of the project nor the names of its contributors
172742Swollman *    may be used to endorse or promote products derived from this software
182742Swollman *    without specific prior written permission.
192742Swollman *
202742Swollman * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
212742Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
222742Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239908Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
242742Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2530711Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
262742Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
272742Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289908Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
292742Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
302742Swollman * SUCH DAMAGE.
3114343Swollman */
3214343Swollman
3314343Swollman#include "opt_mrouting.h"
3414343Swollman#include "opt_inet.h"
3514343Swollman#include "opt_inet6.h"
3614343Swollman
372742Swollman#include <sys/param.h>
389908Swollman#include <sys/systm.h>
3920094Swollman#include <sys/socket.h>
4020094Swollman#include <sys/sockio.h>
4120094Swollman#include <sys/mbuf.h>
4220094Swollman#include <sys/errno.h>
4320094Swollman#include <sys/kernel.h>
4420094Swollman#include <sys/sysctl.h>
4520094Swollman#include <sys/protosw.h>
4620094Swollman
4720094Swollman#include <sys/malloc.h>
4820094Swollman
4920094Swollman#include <net/if.h>
5020094Swollman#include <net/route.h>
5120094Swollman
5221217Swollman#include <netinet/in.h>
5321217Swollman#include <netinet/in_systm.h>
5420094Swollman#include <netinet/ip.h>
5520094Swollman#include <netinet/ip_var.h>
562742Swollman#include <netinet/in_gif.h>
572742Swollman#include <netinet/in_var.h>
5814343Swollman#include <netinet/ip_encap.h>
5914343Swollman#include <netinet/ip_ecn.h>
6021217Swollman
6120094Swollman#ifdef INET6
6220094Swollman#include <netinet/ip6.h>
6320094Swollman#endif
6420094Swollman
6520094Swollman#ifdef MROUTING
662742Swollman#include <netinet/ip_mroute.h>
679908Swollman#endif /* MROUTING */
682742Swollman
6914343Swollman#include <net/if_gif.h>
7014343Swollman
7114343Swollman#include <net/net_osdep.h>
7214343Swollman
7314343Swollmanstatic int gif_validate4(const struct ip *, struct gif_softc *,
7414343Swollman	struct ifnet *);
7514343Swollman
7614343Swollmanextern  struct domain inetdomain;
7714343Swollmanstruct protosw in_gif_protosw = {
782742Swollman	.pr_type =		SOCK_RAW,
792742Swollman	.pr_domain =		&inetdomain,
802742Swollman	.pr_protocol =		0/* IPPROTO_IPV[46] */,
812742Swollman	.pr_flags =		PR_ATOMIC|PR_ADDR,
8214343Swollman	.pr_input =		in_gif_input,
832742Swollman	.pr_output =		(pr_output_t*)rip_output,
842742Swollman	.pr_ctloutput =		rip_ctloutput,
859908Swollman	.pr_usrreqs =		&rip_usrreqs
862742Swollman};
8714343Swollman
8814343Swollmanstatic int ip_gif_ttl = GIF_TTL;
8914343SwollmanSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
9014343Swollman	&ip_gif_ttl,	0, "");
9114343Swollman
9214343Swollmanint
9314343Swollmanin_gif_output(ifp, family, m)
9414343Swollman	struct ifnet	*ifp;
9514343Swollman	int		family;
9614343Swollman	struct mbuf	*m;
9714343Swollman{
9814343Swollman	struct gif_softc *sc = ifp->if_softc;
9914343Swollman	struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
1002742Swollman	struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
1012742Swollman	struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
1022742Swollman	struct ip iphdr;	/* capsule IP header, host byte ordered */
10314343Swollman	int proto, error;
1042742Swollman	u_int8_t tos;
1052742Swollman
1069908Swollman	if (sin_src == NULL || sin_dst == NULL ||
1072742Swollman	    sin_src->sin_family != AF_INET ||
10814343Swollman	    sin_dst->sin_family != AF_INET) {
10914343Swollman		m_freem(m);
11014343Swollman		return EAFNOSUPPORT;
11114343Swollman	}
11214343Swollman
11343543Swollman	switch (family) {
11414343Swollman#ifdef INET
11514343Swollman	case AF_INET:
11643543Swollman	    {
11743543Swollman		struct ip *ip;
1182742Swollman
1192742Swollman		proto = IPPROTO_IPV4;
1202742Swollman		if (m->m_len < sizeof(*ip)) {
12114343Swollman			m = m_pullup(m, sizeof(*ip));
1222742Swollman			if (!m)
1232742Swollman				return ENOBUFS;
1249908Swollman		}
1252742Swollman		ip = mtod(m, struct ip *);
12614343Swollman		tos = ip->ip_tos;
12714343Swollman		break;
12814343Swollman	    }
12914343Swollman#endif /* INET */
13014343Swollman#ifdef INET6
13114343Swollman	case AF_INET6:
13214343Swollman	    {
13343543Swollman		struct ip6_hdr *ip6;
13414343Swollman		proto = IPPROTO_IPV6;
13514343Swollman		if (m->m_len < sizeof(*ip6)) {
13643543Swollman			m = m_pullup(m, sizeof(*ip6));
13743543Swollman			if (!m)
1382742Swollman				return ENOBUFS;
1392742Swollman		}
1402742Swollman		ip6 = mtod(m, struct ip6_hdr *);
14114343Swollman		tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
1422742Swollman		break;
1432742Swollman	    }
1442742Swollman#endif /* INET6 */
1452742Swollman	default:
1462742Swollman#ifdef DEBUG
14714343Swollman		printf("in_gif_output: warning: unknown family %d passed\n",
1482742Swollman			family);
1498029Swollman#endif
15014343Swollman		m_freem(m);
15114343Swollman		return EAFNOSUPPORT;
15214343Swollman	}
15314343Swollman
15414343Swollman	bzero(&iphdr, sizeof(iphdr));
15514343Swollman	iphdr.ip_src = sin_src->sin_addr;
15614343Swollman	/* bidirectional configured tunnel mode */
15714343Swollman	if (sin_dst->sin_addr.s_addr != INADDR_ANY)
15814343Swollman		iphdr.ip_dst = sin_dst->sin_addr;
15914343Swollman	else {
1602742Swollman		m_freem(m);
1612742Swollman		return ENETUNREACH;
16214343Swollman	}
1638029Swollman	iphdr.ip_p = proto;
16414343Swollman	/* version will be set in ip_output() */
1652742Swollman	iphdr.ip_ttl = ip_gif_ttl;
1662742Swollman	iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
16714343Swollman	ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
1682742Swollman		       &iphdr.ip_tos, &tos);
1692742Swollman
17014343Swollman	/* prepend new IP header */
17114343Swollman	M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
17214343Swollman	if (m && m->m_len < sizeof(struct ip))
17314343Swollman		m = m_pullup(m, sizeof(struct ip));
17430711Swollman	if (m == NULL) {
17530711Swollman		printf("ENOBUFS in in_gif_output %d\n", __LINE__);
17630711Swollman		return ENOBUFS;
1772742Swollman	}
17830711Swollman	bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
17930711Swollman
18030711Swollman	if (dst->sin_family != sin_dst->sin_family ||
1812742Swollman	    dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
18243014Swollman		/* cache route doesn't match */
18343014Swollman		bzero(dst, sizeof(*dst));
18443014Swollman		dst->sin_family = sin_dst->sin_family;
18543014Swollman		dst->sin_len = sizeof(struct sockaddr_in);
1862742Swollman		dst->sin_addr = sin_dst->sin_addr;
1872742Swollman		if (sc->gif_ro.ro_rt) {
18843014Swollman			RTFREE(sc->gif_ro.ro_rt);
1892742Swollman			sc->gif_ro.ro_rt = NULL;
19019878Swollman		}
19143014Swollman#if 0
19243014Swollman		GIF2IFP(sc)->if_mtu = GIF_MTU;
1932742Swollman#endif
1942742Swollman	}
19519878Swollman
19619878Swollman	if (sc->gif_ro.ro_rt == NULL) {
1972742Swollman		rtalloc_ign(&sc->gif_ro, 0);
1982742Swollman		if (sc->gif_ro.ro_rt == NULL) {
1992742Swollman			m_freem(m);
2002742Swollman			return ENETUNREACH;
20119878Swollman		}
2022742Swollman
2032742Swollman		/* if it constitutes infinite encapsulation, punt. */
20443543Swollman		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
20543543Swollman			m_freem(m);
20643543Swollman			return ENETUNREACH;	/* XXX */
2072742Swollman		}
2082742Swollman#if 0
20943543Swollman		ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
2102742Swollman			- sizeof(struct ip);
2112742Swollman#endif
2122742Swollman	}
2132742Swollman
21419878Swollman	error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL);
2152742Swollman
21619878Swollman	if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) &&
2172742Swollman	    sc->gif_ro.ro_rt != NULL) {
21819878Swollman		RTFREE(sc->gif_ro.ro_rt);
21943014Swollman		sc->gif_ro.ro_rt = NULL;
22043014Swollman	}
2212742Swollman
2222742Swollman	return (error);
2232742Swollman}
2242742Swollman
2252742Swollmanvoid
2262742Swollmanin_gif_input(m, off)
2272742Swollman	struct mbuf *m;
2282742Swollman	int off;
2292742Swollman{
23019878Swollman	struct ifnet *gifp = NULL;
2312742Swollman	struct gif_softc *sc;
23219878Swollman	struct ip *ip;
23319878Swollman	int af;
23419878Swollman	u_int8_t otos;
2352742Swollman	int proto;
23619878Swollman
23719878Swollman	ip = mtod(m, struct ip *);
23819878Swollman	proto = ip->ip_p;
2392742Swollman
24014343Swollman	sc = (struct gif_softc *)encap_getarg(m);
24114343Swollman	if (sc == NULL) {
24214343Swollman		m_freem(m);
24319878Swollman		ipstat.ips_nogif++;
24419878Swollman		return;
24514343Swollman	}
24614343Swollman
24714343Swollman	gifp = GIF2IFP(sc);
24814343Swollman	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
24919878Swollman		m_freem(m);
25019878Swollman		ipstat.ips_nogif++;
25114343Swollman		return;
25219878Swollman	}
25319878Swollman
25419878Swollman	otos = ip->ip_tos;
25514343Swollman	m_adj(m, off);
25614343Swollman
25714343Swollman	switch (proto) {
25814343Swollman#ifdef INET
25919878Swollman	case IPPROTO_IPV4:
26019878Swollman	    {
26114343Swollman		struct ip *ip;
26219878Swollman		af = AF_INET;
26314343Swollman		if (m->m_len < sizeof(*ip)) {
26419878Swollman			m = m_pullup(m, sizeof(*ip));
26514343Swollman			if (!m)
26619878Swollman				return;
26719878Swollman		}
26814343Swollman		ip = mtod(m, struct ip *);
2692742Swollman		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
2702742Swollman				  ECN_ALLOWED : ECN_NOCARE,
2712742Swollman				  &otos, &ip->ip_tos) == 0) {
27219878Swollman			m_freem(m);
2732742Swollman			return;
27419878Swollman		}
27519878Swollman		break;
2762742Swollman	    }
2772742Swollman#endif
2782742Swollman#ifdef INET6
27919878Swollman	case IPPROTO_IPV6:
28019878Swollman	    {
28143014Swollman		struct ip6_hdr *ip6;
28243014Swollman		u_int8_t itos, oitos;
2832742Swollman
2842742Swollman		af = AF_INET6;
2852742Swollman		if (m->m_len < sizeof(*ip6)) {
2862742Swollman			m = m_pullup(m, sizeof(*ip6));
2872742Swollman			if (!m)
2882742Swollman				return;
2892742Swollman		}
2902742Swollman		ip6 = mtod(m, struct ip6_hdr *);
2912742Swollman		itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
2922742Swollman		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
2932742Swollman				  ECN_ALLOWED : ECN_NOCARE,
2942742Swollman				  &otos, &itos) == 0) {
29514343Swollman			m_freem(m);
2962742Swollman			return;
29714343Swollman		}
29814343Swollman		if (itos != oitos) {
2992742Swollman			ip6->ip6_flow &= ~htonl(0xff << 20);
30014343Swollman			ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
30143014Swollman		}
30214343Swollman		break;
30314343Swollman	    }
30414343Swollman#endif /* INET6 */
3059908Swollman	default:
3069908Swollman		ipstat.ips_nogif++;
3079908Swollman		m_freem(m);
3089908Swollman		return;
3099908Swollman	}
3109908Swollman	gif_input(m, af, gifp);
3119908Swollman	return;
31220094Swollman}
31320094Swollman
3142742Swollman/*
3152742Swollman * validate outer address.
31614343Swollman */
3172742Swollmanstatic int
31820094Swollmangif_validate4(ip, sc, ifp)
3192742Swollman	const struct ip *ip;
3208029Swollman	struct gif_softc *sc;
32130711Swollman	struct ifnet *ifp;
32230711Swollman{
3232742Swollman	struct sockaddr_in *src, *dst;
32430711Swollman	struct in_ifaddr *ia4;
32530711Swollman
32630711Swollman	src = (struct sockaddr_in *)sc->gif_psrc;
32730711Swollman	dst = (struct sockaddr_in *)sc->gif_pdst;
32830711Swollman
3292742Swollman	/* check for address match */
3302742Swollman	if (src->sin_addr.s_addr != ip->ip_dst.s_addr ||
3312742Swollman	    dst->sin_addr.s_addr != ip->ip_src.s_addr)
3322742Swollman		return 0;
3332742Swollman
3342742Swollman	/* martian filters on outer source - NOT done in ip_input! */
33519878Swollman	if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)))
33619878Swollman		return 0;
33719878Swollman	switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) {
3382742Swollman	case 0: case 127: case 255:
3392742Swollman		return 0;
3402742Swollman	}
3412742Swollman	/* reject packets with broadcast on source */
34219878Swollman	TAILQ_FOREACH(ia4, &in_ifaddrhead, ia_link) {
34319878Swollman		if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
3442742Swollman			continue;
3459908Swollman		if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
3469908Swollman			return 0;
3479908Swollman	}
34819878Swollman
3499908Swollman	/* ingress filters on outer source */
3502742Swollman	if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) {
3512742Swollman		struct sockaddr_in sin;
3522742Swollman		struct rtentry *rt;
35319878Swollman
35419878Swollman		bzero(&sin, sizeof(sin));
3552742Swollman		sin.sin_family = AF_INET;
3562742Swollman		sin.sin_len = sizeof(struct sockaddr_in);
3572742Swollman		sin.sin_addr = ip->ip_src;
3582742Swollman		rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
35919878Swollman		if (!rt || rt->rt_ifp != ifp) {
3602742Swollman#if 0
36114343Swollman			log(LOG_WARNING, "%s: packet from 0x%x dropped "
36214343Swollman			    "due to ingress filter\n", if_name(GIF2IFP(sc)),
36314343Swollman			    (u_int32_t)ntohl(sin.sin_addr.s_addr));
36419878Swollman#endif
36514343Swollman			if (rt)
36614343Swollman				rtfree(rt);
36714343Swollman			return 0;
36814343Swollman		}
36914343Swollman		rtfree(rt);
37014343Swollman	}
37114343Swollman
37219878Swollman	return 32 * 2;
37319878Swollman}
37414343Swollman
3752742Swollman/*
3762742Swollman * we know that we are in IFF_UP, outer address available, and outer family
3772742Swollman * matched the physical addr family.  see gif_encapcheck().
3782742Swollman */
37919878Swollmanint
3802742Swollmangif_encapcheck4(m, off, proto, arg)
3812742Swollman	const struct mbuf *m;
3822742Swollman	int off;
3832742Swollman	int proto;
38419878Swollman	void *arg;
3852742Swollman{
3862742Swollman	struct ip ip;
3872742Swollman	struct gif_softc *sc;
3882742Swollman	struct ifnet *ifp;
38919878Swollman
39019878Swollman	/* sanity check done in caller */
3912742Swollman	sc = (struct gif_softc *)arg;
3922742Swollman
3932742Swollman	/* LINTED const cast */
3942742Swollman	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
39519878Swollman	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
3962742Swollman
39743014Swollman	return gif_validate4(&ip, sc, ifp);
39843014Swollman}
39943014Swollman
40043014Swollmanint
40143014Swollmanin_gif_attach(sc)
40243014Swollman	struct gif_softc *sc;
40343014Swollman{
40443014Swollman	sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck,
40543014Swollman	    &in_gif_protosw, sc);
40643014Swollman	if (sc->encap_cookie4 == NULL)
40743014Swollman		return EEXIST;
40843014Swollman	return 0;
40943014Swollman}
41043014Swollman
41143014Swollmanint
41243014Swollmanin_gif_detach(sc)
41343014Swollman	struct gif_softc *sc;
41443014Swollman{
41543014Swollman	int error;
41643014Swollman
41743014Swollman	error = encap_detach(sc->encap_cookie4);
41843014Swollman	if (error == 0)
41943014Swollman		sc->encap_cookie4 = NULL;
42043014Swollman	return error;
42143014Swollman}
42243014Swollman