in6_gif.c revision 139826
1193640Sariff/*	$FreeBSD: head/sys/netinet6/in6_gif.c 139826 2005-01-07 02:30:35Z imp $	*/
2193640Sariff/*	$KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $	*/
3193640Sariff
4193640Sariff/*-
5193640Sariff * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6193640Sariff * All rights reserved.
7193640Sariff *
8193640Sariff * Redistribution and use in source and binary forms, with or without
9193640Sariff * modification, are permitted provided that the following conditions
10193640Sariff * are met:
11193640Sariff * 1. Redistributions of source code must retain the above copyright
12193640Sariff *    notice, this list of conditions and the following disclaimer.
13193640Sariff * 2. Redistributions in binary form must reproduce the above copyright
14193640Sariff *    notice, this list of conditions and the following disclaimer in the
15193640Sariff *    documentation and/or other materials provided with the distribution.
16193640Sariff * 3. Neither the name of the project nor the names of its contributors
17193640Sariff *    may be used to endorse or promote products derived from this software
18193640Sariff *    without specific prior written permission.
19193640Sariff *
20193640Sariff * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21193640Sariff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22193640Sariff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23193640Sariff * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24193640Sariff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25193640Sariff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26193640Sariff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27193640Sariff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28193640Sariff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29193640Sariff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30193640Sariff * SUCH DAMAGE.
31193640Sariff */
32193640Sariff
33193640Sariff#include "opt_inet.h"
34193640Sariff#include "opt_inet6.h"
35193640Sariff
36193640Sariff#include <sys/param.h>
37193640Sariff#include <sys/systm.h>
38193640Sariff#include <sys/socket.h>
39193640Sariff#include <sys/sockio.h>
40193640Sariff#include <sys/mbuf.h>
41193640Sariff#include <sys/errno.h>
42193640Sariff#include <sys/queue.h>
43193640Sariff#include <sys/syslog.h>
44193640Sariff#include <sys/protosw.h>
45193640Sariff
46193640Sariff#include <sys/malloc.h>
47193640Sariff
48193640Sariff#include <net/if.h>
49193640Sariff#include <net/route.h>
50193640Sariff
51193640Sariff#include <netinet/in.h>
52193640Sariff#include <netinet/in_systm.h>
53193640Sariff#ifdef INET
54193640Sariff#include <netinet/ip.h>
55193640Sariff#endif
56193640Sariff#include <netinet/ip_encap.h>
57193640Sariff#ifdef INET6
58193640Sariff#include <netinet/ip6.h>
59193640Sariff#include <netinet6/ip6_var.h>
60193640Sariff#include <netinet6/in6_gif.h>
61193640Sariff#include <netinet6/in6_var.h>
62193640Sariff#endif
63193640Sariff#include <netinet6/ip6protosw.h>
64193640Sariff#include <netinet/ip_ecn.h>
65193640Sariff#ifdef INET6
66193640Sariff#include <netinet6/ip6_ecn.h>
67193640Sariff#endif
68193640Sariff
69193640Sariff#include <net/if_gif.h>
70193640Sariff
71193640Sariff#include <net/net_osdep.h>
72193640Sariff
73193640Sariffstatic int gif_validate6(const struct ip6_hdr *, struct gif_softc *,
74193640Sariff			 struct ifnet *);
75193640Sariff
76193640Sariffextern  struct domain inet6domain;
77193640Sariffstruct ip6protosw in6_gif_protosw =
78193640Sariff{ SOCK_RAW,	&inet6domain,	0/* IPPROTO_IPV[46] */,	PR_ATOMIC|PR_ADDR,
79193640Sariff  in6_gif_input, rip6_output,	0,		rip6_ctloutput,
80193640Sariff  0,
81193640Sariff  0,		0,		0,		0,
82193640Sariff  &rip6_usrreqs
83193640Sariff};
84193640Sariff
85193640Sariffint
86193640Sariffin6_gif_output(ifp, family, m)
87193640Sariff	struct ifnet *ifp;
88193640Sariff	int family; /* family of the packet to be encapsulate. */
89193640Sariff	struct mbuf *m;
90193640Sariff{
91193640Sariff	struct gif_softc *sc = (struct gif_softc*)ifp;
92193640Sariff	struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
93193640Sariff	struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
94193640Sariff	struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
95193640Sariff	struct ip6_hdr *ip6;
96193640Sariff	int proto, error;
97193640Sariff	u_int8_t itos, otos;
98193640Sariff
99193640Sariff	if (sin6_src == NULL || sin6_dst == NULL ||
100193640Sariff	    sin6_src->sin6_family != AF_INET6 ||
101193640Sariff	    sin6_dst->sin6_family != AF_INET6) {
102193640Sariff		m_freem(m);
103193640Sariff		return EAFNOSUPPORT;
104193640Sariff	}
105193640Sariff
106193640Sariff	switch (family) {
107193640Sariff#ifdef INET
108193640Sariff	case AF_INET:
109193640Sariff	    {
110193640Sariff		struct ip *ip;
111193640Sariff
112193640Sariff		proto = IPPROTO_IPV4;
113193640Sariff		if (m->m_len < sizeof(*ip)) {
114193640Sariff			m = m_pullup(m, sizeof(*ip));
115193640Sariff			if (!m)
116193640Sariff				return ENOBUFS;
117193640Sariff		}
118193640Sariff		ip = mtod(m, struct ip *);
119193640Sariff		itos = ip->ip_tos;
120193640Sariff		break;
121193640Sariff	    }
122193640Sariff#endif
123193640Sariff#ifdef INET6
124193640Sariff	case AF_INET6:
125193640Sariff	    {
126193640Sariff		struct ip6_hdr *ip6;
127193640Sariff		proto = IPPROTO_IPV6;
128193640Sariff		if (m->m_len < sizeof(*ip6)) {
129193640Sariff			m = m_pullup(m, sizeof(*ip6));
130193640Sariff			if (!m)
131193640Sariff				return ENOBUFS;
132193640Sariff		}
133193640Sariff		ip6 = mtod(m, struct ip6_hdr *);
134193640Sariff		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
135193640Sariff		break;
136193640Sariff	    }
137193640Sariff#endif
138193640Sariff	default:
139193640Sariff#ifdef DEBUG
140193640Sariff		printf("in6_gif_output: warning: unknown family %d passed\n",
141193640Sariff			family);
142193640Sariff#endif
143193640Sariff		m_freem(m);
144193640Sariff		return EAFNOSUPPORT;
145193640Sariff	}
146193640Sariff
147193640Sariff	/* prepend new IP header */
148193640Sariff	M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
149193640Sariff	if (m && m->m_len < sizeof(struct ip6_hdr))
150193640Sariff		m = m_pullup(m, sizeof(struct ip6_hdr));
151193640Sariff	if (m == NULL) {
152193640Sariff		printf("ENOBUFS in in6_gif_output %d\n", __LINE__);
153193640Sariff		return ENOBUFS;
154193640Sariff	}
155193640Sariff
156193640Sariff	ip6 = mtod(m, struct ip6_hdr *);
157193640Sariff	ip6->ip6_flow	= 0;
158193640Sariff	ip6->ip6_vfc	&= ~IPV6_VERSION_MASK;
159193640Sariff	ip6->ip6_vfc	|= IPV6_VERSION;
160193640Sariff	ip6->ip6_plen	= htons((u_short)m->m_pkthdr.len);
161193640Sariff	ip6->ip6_nxt	= proto;
162193640Sariff	ip6->ip6_hlim	= ip6_gif_hlim;
163193640Sariff	ip6->ip6_src	= sin6_src->sin6_addr;
164193640Sariff	/* bidirectional configured tunnel mode */
165193640Sariff	if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
166193640Sariff		ip6->ip6_dst = sin6_dst->sin6_addr;
167193640Sariff	else  {
168193640Sariff		m_freem(m);
169193640Sariff		return ENETUNREACH;
170193640Sariff	}
171193640Sariff	ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
172193640Sariff		       &otos, &itos);
173193640Sariff	ip6->ip6_flow &= ~htonl(0xff << 20);
174193640Sariff	ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
175193640Sariff
176193640Sariff	if (dst->sin6_family != sin6_dst->sin6_family ||
177193640Sariff	     !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
178193640Sariff		/* cache route doesn't match */
179193640Sariff		bzero(dst, sizeof(*dst));
180193640Sariff		dst->sin6_family = sin6_dst->sin6_family;
181193640Sariff		dst->sin6_len = sizeof(struct sockaddr_in6);
182193640Sariff		dst->sin6_addr = sin6_dst->sin6_addr;
183193640Sariff		if (sc->gif_ro6.ro_rt) {
184193640Sariff			RTFREE(sc->gif_ro6.ro_rt);
185193640Sariff			sc->gif_ro6.ro_rt = NULL;
186193640Sariff		}
187193640Sariff#if 0
188193640Sariff		sc->gif_if.if_mtu = GIF_MTU;
189193640Sariff#endif
190193640Sariff	}
191193640Sariff
192193640Sariff	if (sc->gif_ro6.ro_rt == NULL) {
193193640Sariff		rtalloc((struct route *)&sc->gif_ro6);
194193640Sariff		if (sc->gif_ro6.ro_rt == NULL) {
195193640Sariff			m_freem(m);
196193640Sariff			return ENETUNREACH;
197193640Sariff		}
198193640Sariff
199193640Sariff		/* if it constitutes infinite encapsulation, punt. */
200193640Sariff		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
201193640Sariff			m_freem(m);
202193640Sariff			return ENETUNREACH;	/*XXX*/
203193640Sariff		}
204193640Sariff#if 0
205193640Sariff		ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu
206193640Sariff			- sizeof(struct ip6_hdr);
207193640Sariff#endif
208193640Sariff	}
209193640Sariff
210193640Sariff#ifdef IPV6_MINMTU
211193640Sariff	/*
212193640Sariff	 * force fragmentation to minimum MTU, to avoid path MTU discovery.
213193640Sariff	 * it is too painful to ask for resend of inner packet, to achieve
214193640Sariff	 * path MTU discovery for encapsulated packets.
215193640Sariff	 */
216193640Sariff	error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL);
217193640Sariff#else
218193640Sariff	error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL);
219193640Sariff#endif
220193640Sariff
221193640Sariff	if (!(sc->gif_if.if_flags & IFF_LINK0) &&
222193640Sariff	    sc->gif_ro6.ro_rt != NULL) {
223193640Sariff		RTFREE(sc->gif_ro6.ro_rt);
224193640Sariff		sc->gif_ro6.ro_rt = NULL;
225193640Sariff	}
226193640Sariff
227193640Sariff	return (error);
228193640Sariff}
229193640Sariff
230193640Sariffint
231193640Sariffin6_gif_input(mp, offp, proto)
232193640Sariff	struct mbuf **mp;
233193640Sariff	int *offp, proto;
234193640Sariff{
235193640Sariff	struct mbuf *m = *mp;
236193640Sariff	struct ifnet *gifp = NULL;
237193640Sariff	struct ip6_hdr *ip6;
238193640Sariff	int af = 0;
239193640Sariff	u_int32_t otos;
240193640Sariff
241193640Sariff	ip6 = mtod(m, struct ip6_hdr *);
242193640Sariff
243193640Sariff	gifp = (struct ifnet *)encap_getarg(m);
244193640Sariff
245193640Sariff	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
246193640Sariff		m_freem(m);
247193640Sariff		ip6stat.ip6s_nogif++;
248193640Sariff		return IPPROTO_DONE;
249193640Sariff	}
250193640Sariff
251193640Sariff	otos = ip6->ip6_flow;
252193640Sariff	m_adj(m, *offp);
253193640Sariff
254193640Sariff	switch (proto) {
255193640Sariff#ifdef INET
256193640Sariff	case IPPROTO_IPV4:
257193640Sariff	    {
258193640Sariff		struct ip *ip;
259193640Sariff		u_int8_t otos8;
260193640Sariff		af = AF_INET;
261193640Sariff		otos8 = (ntohl(otos) >> 20) & 0xff;
262193640Sariff		if (m->m_len < sizeof(*ip)) {
263193640Sariff			m = m_pullup(m, sizeof(*ip));
264193640Sariff			if (!m)
265193640Sariff				return IPPROTO_DONE;
266193640Sariff		}
267193640Sariff		ip = mtod(m, struct ip *);
268193640Sariff		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
269193640Sariff				  ECN_ALLOWED : ECN_NOCARE,
270193640Sariff				  &otos8, &ip->ip_tos) == 0) {
271193640Sariff			m_freem(m);
272193640Sariff			return IPPROTO_DONE;
273193640Sariff		}
274193640Sariff		break;
275193640Sariff	    }
276193640Sariff#endif /* INET */
277193640Sariff#ifdef INET6
278193640Sariff	case IPPROTO_IPV6:
279193640Sariff	    {
280193640Sariff		struct ip6_hdr *ip6;
281193640Sariff		af = AF_INET6;
282193640Sariff		if (m->m_len < sizeof(*ip6)) {
283193640Sariff			m = m_pullup(m, sizeof(*ip6));
284193640Sariff			if (!m)
285193640Sariff				return IPPROTO_DONE;
286193640Sariff		}
287193640Sariff		ip6 = mtod(m, struct ip6_hdr *);
288193640Sariff		if (ip6_ecn_egress((gifp->if_flags & IFF_LINK1) ?
289193640Sariff				   ECN_ALLOWED : ECN_NOCARE,
290193640Sariff				   &otos, &ip6->ip6_flow) == 0) {
291193640Sariff			m_freem(m);
292193640Sariff			return IPPROTO_DONE;
293193640Sariff		}
294193640Sariff		break;
295193640Sariff	    }
296193640Sariff#endif
297193640Sariff	default:
298193640Sariff		ip6stat.ip6s_nogif++;
299193640Sariff		m_freem(m);
300193640Sariff		return IPPROTO_DONE;
301	}
302
303	gif_input(m, af, gifp);
304	return IPPROTO_DONE;
305}
306
307/*
308 * validate outer address.
309 */
310static int
311gif_validate6(ip6, sc, ifp)
312	const struct ip6_hdr *ip6;
313	struct gif_softc *sc;
314	struct ifnet *ifp;
315{
316	struct sockaddr_in6 *src, *dst;
317
318	src = (struct sockaddr_in6 *)sc->gif_psrc;
319	dst = (struct sockaddr_in6 *)sc->gif_pdst;
320
321	/*
322	 * Check for address match.  Note that the check is for an incoming
323	 * packet.  We should compare the *source* address in our configuration
324	 * and the *destination* address of the packet, and vice versa.
325	 */
326	if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
327	    !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
328		return 0;
329
330	/* martian filters on outer source - done in ip6_input */
331
332	/* ingress filters on outer source */
333	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
334		struct sockaddr_in6 sin6;
335		struct rtentry *rt;
336
337		bzero(&sin6, sizeof(sin6));
338		sin6.sin6_family = AF_INET6;
339		sin6.sin6_len = sizeof(struct sockaddr_in6);
340		sin6.sin6_addr = ip6->ip6_src;
341		sin6.sin6_scope_id = 0; /* XXX */
342
343		rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
344		if (!rt || rt->rt_ifp != ifp) {
345#if 0
346			log(LOG_WARNING, "%s: packet from %s dropped "
347			    "due to ingress filter\n", if_name(&sc->gif_if),
348			    ip6_sprintf(&sin6.sin6_addr));
349#endif
350			if (rt)
351				rtfree(rt);
352			return 0;
353		}
354		rtfree(rt);
355	}
356
357	return 128 * 2;
358}
359
360/*
361 * we know that we are in IFF_UP, outer address available, and outer family
362 * matched the physical addr family.  see gif_encapcheck().
363 * sanity check for arg should have been done in the caller.
364 */
365int
366gif_encapcheck6(m, off, proto, arg)
367	const struct mbuf *m;
368	int off;
369	int proto;
370	void *arg;
371{
372	struct ip6_hdr ip6;
373	struct gif_softc *sc;
374	struct ifnet *ifp;
375
376	/* sanity check done in caller */
377	sc = (struct gif_softc *)arg;
378
379	/* LINTED const cast */
380	m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6);
381	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
382
383	return gif_validate6(&ip6, sc, ifp);
384}
385
386int
387in6_gif_attach(sc)
388	struct gif_softc *sc;
389{
390	sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
391	    (struct protosw *)&in6_gif_protosw, sc);
392	if (sc->encap_cookie6 == NULL)
393		return EEXIST;
394	return 0;
395}
396
397int
398in6_gif_detach(sc)
399	struct gif_softc *sc;
400{
401	int error;
402
403	error = encap_detach(sc->encap_cookie6);
404	if (error == 0)
405		sc->encap_cookie6 = NULL;
406	return error;
407}
408