xref: /freebsd/sys/netinet/in_gif.c (revision 76039bc84fae9915788b54ff28fe0cc4876952d2)
133841545SHajimu UMEMOTO /*	$KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $	*/
2686cdd19SJun-ichiro itojun Hagino 
3c398230bSWarner Losh /*-
4cfa1ca9dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5cfa1ca9dSYoshinobu Inoue  * All rights reserved.
6cfa1ca9dSYoshinobu Inoue  *
7cfa1ca9dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
8cfa1ca9dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
9cfa1ca9dSYoshinobu Inoue  * are met:
10cfa1ca9dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
11cfa1ca9dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
12cfa1ca9dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
13cfa1ca9dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
14cfa1ca9dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
15cfa1ca9dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
16cfa1ca9dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
17cfa1ca9dSYoshinobu Inoue  *    without specific prior written permission.
18cfa1ca9dSYoshinobu Inoue  *
19cfa1ca9dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20cfa1ca9dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21cfa1ca9dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22cfa1ca9dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23cfa1ca9dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24cfa1ca9dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25cfa1ca9dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26cfa1ca9dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27cfa1ca9dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28cfa1ca9dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29cfa1ca9dSYoshinobu Inoue  * SUCH DAMAGE.
30cfa1ca9dSYoshinobu Inoue  */
31cfa1ca9dSYoshinobu Inoue 
324b421e2dSMike Silbersack #include <sys/cdefs.h>
334b421e2dSMike Silbersack __FBSDID("$FreeBSD$");
344b421e2dSMike Silbersack 
35cfa1ca9dSYoshinobu Inoue #include "opt_mrouting.h"
36686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h"
37cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h"
38cfa1ca9dSYoshinobu Inoue 
39cfa1ca9dSYoshinobu Inoue #include <sys/param.h>
40cfa1ca9dSYoshinobu Inoue #include <sys/systm.h>
41cfa1ca9dSYoshinobu Inoue #include <sys/socket.h>
42cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h>
43cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h>
44cfa1ca9dSYoshinobu Inoue #include <sys/errno.h>
45cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h>
46cfa1ca9dSYoshinobu Inoue #include <sys/sysctl.h>
479426aedfSHajimu UMEMOTO #include <sys/protosw.h>
48686cdd19SJun-ichiro itojun Hagino #include <sys/malloc.h>
49cfa1ca9dSYoshinobu Inoue 
50cfa1ca9dSYoshinobu Inoue #include <net/if.h>
51*76039bc8SGleb Smirnoff #include <net/if_var.h>
52cfa1ca9dSYoshinobu Inoue #include <net/route.h>
53530c0060SRobert Watson #include <net/vnet.h>
54cfa1ca9dSYoshinobu Inoue 
55cfa1ca9dSYoshinobu Inoue #include <netinet/in.h>
56cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h>
57cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h>
586a800098SYoshinobu Inoue #include <netinet/ip_var.h>
596a800098SYoshinobu Inoue #include <netinet/in_gif.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>
63686cdd19SJun-ichiro itojun Hagino 
646a800098SYoshinobu Inoue #ifdef INET6
65686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h>
666a800098SYoshinobu Inoue #endif
67cfa1ca9dSYoshinobu Inoue 
68cfa1ca9dSYoshinobu Inoue #ifdef MROUTING
69cfa1ca9dSYoshinobu Inoue #include <netinet/ip_mroute.h>
70cfa1ca9dSYoshinobu Inoue #endif /* MROUTING */
71cfa1ca9dSYoshinobu Inoue 
72cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h>
73cfa1ca9dSYoshinobu Inoue 
749426aedfSHajimu UMEMOTO static int gif_validate4(const struct ip *, struct gif_softc *,
759426aedfSHajimu UMEMOTO 	struct ifnet *);
769426aedfSHajimu UMEMOTO 
779426aedfSHajimu UMEMOTO extern  struct domain inetdomain;
78303989a2SRuslan Ermilov struct protosw in_gif_protosw = {
79303989a2SRuslan Ermilov 	.pr_type =		SOCK_RAW,
80303989a2SRuslan Ermilov 	.pr_domain =		&inetdomain,
81303989a2SRuslan Ermilov 	.pr_protocol =		0/* IPPROTO_IPV[46] */,
82303989a2SRuslan Ermilov 	.pr_flags =		PR_ATOMIC|PR_ADDR,
83303989a2SRuslan Ermilov 	.pr_input =		in_gif_input,
84303989a2SRuslan Ermilov 	.pr_output =		(pr_output_t*)rip_output,
85303989a2SRuslan Ermilov 	.pr_ctloutput =		rip_ctloutput,
86303989a2SRuslan Ermilov 	.pr_usrreqs =		&rip_usrreqs
879426aedfSHajimu UMEMOTO };
889426aedfSHajimu UMEMOTO 
8982cea7e6SBjoern A. Zeeb VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL;
9082cea7e6SBjoern A. Zeeb #define	V_ip_gif_ttl		VNET(ip_gif_ttl)
91eddfbb76SRobert Watson SYSCTL_VNET_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
92eddfbb76SRobert Watson 	&VNET_NAME(ip_gif_ttl), 0, "");
93cfa1ca9dSYoshinobu Inoue 
94cfa1ca9dSYoshinobu Inoue int
95f2565d68SRobert Watson in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
96cfa1ca9dSYoshinobu Inoue {
97fc74a9f9SBrooks Davis 	struct gif_softc *sc = ifp->if_softc;
98cfa1ca9dSYoshinobu Inoue 	struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
99cfa1ca9dSYoshinobu Inoue 	struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
100cfa1ca9dSYoshinobu Inoue 	struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
101cfa1ca9dSYoshinobu Inoue 	struct ip iphdr;	/* capsule IP header, host byte ordered */
10273ff045cSAndrew Thompson 	struct etherip_header eiphdr;
103c89c8a10SMarius Strobl 	int error, len, proto;
104cfa1ca9dSYoshinobu Inoue 	u_int8_t tos;
105cfa1ca9dSYoshinobu Inoue 
10625af0bb5SGleb Smirnoff 	GIF_LOCK_ASSERT(sc);
10725af0bb5SGleb Smirnoff 
108cfa1ca9dSYoshinobu Inoue 	if (sin_src == NULL || sin_dst == NULL ||
109cfa1ca9dSYoshinobu Inoue 	    sin_src->sin_family != AF_INET ||
110cfa1ca9dSYoshinobu Inoue 	    sin_dst->sin_family != AF_INET) {
111cfa1ca9dSYoshinobu Inoue 		m_freem(m);
112cfa1ca9dSYoshinobu Inoue 		return EAFNOSUPPORT;
113cfa1ca9dSYoshinobu Inoue 	}
114cfa1ca9dSYoshinobu Inoue 
115cfa1ca9dSYoshinobu Inoue 	switch (family) {
116686cdd19SJun-ichiro itojun Hagino #ifdef INET
117cfa1ca9dSYoshinobu Inoue 	case AF_INET:
118cfa1ca9dSYoshinobu Inoue 	    {
119cfa1ca9dSYoshinobu Inoue 		struct ip *ip;
120cfa1ca9dSYoshinobu Inoue 
121cfa1ca9dSYoshinobu Inoue 		proto = IPPROTO_IPV4;
122cfa1ca9dSYoshinobu Inoue 		if (m->m_len < sizeof(*ip)) {
123cfa1ca9dSYoshinobu Inoue 			m = m_pullup(m, sizeof(*ip));
124cfa1ca9dSYoshinobu Inoue 			if (!m)
125cfa1ca9dSYoshinobu Inoue 				return ENOBUFS;
126cfa1ca9dSYoshinobu Inoue 		}
127cfa1ca9dSYoshinobu Inoue 		ip = mtod(m, struct ip *);
128cfa1ca9dSYoshinobu Inoue 		tos = ip->ip_tos;
129cfa1ca9dSYoshinobu Inoue 		break;
130cfa1ca9dSYoshinobu Inoue 	    }
131686cdd19SJun-ichiro itojun Hagino #endif /* INET */
132cfa1ca9dSYoshinobu Inoue #ifdef INET6
133cfa1ca9dSYoshinobu Inoue 	case AF_INET6:
134cfa1ca9dSYoshinobu Inoue 	    {
135686cdd19SJun-ichiro itojun Hagino 		struct ip6_hdr *ip6;
136cfa1ca9dSYoshinobu Inoue 		proto = IPPROTO_IPV6;
137cfa1ca9dSYoshinobu Inoue 		if (m->m_len < sizeof(*ip6)) {
138cfa1ca9dSYoshinobu Inoue 			m = m_pullup(m, sizeof(*ip6));
139cfa1ca9dSYoshinobu Inoue 			if (!m)
140cfa1ca9dSYoshinobu Inoue 				return ENOBUFS;
141cfa1ca9dSYoshinobu Inoue 		}
142cfa1ca9dSYoshinobu Inoue 		ip6 = mtod(m, struct ip6_hdr *);
143cfa1ca9dSYoshinobu Inoue 		tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
144cfa1ca9dSYoshinobu Inoue 		break;
145cfa1ca9dSYoshinobu Inoue 	    }
146cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
14773ff045cSAndrew Thompson 	case AF_LINK:
14873ff045cSAndrew Thompson  		proto = IPPROTO_ETHERIP;
149dbe59260SHiroki Sato 
150dbe59260SHiroki Sato 		/*
151dbe59260SHiroki Sato 		 * GIF_SEND_REVETHIP (disabled by default) intentionally
152dbe59260SHiroki Sato 		 * sends an EtherIP packet with revered version field in
153dbe59260SHiroki Sato 		 * the header.  This is a knob for backward compatibility
154dbe59260SHiroki Sato 		 * with FreeBSD 7.2R or prior.
155dbe59260SHiroki Sato 		 */
156dbe59260SHiroki Sato 		if ((sc->gif_options & GIF_SEND_REVETHIP)) {
157dbe59260SHiroki Sato  			eiphdr.eip_ver = 0;
158dbe59260SHiroki Sato  			eiphdr.eip_resvl = ETHERIP_VERSION;
159dbe59260SHiroki Sato  			eiphdr.eip_resvh = 0;
160dbe59260SHiroki Sato 		} else {
161dbe59260SHiroki Sato  			eiphdr.eip_ver = ETHERIP_VERSION;
162dbe59260SHiroki Sato  			eiphdr.eip_resvl = 0;
163dbe59260SHiroki Sato  			eiphdr.eip_resvh = 0;
164dbe59260SHiroki Sato 		}
16573ff045cSAndrew Thompson  		/* prepend Ethernet-in-IP header */
166eb1b1807SGleb Smirnoff  		M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT);
16773ff045cSAndrew Thompson  		if (m && m->m_len < sizeof(struct etherip_header))
16873ff045cSAndrew Thompson  			m = m_pullup(m, sizeof(struct etherip_header));
16973ff045cSAndrew Thompson  		if (m == NULL)
17073ff045cSAndrew Thompson  			return ENOBUFS;
17173ff045cSAndrew Thompson  		bcopy(&eiphdr, mtod(m, struct etherip_header *),
17273ff045cSAndrew Thompson 		    sizeof(struct etherip_header));
17373ff045cSAndrew Thompson 		break;
17473ff045cSAndrew Thompson 
175cfa1ca9dSYoshinobu Inoue 	default:
176686cdd19SJun-ichiro itojun Hagino #ifdef DEBUG
177cfa1ca9dSYoshinobu Inoue 		printf("in_gif_output: warning: unknown family %d passed\n",
178cfa1ca9dSYoshinobu Inoue 			family);
179cfa1ca9dSYoshinobu Inoue #endif
180cfa1ca9dSYoshinobu Inoue 		m_freem(m);
181cfa1ca9dSYoshinobu Inoue 		return EAFNOSUPPORT;
182cfa1ca9dSYoshinobu Inoue 	}
183cfa1ca9dSYoshinobu Inoue 
184cfa1ca9dSYoshinobu Inoue 	bzero(&iphdr, sizeof(iphdr));
185cfa1ca9dSYoshinobu Inoue 	iphdr.ip_src = sin_src->sin_addr;
186cfa1ca9dSYoshinobu Inoue 	/* bidirectional configured tunnel mode */
187cfa1ca9dSYoshinobu Inoue 	if (sin_dst->sin_addr.s_addr != INADDR_ANY)
188cfa1ca9dSYoshinobu Inoue 		iphdr.ip_dst = sin_dst->sin_addr;
189cfa1ca9dSYoshinobu Inoue 	else {
190cfa1ca9dSYoshinobu Inoue 		m_freem(m);
191cfa1ca9dSYoshinobu Inoue 		return ENETUNREACH;
192cfa1ca9dSYoshinobu Inoue 	}
193cfa1ca9dSYoshinobu Inoue 	iphdr.ip_p = proto;
194cfa1ca9dSYoshinobu Inoue 	/* version will be set in ip_output() */
195603724d3SBjoern A. Zeeb 	iphdr.ip_ttl = V_ip_gif_ttl;
1968f134647SGleb Smirnoff 	iphdr.ip_len = htons(m->m_pkthdr.len + sizeof(struct ip));
19759dfcba4SHajimu UMEMOTO 	ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
19859dfcba4SHajimu UMEMOTO 		       &iphdr.ip_tos, &tos);
199cfa1ca9dSYoshinobu Inoue 
200cfa1ca9dSYoshinobu Inoue 	/* prepend new IP header */
201c89c8a10SMarius Strobl 	len = sizeof(struct ip);
202c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT
203c89c8a10SMarius Strobl 	if (family == AF_LINK)
204c89c8a10SMarius Strobl 		len += ETHERIP_ALIGN;
205c89c8a10SMarius Strobl #endif
206eb1b1807SGleb Smirnoff 	M_PREPEND(m, len, M_NOWAIT);
207c89c8a10SMarius Strobl 	if (m != NULL && m->m_len < len)
208c89c8a10SMarius Strobl 		m = m_pullup(m, len);
209cfa1ca9dSYoshinobu Inoue 	if (m == NULL) {
210cfa1ca9dSYoshinobu Inoue 		printf("ENOBUFS in in_gif_output %d\n", __LINE__);
211cfa1ca9dSYoshinobu Inoue 		return ENOBUFS;
212cfa1ca9dSYoshinobu Inoue 	}
213c89c8a10SMarius Strobl #ifndef __NO_STRICT_ALIGNMENT
214c89c8a10SMarius Strobl 	if (family == AF_LINK) {
215c89c8a10SMarius Strobl 		len = mtod(m, vm_offset_t) & 3;
216c89c8a10SMarius Strobl 		KASSERT(len == 0 || len == ETHERIP_ALIGN,
217c89c8a10SMarius Strobl 		    ("in_gif_output: unexpected misalignment"));
218c89c8a10SMarius Strobl 		m->m_data += len;
219c89c8a10SMarius Strobl 		m->m_len -= ETHERIP_ALIGN;
220c89c8a10SMarius Strobl 	}
221c89c8a10SMarius Strobl #endif
222686cdd19SJun-ichiro itojun Hagino 	bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
223cfa1ca9dSYoshinobu Inoue 
2248b07e49aSJulian Elischer 	M_SETFIB(m, sc->gif_fibnum);
2258b07e49aSJulian Elischer 
226cfa1ca9dSYoshinobu Inoue 	if (dst->sin_family != sin_dst->sin_family ||
227cfa1ca9dSYoshinobu Inoue 	    dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
228cfa1ca9dSYoshinobu Inoue 		/* cache route doesn't match */
22927de0135SBruce M Simpson 		bzero(dst, sizeof(*dst));
230cfa1ca9dSYoshinobu Inoue 		dst->sin_family = sin_dst->sin_family;
231cfa1ca9dSYoshinobu Inoue 		dst->sin_len = sizeof(struct sockaddr_in);
232cfa1ca9dSYoshinobu Inoue 		dst->sin_addr = sin_dst->sin_addr;
233cfa1ca9dSYoshinobu Inoue 		if (sc->gif_ro.ro_rt) {
234cfa1ca9dSYoshinobu Inoue 			RTFREE(sc->gif_ro.ro_rt);
235cfa1ca9dSYoshinobu Inoue 			sc->gif_ro.ro_rt = NULL;
236cfa1ca9dSYoshinobu Inoue 		}
237686cdd19SJun-ichiro itojun Hagino #if 0
238fc74a9f9SBrooks Davis 		GIF2IFP(sc)->if_mtu = GIF_MTU;
239686cdd19SJun-ichiro itojun Hagino #endif
240cfa1ca9dSYoshinobu Inoue 	}
241cfa1ca9dSYoshinobu Inoue 
242cfa1ca9dSYoshinobu Inoue 	if (sc->gif_ro.ro_rt == NULL) {
2438b07e49aSJulian Elischer 		in_rtalloc_ign(&sc->gif_ro, 0, sc->gif_fibnum);
244cfa1ca9dSYoshinobu Inoue 		if (sc->gif_ro.ro_rt == NULL) {
245cfa1ca9dSYoshinobu Inoue 			m_freem(m);
246cfa1ca9dSYoshinobu Inoue 			return ENETUNREACH;
247cfa1ca9dSYoshinobu Inoue 		}
248686cdd19SJun-ichiro itojun Hagino 
249686cdd19SJun-ichiro itojun Hagino 		/* if it constitutes infinite encapsulation, punt. */
250686cdd19SJun-ichiro itojun Hagino 		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
251686cdd19SJun-ichiro itojun Hagino 			m_freem(m);
252686cdd19SJun-ichiro itojun Hagino 			return ENETUNREACH;	/* XXX */
253686cdd19SJun-ichiro itojun Hagino 		}
254686cdd19SJun-ichiro itojun Hagino #if 0
255686cdd19SJun-ichiro itojun Hagino 		ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
256686cdd19SJun-ichiro itojun Hagino 			- sizeof(struct ip);
257686cdd19SJun-ichiro itojun Hagino #endif
258cfa1ca9dSYoshinobu Inoue 	}
259cfa1ca9dSYoshinobu Inoue 
2605d846453SSam Leffler 	error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL);
26198335aa9SGleb Smirnoff 
262fc74a9f9SBrooks Davis 	if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) &&
2635e5da865SGleb Smirnoff 	    sc->gif_ro.ro_rt != NULL) {
26498335aa9SGleb Smirnoff 		RTFREE(sc->gif_ro.ro_rt);
26598335aa9SGleb Smirnoff 		sc->gif_ro.ro_rt = NULL;
26698335aa9SGleb Smirnoff 	}
26798335aa9SGleb Smirnoff 
268cfa1ca9dSYoshinobu Inoue 	return (error);
269cfa1ca9dSYoshinobu Inoue }
270cfa1ca9dSYoshinobu Inoue 
271cfa1ca9dSYoshinobu Inoue void
272f2565d68SRobert Watson in_gif_input(struct mbuf *m, int off)
273cfa1ca9dSYoshinobu Inoue {
274cfa1ca9dSYoshinobu Inoue 	struct ifnet *gifp = NULL;
27567df9f38SBjoern A. Zeeb 	struct gif_softc *sc;
276cfa1ca9dSYoshinobu Inoue 	struct ip *ip;
277686cdd19SJun-ichiro itojun Hagino 	int af;
2786a800098SYoshinobu Inoue 	u_int8_t otos;
279f0ffb944SJulian Elischer 	int proto;
280cfa1ca9dSYoshinobu Inoue 
281cfa1ca9dSYoshinobu Inoue 	ip = mtod(m, struct ip *);
282f0ffb944SJulian Elischer 	proto = ip->ip_p;
283cfa1ca9dSYoshinobu Inoue 
28467df9f38SBjoern A. Zeeb 	sc = (struct gif_softc *)encap_getarg(m);
28567df9f38SBjoern A. Zeeb 	if (sc == NULL) {
28667df9f38SBjoern A. Zeeb 		m_freem(m);
287315e3e38SRobert Watson 		KMOD_IPSTAT_INC(ips_nogif);
28867df9f38SBjoern A. Zeeb 		return;
28967df9f38SBjoern A. Zeeb 	}
290cfa1ca9dSYoshinobu Inoue 
29167df9f38SBjoern A. Zeeb 	gifp = GIF2IFP(sc);
292686cdd19SJun-ichiro itojun Hagino 	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
293cfa1ca9dSYoshinobu Inoue 		m_freem(m);
294315e3e38SRobert Watson 		KMOD_IPSTAT_INC(ips_nogif);
295cfa1ca9dSYoshinobu Inoue 		return;
296cfa1ca9dSYoshinobu Inoue 	}
297cfa1ca9dSYoshinobu Inoue 
2986a800098SYoshinobu Inoue 	otos = ip->ip_tos;
299cfa1ca9dSYoshinobu Inoue 	m_adj(m, off);
300cfa1ca9dSYoshinobu Inoue 
301cfa1ca9dSYoshinobu Inoue 	switch (proto) {
302686cdd19SJun-ichiro itojun Hagino #ifdef INET
303cfa1ca9dSYoshinobu Inoue 	case IPPROTO_IPV4:
304cfa1ca9dSYoshinobu Inoue 	    {
305cfa1ca9dSYoshinobu Inoue 		struct ip *ip;
306cfa1ca9dSYoshinobu Inoue 		af = AF_INET;
307cfa1ca9dSYoshinobu Inoue 		if (m->m_len < sizeof(*ip)) {
308cfa1ca9dSYoshinobu Inoue 			m = m_pullup(m, sizeof(*ip));
309cfa1ca9dSYoshinobu Inoue 			if (!m)
310cfa1ca9dSYoshinobu Inoue 				return;
311cfa1ca9dSYoshinobu Inoue 		}
312cfa1ca9dSYoshinobu Inoue 		ip = mtod(m, struct ip *);
31359dfcba4SHajimu UMEMOTO 		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
31459dfcba4SHajimu UMEMOTO 				  ECN_ALLOWED : ECN_NOCARE,
31559dfcba4SHajimu UMEMOTO 				  &otos, &ip->ip_tos) == 0) {
31659dfcba4SHajimu UMEMOTO 			m_freem(m);
31759dfcba4SHajimu UMEMOTO 			return;
31859dfcba4SHajimu UMEMOTO 		}
319cfa1ca9dSYoshinobu Inoue 		break;
320cfa1ca9dSYoshinobu Inoue 	    }
321686cdd19SJun-ichiro itojun Hagino #endif
322cfa1ca9dSYoshinobu Inoue #ifdef INET6
323cfa1ca9dSYoshinobu Inoue 	case IPPROTO_IPV6:
324cfa1ca9dSYoshinobu Inoue 	    {
325cfa1ca9dSYoshinobu Inoue 		struct ip6_hdr *ip6;
32659dfcba4SHajimu UMEMOTO 		u_int8_t itos, oitos;
32759dfcba4SHajimu UMEMOTO 
328cfa1ca9dSYoshinobu Inoue 		af = AF_INET6;
329cfa1ca9dSYoshinobu Inoue 		if (m->m_len < sizeof(*ip6)) {
330cfa1ca9dSYoshinobu Inoue 			m = m_pullup(m, sizeof(*ip6));
331cfa1ca9dSYoshinobu Inoue 			if (!m)
332cfa1ca9dSYoshinobu Inoue 				return;
333cfa1ca9dSYoshinobu Inoue 		}
334cfa1ca9dSYoshinobu Inoue 		ip6 = mtod(m, struct ip6_hdr *);
33559dfcba4SHajimu UMEMOTO 		itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
33659dfcba4SHajimu UMEMOTO 		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
33759dfcba4SHajimu UMEMOTO 				  ECN_ALLOWED : ECN_NOCARE,
33859dfcba4SHajimu UMEMOTO 				  &otos, &itos) == 0) {
33959dfcba4SHajimu UMEMOTO 			m_freem(m);
34059dfcba4SHajimu UMEMOTO 			return;
34159dfcba4SHajimu UMEMOTO 		}
34259dfcba4SHajimu UMEMOTO 		if (itos != oitos) {
343cfa1ca9dSYoshinobu Inoue 			ip6->ip6_flow &= ~htonl(0xff << 20);
3446a800098SYoshinobu Inoue 			ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
34559dfcba4SHajimu UMEMOTO 		}
346cfa1ca9dSYoshinobu Inoue 		break;
347cfa1ca9dSYoshinobu Inoue 	    }
348cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
34973ff045cSAndrew Thompson  	case IPPROTO_ETHERIP:
35073ff045cSAndrew Thompson  		af = AF_LINK;
35173ff045cSAndrew Thompson  		break;
35273ff045cSAndrew Thompson 
353cfa1ca9dSYoshinobu Inoue 	default:
354315e3e38SRobert Watson 		KMOD_IPSTAT_INC(ips_nogif);
355cfa1ca9dSYoshinobu Inoue 		m_freem(m);
356cfa1ca9dSYoshinobu Inoue 		return;
357cfa1ca9dSYoshinobu Inoue 	}
358cfa1ca9dSYoshinobu Inoue 	gif_input(m, af, gifp);
359cfa1ca9dSYoshinobu Inoue 	return;
360cfa1ca9dSYoshinobu Inoue }
361686cdd19SJun-ichiro itojun Hagino 
362686cdd19SJun-ichiro itojun Hagino /*
3639426aedfSHajimu UMEMOTO  * validate outer address.
364686cdd19SJun-ichiro itojun Hagino  */
3659426aedfSHajimu UMEMOTO static int
366f2565d68SRobert Watson gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp)
3679426aedfSHajimu UMEMOTO {
368686cdd19SJun-ichiro itojun Hagino 	struct sockaddr_in *src, *dst;
369686cdd19SJun-ichiro itojun Hagino 	struct in_ifaddr *ia4;
370686cdd19SJun-ichiro itojun Hagino 
371686cdd19SJun-ichiro itojun Hagino 	src = (struct sockaddr_in *)sc->gif_psrc;
372686cdd19SJun-ichiro itojun Hagino 	dst = (struct sockaddr_in *)sc->gif_pdst;
373686cdd19SJun-ichiro itojun Hagino 
374686cdd19SJun-ichiro itojun Hagino 	/* check for address match */
3759426aedfSHajimu UMEMOTO 	if (src->sin_addr.s_addr != ip->ip_dst.s_addr ||
3769426aedfSHajimu UMEMOTO 	    dst->sin_addr.s_addr != ip->ip_src.s_addr)
377686cdd19SJun-ichiro itojun Hagino 		return 0;
378686cdd19SJun-ichiro itojun Hagino 
379686cdd19SJun-ichiro itojun Hagino 	/* martian filters on outer source - NOT done in ip_input! */
3809426aedfSHajimu UMEMOTO 	if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)))
381686cdd19SJun-ichiro itojun Hagino 		return 0;
3829426aedfSHajimu UMEMOTO 	switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) {
383686cdd19SJun-ichiro itojun Hagino 	case 0: case 127: case 255:
384686cdd19SJun-ichiro itojun Hagino 		return 0;
385686cdd19SJun-ichiro itojun Hagino 	}
3862d9cfabaSRobert Watson 
387686cdd19SJun-ichiro itojun Hagino 	/* reject packets with broadcast on source */
3882d9cfabaSRobert Watson 	/* XXXRW: should use hash lists? */
3892d9cfabaSRobert Watson 	IN_IFADDR_RLOCK();
390603724d3SBjoern A. Zeeb 	TAILQ_FOREACH(ia4, &V_in_ifaddrhead, ia_link) {
391686cdd19SJun-ichiro itojun Hagino 		if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
392686cdd19SJun-ichiro itojun Hagino 			continue;
3932d9cfabaSRobert Watson 		if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) {
3942d9cfabaSRobert Watson 			IN_IFADDR_RUNLOCK();
395686cdd19SJun-ichiro itojun Hagino 			return 0;
396686cdd19SJun-ichiro itojun Hagino 		}
3972d9cfabaSRobert Watson 	}
3982d9cfabaSRobert Watson 	IN_IFADDR_RUNLOCK();
399686cdd19SJun-ichiro itojun Hagino 
400686cdd19SJun-ichiro itojun Hagino 	/* ingress filters on outer source */
401fc74a9f9SBrooks Davis 	if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) {
402686cdd19SJun-ichiro itojun Hagino 		struct sockaddr_in sin;
403686cdd19SJun-ichiro itojun Hagino 		struct rtentry *rt;
404686cdd19SJun-ichiro itojun Hagino 
405686cdd19SJun-ichiro itojun Hagino 		bzero(&sin, sizeof(sin));
406686cdd19SJun-ichiro itojun Hagino 		sin.sin_family = AF_INET;
407686cdd19SJun-ichiro itojun Hagino 		sin.sin_len = sizeof(struct sockaddr_in);
4089426aedfSHajimu UMEMOTO 		sin.sin_addr = ip->ip_src;
4098b07e49aSJulian Elischer 		/* XXX MRT  check for the interface we would use on output */
4108b07e49aSJulian Elischer 		rt = in_rtalloc1((struct sockaddr *)&sin, 0,
4118b07e49aSJulian Elischer 		    0UL, sc->gif_fibnum);
4129426aedfSHajimu UMEMOTO 		if (!rt || rt->rt_ifp != ifp) {
41333841545SHajimu UMEMOTO #if 0
41433841545SHajimu UMEMOTO 			log(LOG_WARNING, "%s: packet from 0x%x dropped "
415fc74a9f9SBrooks Davis 			    "due to ingress filter\n", if_name(GIF2IFP(sc)),
41633841545SHajimu UMEMOTO 			    (u_int32_t)ntohl(sin.sin_addr.s_addr));
41733841545SHajimu UMEMOTO #endif
41833841545SHajimu UMEMOTO 			if (rt)
419bc60490aSChristian S.J. Peron 				RTFREE_LOCKED(rt);
420686cdd19SJun-ichiro itojun Hagino 			return 0;
421686cdd19SJun-ichiro itojun Hagino 		}
422bc60490aSChristian S.J. Peron 		RTFREE_LOCKED(rt);
423686cdd19SJun-ichiro itojun Hagino 	}
424686cdd19SJun-ichiro itojun Hagino 
42533841545SHajimu UMEMOTO 	return 32 * 2;
426686cdd19SJun-ichiro itojun Hagino }
4279426aedfSHajimu UMEMOTO 
4289426aedfSHajimu UMEMOTO /*
4299426aedfSHajimu UMEMOTO  * we know that we are in IFF_UP, outer address available, and outer family
4309426aedfSHajimu UMEMOTO  * matched the physical addr family.  see gif_encapcheck().
4319426aedfSHajimu UMEMOTO  */
4329426aedfSHajimu UMEMOTO int
433f2565d68SRobert Watson gif_encapcheck4(const struct mbuf *m, int off, int proto, void *arg)
4349426aedfSHajimu UMEMOTO {
4359426aedfSHajimu UMEMOTO 	struct ip ip;
4369426aedfSHajimu UMEMOTO 	struct gif_softc *sc;
4379426aedfSHajimu UMEMOTO 	struct ifnet *ifp;
4389426aedfSHajimu UMEMOTO 
4399426aedfSHajimu UMEMOTO 	/* sanity check done in caller */
4409426aedfSHajimu UMEMOTO 	sc = (struct gif_softc *)arg;
4419426aedfSHajimu UMEMOTO 
4429426aedfSHajimu UMEMOTO 	/* LINTED const cast */
4439426aedfSHajimu UMEMOTO 	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
4449426aedfSHajimu UMEMOTO 	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
4459426aedfSHajimu UMEMOTO 
4469426aedfSHajimu UMEMOTO 	return gif_validate4(&ip, sc, ifp);
4479426aedfSHajimu UMEMOTO }
4489426aedfSHajimu UMEMOTO 
4499426aedfSHajimu UMEMOTO int
450f2565d68SRobert Watson in_gif_attach(struct gif_softc *sc)
4519426aedfSHajimu UMEMOTO {
4529426aedfSHajimu UMEMOTO 	sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck,
4539426aedfSHajimu UMEMOTO 	    &in_gif_protosw, sc);
4549426aedfSHajimu UMEMOTO 	if (sc->encap_cookie4 == NULL)
4559426aedfSHajimu UMEMOTO 		return EEXIST;
4569426aedfSHajimu UMEMOTO 	return 0;
4579426aedfSHajimu UMEMOTO }
4589426aedfSHajimu UMEMOTO 
4599426aedfSHajimu UMEMOTO int
460f2565d68SRobert Watson in_gif_detach(struct gif_softc *sc)
4619426aedfSHajimu UMEMOTO {
4629426aedfSHajimu UMEMOTO 	int error;
4639426aedfSHajimu UMEMOTO 
4649426aedfSHajimu UMEMOTO 	error = encap_detach(sc->encap_cookie4);
4659426aedfSHajimu UMEMOTO 	if (error == 0)
4669426aedfSHajimu UMEMOTO 		sc->encap_cookie4 = NULL;
4679426aedfSHajimu UMEMOTO 	return error;
4689426aedfSHajimu UMEMOTO }
469