xref: /freebsd/sys/netinet/in_gif.c (revision 59dfcba4aab31c6484d99cac4075c55a61c99a6a)
1686cdd19SJun-ichiro itojun Hagino /*	$FreeBSD$	*/
233841545SHajimu UMEMOTO /*	$KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $	*/
3686cdd19SJun-ichiro itojun Hagino 
4cfa1ca9dSYoshinobu Inoue /*
5cfa1ca9dSYoshinobu Inoue  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6cfa1ca9dSYoshinobu Inoue  * All rights reserved.
7cfa1ca9dSYoshinobu Inoue  *
8cfa1ca9dSYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
9cfa1ca9dSYoshinobu Inoue  * modification, are permitted provided that the following conditions
10cfa1ca9dSYoshinobu Inoue  * are met:
11cfa1ca9dSYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
12cfa1ca9dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
13cfa1ca9dSYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
14cfa1ca9dSYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
15cfa1ca9dSYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
16cfa1ca9dSYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
17cfa1ca9dSYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
18cfa1ca9dSYoshinobu Inoue  *    without specific prior written permission.
19cfa1ca9dSYoshinobu Inoue  *
20cfa1ca9dSYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21cfa1ca9dSYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22cfa1ca9dSYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23cfa1ca9dSYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24cfa1ca9dSYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25cfa1ca9dSYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26cfa1ca9dSYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27cfa1ca9dSYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28cfa1ca9dSYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29cfa1ca9dSYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30cfa1ca9dSYoshinobu Inoue  * SUCH DAMAGE.
31cfa1ca9dSYoshinobu Inoue  */
32cfa1ca9dSYoshinobu Inoue 
33cfa1ca9dSYoshinobu Inoue #include "opt_mrouting.h"
34686cdd19SJun-ichiro itojun Hagino #include "opt_inet.h"
35cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h"
36cfa1ca9dSYoshinobu Inoue 
37cfa1ca9dSYoshinobu Inoue #include <sys/param.h>
38cfa1ca9dSYoshinobu Inoue #include <sys/systm.h>
39cfa1ca9dSYoshinobu Inoue #include <sys/socket.h>
40cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h>
41cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h>
42cfa1ca9dSYoshinobu Inoue #include <sys/errno.h>
43cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h>
44cfa1ca9dSYoshinobu Inoue #include <sys/sysctl.h>
459426aedfSHajimu UMEMOTO #include <sys/protosw.h>
46686cdd19SJun-ichiro itojun Hagino 
47686cdd19SJun-ichiro itojun Hagino #include <sys/malloc.h>
48cfa1ca9dSYoshinobu Inoue 
49cfa1ca9dSYoshinobu Inoue #include <net/if.h>
50cfa1ca9dSYoshinobu Inoue #include <net/route.h>
51cfa1ca9dSYoshinobu Inoue 
52cfa1ca9dSYoshinobu Inoue #include <netinet/in.h>
53cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h>
54cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h>
556a800098SYoshinobu Inoue #include <netinet/ip_var.h>
566a800098SYoshinobu Inoue #include <netinet/in_gif.h>
57686cdd19SJun-ichiro itojun Hagino #include <netinet/in_var.h>
58686cdd19SJun-ichiro itojun Hagino #include <netinet/ip_encap.h>
596a800098SYoshinobu Inoue #include <netinet/ip_ecn.h>
60686cdd19SJun-ichiro itojun Hagino 
616a800098SYoshinobu Inoue #ifdef INET6
62686cdd19SJun-ichiro itojun Hagino #include <netinet/ip6.h>
636a800098SYoshinobu Inoue #endif
64cfa1ca9dSYoshinobu Inoue 
65cfa1ca9dSYoshinobu Inoue #ifdef MROUTING
66cfa1ca9dSYoshinobu Inoue #include <netinet/ip_mroute.h>
67cfa1ca9dSYoshinobu Inoue #endif /* MROUTING */
68cfa1ca9dSYoshinobu Inoue 
69cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h>
70cfa1ca9dSYoshinobu Inoue 
71cfa1ca9dSYoshinobu Inoue #include <net/net_osdep.h>
72cfa1ca9dSYoshinobu Inoue 
739426aedfSHajimu UMEMOTO static int gif_validate4(const struct ip *, struct gif_softc *,
749426aedfSHajimu UMEMOTO 	struct ifnet *);
759426aedfSHajimu UMEMOTO 
769426aedfSHajimu UMEMOTO extern  struct domain inetdomain;
779426aedfSHajimu UMEMOTO struct protosw in_gif_protosw =
789426aedfSHajimu UMEMOTO { SOCK_RAW,	&inetdomain,	0/* IPPROTO_IPV[46] */,	PR_ATOMIC|PR_ADDR,
799426aedfSHajimu UMEMOTO   in_gif_input,	(pr_output_t*)rip_output, 0,	rip_ctloutput,
809426aedfSHajimu UMEMOTO   0,
819426aedfSHajimu UMEMOTO   0,		0,		0,		0,
829426aedfSHajimu UMEMOTO   &rip_usrreqs
839426aedfSHajimu UMEMOTO };
849426aedfSHajimu UMEMOTO 
85673623b3SBrooks Davis static int ip_gif_ttl = GIF_TTL;
86cfa1ca9dSYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
87cfa1ca9dSYoshinobu Inoue 	&ip_gif_ttl,	0, "");
88cfa1ca9dSYoshinobu Inoue 
89cfa1ca9dSYoshinobu Inoue int
90b6e28453SHajimu UMEMOTO in_gif_output(ifp, family, m)
91cfa1ca9dSYoshinobu Inoue 	struct ifnet	*ifp;
92cfa1ca9dSYoshinobu Inoue 	int		family;
93cfa1ca9dSYoshinobu Inoue 	struct mbuf	*m;
94cfa1ca9dSYoshinobu Inoue {
9533841545SHajimu UMEMOTO 	struct gif_softc *sc = (struct gif_softc*)ifp;
96cfa1ca9dSYoshinobu Inoue 	struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
97cfa1ca9dSYoshinobu Inoue 	struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
98cfa1ca9dSYoshinobu Inoue 	struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
99cfa1ca9dSYoshinobu Inoue 	struct ip iphdr;	/* capsule IP header, host byte ordered */
100cfa1ca9dSYoshinobu Inoue 	int proto, error;
101cfa1ca9dSYoshinobu Inoue 	u_int8_t tos;
102cfa1ca9dSYoshinobu Inoue 
103cfa1ca9dSYoshinobu Inoue 	if (sin_src == NULL || sin_dst == NULL ||
104cfa1ca9dSYoshinobu Inoue 	    sin_src->sin_family != AF_INET ||
105cfa1ca9dSYoshinobu Inoue 	    sin_dst->sin_family != AF_INET) {
106cfa1ca9dSYoshinobu Inoue 		m_freem(m);
107cfa1ca9dSYoshinobu Inoue 		return EAFNOSUPPORT;
108cfa1ca9dSYoshinobu Inoue 	}
109cfa1ca9dSYoshinobu Inoue 
110cfa1ca9dSYoshinobu Inoue 	switch (family) {
111686cdd19SJun-ichiro itojun Hagino #ifdef INET
112cfa1ca9dSYoshinobu Inoue 	case AF_INET:
113cfa1ca9dSYoshinobu Inoue 	    {
114cfa1ca9dSYoshinobu Inoue 		struct ip *ip;
115cfa1ca9dSYoshinobu Inoue 
116cfa1ca9dSYoshinobu Inoue 		proto = IPPROTO_IPV4;
117cfa1ca9dSYoshinobu Inoue 		if (m->m_len < sizeof(*ip)) {
118cfa1ca9dSYoshinobu Inoue 			m = m_pullup(m, sizeof(*ip));
119cfa1ca9dSYoshinobu Inoue 			if (!m)
120cfa1ca9dSYoshinobu Inoue 				return ENOBUFS;
121cfa1ca9dSYoshinobu Inoue 		}
122cfa1ca9dSYoshinobu Inoue 		ip = mtod(m, struct ip *);
123cfa1ca9dSYoshinobu Inoue 		tos = ip->ip_tos;
124cfa1ca9dSYoshinobu Inoue 		break;
125cfa1ca9dSYoshinobu Inoue 	    }
126686cdd19SJun-ichiro itojun Hagino #endif /* INET */
127cfa1ca9dSYoshinobu Inoue #ifdef INET6
128cfa1ca9dSYoshinobu Inoue 	case AF_INET6:
129cfa1ca9dSYoshinobu Inoue 	    {
130686cdd19SJun-ichiro itojun Hagino 		struct ip6_hdr *ip6;
131cfa1ca9dSYoshinobu Inoue 		proto = IPPROTO_IPV6;
132cfa1ca9dSYoshinobu Inoue 		if (m->m_len < sizeof(*ip6)) {
133cfa1ca9dSYoshinobu Inoue 			m = m_pullup(m, sizeof(*ip6));
134cfa1ca9dSYoshinobu Inoue 			if (!m)
135cfa1ca9dSYoshinobu Inoue 				return ENOBUFS;
136cfa1ca9dSYoshinobu Inoue 		}
137cfa1ca9dSYoshinobu Inoue 		ip6 = mtod(m, struct ip6_hdr *);
138cfa1ca9dSYoshinobu Inoue 		tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
139cfa1ca9dSYoshinobu Inoue 		break;
140cfa1ca9dSYoshinobu Inoue 	    }
141cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
142cfa1ca9dSYoshinobu Inoue 	default:
143686cdd19SJun-ichiro itojun Hagino #ifdef DEBUG
144cfa1ca9dSYoshinobu Inoue 		printf("in_gif_output: warning: unknown family %d passed\n",
145cfa1ca9dSYoshinobu Inoue 			family);
146cfa1ca9dSYoshinobu Inoue #endif
147cfa1ca9dSYoshinobu Inoue 		m_freem(m);
148cfa1ca9dSYoshinobu Inoue 		return EAFNOSUPPORT;
149cfa1ca9dSYoshinobu Inoue 	}
150cfa1ca9dSYoshinobu Inoue 
151cfa1ca9dSYoshinobu Inoue 	bzero(&iphdr, sizeof(iphdr));
152cfa1ca9dSYoshinobu Inoue 	iphdr.ip_src = sin_src->sin_addr;
153cfa1ca9dSYoshinobu Inoue 	/* bidirectional configured tunnel mode */
154cfa1ca9dSYoshinobu Inoue 	if (sin_dst->sin_addr.s_addr != INADDR_ANY)
155cfa1ca9dSYoshinobu Inoue 		iphdr.ip_dst = sin_dst->sin_addr;
156cfa1ca9dSYoshinobu Inoue 	else {
157cfa1ca9dSYoshinobu Inoue 		m_freem(m);
158cfa1ca9dSYoshinobu Inoue 		return ENETUNREACH;
159cfa1ca9dSYoshinobu Inoue 	}
160cfa1ca9dSYoshinobu Inoue 	iphdr.ip_p = proto;
161cfa1ca9dSYoshinobu Inoue 	/* version will be set in ip_output() */
162cfa1ca9dSYoshinobu Inoue 	iphdr.ip_ttl = ip_gif_ttl;
163cfa1ca9dSYoshinobu Inoue 	iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
16459dfcba4SHajimu UMEMOTO 	ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
16559dfcba4SHajimu UMEMOTO 		       &iphdr.ip_tos, &tos);
166cfa1ca9dSYoshinobu Inoue 
167cfa1ca9dSYoshinobu Inoue 	/* prepend new IP header */
168a163d034SWarner Losh 	M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
169cfa1ca9dSYoshinobu Inoue 	if (m && m->m_len < sizeof(struct ip))
170cfa1ca9dSYoshinobu Inoue 		m = m_pullup(m, sizeof(struct ip));
171cfa1ca9dSYoshinobu Inoue 	if (m == NULL) {
172cfa1ca9dSYoshinobu Inoue 		printf("ENOBUFS in in_gif_output %d\n", __LINE__);
173cfa1ca9dSYoshinobu Inoue 		return ENOBUFS;
174cfa1ca9dSYoshinobu Inoue 	}
175686cdd19SJun-ichiro itojun Hagino 	bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
176cfa1ca9dSYoshinobu Inoue 
177cfa1ca9dSYoshinobu Inoue 	if (dst->sin_family != sin_dst->sin_family ||
178cfa1ca9dSYoshinobu Inoue 	    dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
179cfa1ca9dSYoshinobu Inoue 		/* cache route doesn't match */
180cfa1ca9dSYoshinobu Inoue 		dst->sin_family = sin_dst->sin_family;
181cfa1ca9dSYoshinobu Inoue 		dst->sin_len = sizeof(struct sockaddr_in);
182cfa1ca9dSYoshinobu Inoue 		dst->sin_addr = sin_dst->sin_addr;
183cfa1ca9dSYoshinobu Inoue 		if (sc->gif_ro.ro_rt) {
184cfa1ca9dSYoshinobu Inoue 			RTFREE(sc->gif_ro.ro_rt);
185cfa1ca9dSYoshinobu Inoue 			sc->gif_ro.ro_rt = NULL;
186cfa1ca9dSYoshinobu Inoue 		}
187686cdd19SJun-ichiro itojun Hagino #if 0
188686cdd19SJun-ichiro itojun Hagino 		sc->gif_if.if_mtu = GIF_MTU;
189686cdd19SJun-ichiro itojun Hagino #endif
190cfa1ca9dSYoshinobu Inoue 	}
191cfa1ca9dSYoshinobu Inoue 
192cfa1ca9dSYoshinobu Inoue 	if (sc->gif_ro.ro_rt == NULL) {
193cfa1ca9dSYoshinobu Inoue 		rtalloc(&sc->gif_ro);
194cfa1ca9dSYoshinobu Inoue 		if (sc->gif_ro.ro_rt == NULL) {
195cfa1ca9dSYoshinobu Inoue 			m_freem(m);
196cfa1ca9dSYoshinobu Inoue 			return ENETUNREACH;
197cfa1ca9dSYoshinobu Inoue 		}
198686cdd19SJun-ichiro itojun Hagino 
199686cdd19SJun-ichiro itojun Hagino 		/* if it constitutes infinite encapsulation, punt. */
200686cdd19SJun-ichiro itojun Hagino 		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
201686cdd19SJun-ichiro itojun Hagino 			m_freem(m);
202686cdd19SJun-ichiro itojun Hagino 			return ENETUNREACH;	/* XXX */
203686cdd19SJun-ichiro itojun Hagino 		}
204686cdd19SJun-ichiro itojun Hagino #if 0
205686cdd19SJun-ichiro itojun Hagino 		ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
206686cdd19SJun-ichiro itojun Hagino 			- sizeof(struct ip);
207686cdd19SJun-ichiro itojun Hagino #endif
208cfa1ca9dSYoshinobu Inoue 	}
209cfa1ca9dSYoshinobu Inoue 
2105d846453SSam Leffler 	error = ip_output(m, NULL, &sc->gif_ro, 0, NULL, NULL);
211cfa1ca9dSYoshinobu Inoue 	return (error);
212cfa1ca9dSYoshinobu Inoue }
213cfa1ca9dSYoshinobu Inoue 
214cfa1ca9dSYoshinobu Inoue void
215f0ffb944SJulian Elischer in_gif_input(m, off)
216686cdd19SJun-ichiro itojun Hagino 	struct mbuf *m;
21753dab5feSBrooks Davis 	int off;
218cfa1ca9dSYoshinobu Inoue {
219cfa1ca9dSYoshinobu Inoue 	struct ifnet *gifp = NULL;
220cfa1ca9dSYoshinobu Inoue 	struct ip *ip;
221686cdd19SJun-ichiro itojun Hagino 	int af;
2226a800098SYoshinobu Inoue 	u_int8_t otos;
223f0ffb944SJulian Elischer 	int proto;
224cfa1ca9dSYoshinobu Inoue 
225cfa1ca9dSYoshinobu Inoue 	ip = mtod(m, struct ip *);
226f0ffb944SJulian Elischer 	proto = ip->ip_p;
227cfa1ca9dSYoshinobu Inoue 
228686cdd19SJun-ichiro itojun Hagino 	gifp = (struct ifnet *)encap_getarg(m);
229cfa1ca9dSYoshinobu Inoue 
230686cdd19SJun-ichiro itojun Hagino 	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
231cfa1ca9dSYoshinobu Inoue 		m_freem(m);
232cfa1ca9dSYoshinobu Inoue 		ipstat.ips_nogif++;
233cfa1ca9dSYoshinobu Inoue 		return;
234cfa1ca9dSYoshinobu Inoue 	}
235cfa1ca9dSYoshinobu Inoue 
2366a800098SYoshinobu Inoue 	otos = ip->ip_tos;
237cfa1ca9dSYoshinobu Inoue 	m_adj(m, off);
238cfa1ca9dSYoshinobu Inoue 
239cfa1ca9dSYoshinobu Inoue 	switch (proto) {
240686cdd19SJun-ichiro itojun Hagino #ifdef INET
241cfa1ca9dSYoshinobu Inoue 	case IPPROTO_IPV4:
242cfa1ca9dSYoshinobu Inoue 	    {
243cfa1ca9dSYoshinobu Inoue 		struct ip *ip;
244cfa1ca9dSYoshinobu Inoue 		af = AF_INET;
245cfa1ca9dSYoshinobu Inoue 		if (m->m_len < sizeof(*ip)) {
246cfa1ca9dSYoshinobu Inoue 			m = m_pullup(m, sizeof(*ip));
247cfa1ca9dSYoshinobu Inoue 			if (!m)
248cfa1ca9dSYoshinobu Inoue 				return;
249cfa1ca9dSYoshinobu Inoue 		}
250cfa1ca9dSYoshinobu Inoue 		ip = mtod(m, struct ip *);
25159dfcba4SHajimu UMEMOTO 		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
25259dfcba4SHajimu UMEMOTO 				  ECN_ALLOWED : ECN_NOCARE,
25359dfcba4SHajimu UMEMOTO 				  &otos, &ip->ip_tos) == 0) {
25459dfcba4SHajimu UMEMOTO 			m_freem(m);
25559dfcba4SHajimu UMEMOTO 			return;
25659dfcba4SHajimu UMEMOTO 		}
257cfa1ca9dSYoshinobu Inoue 		break;
258cfa1ca9dSYoshinobu Inoue 	    }
259686cdd19SJun-ichiro itojun Hagino #endif
260cfa1ca9dSYoshinobu Inoue #ifdef INET6
261cfa1ca9dSYoshinobu Inoue 	case IPPROTO_IPV6:
262cfa1ca9dSYoshinobu Inoue 	    {
263cfa1ca9dSYoshinobu Inoue 		struct ip6_hdr *ip6;
26459dfcba4SHajimu UMEMOTO 		u_int8_t itos, oitos;
26559dfcba4SHajimu UMEMOTO 
266cfa1ca9dSYoshinobu Inoue 		af = AF_INET6;
267cfa1ca9dSYoshinobu Inoue 		if (m->m_len < sizeof(*ip6)) {
268cfa1ca9dSYoshinobu Inoue 			m = m_pullup(m, sizeof(*ip6));
269cfa1ca9dSYoshinobu Inoue 			if (!m)
270cfa1ca9dSYoshinobu Inoue 				return;
271cfa1ca9dSYoshinobu Inoue 		}
272cfa1ca9dSYoshinobu Inoue 		ip6 = mtod(m, struct ip6_hdr *);
27359dfcba4SHajimu UMEMOTO 		itos = oitos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
27459dfcba4SHajimu UMEMOTO 		if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
27559dfcba4SHajimu UMEMOTO 				  ECN_ALLOWED : ECN_NOCARE,
27659dfcba4SHajimu UMEMOTO 				  &otos, &itos) == 0) {
27759dfcba4SHajimu UMEMOTO 			m_freem(m);
27859dfcba4SHajimu UMEMOTO 			return;
27959dfcba4SHajimu UMEMOTO 		}
28059dfcba4SHajimu UMEMOTO 		if (itos != oitos) {
281cfa1ca9dSYoshinobu Inoue 			ip6->ip6_flow &= ~htonl(0xff << 20);
2826a800098SYoshinobu Inoue 			ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
28359dfcba4SHajimu UMEMOTO 		}
284cfa1ca9dSYoshinobu Inoue 		break;
285cfa1ca9dSYoshinobu Inoue 	    }
286cfa1ca9dSYoshinobu Inoue #endif /* INET6 */
287cfa1ca9dSYoshinobu Inoue 	default:
288cfa1ca9dSYoshinobu Inoue 		ipstat.ips_nogif++;
289cfa1ca9dSYoshinobu Inoue 		m_freem(m);
290cfa1ca9dSYoshinobu Inoue 		return;
291cfa1ca9dSYoshinobu Inoue 	}
292cfa1ca9dSYoshinobu Inoue 	gif_input(m, af, gifp);
293cfa1ca9dSYoshinobu Inoue 	return;
294cfa1ca9dSYoshinobu Inoue }
295686cdd19SJun-ichiro itojun Hagino 
296686cdd19SJun-ichiro itojun Hagino /*
2979426aedfSHajimu UMEMOTO  * validate outer address.
298686cdd19SJun-ichiro itojun Hagino  */
2999426aedfSHajimu UMEMOTO static int
3009426aedfSHajimu UMEMOTO gif_validate4(ip, sc, ifp)
3019426aedfSHajimu UMEMOTO 	const struct ip *ip;
302686cdd19SJun-ichiro itojun Hagino 	struct gif_softc *sc;
3039426aedfSHajimu UMEMOTO 	struct ifnet *ifp;
3049426aedfSHajimu UMEMOTO {
305686cdd19SJun-ichiro itojun Hagino 	struct sockaddr_in *src, *dst;
306686cdd19SJun-ichiro itojun Hagino 	struct in_ifaddr *ia4;
307686cdd19SJun-ichiro itojun Hagino 
308686cdd19SJun-ichiro itojun Hagino 	src = (struct sockaddr_in *)sc->gif_psrc;
309686cdd19SJun-ichiro itojun Hagino 	dst = (struct sockaddr_in *)sc->gif_pdst;
310686cdd19SJun-ichiro itojun Hagino 
311686cdd19SJun-ichiro itojun Hagino 	/* check for address match */
3129426aedfSHajimu UMEMOTO 	if (src->sin_addr.s_addr != ip->ip_dst.s_addr ||
3139426aedfSHajimu UMEMOTO 	    dst->sin_addr.s_addr != ip->ip_src.s_addr)
314686cdd19SJun-ichiro itojun Hagino 		return 0;
315686cdd19SJun-ichiro itojun Hagino 
316686cdd19SJun-ichiro itojun Hagino 	/* martian filters on outer source - NOT done in ip_input! */
3179426aedfSHajimu UMEMOTO 	if (IN_MULTICAST(ntohl(ip->ip_src.s_addr)))
318686cdd19SJun-ichiro itojun Hagino 		return 0;
3199426aedfSHajimu UMEMOTO 	switch ((ntohl(ip->ip_src.s_addr) & 0xff000000) >> 24) {
320686cdd19SJun-ichiro itojun Hagino 	case 0: case 127: case 255:
321686cdd19SJun-ichiro itojun Hagino 		return 0;
322686cdd19SJun-ichiro itojun Hagino 	}
323686cdd19SJun-ichiro itojun Hagino 	/* reject packets with broadcast on source */
32406cd0a3fSHajimu UMEMOTO 	TAILQ_FOREACH(ia4, &in_ifaddrhead, ia_link) {
325686cdd19SJun-ichiro itojun Hagino 		if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
326686cdd19SJun-ichiro itojun Hagino 			continue;
3279426aedfSHajimu UMEMOTO 		if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
328686cdd19SJun-ichiro itojun Hagino 			return 0;
329686cdd19SJun-ichiro itojun Hagino 	}
330686cdd19SJun-ichiro itojun Hagino 
331686cdd19SJun-ichiro itojun Hagino 	/* ingress filters on outer source */
3329426aedfSHajimu UMEMOTO 	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {
333686cdd19SJun-ichiro itojun Hagino 		struct sockaddr_in sin;
334686cdd19SJun-ichiro itojun Hagino 		struct rtentry *rt;
335686cdd19SJun-ichiro itojun Hagino 
336686cdd19SJun-ichiro itojun Hagino 		bzero(&sin, sizeof(sin));
337686cdd19SJun-ichiro itojun Hagino 		sin.sin_family = AF_INET;
338686cdd19SJun-ichiro itojun Hagino 		sin.sin_len = sizeof(struct sockaddr_in);
3399426aedfSHajimu UMEMOTO 		sin.sin_addr = ip->ip_src;
340686cdd19SJun-ichiro itojun Hagino 		rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
3419426aedfSHajimu UMEMOTO 		if (!rt || rt->rt_ifp != ifp) {
34233841545SHajimu UMEMOTO #if 0
34333841545SHajimu UMEMOTO 			log(LOG_WARNING, "%s: packet from 0x%x dropped "
34433841545SHajimu UMEMOTO 			    "due to ingress filter\n", if_name(&sc->gif_if),
34533841545SHajimu UMEMOTO 			    (u_int32_t)ntohl(sin.sin_addr.s_addr));
34633841545SHajimu UMEMOTO #endif
34733841545SHajimu UMEMOTO 			if (rt)
348686cdd19SJun-ichiro itojun Hagino 				rtfree(rt);
349686cdd19SJun-ichiro itojun Hagino 			return 0;
350686cdd19SJun-ichiro itojun Hagino 		}
351686cdd19SJun-ichiro itojun Hagino 		rtfree(rt);
352686cdd19SJun-ichiro itojun Hagino 	}
353686cdd19SJun-ichiro itojun Hagino 
35433841545SHajimu UMEMOTO 	return 32 * 2;
355686cdd19SJun-ichiro itojun Hagino }
3569426aedfSHajimu UMEMOTO 
3579426aedfSHajimu UMEMOTO /*
3589426aedfSHajimu UMEMOTO  * we know that we are in IFF_UP, outer address available, and outer family
3599426aedfSHajimu UMEMOTO  * matched the physical addr family.  see gif_encapcheck().
3609426aedfSHajimu UMEMOTO  */
3619426aedfSHajimu UMEMOTO int
3629426aedfSHajimu UMEMOTO gif_encapcheck4(m, off, proto, arg)
3639426aedfSHajimu UMEMOTO 	const struct mbuf *m;
3649426aedfSHajimu UMEMOTO 	int off;
3659426aedfSHajimu UMEMOTO 	int proto;
3669426aedfSHajimu UMEMOTO 	void *arg;
3679426aedfSHajimu UMEMOTO {
3689426aedfSHajimu UMEMOTO 	struct ip ip;
3699426aedfSHajimu UMEMOTO 	struct gif_softc *sc;
3709426aedfSHajimu UMEMOTO 	struct ifnet *ifp;
3719426aedfSHajimu UMEMOTO 
3729426aedfSHajimu UMEMOTO 	/* sanity check done in caller */
3739426aedfSHajimu UMEMOTO 	sc = (struct gif_softc *)arg;
3749426aedfSHajimu UMEMOTO 
3759426aedfSHajimu UMEMOTO 	/* LINTED const cast */
3769426aedfSHajimu UMEMOTO 	m_copydata(m, 0, sizeof(ip), (caddr_t)&ip);
3779426aedfSHajimu UMEMOTO 	ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
3789426aedfSHajimu UMEMOTO 
3799426aedfSHajimu UMEMOTO 	return gif_validate4(&ip, sc, ifp);
3809426aedfSHajimu UMEMOTO }
3819426aedfSHajimu UMEMOTO 
3829426aedfSHajimu UMEMOTO int
3839426aedfSHajimu UMEMOTO in_gif_attach(sc)
3849426aedfSHajimu UMEMOTO 	struct gif_softc *sc;
3859426aedfSHajimu UMEMOTO {
3869426aedfSHajimu UMEMOTO 	sc->encap_cookie4 = encap_attach_func(AF_INET, -1, gif_encapcheck,
3879426aedfSHajimu UMEMOTO 	    &in_gif_protosw, sc);
3889426aedfSHajimu UMEMOTO 	if (sc->encap_cookie4 == NULL)
3899426aedfSHajimu UMEMOTO 		return EEXIST;
3909426aedfSHajimu UMEMOTO 	return 0;
3919426aedfSHajimu UMEMOTO }
3929426aedfSHajimu UMEMOTO 
3939426aedfSHajimu UMEMOTO int
3949426aedfSHajimu UMEMOTO in_gif_detach(sc)
3959426aedfSHajimu UMEMOTO 	struct gif_softc *sc;
3969426aedfSHajimu UMEMOTO {
3979426aedfSHajimu UMEMOTO 	int error;
3989426aedfSHajimu UMEMOTO 
3999426aedfSHajimu UMEMOTO 	error = encap_detach(sc->encap_cookie4);
4009426aedfSHajimu UMEMOTO 	if (error == 0)
4019426aedfSHajimu UMEMOTO 		sc->encap_cookie4 = NULL;
4029426aedfSHajimu UMEMOTO 	return error;
4039426aedfSHajimu UMEMOTO }
404