xref: /netbsd-src/sys/netipsec/xform_ipip.c (revision 481d3881954fd794ca5f2d880b68c53a5db8620e)
1*481d3881Srin /*	$NetBSD: xform_ipip.c,v 1.79 2024/07/05 04:31:54 rin Exp $	*/
2e2c8a664Smaxv /*	$FreeBSD: xform_ipip.c,v 1.3.2.1 2003/01/24 05:11:36 sam Exp $	*/
374029031Sjonathan /*	$OpenBSD: ip_ipip.c,v 1.25 2002/06/10 18:04:55 itojun Exp $ */
474029031Sjonathan 
574029031Sjonathan /*
674029031Sjonathan  * The authors of this code are John Ioannidis (ji@tla.org),
774029031Sjonathan  * Angelos D. Keromytis (kermit@csd.uch.gr) and
874029031Sjonathan  * Niels Provos (provos@physnet.uni-hamburg.de).
974029031Sjonathan  *
1074029031Sjonathan  * The original version of this code was written by John Ioannidis
1174029031Sjonathan  * for BSD/OS in Athens, Greece, in November 1995.
1274029031Sjonathan  *
1374029031Sjonathan  * Ported to OpenBSD and NetBSD, with additional transforms, in December 1996,
1474029031Sjonathan  * by Angelos D. Keromytis.
1574029031Sjonathan  *
1674029031Sjonathan  * Additional transforms and features in 1997 and 1998 by Angelos D. Keromytis
1774029031Sjonathan  * and Niels Provos.
1874029031Sjonathan  *
1974029031Sjonathan  * Additional features in 1999 by Angelos D. Keromytis.
2074029031Sjonathan  *
2174029031Sjonathan  * Copyright (C) 1995, 1996, 1997, 1998, 1999 by John Ioannidis,
2274029031Sjonathan  * Angelos D. Keromytis and Niels Provos.
2374029031Sjonathan  * Copyright (c) 2001, Angelos D. Keromytis.
2474029031Sjonathan  *
2574029031Sjonathan  * Permission to use, copy, and modify this software with or without fee
2674029031Sjonathan  * is hereby granted, provided that this entire notice is included in
2774029031Sjonathan  * all copies of any software which is or includes a copy or
2874029031Sjonathan  * modification of this software.
2974029031Sjonathan  * You may use this code under the GNU public license if you so wish. Please
3074029031Sjonathan  * contribute changes back to the authors under this freer than GPL license
3174029031Sjonathan  * so that we may further the use of strong encryption without limitations to
3274029031Sjonathan  * all.
3374029031Sjonathan  *
3474029031Sjonathan  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
3574029031Sjonathan  * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
3674029031Sjonathan  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
3774029031Sjonathan  * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
3874029031Sjonathan  * PURPOSE.
3974029031Sjonathan  */
4074029031Sjonathan 
4174029031Sjonathan #include <sys/cdefs.h>
42*481d3881Srin __KERNEL_RCSID(0, "$NetBSD: xform_ipip.c,v 1.79 2024/07/05 04:31:54 rin Exp $");
4374029031Sjonathan 
4480d40a78Sozaki-r #if defined(_KERNEL_OPT)
4574029031Sjonathan #include "opt_inet.h"
4680d40a78Sozaki-r #endif
4774029031Sjonathan 
48436305f8Smaxv /*
49436305f8Smaxv  * IP-inside-IP processing.
50436305f8Smaxv  *
51436305f8Smaxv  * The input point is encapsw{4,6}, called via the encap callback. The
52436305f8Smaxv  * output point is ipip_output, called directly. XF_IP4 has no more
53436305f8Smaxv  * meaning here, ipe4_xformsw is dummy.
54436305f8Smaxv  */
55436305f8Smaxv 
5674029031Sjonathan #include <sys/param.h>
5774029031Sjonathan #include <sys/systm.h>
5874029031Sjonathan #include <sys/mbuf.h>
5974029031Sjonathan #include <sys/kernel.h>
60e588d95cSriastradh #include <sys/protosw.h>
6174029031Sjonathan 
6274029031Sjonathan #include <net/if.h>
6374029031Sjonathan 
6474029031Sjonathan #include <netinet/in.h>
6574029031Sjonathan #include <netinet/in_systm.h>
6674029031Sjonathan #include <netinet/in_var.h>
6774029031Sjonathan #include <netinet/ip.h>
6874029031Sjonathan #include <netinet/ip_ecn.h>
6974029031Sjonathan #include <netinet/ip_var.h>
7074029031Sjonathan #include <netinet/ip_encap.h>
7174029031Sjonathan 
7274029031Sjonathan #include <netipsec/ipsec.h>
73caf49ea5Sthorpej #include <netipsec/ipsec_private.h>
7474029031Sjonathan #include <netipsec/xform.h>
7574029031Sjonathan 
7674029031Sjonathan #include <netipsec/ipip_var.h>
7774029031Sjonathan 
7874029031Sjonathan #ifdef INET6
7974029031Sjonathan #include <netinet/ip6.h>
8074029031Sjonathan #include <netipsec/ipsec6.h>
8174029031Sjonathan #include <netinet6/in6_var.h>
82e588d95cSriastradh #include <netinet6/ip6protosw.h>
8374029031Sjonathan #endif
8474029031Sjonathan 
859355900eStls #include <netipsec/key.h>
869355900eStls #include <netipsec/key_debug.h>
8774029031Sjonathan 
8874029031Sjonathan /* XXX IPCOMP */
893e02f4faSmaxv #define	M_IPSEC	(M_AUTHIPHDR|M_DECRYPTED)
9074029031Sjonathan 
9148c5ec19Smaxv int ipip_spoofcheck = 1;
92d8dc4e58Smaxv percpu_t *ipipstat_percpu;
93d8dc4e58Smaxv 
94bad5f599Smaxv static void _ipip_input(struct mbuf *, int);
9574029031Sjonathan 
9674029031Sjonathan #ifdef INET6
97a3d9b92cSmaxv static int
ip4_input6(struct mbuf ** m,int * offp,int proto,void * eparg __unused)98fb23bb2cSknakahara ip4_input6(struct mbuf **m, int *offp, int proto, void *eparg __unused)
9974029031Sjonathan {
100bad5f599Smaxv 	_ipip_input(*m, *offp);
10174029031Sjonathan 	return IPPROTO_DONE;
10274029031Sjonathan }
103d8dc4e58Smaxv #endif
10474029031Sjonathan 
10574029031Sjonathan #ifdef INET
106a3d9b92cSmaxv static void
ip4_input(struct mbuf * m,int off,int proto,void * eparg __unused)107fb23bb2cSknakahara ip4_input(struct mbuf *m, int off, int proto, void *eparg __unused)
10874029031Sjonathan {
109bad5f599Smaxv 	_ipip_input(m, off);
11074029031Sjonathan }
111d8dc4e58Smaxv #endif
11274029031Sjonathan 
11374029031Sjonathan /*
114bad5f599Smaxv  * _ipip_input gets called when we receive an IP{46} encapsulated packet,
115bad5f599Smaxv  * because AH or ESP were being used in tunnel mode.
11674029031Sjonathan  */
11774029031Sjonathan static void
_ipip_input(struct mbuf * m,int iphlen)118bad5f599Smaxv _ipip_input(struct mbuf *m, int iphlen)
11974029031Sjonathan {
12074029031Sjonathan 	register struct sockaddr_in *sin;
12174029031Sjonathan 	register struct ifnet *ifp;
12274029031Sjonathan 	register struct ifaddr *ifa;
12360d350cfSrmind 	pktqueue_t *pktq = NULL;
124a0cc5376Smaxv 	struct ip *ip4 = NULL;
12574029031Sjonathan #ifdef INET6
12674029031Sjonathan 	register struct sockaddr_in6 *sin6;
12774029031Sjonathan 	struct ip6_hdr *ip6 = NULL;
1283d6520b3Schristos 	uint8_t itos;
12974029031Sjonathan #endif
1303d6520b3Schristos 	uint8_t otos;
1313d6520b3Schristos 	uint8_t v;
13274029031Sjonathan 	int hlen;
13374029031Sjonathan 
134caf49ea5Sthorpej 	IPIP_STATINC(IPIP_STAT_IPACKETS);
13574029031Sjonathan 
13674029031Sjonathan 	m_copydata(m, 0, 1, &v);
13774029031Sjonathan 
13874029031Sjonathan 	switch (v >> 4) {
13974029031Sjonathan #ifdef INET
14074029031Sjonathan 	case 4:
14174029031Sjonathan 		hlen = sizeof(struct ip);
14274029031Sjonathan 		break;
143d8dc4e58Smaxv #endif
14474029031Sjonathan #ifdef INET6
14574029031Sjonathan 	case 6:
14674029031Sjonathan 		hlen = sizeof(struct ip6_hdr);
14774029031Sjonathan 		break;
14874029031Sjonathan #endif
14974029031Sjonathan 	default:
1504a07f437Schristos 		DPRINTF("bad protocol version 0x%x (%u) "
1514a07f437Schristos 		    "for outer header\n", v, v>>4);
152caf49ea5Sthorpej 		IPIP_STATINC(IPIP_STAT_FAMILY);
15374029031Sjonathan 		m_freem(m);
154d8dc4e58Smaxv 		return;
15574029031Sjonathan 	}
15674029031Sjonathan 
15774029031Sjonathan 	/* Bring the IP header in the first mbuf, if not there already */
15874029031Sjonathan 	if (m->m_len < hlen) {
15974029031Sjonathan 		if ((m = m_pullup(m, hlen)) == NULL) {
1604a07f437Schristos 			DPRINTF("m_pullup (1) failed\n");
161caf49ea5Sthorpej 			IPIP_STATINC(IPIP_STAT_HDROPS);
16274029031Sjonathan 			return;
16374029031Sjonathan 		}
16474029031Sjonathan 	}
16574029031Sjonathan 
16674029031Sjonathan 	/* Keep outer ecn field. */
16774029031Sjonathan 	switch (v >> 4) {
16874029031Sjonathan #ifdef INET
16974029031Sjonathan 	case 4:
170a0cc5376Smaxv 		otos = mtod(m, struct ip *)->ip_tos;
17174029031Sjonathan 		break;
172d8dc4e58Smaxv #endif
17374029031Sjonathan #ifdef INET6
17474029031Sjonathan 	case 6:
17574029031Sjonathan 		otos = (ntohl(mtod(m, struct ip6_hdr *)->ip6_flow) >> 20) & 0xff;
17674029031Sjonathan 		break;
17774029031Sjonathan #endif
17874029031Sjonathan 	default:
179bad5f599Smaxv 		panic("%s: impossible (1)", __func__);
18074029031Sjonathan 	}
18174029031Sjonathan 
18274029031Sjonathan 	/* Remove outer IP header */
18374029031Sjonathan 	m_adj(m, iphlen);
18474029031Sjonathan 
18574029031Sjonathan 	/* Sanity check */
18674029031Sjonathan 	if (m->m_pkthdr.len < sizeof(struct ip))  {
187caf49ea5Sthorpej 		IPIP_STATINC(IPIP_STAT_HDROPS);
18874029031Sjonathan 		m_freem(m);
18974029031Sjonathan 		return;
19074029031Sjonathan 	}
19174029031Sjonathan 
19274029031Sjonathan 	m_copydata(m, 0, 1, &v);
19374029031Sjonathan 
19474029031Sjonathan 	switch (v >> 4) {
19574029031Sjonathan #ifdef INET
19674029031Sjonathan 	case 4:
19774029031Sjonathan 		hlen = sizeof(struct ip);
19879a77859Smaxv 		pktq = ip_pktq;
19974029031Sjonathan 		break;
200d8dc4e58Smaxv #endif
20174029031Sjonathan #ifdef INET6
20274029031Sjonathan 	case 6:
20374029031Sjonathan 		hlen = sizeof(struct ip6_hdr);
20479a77859Smaxv 		pktq = ip6_pktq;
20574029031Sjonathan 		break;
20674029031Sjonathan #endif
20774029031Sjonathan 	default:
2084a07f437Schristos 		DPRINTF("bad protocol version %#x (%u) "
2094a07f437Schristos 		    "for inner header\n", v, v >> 4);
210caf49ea5Sthorpej 		IPIP_STATINC(IPIP_STAT_FAMILY);
21174029031Sjonathan 		m_freem(m);
212d8dc4e58Smaxv 		return;
21374029031Sjonathan 	}
21474029031Sjonathan 
21574029031Sjonathan 	/*
21674029031Sjonathan 	 * Bring the inner IP header in the first mbuf, if not there already.
21774029031Sjonathan 	 */
21874029031Sjonathan 	if (m->m_len < hlen) {
21974029031Sjonathan 		if ((m = m_pullup(m, hlen)) == NULL) {
2204a07f437Schristos 			DPRINTF("m_pullup (2) failed\n");
221caf49ea5Sthorpej 			IPIP_STATINC(IPIP_STAT_HDROPS);
22274029031Sjonathan 			return;
22374029031Sjonathan 		}
22474029031Sjonathan 	}
22574029031Sjonathan 
22674029031Sjonathan 	/*
22774029031Sjonathan 	 * RFC 1853 specifies that the inner TTL should not be touched on
22874029031Sjonathan 	 * decapsulation. There's no reason this comment should be here, but
22974029031Sjonathan 	 * this is as good as any a position.
23074029031Sjonathan 	 */
23174029031Sjonathan 
23274029031Sjonathan 	/* Some sanity checks in the inner IP header */
23374029031Sjonathan 	switch (v >> 4) {
23474029031Sjonathan #ifdef INET
23574029031Sjonathan 	case 4:
236a0cc5376Smaxv 		ip4 = mtod(m, struct ip *);
237a0cc5376Smaxv 		ip_ecn_egress(ip4_ipsec_ecn, &otos, &ip4->ip_tos);
23874029031Sjonathan 		break;
239d8dc4e58Smaxv #endif
24074029031Sjonathan #ifdef INET6
24174029031Sjonathan 	case 6:
242715fe7f3Smaxv 		ip6 = mtod(m, struct ip6_hdr *);
24374029031Sjonathan 		itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
24474029031Sjonathan 		ip_ecn_egress(ip6_ipsec_ecn, &otos, &itos);
24574029031Sjonathan 		ip6->ip6_flow &= ~htonl(0xff << 20);
2463d6520b3Schristos 		ip6->ip6_flow |= htonl((uint32_t)itos << 20);
24774029031Sjonathan 		break;
24874029031Sjonathan #endif
24974029031Sjonathan 	default:
250bad5f599Smaxv 		panic("%s: impossible (2)", __func__);
25174029031Sjonathan 	}
25274029031Sjonathan 
25374029031Sjonathan 	/* Check for local address spoofing. */
254fe6d4275Sozaki-r 	if ((m_get_rcvif_NOMPSAFE(m) == NULL ||
255fe6d4275Sozaki-r 	    !(m_get_rcvif_NOMPSAFE(m)->if_flags & IFF_LOOPBACK)) &&
25648c5ec19Smaxv 	    ipip_spoofcheck) {
257040205aeSozaki-r 		int s = pserialize_read_enter();
258040205aeSozaki-r 		IFNET_READER_FOREACH(ifp) {
2599e4c2bdaSozaki-r 			IFADDR_READER_FOREACH(ifa, ifp) {
26074029031Sjonathan #ifdef INET
261a0cc5376Smaxv 				if (ip4) {
26274029031Sjonathan 					if (ifa->ifa_addr->sa_family !=
26374029031Sjonathan 					    AF_INET)
26474029031Sjonathan 						continue;
26574029031Sjonathan 
26674029031Sjonathan 					sin = (struct sockaddr_in *)ifa->ifa_addr;
26774029031Sjonathan 
26874029031Sjonathan 					if (sin->sin_addr.s_addr ==
269a0cc5376Smaxv 					    ip4->ip_src.s_addr)	{
270040205aeSozaki-r 						pserialize_read_exit(s);
271caf49ea5Sthorpej 						IPIP_STATINC(IPIP_STAT_SPOOF);
27274029031Sjonathan 						m_freem(m);
27374029031Sjonathan 						return;
27474029031Sjonathan 					}
27574029031Sjonathan 				}
2761e45b2f1Smaxv #endif
27774029031Sjonathan 
27874029031Sjonathan #ifdef INET6
27974029031Sjonathan 				if (ip6) {
28074029031Sjonathan 					if (ifa->ifa_addr->sa_family !=
28174029031Sjonathan 					    AF_INET6)
28274029031Sjonathan 						continue;
28374029031Sjonathan 
28474029031Sjonathan 					sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
28574029031Sjonathan 
28674029031Sjonathan 					if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &ip6->ip6_src)) {
287040205aeSozaki-r 						pserialize_read_exit(s);
288caf49ea5Sthorpej 						IPIP_STATINC(IPIP_STAT_SPOOF);
28974029031Sjonathan 						m_freem(m);
29074029031Sjonathan 						return;
29174029031Sjonathan 					}
29274029031Sjonathan 
29374029031Sjonathan 				}
2941e45b2f1Smaxv #endif
29574029031Sjonathan 			}
29674029031Sjonathan 		}
297040205aeSozaki-r 		pserialize_read_exit(s);
29874029031Sjonathan 	}
29974029031Sjonathan 
3007c3a8f9aSmaxv 	/* Statistics: m->m_pkthdr.len is the length of the inner packet */
3017c3a8f9aSmaxv 	IPIP_STATADD(IPIP_STAT_IBYTES, m->m_pkthdr.len);
30274029031Sjonathan 
30374029031Sjonathan 	/*
30474029031Sjonathan 	 * Interface pointer stays the same; if no IPsec processing has
30574029031Sjonathan 	 * been done (or will be done), this will point to a normal
30674029031Sjonathan 	 * interface. Otherwise, it'll point to an enc interface, which
30774029031Sjonathan 	 * will allow a packet filter to distinguish between secure and
30874029031Sjonathan 	 * untrusted packets.
30974029031Sjonathan 	 */
31074029031Sjonathan 
31160d350cfSrmind 	int s = splnet();
31260d350cfSrmind 	if (__predict_false(!pktq_enqueue(pktq, m, 0))) {
313caf49ea5Sthorpej 		IPIP_STATINC(IPIP_STAT_QFULL);
31460d350cfSrmind 		m_freem(m);
31574029031Sjonathan 	}
31660d350cfSrmind 	splx(s);
31774029031Sjonathan }
31874029031Sjonathan 
31974029031Sjonathan int
ipip_output(struct mbuf * m,struct secasvar * sav,struct mbuf ** mp)32020668b06Smaxv ipip_output(struct mbuf *m, struct secasvar *sav, struct mbuf **mp)
32174029031Sjonathan {
322dd8c81f5Sryo 	char buf[IPSEC_ADDRSTRLEN];
3233d6520b3Schristos 	uint8_t tp, otos;
32474029031Sjonathan 	struct secasindex *saidx;
325f281f715Smaxv 	int error, iphlen;
32674029031Sjonathan #ifdef INET
3273d6520b3Schristos 	uint8_t itos;
32874029031Sjonathan 	struct ip *ipo;
329d8dc4e58Smaxv #endif
33074029031Sjonathan #ifdef INET6
33174029031Sjonathan 	struct ip6_hdr *ip6, *ip6o;
332d8dc4e58Smaxv #endif
33374029031Sjonathan 
33438b8f795Sozaki-r 	KASSERT(sav != NULL);
33574029031Sjonathan 
33674029031Sjonathan 	/* XXX Deal with empty TDB source/destination addresses. */
33774029031Sjonathan 
33874029031Sjonathan 	m_copydata(m, 0, 1, &tp);
33974029031Sjonathan 	tp = (tp >> 4) & 0xff;  /* Get the IP version number. */
34074029031Sjonathan 
34174029031Sjonathan 	saidx = &sav->sah->saidx;
34274029031Sjonathan 	switch (saidx->dst.sa.sa_family) {
34374029031Sjonathan #ifdef INET
34474029031Sjonathan 	case AF_INET:
34574029031Sjonathan 		if (saidx->src.sa.sa_family != AF_INET ||
34674029031Sjonathan 		    saidx->src.sin.sin_addr.s_addr == INADDR_ANY ||
34774029031Sjonathan 		    saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) {
3484a07f437Schristos 			DPRINTF("unspecified tunnel endpoint "
3494a07f437Schristos 			    "address in SA %s/%08lx\n",
350dd8c81f5Sryo 			    ipsec_address(&saidx->dst, buf, sizeof(buf)),
3514a07f437Schristos 			    (u_long)ntohl(sav->spi));
352caf49ea5Sthorpej 			IPIP_STATINC(IPIP_STAT_UNSPEC);
35374029031Sjonathan 			error = EINVAL;
35474029031Sjonathan 			goto bad;
35574029031Sjonathan 		}
35674029031Sjonathan 
35774029031Sjonathan 		M_PREPEND(m, sizeof(struct ip), M_DONTWAIT);
358d8dc4e58Smaxv 		if (m == NULL) {
3594a07f437Schristos 			DPRINTF("M_PREPEND failed\n");
360caf49ea5Sthorpej 			IPIP_STATINC(IPIP_STAT_HDROPS);
36174029031Sjonathan 			error = ENOBUFS;
36274029031Sjonathan 			goto bad;
36374029031Sjonathan 		}
36474029031Sjonathan 
365f281f715Smaxv 		iphlen = sizeof(struct ip);
36674029031Sjonathan 
367f281f715Smaxv 		ipo = mtod(m, struct ip *);
36874029031Sjonathan 		ipo->ip_v = IPVERSION;
36974029031Sjonathan 		ipo->ip_hl = 5;
37074029031Sjonathan 		ipo->ip_len = htons(m->m_pkthdr.len);
37174029031Sjonathan 		ipo->ip_ttl = ip_defttl;
37274029031Sjonathan 		ipo->ip_sum = 0;
37374029031Sjonathan 		ipo->ip_src = saidx->src.sin.sin_addr;
37474029031Sjonathan 		ipo->ip_dst = saidx->dst.sin.sin_addr;
375f3f9c5b3Sdegroote 		ipo->ip_id = ip_newid(NULL);
37674029031Sjonathan 
37774029031Sjonathan 		/* If the inner protocol is IP... */
37874029031Sjonathan 		if (tp == IPVERSION) {
37974029031Sjonathan 			/* Save ECN notification */
38074029031Sjonathan 			m_copydata(m, sizeof(struct ip) +
38174029031Sjonathan 			    offsetof(struct ip, ip_tos),
3823d6520b3Schristos 			    sizeof(uint8_t), &itos);
38374029031Sjonathan 
38474029031Sjonathan 			ipo->ip_p = IPPROTO_IPIP;
38574029031Sjonathan 
38674029031Sjonathan 			/*
38774029031Sjonathan 			 * We should be keeping tunnel soft-state and
38874029031Sjonathan 			 * send back ICMPs if needed.
38974029031Sjonathan 			 */
39074029031Sjonathan 			m_copydata(m, sizeof(struct ip) +
39174029031Sjonathan 			    offsetof(struct ip, ip_off),
3923d6520b3Schristos 			    sizeof(uint16_t), &ipo->ip_off);
393ef67739aSozaki-r 			ipo->ip_off &= ~ htons(IP_DF | IP_MF | IP_OFFMASK);
39474029031Sjonathan 		}
39574029031Sjonathan #ifdef INET6
39674029031Sjonathan 		else if (tp == (IPV6_VERSION >> 4)) {
3973d6520b3Schristos 			uint32_t itos32;
39874029031Sjonathan 
39974029031Sjonathan 			/* Save ECN notification. */
40074029031Sjonathan 			m_copydata(m, sizeof(struct ip) +
40174029031Sjonathan 			    offsetof(struct ip6_hdr, ip6_flow),
4023d6520b3Schristos 			    sizeof(uint32_t), &itos32);
40374029031Sjonathan 			itos = ntohl(itos32) >> 20;
40474029031Sjonathan 			ipo->ip_p = IPPROTO_IPV6;
40574029031Sjonathan 			ipo->ip_off = 0;
40674029031Sjonathan 		}
4071e45b2f1Smaxv #endif
40874029031Sjonathan 		else {
40974029031Sjonathan 			goto nofamily;
41074029031Sjonathan 		}
41174029031Sjonathan 
41274029031Sjonathan 		otos = 0;
41374029031Sjonathan 		ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
41474029031Sjonathan 		ipo->ip_tos = otos;
41574029031Sjonathan 		break;
41674029031Sjonathan #endif /* INET */
41774029031Sjonathan 
41874029031Sjonathan #ifdef INET6
41974029031Sjonathan 	case AF_INET6:
42074029031Sjonathan 		if (IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr) ||
42174029031Sjonathan 		    saidx->src.sa.sa_family != AF_INET6 ||
42274029031Sjonathan 		    IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr)) {
4234a07f437Schristos 			DPRINTF("unspecified tunnel endpoint "
4244a07f437Schristos 			    "address in SA %s/%08lx\n",
425dd8c81f5Sryo 			    ipsec_address(&saidx->dst, buf, sizeof(buf)),
4264a07f437Schristos 			    (u_long)ntohl(sav->spi));
427caf49ea5Sthorpej 			IPIP_STATINC(IPIP_STAT_UNSPEC);
42874029031Sjonathan 			error = ENOBUFS;
42974029031Sjonathan 			goto bad;
43074029031Sjonathan 		}
43174029031Sjonathan 
432a46f4db6Sdrochner 		if (tp == (IPV6_VERSION >> 4)) {
43374029031Sjonathan 			/* scoped address handling */
43474029031Sjonathan 			ip6 = mtod(m, struct ip6_hdr *);
43574029031Sjonathan 			if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
43674029031Sjonathan 				ip6->ip6_src.s6_addr16[1] = 0;
43774029031Sjonathan 			if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
43874029031Sjonathan 				ip6->ip6_dst.s6_addr16[1] = 0;
439a46f4db6Sdrochner 		}
44074029031Sjonathan 
44174029031Sjonathan 		M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
442d8dc4e58Smaxv 		if (m == NULL) {
4434a07f437Schristos 			DPRINTF("M_PREPEND failed\n");
444caf49ea5Sthorpej 			IPIP_STATINC(IPIP_STAT_HDROPS);
44574029031Sjonathan 			error = ENOBUFS;
44674029031Sjonathan 			goto bad;
44774029031Sjonathan 		}
44874029031Sjonathan 
449f281f715Smaxv 		iphlen = sizeof(struct ip6_hdr);
450f281f715Smaxv 
45174029031Sjonathan 		/* Initialize IPv6 header */
45274029031Sjonathan 		ip6o = mtod(m, struct ip6_hdr *);
45374029031Sjonathan 		ip6o->ip6_flow = 0;
45474029031Sjonathan 		ip6o->ip6_vfc &= ~IPV6_VERSION_MASK;
45574029031Sjonathan 		ip6o->ip6_vfc |= IPV6_VERSION;
4564a345c31Schristos 		ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6o));
45774029031Sjonathan 		ip6o->ip6_hlim = ip_defttl;
45874029031Sjonathan 		ip6o->ip6_dst = saidx->dst.sin6.sin6_addr;
45974029031Sjonathan 		ip6o->ip6_src = saidx->src.sin6.sin6_addr;
460a46f4db6Sdrochner 		if (IN6_IS_SCOPE_LINKLOCAL(&ip6o->ip6_dst))
461a46f4db6Sdrochner 			ip6o->ip6_dst.s6_addr16[1] = htons(saidx->dst.sin6.sin6_scope_id);
462a46f4db6Sdrochner 		if (IN6_IS_SCOPE_LINKLOCAL(&ip6o->ip6_src))
463a46f4db6Sdrochner 			ip6o->ip6_src.s6_addr16[1] = htons(saidx->src.sin6.sin6_scope_id);
46474029031Sjonathan 
46574029031Sjonathan #ifdef INET
46674029031Sjonathan 		if (tp == IPVERSION) {
46774029031Sjonathan 			/* Save ECN notification */
46874029031Sjonathan 			m_copydata(m, sizeof(struct ip6_hdr) +
4693d6520b3Schristos 			    offsetof(struct ip, ip_tos), sizeof(uint8_t),
470dd86ba72Sdegroote 			    &itos);
47174029031Sjonathan 
47274029031Sjonathan 			/* This is really IPVERSION. */
47374029031Sjonathan 			ip6o->ip6_nxt = IPPROTO_IPIP;
47474029031Sjonathan 		} else
4751e45b2f1Smaxv #endif
47674029031Sjonathan 		if (tp == (IPV6_VERSION >> 4)) {
4773d6520b3Schristos 			uint32_t itos32;
47874029031Sjonathan 
47974029031Sjonathan 			/* Save ECN notification. */
48074029031Sjonathan 			m_copydata(m, sizeof(struct ip6_hdr) +
48174029031Sjonathan 			    offsetof(struct ip6_hdr, ip6_flow),
4823d6520b3Schristos 			    sizeof(uint32_t), &itos32);
48374029031Sjonathan 			itos = ntohl(itos32) >> 20;
48474029031Sjonathan 
48574029031Sjonathan 			ip6o->ip6_nxt = IPPROTO_IPV6;
48674029031Sjonathan 		} else {
48774029031Sjonathan 			goto nofamily;
48874029031Sjonathan 		}
48974029031Sjonathan 
49074029031Sjonathan 		otos = 0;
49174029031Sjonathan 		ip_ecn_ingress(ECN_ALLOWED, &otos, &itos);
4923d6520b3Schristos 		ip6o->ip6_flow |= htonl((uint32_t)otos << 20);
49374029031Sjonathan 		break;
49474029031Sjonathan #endif /* INET6 */
49574029031Sjonathan 
49674029031Sjonathan 	default:
49774029031Sjonathan nofamily:
4984a07f437Schristos 		DPRINTF("unsupported protocol family %u\n",
4994a07f437Schristos 		    saidx->dst.sa.sa_family);
500caf49ea5Sthorpej 		IPIP_STATINC(IPIP_STAT_FAMILY);
501f281f715Smaxv 		error = EAFNOSUPPORT;
50274029031Sjonathan 		goto bad;
50374029031Sjonathan 	}
50474029031Sjonathan 
505caf49ea5Sthorpej 	IPIP_STATINC(IPIP_STAT_OPACKETS);
506f281f715Smaxv 	IPIP_STATADD(IPIP_STAT_OBYTES, m->m_pkthdr.len - iphlen);
507f281f715Smaxv 
50874029031Sjonathan 	*mp = m;
50974029031Sjonathan 	return 0;
510d8dc4e58Smaxv 
51174029031Sjonathan bad:
512f8d2d740Sscw 	m_freem(m);
513f8d2d740Sscw 	*mp = NULL;
514d8dc4e58Smaxv 	return error;
51574029031Sjonathan }
51674029031Sjonathan 
517e2211411Sdegroote #ifdef INET
518b546d527Sknakahara static struct encapsw ipe4_encapsw = {
519b546d527Sknakahara 	.encapsw4 = {
520e588d95cSriastradh 		.pr_input = ip4_input,
521b546d527Sknakahara 		.pr_ctlinput = NULL,
522b546d527Sknakahara 	}
52374029031Sjonathan };
524e2211411Sdegroote #endif
525e2211411Sdegroote #ifdef INET6
526b546d527Sknakahara static struct encapsw ipe4_encapsw6 = {
527b546d527Sknakahara 	.encapsw6 = {
528e588d95cSriastradh 		.pr_input = ip4_input6,
529b546d527Sknakahara 		.pr_ctlinput = NULL,
530b546d527Sknakahara 	}
531e2211411Sdegroote };
532e2211411Sdegroote #endif
533e2211411Sdegroote 
53474029031Sjonathan /*
53574029031Sjonathan  * Check the encapsulated packet to see if we want it
53674029031Sjonathan  */
53774029031Sjonathan static int
ipe4_encapcheck(struct mbuf * m,int off,int proto,void * arg)538d8dc4e58Smaxv ipe4_encapcheck(struct mbuf *m, int off, int proto, void *arg)
53974029031Sjonathan {
54074029031Sjonathan 	/*
54174029031Sjonathan 	 * Only take packets coming from IPSEC tunnels; the rest
54274029031Sjonathan 	 * must be handled by the gif tunnel code.  Note that we
54374029031Sjonathan 	 * also return a minimum priority when we want the packet
54474029031Sjonathan 	 * so any explicit gif tunnels take precedence.
54574029031Sjonathan 	 */
54674029031Sjonathan 	return ((m->m_flags & M_IPSEC) != 0 ? 1 : 0);
54774029031Sjonathan }
54874029031Sjonathan 
549a3d9b92cSmaxv /* -------------------------------------------------------------------------- */
550a3d9b92cSmaxv 
551a3d9b92cSmaxv static int
ipe4_init(struct secasvar * sav,const struct xformsw * xsp)552a3d9b92cSmaxv ipe4_init(struct secasvar *sav, const struct xformsw *xsp)
553a3d9b92cSmaxv {
554a3d9b92cSmaxv 	sav->tdb_xform = xsp;
555a3d9b92cSmaxv 	return 0;
556a3d9b92cSmaxv }
557a3d9b92cSmaxv 
55856192e56Sriastradh static void
ipe4_zeroize(struct secasvar * sav)559a3d9b92cSmaxv ipe4_zeroize(struct secasvar *sav)
560a3d9b92cSmaxv {
561a3d9b92cSmaxv 	sav->tdb_xform = NULL;
562a3d9b92cSmaxv }
563a3d9b92cSmaxv 
564a3d9b92cSmaxv static int
ipe4_input(struct mbuf * m,struct secasvar * sav,int skip,int protoff)565a3d9b92cSmaxv ipe4_input(struct mbuf *m, struct secasvar *sav, int skip, int protoff)
566a3d9b92cSmaxv {
567a3d9b92cSmaxv 	/* This is a rather serious mistake, so no conditional printing. */
5684a07f437Schristos 	printf("should never be called\n");
569a3d9b92cSmaxv 	m_freem(m);
570a3d9b92cSmaxv 	return EOPNOTSUPP;
571a3d9b92cSmaxv }
572a3d9b92cSmaxv 
573a3d9b92cSmaxv static int
ipe4_output(struct mbuf * m,const struct ipsecrequest * isr,struct secasvar * sav,int skip,int protoff,int flags)574a3d9b92cSmaxv ipe4_output(struct mbuf *m, const struct ipsecrequest *isr,
575c535599fSknakahara     struct secasvar *sav, int skip, int protoff, int flags)
576a3d9b92cSmaxv {
577a3d9b92cSmaxv 	panic("%s: should not have been called", __func__);
578a3d9b92cSmaxv }
579a3d9b92cSmaxv 
580a3d9b92cSmaxv static struct xformsw ipe4_xformsw = {
581a3d9b92cSmaxv 	.xf_type	= XF_IP4,
582a3d9b92cSmaxv 	.xf_flags	= 0,
583a3d9b92cSmaxv 	.xf_name	= "IPv4 Simple Encapsulation",
584a3d9b92cSmaxv 	.xf_init	= ipe4_init,
585a3d9b92cSmaxv 	.xf_zeroize	= ipe4_zeroize,
586a3d9b92cSmaxv 	.xf_input	= ipe4_input,
587a3d9b92cSmaxv 	.xf_output	= ipe4_output,
588a3d9b92cSmaxv 	.xf_next	= NULL,
589a3d9b92cSmaxv };
590a3d9b92cSmaxv 
591a3d9b92cSmaxv /* -------------------------------------------------------------------------- */
592a3d9b92cSmaxv 
593ef67739aSozaki-r void
ipe4_attach(void)59474029031Sjonathan ipe4_attach(void)
59574029031Sjonathan {
596caf49ea5Sthorpej 
597caf49ea5Sthorpej 	ipipstat_percpu = percpu_alloc(sizeof(uint64_t) * IPIP_NSTATS);
598caf49ea5Sthorpej 
59974029031Sjonathan 	xform_register(&ipe4_xformsw);
60074029031Sjonathan 	/* attach to encapsulation framework */
60174029031Sjonathan 	/* XXX save return cookie for detach on module remove */
602c544c867Sknakahara 
603c544c867Sknakahara 	encapinit();
604c544c867Sknakahara 	/* This function is called before ifinit(). Who else gets lock? */
605c544c867Sknakahara 	(void)encap_lock_enter();
606b71542e5Sknakahara 	/* ipe4_encapsw and ipe4_encapsw must be added atomically */
607e2211411Sdegroote #ifdef INET
608d8dc4e58Smaxv 	(void)encap_attach_func(AF_INET, -1, ipe4_encapcheck, &ipe4_encapsw,
609d8dc4e58Smaxv 	    NULL);
610e2211411Sdegroote #endif
61174029031Sjonathan #ifdef INET6
612d8dc4e58Smaxv 	(void)encap_attach_func(AF_INET6, -1, ipe4_encapcheck, &ipe4_encapsw6,
613d8dc4e58Smaxv 	    NULL);
61474029031Sjonathan #endif
615b71542e5Sknakahara 	encap_lock_exit();
61674029031Sjonathan }
617