in6_gif.c revision 189494
118334Speter/*-
290075Sobrien * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3169689Skan * All rights reserved.
4169689Skan *
518334Speter * Redistribution and use in source and binary forms, with or without
690075Sobrien * modification, are permitted provided that the following conditions
718334Speter * are met:
890075Sobrien * 1. Redistributions of source code must retain the above copyright
990075Sobrien *    notice, this list of conditions and the following disclaimer.
1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1190075Sobrien *    notice, this list of conditions and the following disclaimer in the
1218334Speter *    documentation and/or other materials provided with the distribution.
1390075Sobrien * 3. Neither the name of the project nor the names of its contributors
1490075Sobrien *    may be used to endorse or promote products derived from this software
1590075Sobrien *    without specific prior written permission.
1690075Sobrien *
1718334Speter * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1818334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1990075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20169689Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2218334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27169689Skan * SUCH DAMAGE.
28169689Skan *
29169689Skan *	$KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $
30169689Skan */
31169689Skan
32169689Skan#include <sys/cdefs.h>
33169689Skan__FBSDID("$FreeBSD: head/sys/netinet6/in6_gif.c 189494 2009-03-07 19:08:58Z marius $");
34169689Skan
35169689Skan#include "opt_inet.h"
36169689Skan#include "opt_inet6.h"
37169689Skan
3818334Speter#include <sys/param.h>
3918334Speter#include <sys/systm.h>
4018334Speter#include <sys/socket.h>
4118334Speter#include <sys/sockio.h>
4218334Speter#include <sys/mbuf.h>
4318334Speter#include <sys/errno.h>
44117395Skan#include <sys/queue.h>
45169689Skan#include <sys/syslog.h>
4618334Speter#include <sys/protosw.h>
4718334Speter#include <sys/malloc.h>
4818334Speter#include <sys/vimage.h>
4950397Sobrien
50117395Skan#include <net/if.h>
51117395Skan#include <net/route.h>
52117395Skan
53169689Skan#include <netinet/in.h>
54117395Skan#include <netinet/in_systm.h>
55117395Skan#ifdef INET
5618334Speter#include <netinet/ip.h>
5752284Sobrien#endif
5852284Sobrien#include <netinet/ip_encap.h>
5952284Sobrien#ifdef INET6
6052284Sobrien#include <netinet/ip6.h>
6152284Sobrien#include <netinet6/ip6_var.h>
6252284Sobrien#include <netinet6/in6_gif.h>
6352284Sobrien#include <netinet6/in6_var.h>
6418334Speter#endif
65132718Skan#include <netinet6/ip6protosw.h>
66169689Skan#include <netinet/ip_ecn.h>
67132718Skan#ifdef INET6
68132718Skan#include <netinet6/ip6_ecn.h>
69169689Skan#include <netinet6/vinet6.h>
70132718Skan#endif
71132718Skan
72132718Skan#include <net/if_gif.h>
73132718Skan
74132718Skanstatic int gif_validate6(const struct ip6_hdr *, struct gif_softc *,
75132718Skan			 struct ifnet *);
76132718Skan
77132718Skanextern  struct domain inet6domain;
78169689Skanstruct ip6protosw in6_gif_protosw = {
79132718Skan	.pr_type =	SOCK_RAW,
80132718Skan	.pr_domain =	&inet6domain,
81169689Skan	.pr_protocol =	0,			/* IPPROTO_IPV[46] */
82132718Skan	.pr_flags =	PR_ATOMIC|PR_ADDR,
83132718Skan	.pr_input =	in6_gif_input,
84132718Skan	.pr_output =	rip6_output,
85132718Skan	.pr_ctloutput =	rip6_ctloutput,
86132718Skan	.pr_usrreqs =	&rip6_usrreqs
87132718Skan};
88132718Skan
89132718Skanint
90132718Skanin6_gif_output(struct ifnet *ifp,
9118334Speter    int family,			/* family of the packet to be encapsulate */
9290075Sobrien    struct mbuf *m)
9390075Sobrien{
9490075Sobrien	INIT_VNET_GIF(ifp->if_vnet);
9518334Speter	struct gif_softc *sc = ifp->if_softc;
9618334Speter	struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
9718334Speter	struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
9850397Sobrien	struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
9918334Speter	struct ip6_hdr *ip6;
10018334Speter	struct etherip_header eiphdr;
10118334Speter	int error, len, proto;
102132718Skan	u_int8_t itos, otos;
103132718Skan
104132718Skan	GIF_LOCK_ASSERT(sc);
105132718Skan
106132718Skan	if (sin6_src == NULL || sin6_dst == NULL ||
107132718Skan	    sin6_src->sin6_family != AF_INET6 ||
108132718Skan	    sin6_dst->sin6_family != AF_INET6) {
109132718Skan		m_freem(m);
110132718Skan		return EAFNOSUPPORT;
111132718Skan	}
112132718Skan
113132718Skan	switch (family) {
114132718Skan#ifdef INET
115132718Skan	case AF_INET:
116132718Skan	    {
117132718Skan		struct ip *ip;
118132718Skan
119132718Skan		proto = IPPROTO_IPV4;
120169689Skan		if (m->m_len < sizeof(*ip)) {
121169689Skan			m = m_pullup(m, sizeof(*ip));
122132718Skan			if (!m)
123132718Skan				return ENOBUFS;
12418334Speter		}
12518334Speter		ip = mtod(m, struct ip *);
126169689Skan		itos = ip->ip_tos;
127169689Skan		break;
128169689Skan	    }
129169689Skan#endif
130169689Skan#ifdef INET6
131169689Skan	case AF_INET6:
132169689Skan	    {
133169689Skan		struct ip6_hdr *ip6;
134169689Skan		proto = IPPROTO_IPV6;
135169689Skan		if (m->m_len < sizeof(*ip6)) {
13696263Sobrien			m = m_pullup(m, sizeof(*ip6));
13718334Speter			if (!m)
138169689Skan				return ENOBUFS;
139169689Skan		}
140169689Skan		ip6 = mtod(m, struct ip6_hdr *);
141169689Skan		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
142169689Skan		break;
143169689Skan	    }
144169689Skan#endif
145169689Skan	case AF_LINK:
146169689Skan		proto = IPPROTO_ETHERIP;
147169689Skan		eiphdr.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
148169689Skan		eiphdr.eip_pad = 0;
14996263Sobrien		/* prepend Ethernet-in-IP header */
15018334Speter		M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
15190075Sobrien		if (m && m->m_len < sizeof(struct etherip_header))
15290075Sobrien			m = m_pullup(m, sizeof(struct etherip_header));
15390075Sobrien		if (m == NULL)
15490075Sobrien			return ENOBUFS;
155169689Skan		bcopy(&eiphdr, mtod(m, struct etherip_header *),
15696263Sobrien		    sizeof(struct etherip_header));
15790075Sobrien		break;
15818334Speter
15990075Sobrien	default:
16090075Sobrien#ifdef DEBUG
161169689Skan		printf("in6_gif_output: warning: unknown family %d passed\n",
16218334Speter			family);
16318334Speter#endif
16418334Speter		m_freem(m);
16518334Speter		return EAFNOSUPPORT;
16618334Speter	}
167132718Skan
16818334Speter	/* prepend new IP header */
16918334Speter	len = sizeof(struct ip6_hdr);
17018334Speter#ifndef __NO_STRICT_ALIGNMENT
17118334Speter	if (family == AF_LINK)
17218334Speter		len += ETHERIP_ALIGN;
17318334Speter#endif
17418334Speter	M_PREPEND(m, len, M_DONTWAIT);
175132718Skan	if (m != NULL && m->m_len < len)
176132718Skan		m = m_pullup(m, len);
177132718Skan	if (m == NULL) {
178132718Skan		printf("ENOBUFS in in6_gif_output %d\n", __LINE__);
17918334Speter		return ENOBUFS;
18018334Speter	}
18118334Speter#ifndef __NO_STRICT_ALIGNMENT
18218334Speter	if (family == AF_LINK) {
18318334Speter		len = mtod(m, vm_offset_t) & 3;
184117395Skan		KASSERT(len == 0 || len == ETHERIP_ALIGN,
18518334Speter		    ("in6_gif_output: unexpected misalignment"));
18618334Speter		m->m_data += len;
18718334Speter		m->m_len -= ETHERIP_ALIGN;
18818334Speter	}
18950397Sobrien#endif
19050397Sobrien
19150397Sobrien	ip6 = mtod(m, struct ip6_hdr *);
19250397Sobrien	ip6->ip6_flow	= 0;
19350397Sobrien	ip6->ip6_vfc	&= ~IPV6_VERSION_MASK;
19450397Sobrien	ip6->ip6_vfc	|= IPV6_VERSION;
19550397Sobrien	ip6->ip6_plen	= htons((u_short)m->m_pkthdr.len);
19650397Sobrien	ip6->ip6_nxt	= proto;
19750397Sobrien	ip6->ip6_hlim	= V_ip6_gif_hlim;
19850397Sobrien	ip6->ip6_src	= sin6_src->sin6_addr;
19950397Sobrien	/* bidirectional configured tunnel mode */
20050397Sobrien	if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
20150397Sobrien		ip6->ip6_dst = sin6_dst->sin6_addr;
20250397Sobrien	else  {
20350397Sobrien		m_freem(m);
20450397Sobrien		return ENETUNREACH;
20550397Sobrien	}
20650397Sobrien	ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
20750397Sobrien		       &otos, &itos);
20850397Sobrien	ip6->ip6_flow &= ~htonl(0xff << 20);
20950397Sobrien	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
21050397Sobrien
21150397Sobrien	if (dst->sin6_family != sin6_dst->sin6_family ||
21250397Sobrien	     !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
21350397Sobrien		/* cache route doesn't match */
21450397Sobrien		bzero(dst, sizeof(*dst));
21550397Sobrien		dst->sin6_family = sin6_dst->sin6_family;
21650397Sobrien		dst->sin6_len = sizeof(struct sockaddr_in6);
21750397Sobrien		dst->sin6_addr = sin6_dst->sin6_addr;
21850397Sobrien		if (sc->gif_ro6.ro_rt) {
21950397Sobrien			RTFREE(sc->gif_ro6.ro_rt);
22050397Sobrien			sc->gif_ro6.ro_rt = NULL;
22150397Sobrien		}
22250397Sobrien#if 0
22350397Sobrien		GIF2IFP(sc)->if_mtu = GIF_MTU;
22450397Sobrien#endif
22550397Sobrien	}
22650397Sobrien
22750397Sobrien	if (sc->gif_ro6.ro_rt == NULL) {
22850397Sobrien		rtalloc((struct route *)&sc->gif_ro6);
22950397Sobrien		if (sc->gif_ro6.ro_rt == NULL) {
23050397Sobrien			m_freem(m);
23150397Sobrien			return ENETUNREACH;
23250397Sobrien		}
23350397Sobrien
23450397Sobrien		/* if it constitutes infinite encapsulation, punt. */
23550397Sobrien		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
23650397Sobrien			m_freem(m);
23750397Sobrien			return ENETUNREACH;	/*XXX*/
23850397Sobrien		}
23950397Sobrien#if 0
24050397Sobrien		ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu
24150397Sobrien			- sizeof(struct ip6_hdr);
24218334Speter#endif
24390075Sobrien	}
24490075Sobrien
24518334Speter#ifdef IPV6_MINMTU
24690075Sobrien	/*
24790075Sobrien	 * force fragmentation to minimum MTU, to avoid path MTU discovery.
24890075Sobrien	 * it is too painful to ask for resend of inner packet, to achieve
24990075Sobrien	 * path MTU discovery for encapsulated packets.
25090075Sobrien	 */
25190075Sobrien	error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL);
25218334Speter#else
25318334Speter	error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL);
25418334Speter#endif
25518334Speter
25618334Speter	if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) &&
25718334Speter	    sc->gif_ro6.ro_rt != NULL) {
25818334Speter		RTFREE(sc->gif_ro6.ro_rt);
25918334Speter		sc->gif_ro6.ro_rt = NULL;
26018334Speter	}
26118334Speter
26290075Sobrien	return (error);
26390075Sobrien}
26490075Sobrien
265132718Skanint
266132718Skanin6_gif_input(struct mbuf **mp, int *offp, int proto)
267132718Skan{
268132718Skan	INIT_VNET_INET6(curvnet);
26918334Speter	struct mbuf *m = *mp;
27090075Sobrien	struct ifnet *gifp = NULL;
27190075Sobrien	struct gif_softc *sc;
272132718Skan	struct ip6_hdr *ip6;
27318334Speter	int af = 0;
27490075Sobrien	u_int32_t otos;
275132718Skan
27618334Speter	ip6 = mtod(m, struct ip6_hdr *);
27790075Sobrien
27890075Sobrien	sc = (struct gif_softc *)encap_getarg(m);
279169689Skan	if (sc == NULL) {
280132718Skan		m_freem(m);
281132718Skan		V_ip6stat.ip6s_nogif++;
282132718Skan		return IPPROTO_DONE;
283132718Skan	}
284132718Skan
285132718Skan	gifp = GIF2IFP(sc);
286132718Skan	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
28718334Speter		m_freem(m);
288117395Skan		V_ip6stat.ip6s_nogif++;
28952284Sobrien		return IPPROTO_DONE;
290132718Skan	}
291132718Skan
29252284Sobrien	otos = ip6->ip6_flow;
29318334Speter	m_adj(m, *offp);
294132718Skan
29518334Speter	switch (proto) {
296169689Skan#ifdef INET
297169689Skan	case IPPROTO_IPV4:
298169689Skan	    {
299169689Skan		struct ip *ip;
300169689Skan		u_int8_t otos8;
30118334Speter		af = AF_INET;
30218334Speter		otos8 = (ntohl(otos) >> 20) & 0xff;
303132718Skan		if (m->m_len < sizeof(*ip)) {
304132718Skan			m = m_pullup(m, sizeof(*ip));
30518334Speter			if (!m)
306117395Skan				return IPPROTO_DONE;
307132718Skan		}
30850397Sobrien		ip = mtod(m, struct ip *);
30918334Speter		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
310132718Skan				  ECN_ALLOWED : ECN_NOCARE,
311132718Skan				  &otos8, &ip->ip_tos) == 0) {
31218334Speter			m_freem(m);
313169689Skan			return IPPROTO_DONE;
314169689Skan		}
315169689Skan		break;
316169689Skan	    }
317169689Skan#endif /* INET */
31818334Speter#ifdef INET6
31918334Speter	case IPPROTO_IPV6:
32018334Speter	    {
32118334Speter		struct ip6_hdr *ip6;
32218334Speter		af = AF_INET6;
323132718Skan		if (m->m_len < sizeof(*ip6)) {
32418334Speter			m = m_pullup(m, sizeof(*ip6));
32518334Speter			if (!m)
326132718Skan				return IPPROTO_DONE;
32718334Speter		}
32818334Speter		ip6 = mtod(m, struct ip6_hdr *);
329132718Skan		if (ip6_ecn_egress((gifp->if_flags & IFF_LINK1) ?
330132718Skan				   ECN_ALLOWED : ECN_NOCARE,
33118334Speter				   &otos, &ip6->ip6_flow) == 0) {
33250397Sobrien			m_freem(m);
333132718Skan			return IPPROTO_DONE;
334132718Skan		}
33518334Speter		break;
33690075Sobrien	    }
337132718Skan#endif
338132718Skan	case IPPROTO_ETHERIP:
339132718Skan		af = AF_LINK;
340132718Skan		break;
341132718Skan
342132718Skan	default:
343132718Skan		V_ip6stat.ip6s_nogif++;
344132718Skan		m_freem(m);
34590075Sobrien		return IPPROTO_DONE;
34618334Speter	}
34718334Speter
34818334Speter	gif_input(m, af, gifp);
34918334Speter	return IPPROTO_DONE;
350132718Skan}
35118334Speter
35218334Speter/*
353132718Skan * validate outer address.
35418334Speter */
35518334Speterstatic int
35618334Spetergif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc,
357132718Skan    struct ifnet *ifp)
35818334Speter{
35918334Speter	struct sockaddr_in6 *src, *dst;
360132718Skan
36118334Speter	src = (struct sockaddr_in6 *)sc->gif_psrc;
36218334Speter	dst = (struct sockaddr_in6 *)sc->gif_pdst;
363132718Skan
36418334Speter	/*
36518334Speter	 * Check for address match.  Note that the check is for an incoming
36618334Speter	 * packet.  We should compare the *source* address in our configuration
367117395Skan	 * and the *destination* address of the packet, and vice versa.
368117395Skan	 */
369117395Skan	if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
370117395Skan	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
371169689Skan		return 0;
372169689Skan
373169689Skan	/* martian filters on outer source - done in ip6_input */
374117395Skan
375117395Skan	/* ingress filters on outer source */
376132718Skan	if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) {
377132718Skan		struct sockaddr_in6 sin6;
378117395Skan		struct rtentry *rt;
379132718Skan
380132718Skan		bzero(&sin6, sizeof(sin6));
38118334Speter		sin6.sin6_family = AF_INET6;
38218334Speter		sin6.sin6_len = sizeof(struct sockaddr_in6);
383132718Skan		sin6.sin6_addr = ip6->ip6_src;
38418334Speter		sin6.sin6_scope_id = 0; /* XXX */
38518334Speter
38618334Speter		rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
387132718Skan		if (!rt || rt->rt_ifp != ifp) {
38818334Speter#if 0
389117395Skan			char ip6buf[INET6_ADDRSTRLEN];
390132718Skan			log(LOG_WARNING, "%s: packet from %s dropped "
391117395Skan			    "due to ingress filter\n", if_name(GIF2IFP(sc)),
39250397Sobrien			    ip6_sprintf(ip6buf, &sin6.sin6_addr));
39350397Sobrien#endif
394132718Skan			if (rt)
39590075Sobrien				RTFREE_LOCKED(rt);
396169689Skan			return 0;
397169689Skan		}
398169689Skan		RTFREE_LOCKED(rt);
399117395Skan	}
400117395Skan
401132718Skan	return 128 * 2;
402117395Skan}
403169689Skan
404169689Skan/*
405169689Skan * we know that we are in IFF_UP, outer address available, and outer family
40650397Sobrien * matched the physical addr family.  see gif_encapcheck().
40750397Sobrien * sanity check for arg should have been done in the caller.
408132718Skan */
40950397Sobrienint
41090075Sobriengif_encapcheck6(const struct mbuf *m, int off, int proto, void *arg)
411132718Skan{
41252284Sobrien	struct ip6_hdr ip6;
41318334Speter	struct gif_softc *sc;
414132718Skan	struct ifnet *ifp;
41590075Sobrien
41618334Speter	/* sanity check done in caller */
41718334Speter	sc = (struct gif_softc *)arg;
418132718Skan
41990075Sobrien	/* LINTED const cast */
42050397Sobrien	m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6);
421132718Skan	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
42218334Speter
42318334Speter	return gif_validate6(&ip6, sc, ifp);
42490075Sobrien}
425169689Skan
42618334Speterint
427169689Skanin6_gif_attach(struct gif_softc *sc)
428169689Skan{
429169689Skan	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
430132718Skan	    (void *)&in6_gif_protosw, sc);
431132718Skan	if (sc->encap_cookie6 == NULL)
432132718Skan		return EEXIST;
433132718Skan	return 0;
434132718Skan}
435117395Skan
43690075Sobrienint
43790075Sobrienin6_gif_detach(struct gif_softc *sc)
43890075Sobrien{
43990075Sobrien	int error;
440132718Skan
441132718Skan	error = encap_detach(sc->encap_cookie6);
442132718Skan	if (error == 0)
443132718Skan		sc->encap_cookie6 = NULL;
44490075Sobrien	return error;
44590075Sobrien}
44690075Sobrien