xref: /freebsd/sys/netinet/in_gif.c (revision 65ff3638df7d7d993e284971e2c78b3ca9613c8d)
1c398230bSWarner Losh /*-
2cfa1ca9dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3cfa1ca9dSYoshinobu Inoue  * All rights reserved.
4cfa1ca9dSYoshinobu Inoue  *
5cfa1ca9dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
6cfa1ca9dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
7cfa1ca9dSYoshinobu Inoue  * are met:
8cfa1ca9dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
9cfa1ca9dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
10cfa1ca9dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
11cfa1ca9dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
12cfa1ca9dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
13cfa1ca9dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
14cfa1ca9dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
15cfa1ca9dSYoshinobu Inoue  *    without specific prior written permission.
16cfa1ca9dSYoshinobu Inoue  *
17cfa1ca9dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18cfa1ca9dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19cfa1ca9dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20cfa1ca9dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21cfa1ca9dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22cfa1ca9dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23cfa1ca9dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24cfa1ca9dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25cfa1ca9dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26cfa1ca9dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27cfa1ca9dSYoshinobu Inoue  * SUCH DAMAGE.
280b9f5f8aSAndrey V. Elsukov  *
290b9f5f8aSAndrey V. Elsukov  *	$KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $
30cfa1ca9dSYoshinobu Inoue  */
31cfa1ca9dSYoshinobu Inoue 
324b421e2dSMike Silbersack #include <sys/cdefs.h>
334b421e2dSMike Silbersack __FBSDID("$FreeBSD$");
344b421e2dSMike Silbersack 
35686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h"
36cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h"
37cfa1ca9dSYoshinobu Inoue 
38cfa1ca9dSYoshinobu Inoue #include <sys/param.h>
390b9f5f8aSAndrey V. Elsukov #include <sys/lock.h>
400b9f5f8aSAndrey V. Elsukov #include <sys/rmlock.h>
41cfa1ca9dSYoshinobu Inoue #include <sys/systm.h>
42cfa1ca9dSYoshinobu Inoue #include <sys/socket.h>
43cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h>
44cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h>
45cfa1ca9dSYoshinobu Inoue #include <sys/errno.h>
46cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h>
47cfa1ca9dSYoshinobu Inoue #include <sys/sysctl.h>
489426aedfSHajimu UMEMOTO #include <sys/protosw.h>
49686cdd19SJun-ichiro itojun Hagino #include <sys/malloc.h>
50cfa1ca9dSYoshinobu Inoue 
51cfa1ca9dSYoshinobu Inoue #include <net/if.h>
5276039bc8SGleb Smirnoff #include <net/if_var.h>
53cfa1ca9dSYoshinobu Inoue #include <net/route.h>
54530c0060SRobert Watson #include <net/vnet.h>
55cfa1ca9dSYoshinobu Inoue 
56cfa1ca9dSYoshinobu Inoue #include <netinet/in.h>
57cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h>
58cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h>
596a800098SYoshinobu Inoue #include <netinet/ip_var.h>
60686cdd19SJun-ichiro itojun Hagino #include <netinet/in_var.h>
61686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h>
626a800098SYoshinobu Inoue #include <netinet/ip_ecn.h>
63*65ff3638SAlexander V. Chernikov #include <netinet/in_fib.h>
64686cdd19SJun-ichiro itojun Hagino 
656a800098SYoshinobu Inoue #ifdef INET6
66686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h>
676a800098SYoshinobu Inoue #endif
68cfa1ca9dSYoshinobu Inoue 
69cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h>
70cfa1ca9dSYoshinobu Inoue 
71132c4490SAndrey V. Elsukov static int in_gif_input(struct mbuf **, int *, int);
729426aedfSHajimu UMEMOTO 
739426aedfSHajimu UMEMOTO extern  struct domain inetdomain;
74132c4490SAndrey V. Elsukov static struct protosw in_gif_protosw = {
75303989a2SRuslan Ermilov 	.pr_type =		SOCK_RAW,
76303989a2SRuslan Ermilov 	.pr_domain =		&inetdomain,
77303989a2SRuslan Ermilov 	.pr_protocol =		0/* IPPROTO_IPV[46] */,
78303989a2SRuslan Ermilov 	.pr_flags =		PR_ATOMIC|PR_ADDR,
79303989a2SRuslan Ermilov 	.pr_input =		in_gif_input,
8073d76e77SKevin Lo 	.pr_output =		rip_output,
81303989a2SRuslan Ermilov 	.pr_ctloutput =		rip_ctloutput,
82303989a2SRuslan Ermilov 	.pr_usrreqs =		&rip_usrreqs
839426aedfSHajimu UMEMOTO };
849426aedfSHajimu UMEMOTO 
85132c4490SAndrey V. Elsukov #define GIF_TTL		30
86132c4490SAndrey V. Elsukov static VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL;
8782cea7e6SBjoern A. Zeeb #define	V_ip_gif_ttl		VNET(ip_gif_ttl)
886df8a710SGleb Smirnoff SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW,
89eddfbb76SRobert Watson 	&VNET_NAME(ip_gif_ttl), 0, "");
90cfa1ca9dSYoshinobu Inoue 
91cfa1ca9dSYoshinobu Inoue int
920b9f5f8aSAndrey V. Elsukov in_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
93cfa1ca9dSYoshinobu Inoue {
940b9f5f8aSAndrey V. Elsukov 	GIF_RLOCK_TRACKER;
95fc74a9f9SBrooks Davis 	struct gif_softc *sc = ifp->if_softc;
96cfa1ca9dSYoshinobu Inoue 	struct ip *ip;
970b9f5f8aSAndrey V. Elsukov 	int len;
98cfa1ca9dSYoshinobu Inoue 
99cfa1ca9dSYoshinobu Inoue 	/* prepend new IP header */
100c89c8a10SMarius Strobl 	len = sizeof(struct ip);
101c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT
1020b9f5f8aSAndrey V. Elsukov 	if (proto == IPPROTO_ETHERIP)
103c89c8a10SMarius Strobl 		len += ETHERIP_ALIGN;
104c89c8a10SMarius Strobl #endif
105eb1b1807SGleb Smirnoff 	M_PREPEND(m, len, M_NOWAIT);
1060b9f5f8aSAndrey V. Elsukov 	if (m == NULL)
1070b9f5f8aSAndrey V. Elsukov 		return (ENOBUFS);
108c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT
1090b9f5f8aSAndrey V. Elsukov 	if (proto == IPPROTO_ETHERIP) {
110c89c8a10SMarius Strobl 		len = mtod(m, vm_offset_t) & 3;
111c89c8a10SMarius Strobl 		KASSERT(len == 0 || len == ETHERIP_ALIGN,
112c89c8a10SMarius Strobl 		    ("in_gif_output: unexpected misalignment"));
113c89c8a10SMarius Strobl 		m->m_data += len;
114c89c8a10SMarius Strobl 		m->m_len -= ETHERIP_ALIGN;
115c89c8a10SMarius Strobl 	}
116c89c8a10SMarius Strobl #endif
1170b9f5f8aSAndrey V. Elsukov 	ip = mtod(m, struct ip *);
1180b9f5f8aSAndrey V. Elsukov 	GIF_RLOCK(sc);
1190b9f5f8aSAndrey V. Elsukov 	if (sc->gif_family != AF_INET) {
120cfa1ca9dSYoshinobu Inoue 		m_freem(m);
1210b9f5f8aSAndrey V. Elsukov 		GIF_RUNLOCK(sc);
1220b9f5f8aSAndrey V. Elsukov 		return (ENETDOWN);
123cfa1ca9dSYoshinobu Inoue 	}
1240b9f5f8aSAndrey V. Elsukov 	bcopy(sc->gif_iphdr, ip, sizeof(struct ip));
1250b9f5f8aSAndrey V. Elsukov 	GIF_RUNLOCK(sc);
126686cdd19SJun-ichiro itojun Hagino 
1270b9f5f8aSAndrey V. Elsukov 	ip->ip_p = proto;
1280b9f5f8aSAndrey V. Elsukov 	/* version will be set in ip_output() */
1290b9f5f8aSAndrey V. Elsukov 	ip->ip_ttl = V_ip_gif_ttl;
1300b9f5f8aSAndrey V. Elsukov 	ip->ip_len = htons(m->m_pkthdr.len);
1310b9f5f8aSAndrey V. Elsukov 	ip->ip_tos = ecn;
132cfa1ca9dSYoshinobu Inoue 
1330b9f5f8aSAndrey V. Elsukov 	return (ip_output(m, NULL, NULL, 0, NULL, NULL));
134cfa1ca9dSYoshinobu Inoue }
135cfa1ca9dSYoshinobu Inoue 
136132c4490SAndrey V. Elsukov static int
1378f5a8818SKevin Lo in_gif_input(struct mbuf **mp, int *offp, int proto)
138cfa1ca9dSYoshinobu Inoue {
1390b9f5f8aSAndrey V. Elsukov 	struct mbuf *m = *mp;
14067df9f38SBjoern A. Zeeb 	struct gif_softc *sc;
1410b9f5f8aSAndrey V. Elsukov 	struct ifnet *gifp;
142cfa1ca9dSYoshinobu Inoue 	struct ip *ip;
1430b9f5f8aSAndrey V. Elsukov 	uint8_t ecn;
144cfa1ca9dSYoshinobu Inoue 
1450b9f5f8aSAndrey V. Elsukov 	sc = encap_getarg(m);
14667df9f38SBjoern A. Zeeb 	if (sc == NULL) {
14767df9f38SBjoern A. Zeeb 		m_freem(m);
148315e3e38SRobert Watson 		KMOD_IPSTAT_INC(ips_nogif);
1498f5a8818SKevin Lo 		return (IPPROTO_DONE);
15067df9f38SBjoern A. Zeeb 	}
15167df9f38SBjoern A. Zeeb 	gifp = GIF2IFP(sc);
1520b9f5f8aSAndrey V. Elsukov 	if ((gifp->if_flags & IFF_UP) != 0) {
153cfa1ca9dSYoshinobu Inoue 		ip = mtod(m, struct ip *);
1540b9f5f8aSAndrey V. Elsukov 		ecn = ip->ip_tos;
1550b9f5f8aSAndrey V. Elsukov 		m_adj(m, *offp);
1560b9f5f8aSAndrey V. Elsukov 		gif_input(m, gifp, proto, ecn);
1570b9f5f8aSAndrey V. Elsukov 	} else {
15859dfcba4SHajimu UMEMOTO 		m_freem(m);
159315e3e38SRobert Watson 		KMOD_IPSTAT_INC(ips_nogif);
160cfa1ca9dSYoshinobu Inoue 	}
1618f5a8818SKevin Lo 	return (IPPROTO_DONE);
162cfa1ca9dSYoshinobu Inoue }
163686cdd19SJun-ichiro itojun Hagino 
164686cdd19SJun-ichiro itojun Hagino /*
16510a0e0bfSAndrey V. Elsukov  * we know that we are in IFF_UP, outer address available, and outer family
16610a0e0bfSAndrey V. Elsukov  * matched the physical addr family.  see gif_encapcheck().
167686cdd19SJun-ichiro itojun Hagino  */
16810a0e0bfSAndrey V. Elsukov int
16910a0e0bfSAndrey V. Elsukov in_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
1709426aedfSHajimu UMEMOTO {
17110a0e0bfSAndrey V. Elsukov 	const struct ip *ip;
17210a0e0bfSAndrey V. Elsukov 	struct gif_softc *sc;
173c1b4f79dSAndrey V. Elsukov 	int ret;
174686cdd19SJun-ichiro itojun Hagino 
17510a0e0bfSAndrey V. Elsukov 	/* sanity check done in caller */
17610a0e0bfSAndrey V. Elsukov 	sc = (struct gif_softc *)arg;
1770b9f5f8aSAndrey V. Elsukov 	GIF_RLOCK_ASSERT(sc);
178686cdd19SJun-ichiro itojun Hagino 
179686cdd19SJun-ichiro itojun Hagino 	/* check for address match */
18010a0e0bfSAndrey V. Elsukov 	ip = mtod(m, const struct ip *);
181c1b4f79dSAndrey V. Elsukov 	if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr)
1820b9f5f8aSAndrey V. Elsukov 		return (0);
183c1b4f79dSAndrey V. Elsukov 	ret = 32;
184c1b4f79dSAndrey V. Elsukov 	if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) {
185c1b4f79dSAndrey V. Elsukov 		if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0)
186c1b4f79dSAndrey V. Elsukov 			return (0);
187c1b4f79dSAndrey V. Elsukov 	} else
188c1b4f79dSAndrey V. Elsukov 		ret += 32;
189686cdd19SJun-ichiro itojun Hagino 
190686cdd19SJun-ichiro itojun Hagino 	/* ingress filters on outer source */
19110a0e0bfSAndrey V. Elsukov 	if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) {
192*65ff3638SAlexander V. Chernikov 		struct nhop4_basic nh4;
193*65ff3638SAlexander V. Chernikov 		struct in_addr dst;
194686cdd19SJun-ichiro itojun Hagino 
195*65ff3638SAlexander V. Chernikov 		dst = ip->ip_src;
196*65ff3638SAlexander V. Chernikov 
197*65ff3638SAlexander V. Chernikov 		if (fib4_lookup_nh_basic(sc->gif_fibnum, dst, 0, 0, &nh4) != 0)
1980b9f5f8aSAndrey V. Elsukov 			return (0);
199*65ff3638SAlexander V. Chernikov 
200*65ff3638SAlexander V. Chernikov 		if (nh4.nh_ifp != m->m_pkthdr.rcvif)
201*65ff3638SAlexander V. Chernikov 			return (0);
202686cdd19SJun-ichiro itojun Hagino 	}
203c1b4f79dSAndrey V. Elsukov 	return (ret);
204686cdd19SJun-ichiro itojun Hagino }
2059426aedfSHajimu UMEMOTO 
2069426aedfSHajimu UMEMOTO int
207f2565d68SRobert Watson in_gif_attach(struct gif_softc *sc)
2089426aedfSHajimu UMEMOTO {
2090b9f5f8aSAndrey V. Elsukov 
2100b9f5f8aSAndrey V. Elsukov 	KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL"));
2110b9f5f8aSAndrey V. Elsukov 	sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck,
2129426aedfSHajimu UMEMOTO 	    &in_gif_protosw, sc);
2130b9f5f8aSAndrey V. Elsukov 	if (sc->gif_ecookie == NULL)
2140b9f5f8aSAndrey V. Elsukov 		return (EEXIST);
2150b9f5f8aSAndrey V. Elsukov 	return (0);
2169426aedfSHajimu UMEMOTO }
217