in_gif.c revision 82884
112580Speter/*	$FreeBSD: head/sys/netinet/in_gif.c 82884 2001-09-03 20:03:55Z julian $	*/
212580Speter/*	$KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $	*/
312580Speter
412580Speter/*
512580Speter * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
612580Speter * All rights reserved.
712580Speter *
812580Speter * Redistribution and use in source and binary forms, with or without
912580Speter * modification, are permitted provided that the following conditions
1012580Speter * are met:
1112580Speter * 1. Redistributions of source code must retain the above copyright
1212580Speter *    notice, this list of conditions and the following disclaimer.
1312580Speter * 2. Redistributions in binary form must reproduce the above copyright
1412580Speter *    notice, this list of conditions and the following disclaimer in the
1512580Speter *    documentation and/or other materials provided with the distribution.
1612580Speter * 3. Neither the name of the project nor the names of its contributors
1712580Speter *    may be used to endorse or promote products derived from this software
1812580Speter *    without specific prior written permission.
1912580Speter *
2012580Speter * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2112580Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2212580Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2312580Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2412580Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2512580Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2612580Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2712580Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2812580Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2912580Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3012580Speter * SUCH DAMAGE.
3112580Speter */
3212580Speter
3312580Speter#include "opt_mrouting.h"
3412580Speter#include "opt_inet.h"
3512580Speter#include "opt_inet6.h"
3612580Speter
37203005Sgshapiro#include <sys/param.h>
3842585Speter#include <sys/systm.h>
3942585Speter#include <sys/socket.h>
4012580Speter#include <sys/sockio.h>
4142585Speter#include <sys/mbuf.h>
4272842Sgshapiro#include <sys/errno.h>
4342585Speter#include <sys/kernel.h>
44249732Sgshapiro#include <sys/sysctl.h>
45256982Sjmg
46256982Sjmg#include <sys/malloc.h>
47256982Sjmg
48256982Sjmg#include <net/if.h>
49256982Sjmg#include <net/route.h>
5012580Speter
5172842Sgshapiro#include <netinet/in.h>
5250958Speter#include <netinet/in_systm.h>
53147357Sgshapiro#include <netinet/ip.h>
5472842Sgshapiro#include <netinet/ip_var.h>
5572842Sgshapiro#include <netinet/in_gif.h>
5690801Sgshapiro#include <netinet/in_var.h>
5772842Sgshapiro#include <netinet/ip_encap.h>
5872842Sgshapiro#include <netinet/ip_ecn.h>
5972842Sgshapiro
6072842Sgshapiro#ifdef INET6
6172842Sgshapiro#include <netinet/ip6.h>
62256982Sjmg#endif
63256982Sjmg
64256982Sjmg#ifdef MROUTING
65256982Sjmg#include <netinet/ip_mroute.h>
66256982Sjmg#endif /* MROUTING */
67256982Sjmg
68256982Sjmg#include <net/if_gif.h>
69256982Sjmg
70256982Sjmg#include <net/net_osdep.h>
71256982Sjmg
7290811Sgshapiroint ip_gif_ttl = GIF_TTL;
7390811SgshapiroSYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW,
7490811Sgshapiro	&ip_gif_ttl,	0, "");
7590811Sgshapiro
7690811Sgshapiroint
7792933Sgshapiroin_gif_output(ifp, family, m, rt)
7892933Sgshapiro	struct ifnet	*ifp;
7993231Sgshapiro	int		family;
8093231Sgshapiro	struct mbuf	*m;
81244835Sgshapiro	struct rtentry *rt;
82244835Sgshapiro{
8392933Sgshapiro	struct gif_softc *sc = (struct gif_softc*)ifp;
84223068Sgshapiro	struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst;
85223068Sgshapiro	struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc;
8692933Sgshapiro	struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst;
87244830Sgshapiro	struct ip iphdr;	/* capsule IP header, host byte ordered */
8872842Sgshapiro	int proto, error;
8951616Sjmb	u_int8_t tos;
9072842Sgshapiro
9172842Sgshapiro	if (sin_src == NULL || sin_dst == NULL ||
9264622Sgshapiro	    sin_src->sin_family != AF_INET ||
9364622Sgshapiro	    sin_dst->sin_family != AF_INET) {
9472842Sgshapiro		m_freem(m);
9572842Sgshapiro		return EAFNOSUPPORT;
9672842Sgshapiro	}
97123820Sgshapiro
98123820Sgshapiro	switch (family) {
99123820Sgshapiro#ifdef INET
10073303Sgshapiro	case AF_INET:
10197029Sgshapiro	    {
10272842Sgshapiro		struct ip *ip;
10372842Sgshapiro
10472842Sgshapiro		proto = IPPROTO_IPV4;
10572842Sgshapiro		if (m->m_len < sizeof(*ip)) {
106			m = m_pullup(m, sizeof(*ip));
107			if (!m)
108				return ENOBUFS;
109		}
110		ip = mtod(m, struct ip *);
111		tos = ip->ip_tos;
112		break;
113	    }
114#endif /*INET*/
115#ifdef INET6
116	case AF_INET6:
117	    {
118		struct ip6_hdr *ip6;
119		proto = IPPROTO_IPV6;
120		if (m->m_len < sizeof(*ip6)) {
121			m = m_pullup(m, sizeof(*ip6));
122			if (!m)
123				return ENOBUFS;
124		}
125		ip6 = mtod(m, struct ip6_hdr *);
126		tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
127		break;
128	    }
129#endif /*INET6*/
130	default:
131#ifdef DEBUG
132		printf("in_gif_output: warning: unknown family %d passed\n",
133			family);
134#endif
135		m_freem(m);
136		return EAFNOSUPPORT;
137	}
138
139	bzero(&iphdr, sizeof(iphdr));
140	iphdr.ip_src = sin_src->sin_addr;
141	/* bidirectional configured tunnel mode */
142	if (sin_dst->sin_addr.s_addr != INADDR_ANY)
143		iphdr.ip_dst = sin_dst->sin_addr;
144	else {
145		m_freem(m);
146		return ENETUNREACH;
147	}
148	iphdr.ip_p = proto;
149	/* version will be set in ip_output() */
150	iphdr.ip_ttl = ip_gif_ttl;
151	iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip);
152	if (ifp->if_flags & IFF_LINK1)
153		ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos);
154	else
155		ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos);
156
157	/* prepend new IP header */
158	M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
159	if (m && m->m_len < sizeof(struct ip))
160		m = m_pullup(m, sizeof(struct ip));
161	if (m == NULL) {
162		printf("ENOBUFS in in_gif_output %d\n", __LINE__);
163		return ENOBUFS;
164	}
165	bcopy(&iphdr, mtod(m, struct ip *), sizeof(struct ip));
166
167	if (dst->sin_family != sin_dst->sin_family ||
168	    dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) {
169		/* cache route doesn't match */
170		dst->sin_family = sin_dst->sin_family;
171		dst->sin_len = sizeof(struct sockaddr_in);
172		dst->sin_addr = sin_dst->sin_addr;
173		if (sc->gif_ro.ro_rt) {
174			RTFREE(sc->gif_ro.ro_rt);
175			sc->gif_ro.ro_rt = NULL;
176		}
177#if 0
178		sc->gif_if.if_mtu = GIF_MTU;
179#endif
180	}
181
182	if (sc->gif_ro.ro_rt == NULL) {
183		rtalloc(&sc->gif_ro);
184		if (sc->gif_ro.ro_rt == NULL) {
185			m_freem(m);
186			return ENETUNREACH;
187		}
188
189		/* if it constitutes infinite encapsulation, punt. */
190		if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
191			m_freem(m);
192			return ENETUNREACH;	/*XXX*/
193		}
194#if 0
195		ifp->if_mtu = sc->gif_ro.ro_rt->rt_ifp->if_mtu
196			- sizeof(struct ip);
197#endif
198	}
199
200	error = ip_output(m, NULL, &sc->gif_ro, 0, NULL);
201	return(error);
202}
203
204void
205in_gif_input(m, off)
206	struct mbuf *m;
207	int off;
208{
209	struct ifnet *gifp = NULL;
210	struct ip *ip;
211	int af;
212	u_int8_t otos;
213	int proto;
214
215	ip = mtod(m, struct ip *);
216	proto = ip->ip_p;
217
218	gifp = (struct ifnet *)encap_getarg(m);
219
220	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
221		m_freem(m);
222		ipstat.ips_nogif++;
223		return;
224	}
225
226	otos = ip->ip_tos;
227	m_adj(m, off);
228
229	switch (proto) {
230#ifdef INET
231	case IPPROTO_IPV4:
232	    {
233		struct ip *ip;
234		af = AF_INET;
235		if (m->m_len < sizeof(*ip)) {
236			m = m_pullup(m, sizeof(*ip));
237			if (!m)
238				return;
239		}
240		ip = mtod(m, struct ip *);
241		if (gifp->if_flags & IFF_LINK1)
242			ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos);
243		else
244			ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos);
245		break;
246	    }
247#endif
248#ifdef INET6
249	case IPPROTO_IPV6:
250	    {
251		struct ip6_hdr *ip6;
252		u_int8_t itos;
253		af = AF_INET6;
254		if (m->m_len < sizeof(*ip6)) {
255			m = m_pullup(m, sizeof(*ip6));
256			if (!m)
257				return;
258		}
259		ip6 = mtod(m, struct ip6_hdr *);
260		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
261		if (gifp->if_flags & IFF_LINK1)
262			ip_ecn_egress(ECN_ALLOWED, &otos, &itos);
263		else
264			ip_ecn_egress(ECN_NOCARE, &otos, &itos);
265		ip6->ip6_flow &= ~htonl(0xff << 20);
266		ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
267		break;
268	    }
269#endif /* INET6 */
270	default:
271		ipstat.ips_nogif++;
272		m_freem(m);
273		return;
274	}
275	gif_input(m, af, gifp);
276	return;
277}
278
279/*
280 * we know that we are in IFF_UP, outer address available, and outer family
281 * matched the physical addr family.  see gif_encapcheck().
282 */
283int
284gif_encapcheck4(m, off, proto, arg)
285	const struct mbuf *m;
286	int off;
287	int proto;
288	void *arg;
289{
290	struct ip ip;
291	struct gif_softc *sc;
292	struct sockaddr_in *src, *dst;
293	int addrmatch;
294	struct in_ifaddr *ia4;
295
296	/* sanity check done in caller */
297	sc = (struct gif_softc *)arg;
298	src = (struct sockaddr_in *)sc->gif_psrc;
299	dst = (struct sockaddr_in *)sc->gif_pdst;
300
301	/* LINTED const cast */
302	m_copydata((struct mbuf *)m, 0, sizeof(ip), (caddr_t)&ip);
303
304	/* check for address match */
305	addrmatch = 0;
306	if (src->sin_addr.s_addr == ip.ip_dst.s_addr)
307		addrmatch |= 1;
308	if (dst->sin_addr.s_addr == ip.ip_src.s_addr)
309		addrmatch |= 2;
310	if (addrmatch != 3)
311		return 0;
312
313	/* martian filters on outer source - NOT done in ip_input! */
314	if (IN_MULTICAST(ntohl(ip.ip_src.s_addr)))
315		return 0;
316	switch ((ntohl(ip.ip_src.s_addr) & 0xff000000) >> 24) {
317	case 0: case 127: case 255:
318		return 0;
319	}
320	/* reject packets with broadcast on source */
321	TAILQ_FOREACH(ia4, &in_ifaddrhead, ia_link)
322	{
323		if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
324			continue;
325		if (ip.ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
326			return 0;
327	}
328
329	/* ingress filters on outer source */
330	if ((sc->gif_if.if_flags & IFF_LINK2) == 0 &&
331	    (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) {
332		struct sockaddr_in sin;
333		struct rtentry *rt;
334
335		bzero(&sin, sizeof(sin));
336		sin.sin_family = AF_INET;
337		sin.sin_len = sizeof(struct sockaddr_in);
338		sin.sin_addr = ip.ip_src;
339		rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL);
340		if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) {
341#if 0
342			log(LOG_WARNING, "%s: packet from 0x%x dropped "
343			    "due to ingress filter\n", if_name(&sc->gif_if),
344			    (u_int32_t)ntohl(sin.sin_addr.s_addr));
345#endif
346			if (rt)
347				rtfree(rt);
348			return 0;
349		}
350		rtfree(rt);
351	}
352
353	return 32 * 2;
354}
355