xref: /openbsd/sys/netinet/ip_ipip.c (revision 70464ff2)
1*70464ff2Sgnezdo /*	$OpenBSD: ip_ipip.c,v 1.90 2021/01/09 20:59:44 gnezdo Exp $ */
29a570b6dSangelos /*
39a570b6dSangelos  * The authors of this code are John Ioannidis (ji@tla.org),
49a570b6dSangelos  * Angelos D. Keromytis (kermit@csd.uch.gr) and
59a570b6dSangelos  * Niels Provos (provos@physnet.uni-hamburg.de).
69a570b6dSangelos  *
7b1efc16cSangelos  * The original version of this code was written by John Ioannidis
8b1efc16cSangelos  * for BSD/OS in Athens, Greece, in November 1995.
99a570b6dSangelos  *
109a570b6dSangelos  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
119a570b6dSangelos  * by Angelos D. Keromytis.
129a570b6dSangelos  *
139a570b6dSangelos  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
149a570b6dSangelos  * and Niels Provos.
159a570b6dSangelos  *
169a570b6dSangelos  * Additional features in 1999 by Angelos D. Keromytis.
179a570b6dSangelos  *
189a570b6dSangelos  * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
199a570b6dSangelos  * Angelos D. Keromytis and Niels Provos.
200775ebe4Sangelos  * Copyright (c) 2001, Angelos D. Keromytis.
219a570b6dSangelos  *
220775ebe4Sangelos  * Permission to use, copy, and modify this software with or without fee
239a570b6dSangelos  * is hereby granted, provided that this entire notice is included in
249a570b6dSangelos  * all copies of any software which is or includes a copy or
259a570b6dSangelos  * modification of this software.
269a570b6dSangelos  * You may use this code under the GNU public license if you so wish. Please
279a570b6dSangelos  * contribute changes back to the authors under this freer than GPL license
289a570b6dSangelos  * so that we may further the use of strong encryption without limitations to
299a570b6dSangelos  * all.
309a570b6dSangelos  *
319a570b6dSangelos  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
329a570b6dSangelos  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
339a570b6dSangelos  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
349a570b6dSangelos  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
359a570b6dSangelos  * PURPOSE.
369a570b6dSangelos  */
379a570b6dSangelos 
389a570b6dSangelos /*
399a570b6dSangelos  * IP-inside-IP processing
409a570b6dSangelos  */
419a570b6dSangelos 
42ab2f8295Sbluhm #include "bpfilter.h"
43ab2f8295Sbluhm #include "gif.h"
440c8db51fShenning #include "pf.h"
450c8db51fShenning 
469a570b6dSangelos #include <sys/param.h>
4764c11355Sderaadt #include <sys/systm.h>
489a570b6dSangelos #include <sys/mbuf.h>
499a570b6dSangelos #include <sys/socket.h>
509a570b6dSangelos #include <sys/sysctl.h>
519a570b6dSangelos 
529a570b6dSangelos #include <net/if.h>
53ab2f8295Sbluhm #include <net/if_types.h>
540deb6685Smpi #include <net/if_var.h>
559a570b6dSangelos #include <net/route.h>
569a570b6dSangelos #include <net/netisr.h>
579acf6950Sangelos #include <net/bpf.h>
589a570b6dSangelos 
599a570b6dSangelos #include <netinet/in.h>
609a570b6dSangelos #include <netinet/ip.h>
619a570b6dSangelos #include <netinet/in_pcb.h>
629a570b6dSangelos #include <netinet/ip_var.h>
639a570b6dSangelos #include <netinet/ip_ecn.h>
64ea784840Sbluhm #include <netinet/ip_ipip.h>
659a570b6dSangelos 
669a570b6dSangelos #ifdef MROUTING
679a570b6dSangelos #include <netinet/ip_mroute.h>
689a570b6dSangelos #endif
699a570b6dSangelos 
700c8db51fShenning #if NPF > 0
710c8db51fShenning #include <net/pfvar.h>
720c8db51fShenning #endif
730c8db51fShenning 
749a570b6dSangelos #ifdef ENCDEBUG
759a570b6dSangelos #define DPRINTF(x)	if (encdebug) printf x
769a570b6dSangelos #else
779a570b6dSangelos #define DPRINTF(x)
789a570b6dSangelos #endif
799a570b6dSangelos 
809a570b6dSangelos /*
819a570b6dSangelos  * We can control the acceptance of IP4 packets by altering the sysctl
829a570b6dSangelos  * net.inet.ipip.allow value.  Zero means drop them, all else is acceptance.
839a570b6dSangelos  */
849a570b6dSangelos int ipip_allow = 0;
859a570b6dSangelos 
8660dafcf9Sjca struct cpumem *ipipcounters;
8760dafcf9Sjca 
8860dafcf9Sjca void
8960dafcf9Sjca ipip_init(void)
9060dafcf9Sjca {
9160dafcf9Sjca 	ipipcounters = counters_alloc(ipips_ncounters);
9260dafcf9Sjca }
939a570b6dSangelos 
949a570b6dSangelos /*
95ab2f8295Sbluhm  * Really only a wrapper for ipip_input_if(), for use with pr_input.
969a570b6dSangelos  */
979a570b6dSangelos int
98ab2f8295Sbluhm ipip_input(struct mbuf **mp, int *offp, int nxt, int af)
999a570b6dSangelos {
100ab2f8295Sbluhm 	struct ifnet *ifp;
101ab2f8295Sbluhm 
102ae26b3edSitojun 	/* If we do not accept IP-in-IP explicitly, drop.  */
103f0c13189Sderaadt 	if (!ipip_allow && ((*mp)->m_flags & (M_AUTH|M_CONF)) == 0) {
104ea784840Sbluhm 		DPRINTF(("%s: dropped due to policy\n", __func__));
10560dafcf9Sjca 		ipipstat_inc(ipips_pdrops);
10636c0109eSbluhm 		m_freemp(mp);
1079a570b6dSangelos 		return IPPROTO_DONE;
1089a570b6dSangelos 	}
1099a570b6dSangelos 
110ab2f8295Sbluhm 	ifp = if_get((*mp)->m_pkthdr.ph_ifidx);
111ab2f8295Sbluhm 	if (ifp == NULL) {
112ab2f8295Sbluhm 		m_freemp(mp);
113ab2f8295Sbluhm 		return IPPROTO_DONE;
114ab2f8295Sbluhm 	}
115ab2f8295Sbluhm 	nxt = ipip_input_if(mp, offp, nxt, af, ifp);
116ab2f8295Sbluhm 	if_put(ifp);
117ab2f8295Sbluhm 
118ab2f8295Sbluhm 	return nxt;
1199a570b6dSangelos }
1209a570b6dSangelos 
1219a570b6dSangelos /*
1229a570b6dSangelos  * ipip_input gets called when we receive an IP{46} encapsulated packet,
1239a570b6dSangelos  * either because we got it at a real interface, or because AH or ESP
124fb492c37Smpi  * were being used in tunnel mode (in which case the ph_ifidx element
125fb492c37Smpi  * will contain the index of the encX interface associated with the
126fb492c37Smpi  * tunnel.
1279a570b6dSangelos  */
1289a570b6dSangelos 
12996be3d96Sbluhm int
130ab2f8295Sbluhm ipip_input_if(struct mbuf **mp, int *offp, int proto, int oaf,
131ab2f8295Sbluhm     struct ifnet *ifp)
1329a570b6dSangelos {
13396be3d96Sbluhm 	struct mbuf *m = *mp;
13464aa4cc7Sitojun 	struct sockaddr_in *sin;
1351bcb5a76Sbluhm 	struct ip *ip;
1369a570b6dSangelos #ifdef INET6
13764aa4cc7Sitojun 	struct sockaddr_in6 *sin6;
13821579e10Sclaudio 	struct ip6_hdr *ip6;
1399a570b6dSangelos #endif
14098a920fdSdlg 	int mode, hlen;
141c9857360Smarkus 	u_int8_t itos, otos;
142ea784840Sbluhm 	sa_family_t iaf;
1439a570b6dSangelos 
14460dafcf9Sjca 	ipipstat_inc(ipips_ipackets);
1459a570b6dSangelos 
146289a9ae9Sbluhm 	switch (oaf) {
147289a9ae9Sbluhm 	case AF_INET:
1489a570b6dSangelos 		hlen = sizeof(struct ip);
1499a570b6dSangelos 		break;
1509a570b6dSangelos #ifdef INET6
151289a9ae9Sbluhm 	case AF_INET6:
1529a570b6dSangelos 		hlen = sizeof(struct ip6_hdr);
1539a570b6dSangelos 		break;
1549a570b6dSangelos #endif
155795830a0Sangelos 	default:
156289a9ae9Sbluhm 		unhandled_af(oaf);
1579a570b6dSangelos 	}
1589a570b6dSangelos 
1599a570b6dSangelos 	/* Bring the IP header in the first mbuf, if not there already */
1606593f73dSangelos 	if (m->m_len < hlen) {
161eabae73bSbluhm 		if ((m = *mp = m_pullup(m, hlen)) == NULL) {
162ea784840Sbluhm 			DPRINTF(("%s: m_pullup() failed\n", __func__));
16360dafcf9Sjca 			ipipstat_inc(ipips_hdrops);
164458cfda4Sbluhm 			goto bad;
1659a570b6dSangelos 		}
1669a570b6dSangelos 	}
1679a570b6dSangelos 
1686593f73dSangelos 	/* Keep outer ecn field. */
169289a9ae9Sbluhm 	switch (oaf) {
170289a9ae9Sbluhm 	case AF_INET:
1711bcb5a76Sbluhm 		ip = mtod(m, struct ip *);
1721bcb5a76Sbluhm 		otos = ip->ip_tos;
173ae26b3edSitojun 		break;
1749a570b6dSangelos #ifdef INET6
175289a9ae9Sbluhm 	case AF_INET6:
17621579e10Sclaudio 		ip6 = mtod(m, struct ip6_hdr *);
17721579e10Sclaudio 		otos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
178ae26b3edSitojun 		break;
1799a570b6dSangelos #endif
180ae26b3edSitojun 	}
1819a570b6dSangelos 
1822b1f9644Sangelos 	/* Remove outer IP header */
1831bcb5a76Sbluhm 	KASSERT(*offp > 0);
1841bcb5a76Sbluhm 	m_adj(m, *offp);
1851bcb5a76Sbluhm 	*offp = 0;
1861bcb5a76Sbluhm 	ip = NULL;
1871bcb5a76Sbluhm #ifdef INET6
1881bcb5a76Sbluhm 	ip6 = NULL;
1891bcb5a76Sbluhm #endif
1906d386255Sangelos 
19121579e10Sclaudio 	switch (proto) {
19221579e10Sclaudio 	case IPPROTO_IPV4:
1939a570b6dSangelos 		hlen = sizeof(struct ip);
1949a570b6dSangelos 		break;
1959a570b6dSangelos 
1969a570b6dSangelos #ifdef INET6
19721579e10Sclaudio 	case IPPROTO_IPV6:
1989a570b6dSangelos 		hlen = sizeof(struct ip6_hdr);
1999a570b6dSangelos 		break;
2009a570b6dSangelos #endif
201ae26b3edSitojun 	default:
20260dafcf9Sjca 		ipipstat_inc(ipips_family);
203458cfda4Sbluhm 		goto bad;
2049a570b6dSangelos 	}
2059a570b6dSangelos 
2061bcb5a76Sbluhm 	/* Sanity check */
2071bcb5a76Sbluhm 	if (m->m_pkthdr.len < hlen) {
2081bcb5a76Sbluhm 		ipipstat_inc(ipips_hdrops);
209458cfda4Sbluhm 		goto bad;
2101bcb5a76Sbluhm 	}
2111bcb5a76Sbluhm 
2126593f73dSangelos 	/*
21321579e10Sclaudio 	 * Bring the inner header into the first mbuf, if not there already.
2146593f73dSangelos 	 */
2156593f73dSangelos 	if (m->m_len < hlen) {
216eabae73bSbluhm 		if ((m = *mp = m_pullup(m, hlen)) == NULL) {
217ea784840Sbluhm 			DPRINTF(("%s: m_pullup() failed\n", __func__));
21860dafcf9Sjca 			ipipstat_inc(ipips_hdrops);
219458cfda4Sbluhm 			goto bad;
2209a570b6dSangelos 		}
2219a570b6dSangelos 	}
2229a570b6dSangelos 
2239a570b6dSangelos 	/*
2249a570b6dSangelos 	 * RFC 1853 specifies that the inner TTL should not be touched on
2259a570b6dSangelos 	 * decapsulation. There's no reason this comment should be here, but
2269a570b6dSangelos 	 * this is as good as any a position.
2279a570b6dSangelos 	 */
2289a570b6dSangelos 
229ae26b3edSitojun 	/* Some sanity checks in the inner IP header */
23021579e10Sclaudio 	switch (proto) {
23121579e10Sclaudio     	case IPPROTO_IPV4:
232ca37dd6cSbluhm 		iaf = AF_INET;
2331bcb5a76Sbluhm 		ip = mtod(m, struct ip *);
2341bcb5a76Sbluhm 		hlen = ip->ip_hl << 2;
2351bcb5a76Sbluhm 		if (m->m_pkthdr.len < hlen) {
2361bcb5a76Sbluhm 			ipipstat_inc(ipips_hdrops);
237ab2f8295Sbluhm 			goto bad;
2381bcb5a76Sbluhm 		}
2391bcb5a76Sbluhm 		itos = ip->ip_tos;
240c9857360Smarkus 		mode = m->m_flags & (M_AUTH|M_CONF) ?
241c9857360Smarkus 		    ECN_ALLOWED_IPSEC : ECN_ALLOWED;
242412c1a0aSdlg 		if (!ip_ecn_egress(mode, &otos, &itos)) {
243ea784840Sbluhm 			DPRINTF(("%s: ip_ecn_egress() failed\n", __func__));
24460dafcf9Sjca 			ipipstat_inc(ipips_pdrops);
245458cfda4Sbluhm 			goto bad;
24674e8fb40Skjc 		}
247c9857360Smarkus 		/* re-calculate the checksum if ip_tos was changed */
248412c1a0aSdlg 		if (itos != ip->ip_tos)
249412c1a0aSdlg 			ip_tos_patch(ip, itos);
2509a570b6dSangelos 		break;
2519a570b6dSangelos #ifdef INET6
25221579e10Sclaudio     	case IPPROTO_IPV6:
253ca37dd6cSbluhm 		iaf = AF_INET6;
25421579e10Sclaudio 		ip6 = mtod(m, struct ip6_hdr *);
2559a570b6dSangelos 		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
25674e8fb40Skjc 		if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) {
257ea784840Sbluhm 			DPRINTF(("%s: ip_ecn_egress() failed\n", __func__));
25860dafcf9Sjca 			ipipstat_inc(ipips_pdrops);
259458cfda4Sbluhm 			goto bad;
26074e8fb40Skjc 		}
2619a570b6dSangelos 		ip6->ip6_flow &= ~htonl(0xff << 20);
2629a570b6dSangelos 		ip6->ip6_flow |= htonl((u_int32_t) itos << 20);
2639a570b6dSangelos 		break;
2649a570b6dSangelos #endif
2659a570b6dSangelos 	}
2669a570b6dSangelos 
2679a570b6dSangelos 	/* Check for local address spoofing. */
268ab2f8295Sbluhm 	if (!(ifp->if_flags & IFF_LOOPBACK) && ipip_allow != 2) {
269d33580a9Smpi 		struct sockaddr_storage ss;
270d33580a9Smpi 		struct rtentry *rt;
271d33580a9Smpi 
272d33580a9Smpi 		memset(&ss, 0, sizeof(ss));
273d33580a9Smpi 
2741bcb5a76Sbluhm 		if (ip) {
275d33580a9Smpi 			sin = (struct sockaddr_in *)&ss;
276d33580a9Smpi 			sin->sin_family = AF_INET;
277d33580a9Smpi 			sin->sin_len = sizeof(*sin);
2781bcb5a76Sbluhm 			sin->sin_addr = ip->ip_src;
2799a570b6dSangelos #ifdef INET6
280d33580a9Smpi 		} else if (ip6) {
281d33580a9Smpi 			sin6 = (struct sockaddr_in6 *)&ss;
282d33580a9Smpi 			sin6->sin6_family = AF_INET6;
283d33580a9Smpi 			sin6->sin6_len = sizeof(*sin6);
284d33580a9Smpi 			sin6->sin6_addr = ip6->ip6_src;
2859a570b6dSangelos #endif /* INET6 */
2869a570b6dSangelos 		}
2879c681c75Sbluhm 		rt = rtalloc(sstosa(&ss), 0, m->m_pkthdr.ph_rtableid);
288d33580a9Smpi 		if ((rt != NULL) && (rt->rt_flags & RTF_LOCAL)) {
28960dafcf9Sjca 			ipipstat_inc(ipips_spoof);
290d33580a9Smpi 			rtfree(rt);
291458cfda4Sbluhm 			goto bad;
2929a570b6dSangelos  		}
293d33580a9Smpi 		rtfree(rt);
2949a570b6dSangelos 	}
2959a570b6dSangelos 
2969a570b6dSangelos 	/* Statistics */
2971bcb5a76Sbluhm 	ipipstat_add(ipips_ibytes, m->m_pkthdr.len - hlen);
2989a570b6dSangelos 
299ab2f8295Sbluhm #if NBPFILTER > 0 && NGIF > 0
300ab2f8295Sbluhm 	if (ifp->if_type == IFT_GIF && ifp->if_bpf != NULL)
301ab2f8295Sbluhm 		bpf_mtap_af(ifp->if_bpf, iaf, m, BPF_DIRECTION_IN);
302ca37dd6cSbluhm #endif
303ca37dd6cSbluhm #if NPF > 0
304ca37dd6cSbluhm 	pf_pkt_addr_changed(m);
305ca37dd6cSbluhm #endif
306ca37dd6cSbluhm 
3079a570b6dSangelos 	/*
3089a570b6dSangelos 	 * Interface pointer stays the same; if no IPsec processing has
3099a570b6dSangelos 	 * been done (or will be done), this will point to a normal
3109a570b6dSangelos 	 * interface. Otherwise, it'll point to an enc interface, which
3119a570b6dSangelos 	 * will allow a packet filter to distinguish between secure and
3129a570b6dSangelos 	 * untrusted packets.
3139a570b6dSangelos 	 */
3149a570b6dSangelos 
31521579e10Sclaudio 	switch (proto) {
31621579e10Sclaudio 	case IPPROTO_IPV4:
317bb24c526Sbluhm 		return ip_input_if(mp, offp, proto, oaf, ifp);
3189a570b6dSangelos #ifdef INET6
31921579e10Sclaudio 	case IPPROTO_IPV6:
320bb24c526Sbluhm 		return ip6_input_if(mp, offp, proto, oaf, ifp);
321ae26b3edSitojun #endif
3229a570b6dSangelos 	}
323458cfda4Sbluhm  bad:
32436c0109eSbluhm 	m_freemp(mp);
32596be3d96Sbluhm 	return IPPROTO_DONE;
3269a570b6dSangelos }
3279a570b6dSangelos 
3289a570b6dSangelos int
3290085a3a2Sclaudio ipip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int dummy,
3300085a3a2Sclaudio     int dummy2)
3319a570b6dSangelos {
3322edaa7baSmpi 	u_int8_t tp, otos, itos;
3332edaa7baSmpi 	u_int64_t obytes;
3349a570b6dSangelos 	struct ip *ipo;
3359a570b6dSangelos #ifdef INET6
336d5b56032Sitojun 	struct ip6_hdr *ip6, *ip6o;
3379a570b6dSangelos #endif /* INET6 */
3383514aacbSmikeb #ifdef ENCDEBUG
3393514aacbSmikeb 	char buf[INET6_ADDRSTRLEN];
3403514aacbSmikeb #endif
3419a570b6dSangelos 
3426593f73dSangelos 	/* XXX Deal with empty TDB source/destination addresses. */
3439a570b6dSangelos 
3449a570b6dSangelos 	m_copydata(m, 0, 1, &tp);
3456593f73dSangelos 	tp = (tp >> 4) & 0xff;  /* Get the IP version number. */
3469a570b6dSangelos 
3476593f73dSangelos 	switch (tdb->tdb_dst.sa.sa_family) {
3489a570b6dSangelos 	case AF_INET:
3496593f73dSangelos 		if (tdb->tdb_src.sa.sa_family != AF_INET ||
3506593f73dSangelos 		    tdb->tdb_src.sin.sin_addr.s_addr == INADDR_ANY ||
3516593f73dSangelos 		    tdb->tdb_dst.sin.sin_addr.s_addr == INADDR_ANY) {
3526593f73dSangelos 
353ea784840Sbluhm 			DPRINTF(("%s: unspecified tunnel endpoind "
354ea784840Sbluhm 			    "address in SA %s/%08x\n", __func__,
3553514aacbSmikeb 			    ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
3563514aacbSmikeb 			    ntohl(tdb->tdb_spi)));
3576593f73dSangelos 
35860dafcf9Sjca 			ipipstat_inc(ipips_unspec);
3599a570b6dSangelos 			m_freem(m);
3609a570b6dSangelos 			*mp = NULL;
3619a570b6dSangelos 			return EINVAL;
3629a570b6dSangelos 		}
3639a570b6dSangelos 
3649a570b6dSangelos 		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
36564a3f76cSjsg 		if (m == NULL) {
366ea784840Sbluhm 			DPRINTF(("%s: M_PREPEND failed\n", __func__));
36760dafcf9Sjca 			ipipstat_inc(ipips_hdrops);
3689a570b6dSangelos 			*mp = NULL;
3699a570b6dSangelos 			return ENOBUFS;
3709a570b6dSangelos 		}
3719a570b6dSangelos 
3729a570b6dSangelos 		ipo = mtod(m, struct ip *);
3739a570b6dSangelos 
3749a570b6dSangelos 		ipo->ip_v = IPVERSION;
3759a570b6dSangelos 		ipo->ip_hl = 5;
3769a570b6dSangelos 		ipo->ip_len = htons(m->m_pkthdr.len);
3779a570b6dSangelos 		ipo->ip_ttl = ip_defttl;
3789a570b6dSangelos 		ipo->ip_sum = 0;
3799a570b6dSangelos 		ipo->ip_src = tdb->tdb_src.sin.sin_addr;
3809a570b6dSangelos 		ipo->ip_dst = tdb->tdb_dst.sin.sin_addr;
3819a570b6dSangelos 
3829a570b6dSangelos 		/*
3839a570b6dSangelos 		 * We do the htons() to prevent snoopers from determining our
3849a570b6dSangelos 		 * endianness.
3859a570b6dSangelos 		 */
3869a570b6dSangelos 		ipo->ip_id = htons(ip_randomid());
3879a570b6dSangelos 
3886593f73dSangelos 		/* If the inner protocol is IP... */
3896593f73dSangelos 		if (tp == IPVERSION) {
3909a570b6dSangelos 			/* Save ECN notification */
3916593f73dSangelos 			m_copydata(m, sizeof(struct ip) +
3926593f73dSangelos 			    offsetof(struct ip, ip_tos),
3939a570b6dSangelos 			    sizeof(u_int8_t), (caddr_t) &itos);
3949a570b6dSangelos 
3959a570b6dSangelos 			ipo->ip_p = IPPROTO_IPIP;
3969a570b6dSangelos 
3979a570b6dSangelos 			/*
3986593f73dSangelos 			 * We should be keeping tunnel soft-state and
3996593f73dSangelos 			 * send back ICMPs if needed.
4009a570b6dSangelos 			 */
4016593f73dSangelos 			m_copydata(m, sizeof(struct ip) +
4026593f73dSangelos 			    offsetof(struct ip, ip_off),
4039a570b6dSangelos 			    sizeof(u_int16_t), (caddr_t) &ipo->ip_off);
404faf7e06fSmpi 			ipo->ip_off = ntohs(ipo->ip_off);
40570d36f83Sangelos 			ipo->ip_off &= ~(IP_DF | IP_MF | IP_OFFMASK);
406faf7e06fSmpi 			ipo->ip_off = htons(ipo->ip_off);
4079a570b6dSangelos 		}
4089a570b6dSangelos #ifdef INET6
4096593f73dSangelos 		else if (tp == (IPV6_VERSION >> 4)) {
4109a570b6dSangelos 			u_int32_t itos32;
4116593f73dSangelos 
4126593f73dSangelos 			/* Save ECN notification. */
4139a570b6dSangelos 			m_copydata(m, sizeof(struct ip) +
4149a570b6dSangelos 			    offsetof(struct ip6_hdr, ip6_flow),
4159a570b6dSangelos 			    sizeof(u_int32_t), (caddr_t) &itos32);
4169a570b6dSangelos 			itos = ntohl(itos32) >> 20;
4179a570b6dSangelos 			ipo->ip_p = IPPROTO_IPV6;
4189a570b6dSangelos 			ipo->ip_off = 0;
4199a570b6dSangelos 		}
4209a570b6dSangelos #endif /* INET6 */
4216593f73dSangelos 		else {
4229a570b6dSangelos 			m_freem(m);
4239a570b6dSangelos 			*mp = NULL;
42460dafcf9Sjca 			ipipstat_inc(ipips_family);
4259a570b6dSangelos 			return EAFNOSUPPORT;
4269a570b6dSangelos 		}
4279a570b6dSangelos 
4289a570b6dSangelos 		otos = 0;
4299a570b6dSangelos 		ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
4309a570b6dSangelos 		ipo->ip_tos = otos;
4319a570b6dSangelos 		break;
4329a570b6dSangelos 
4339a570b6dSangelos #ifdef INET6
4349a570b6dSangelos 	case AF_INET6:
4359a570b6dSangelos 		if (IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_dst.sin6.sin6_addr) ||
4366593f73dSangelos 		    tdb->tdb_src.sa.sa_family != AF_INET6 ||
4376593f73dSangelos 		    IN6_IS_ADDR_UNSPECIFIED(&tdb->tdb_src.sin6.sin6_addr)) {
4386593f73dSangelos 
439ea784840Sbluhm 			DPRINTF(("%s: unspecified tunnel endpoind "
440ea784840Sbluhm 			    "address in SA %s/%08x\n", __func__,
4413514aacbSmikeb 			    ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)),
4423514aacbSmikeb 			    ntohl(tdb->tdb_spi)));
4436593f73dSangelos 
44460dafcf9Sjca 			ipipstat_inc(ipips_unspec);
4459a570b6dSangelos 			m_freem(m);
4469a570b6dSangelos 			*mp = NULL;
4479a570b6dSangelos 			return ENOBUFS;
4489a570b6dSangelos 		}
4499a570b6dSangelos 
450424a21eaStodd 		/* If the inner protocol is IPv6, clear link local scope */
451424a21eaStodd 		if (tp == (IPV6_VERSION >> 4)) {
452d5b56032Sitojun 			/* scoped address handling */
453d5b56032Sitojun 			ip6 = mtod(m, struct ip6_hdr *);
45465b748d4Sitojun 			if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
455d5b56032Sitojun 				ip6->ip6_src.s6_addr16[1] = 0;
45665b748d4Sitojun 			if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
457d5b56032Sitojun 				ip6->ip6_dst.s6_addr16[1] = 0;
458424a21eaStodd 		}
459d5b56032Sitojun 
4609a570b6dSangelos 		M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
46164a3f76cSjsg 		if (m == NULL) {
462ea784840Sbluhm 			DPRINTF(("%s: M_PREPEND failed\n", __func__));
46360dafcf9Sjca 			ipipstat_inc(ipips_hdrops);
4649a570b6dSangelos 			*mp = NULL;
4659a570b6dSangelos 			return ENOBUFS;
4669a570b6dSangelos 		}
4679a570b6dSangelos 
4689a570b6dSangelos 		/* Initialize IPv6 header */
4699a570b6dSangelos 		ip6o = mtod(m, struct ip6_hdr *);
4709a570b6dSangelos 		ip6o->ip6_flow = 0;
4719a570b6dSangelos 		ip6o->ip6_vfc &= ~IPV6_VERSION_MASK;
4729a570b6dSangelos 		ip6o->ip6_vfc |= IPV6_VERSION;
473086d35e9Smarkus 		ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6o));
4749a570b6dSangelos 		ip6o->ip6_hlim = ip_defttl;
4752305623bSclaudio 		in6_embedscope(&ip6o->ip6_src, &tdb->tdb_src.sin6, NULL);
4762305623bSclaudio 		in6_embedscope(&ip6o->ip6_dst, &tdb->tdb_dst.sin6, NULL);
4779a570b6dSangelos 
4786593f73dSangelos 		if (tp == IPVERSION) {
4799a570b6dSangelos 			/* Save ECN notification */
4809a570b6dSangelos 			m_copydata(m, sizeof(struct ip6_hdr) +
4819a570b6dSangelos 			    offsetof(struct ip, ip_tos), sizeof(u_int8_t),
4829a570b6dSangelos 			    (caddr_t) &itos);
4839a570b6dSangelos 
4846593f73dSangelos 			/* This is really IPVERSION. */
4856593f73dSangelos 			ip6o->ip6_nxt = IPPROTO_IPIP;
4869a570b6dSangelos 		}
4879a570b6dSangelos 		else
4886593f73dSangelos 			if (tp == (IPV6_VERSION >> 4)) {
4899a570b6dSangelos 				u_int32_t itos32;
4906593f73dSangelos 
4916593f73dSangelos 				/* Save ECN notification. */
4929a570b6dSangelos 				m_copydata(m, sizeof(struct ip6_hdr) +
4939a570b6dSangelos 				    offsetof(struct ip6_hdr, ip6_flow),
4949a570b6dSangelos 				    sizeof(u_int32_t), (caddr_t) &itos32);
4959a570b6dSangelos 				itos = ntohl(itos32) >> 20;
4969a570b6dSangelos 
4979a570b6dSangelos 				ip6o->ip6_nxt = IPPROTO_IPV6;
4986593f73dSangelos 			} else {
4999a570b6dSangelos 				m_freem(m);
5009a570b6dSangelos 				*mp = NULL;
50160dafcf9Sjca 				ipipstat_inc(ipips_family);
5029a570b6dSangelos 				return EAFNOSUPPORT;
5039a570b6dSangelos 			}
5049a570b6dSangelos 
5059a570b6dSangelos 		otos = 0;
5069a570b6dSangelos 		ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
5079a570b6dSangelos 		ip6o->ip6_flow |= htonl((u_int32_t) otos << 20);
5089a570b6dSangelos 		break;
5099a570b6dSangelos #endif /* INET6 */
5109a570b6dSangelos 
5119a570b6dSangelos 	default:
512ea784840Sbluhm 		DPRINTF(("%s: unsupported protocol family %d\n", __func__,
5139a570b6dSangelos 		    tdb->tdb_dst.sa.sa_family));
5149a570b6dSangelos 		m_freem(m);
5159a570b6dSangelos 		*mp = NULL;
51660dafcf9Sjca 		ipipstat_inc(ipips_family);
51767a9371aSangelos 		return EAFNOSUPPORT;
5189a570b6dSangelos 	}
5199a570b6dSangelos 
52060dafcf9Sjca 	ipipstat_inc(ipips_opackets);
5219a570b6dSangelos 	*mp = m;
5229a570b6dSangelos 
5236593f73dSangelos 	if (tdb->tdb_dst.sa.sa_family == AF_INET) {
5242edaa7baSmpi 		obytes = m->m_pkthdr.len - sizeof(struct ip);
5259a570b6dSangelos 		if (tdb->tdb_xform->xf_type == XF_IP4)
5262edaa7baSmpi 			tdb->tdb_cur_bytes += obytes;
5279a570b6dSangelos 
5282edaa7baSmpi 		ipipstat_add(ipips_obytes, obytes);
5299a570b6dSangelos 	}
5309a570b6dSangelos 
5319a570b6dSangelos #ifdef INET6
5326593f73dSangelos 	if (tdb->tdb_dst.sa.sa_family == AF_INET6) {
5332edaa7baSmpi 		obytes = m->m_pkthdr.len - sizeof(struct ip6_hdr);
5349a570b6dSangelos 		if (tdb->tdb_xform->xf_type == XF_IP4)
5352edaa7baSmpi 			tdb->tdb_cur_bytes += obytes;
5369a570b6dSangelos 
5372edaa7baSmpi 		ipipstat_add(ipips_obytes, obytes);
5389a570b6dSangelos 	}
5399a570b6dSangelos #endif /* INET6 */
5409a570b6dSangelos 
5419a570b6dSangelos 	return 0;
5429a570b6dSangelos }
5439a570b6dSangelos 
5449a570b6dSangelos #ifdef IPSEC
5459a570b6dSangelos int
546c799dc6dSnaddy ipe4_attach(void)
5479a570b6dSangelos {
5489a570b6dSangelos 	return 0;
5499a570b6dSangelos }
5509a570b6dSangelos 
5519a570b6dSangelos int
5529a570b6dSangelos ipe4_init(struct tdb *tdbp, struct xformsw *xsp, struct ipsecinit *ii)
5539a570b6dSangelos {
5549a570b6dSangelos 	tdbp->tdb_xform = xsp;
5559a570b6dSangelos 	return 0;
5569a570b6dSangelos }
5579a570b6dSangelos 
5589a570b6dSangelos int
5599a570b6dSangelos ipe4_zeroize(struct tdb *tdbp)
5609a570b6dSangelos {
5619a570b6dSangelos 	return 0;
5629a570b6dSangelos }
5639a570b6dSangelos 
564dde15c32Sbluhm int
565dde15c32Sbluhm ipe4_input(struct mbuf *m, struct tdb *tdb, int hlen, int proto)
5669a570b6dSangelos {
5676593f73dSangelos 	/* This is a rather serious mistake, so no conditional printing. */
5689a570b6dSangelos 	printf("ipe4_input(): should never be called\n");
5699a570b6dSangelos 	m_freem(m);
570dde15c32Sbluhm 	return EINVAL;
5719a570b6dSangelos }
5729a570b6dSangelos #endif	/* IPSEC */
5739a570b6dSangelos 
5749a570b6dSangelos int
57560dafcf9Sjca ipip_sysctl_ipipstat(void *oldp, size_t *oldlenp, void *newp)
57660dafcf9Sjca {
57760dafcf9Sjca 	struct ipipstat ipipstat;
57860dafcf9Sjca 
57960dafcf9Sjca 	CTASSERT(sizeof(ipipstat) == (ipips_ncounters * sizeof(uint64_t)));
580c8915b1eSderaadt 	memset(&ipipstat, 0, sizeof ipipstat);
58160dafcf9Sjca 	counters_read(ipipcounters, (uint64_t *)&ipipstat, ipips_ncounters);
58260dafcf9Sjca 	return (sysctl_rdstruct(oldp, oldlenp, newp,
58360dafcf9Sjca 	    &ipipstat, sizeof(ipipstat)));
58460dafcf9Sjca }
58560dafcf9Sjca 
58660dafcf9Sjca int
5876593f73dSangelos ipip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
5886593f73dSangelos     size_t newlen)
5899a570b6dSangelos {
590df4a15bcSmpi 	int error;
591df4a15bcSmpi 
5929a570b6dSangelos 	/* All sysctl names at this level are terminal. */
5939a570b6dSangelos 	if (namelen != 1)
5949a570b6dSangelos 		return (ENOTDIR);
5959a570b6dSangelos 
5969a570b6dSangelos 	switch (name[0]) {
5979a570b6dSangelos 	case IPIPCTL_ALLOW:
598df4a15bcSmpi 		NET_LOCK();
599*70464ff2Sgnezdo 		error = sysctl_int_bounded(oldp, oldlenp, newp, newlen,
600*70464ff2Sgnezdo 		    &ipip_allow, 0, 2);
601df4a15bcSmpi 		NET_UNLOCK();
602df4a15bcSmpi 		return (error);
603ab46c28dSderaadt 	case IPIPCTL_STATS:
60460dafcf9Sjca 		return (ipip_sysctl_ipipstat(oldp, oldlenp, newp));
6059a570b6dSangelos 	default:
6069a570b6dSangelos 		return (ENOPROTOOPT);
6079a570b6dSangelos 	}
6089a570b6dSangelos 	/* NOTREACHED */
6099a570b6dSangelos }
610