ipsec_output.c revision 159965
1125461Speter/*-
2125461Speter * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
3125461Speter * All rights reserved.
4125461Speter *
5125461Speter * Redistribution and use in source and binary forms, with or without
6125984Sobrien * modification, are permitted provided that the following conditions
7125461Speter * are met:
8125461Speter * 1. Redistributions of source code must retain the above copyright
9125461Speter *    notice, this list of conditions and the following disclaimer.
10125461Speter * 2. Redistributions in binary form must reproduce the above copyright
11126929Speter *    notice, this list of conditions and the following disclaimer in the
12147687Speter *    documentation and/or other materials provided with the distribution.
13125461Speter *
14209313Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15209313Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16209313Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17209313Skib * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18209313Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19209313Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20284227Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21284227Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22284227Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23284227Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24284227Sbr * SUCH DAMAGE.
25284227Sbr *
26284227Sbr * $FreeBSD: head/sys/netipsec/ipsec_output.c 159965 2006-06-26 22:30:08Z thompsa $
27284227Sbr */
28284227Sbr
29284227Sbr/*
30284227Sbr * IPsec output processing.
31284227Sbr */
32284227Sbr#include "opt_inet.h"
33284227Sbr#include "opt_inet6.h"
34284227Sbr#include "opt_ipsec.h"
35284227Sbr#include "opt_enc.h"
36125461Speter
37126541Sobrien#include <sys/param.h>
38126541Sobrien#include <sys/systm.h>
39126541Sobrien#include <sys/mbuf.h>
40126541Sobrien#include <sys/domain.h>
41126541Sobrien#include <sys/protosw.h>
42147378Sups#include <sys/socket.h>
43147378Sups#include <sys/errno.h>
44125461Speter#include <sys/syslog.h>
45126541Sobrien
46147378Sups#include <net/if.h>
47126638Sobrien#include <net/route.h>
48126637Sobrien
49126541Sobrien#include <netinet/in.h>
50142732Sobrien#include <netinet/in_systm.h>
51142732Sobrien#include <netinet/ip.h>
52142732Sobrien#include <netinet/ip_var.h>
53142732Sobrien#include <netinet/in_var.h>
54142732Sobrien#include <netinet/ip_ecn.h>
55209248Smav#ifdef INET6
56209248Smav#include <netinet6/ip6_ecn.h>
57209248Smav#endif
58209248Smav
59145727Sdwhite#include <netinet/ip6.h>
60209248Smav#ifdef INET6
61126541Sobrien#include <netinet6/ip6_var.h>
62126541Sobrien#endif
63126541Sobrien#include <netinet/in_pcb.h>
64126541Sobrien#ifdef INET6
65125461Speter#include <netinet/icmp6.h>
66126541Sobrien#endif
67126541Sobrien
68126541Sobrien#include <netipsec/ipsec.h>
69126541Sobrien#ifdef INET6
70126541Sobrien#include <netipsec/ipsec6.h>
71126541Sobrien#endif
72126541Sobrien#include <netipsec/ah_var.h>
73126541Sobrien#include <netipsec/esp_var.h>
74126541Sobrien#include <netipsec/ipcomp_var.h>
75126541Sobrien
76126541Sobrien#include <netipsec/xform.h>
77125461Speter
78125461Speter#include <netipsec/key.h>
79125461Speter#include <netipsec/keydb.h>
80126541Sobrien#include <netipsec/key_debug.h>
81125461Speter
82125461Speter#include <machine/in_cksum.h>
83125461Speter
84125461Speterint
85125461Speteripsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
86125461Speter{
87125461Speter	struct tdb_ident *tdbi;
88125461Speter	struct m_tag *mtag;
89125461Speter	struct secasvar *sav;
90125461Speter	struct secasindex *saidx;
91126541Sobrien	int error;
92125461Speter
93125461Speter	IPSEC_SPLASSERT_SOFTNET(__func__);
94125461Speter
95151051Sglebius	IPSEC_ASSERT(m != NULL, ("null mbuf"));
96151051Sglebius	IPSEC_ASSERT(isr != NULL, ("null ISR"));
97151051Sglebius	sav = isr->sav;
98151051Sglebius	IPSEC_ASSERT(sav != NULL, ("null SA"));
99125461Speter	IPSEC_ASSERT(sav->sah != NULL, ("null SAH"));
100126541Sobrien
101126541Sobrien	saidx = &sav->sah->saidx;
102125461Speter	switch (saidx->dst.sa.sa_family) {
103125461Speter#ifdef INET
104125461Speter	case AF_INET:
105177586Sjkim		/* Fix the header length, for AH processing. */
106177586Sjkim		mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
107191954Skuriyama		break;
108177586Sjkim#endif /* INET */
109234183Sjhb#ifdef INET6
110234183Sjhb	case AF_INET6:
111234183Sjhb		/* Fix the header length, for AH processing. */
112234183Sjhb		if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
113234183Sjhb			error = ENXIO;
114234183Sjhb			goto bad;
115234183Sjhb		}
116234183Sjhb		if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
117239771Sjhb			/* No jumbogram support. */
118234183Sjhb			error = ENXIO;	/*?*/
119234183Sjhb			goto bad;
120234183Sjhb		}
121234183Sjhb		mtod(m, struct ip6_hdr *)->ip6_plen =
122125461Speter			htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
123125461Speter		break;
124125461Speter#endif /* INET6 */
125125461Speter	default:
126173160Speter		DPRINTF(("%s: unknown protocol family %u\n", __func__,
127173160Speter		    saidx->dst.sa.sa_family));
128173160Speter		error = ENXIO;
129125461Speter		goto bad;
130125461Speter	}
131125461Speter
132125461Speter	/*
133152306Sru	 * Add a record of what we've done or what needs to be done to the
134152306Sru	 * packet.
135152306Sru	 */
136126541Sobrien	mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE,
137125461Speter			sizeof(struct tdb_ident), M_NOWAIT);
138125461Speter	if (mtag == NULL) {
139125461Speter		DPRINTF(("%s: could not get packet tag\n", __func__));
140125461Speter		error = ENOMEM;
141125461Speter		goto bad;
142125461Speter	}
143125461Speter
144125461Speter	tdbi = (struct tdb_ident *)(mtag + 1);
145125461Speter	tdbi->dst = saidx->dst;
146125461Speter	tdbi->proto = saidx->proto;
147125461Speter	tdbi->spi = sav->spi;
148125461Speter	m_tag_prepend(m, mtag);
149125461Speter
150125461Speter	/*
151125461Speter	 * If there's another (bundled) SA to apply, do so.
152125461Speter	 * Note that this puts a burden on the kernel stack size.
153125461Speter	 * If this is a problem we'll need to introduce a queue
154125461Speter	 * to set the packet on so we can unwind the stack before
155125461Speter	 * doing further processing.
156125461Speter	 */
157125461Speter	if (isr->next) {
158125461Speter		newipsecstat.ips_out_bundlesa++;
159125461Speter		return ipsec4_process_packet(m, isr->next, 0, 0);
160125461Speter	}
161125461Speter	key_sa_recordxfer(sav, m);		/* record data transfer */
162125461Speter
163125461Speter	/*
164125461Speter	 * We're done with IPsec processing, transmit the packet using the
165125461Speter	 * appropriate network protocol (IP or IPv6). SPD lookup will be
166125461Speter	 * performed again there.
167125461Speter	 */
168125461Speter	switch (saidx->dst.sa.sa_family) {
169125461Speter#ifdef INET
170125461Speter	struct ip *ip;
171125461Speter	case AF_INET:
172125461Speter		ip = mtod(m, struct ip *);
173126541Sobrien		ip->ip_len = ntohs(ip->ip_len);
174126541Sobrien		ip->ip_off = ntohs(ip->ip_off);
175126541Sobrien
176125461Speter		return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL);
177125461Speter#endif /* INET */
178125461Speter#ifdef INET6
179125461Speter	case AF_INET6:
180125461Speter		/*
181125461Speter		 * We don't need massage, IPv6 header fields are always in
182125461Speter		 * net endian.
183188247Swkoszek		 */
184188247Swkoszek		return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
185188247Swkoszek#endif /* INET6 */
186191954Skuriyama	}
187188247Swkoszek	panic("ipsec_process_done");
188125461Speterbad:
189125461Speter	m_freem(m);
190125461Speter	KEY_FREESAV(&sav);
191125461Speter	return (error);
192197380Sdelphij}
193197025Sdelphij
194197025Sdelphijstatic struct ipsecrequest *
195197025Sdelphijipsec_nextisr(
196197025Sdelphij	struct mbuf *m,
197197025Sdelphij	struct ipsecrequest *isr,
198197397Sdelphij	int af,
199197397Sdelphij	struct secasindex *saidx,
200197397Sdelphij	int *error
201263301Simp)
202197397Sdelphij{
203125461Speter#define IPSEC_OSTAT(x,y,z) (isr->saidx.proto == IPPROTO_ESP ? (x)++ : \
204125461Speter			    isr->saidx.proto == IPPROTO_AH ? (y)++ : (z)++)
205125461Speter	struct secasvar *sav;
206125461Speter
207163535Sdes	IPSEC_SPLASSERT_SOFTNET(__func__);
208163535Sdes	IPSECREQUEST_LOCK_ASSERT(isr);
209163535Sdes
210163535Sdes	IPSEC_ASSERT(af == AF_INET || af == AF_INET6,
211163535Sdes		("invalid address family %u", af));
212163535Sdesagain:
213163535Sdes	/*
214163535Sdes	 * Craft SA index to search for proper SA.  Note that
215163535Sdes	 * we only fillin unspecified SA peers for transport
216163535Sdes	 * mode; for tunnel mode they must already be filled in.
217163535Sdes	 */
218163535Sdes	*saidx = isr->saidx;
219163535Sdes	if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
220163535Sdes		/* Fillin unspecified SA peers only for transport mode */
221163535Sdes		if (af == AF_INET) {
222163535Sdes			struct sockaddr_in *sin;
223163535Sdes			struct ip *ip = mtod(m, struct ip *);
224163535Sdes
225163535Sdes			if (saidx->src.sa.sa_len == 0) {
226163535Sdes				sin = &saidx->src.sin;
227163535Sdes				sin->sin_len = sizeof(*sin);
228163535Sdes				sin->sin_family = AF_INET;
229276208Sphk				sin->sin_port = IPSEC_PORT_ANY;
230163535Sdes				sin->sin_addr = ip->ip_src;
231163535Sdes			}
232163535Sdes			if (saidx->dst.sa.sa_len == 0) {
233163535Sdes				sin = &saidx->dst.sin;
234163535Sdes				sin->sin_len = sizeof(*sin);
235163535Sdes				sin->sin_family = AF_INET;
236163535Sdes				sin->sin_port = IPSEC_PORT_ANY;
237163535Sdes				sin->sin_addr = ip->ip_dst;
238163535Sdes			}
239163535Sdes		} else {
240163535Sdes			struct sockaddr_in6 *sin6;
241163535Sdes			struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
242163535Sdes
243163535Sdes			if (saidx->src.sin6.sin6_len == 0) {
244163535Sdes				sin6 = (struct sockaddr_in6 *)&saidx->src;
245163535Sdes				sin6->sin6_len = sizeof(*sin6);
246163535Sdes				sin6->sin6_family = AF_INET6;
247163535Sdes				sin6->sin6_port = IPSEC_PORT_ANY;
248163535Sdes				sin6->sin6_addr = ip6->ip6_src;
249163535Sdes				if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
250163535Sdes					/* fix scope id for comparing SPD */
251163535Sdes					sin6->sin6_addr.s6_addr16[1] = 0;
252163535Sdes					sin6->sin6_scope_id =
253163535Sdes					    ntohs(ip6->ip6_src.s6_addr16[1]);
254163535Sdes				}
255163535Sdes			}
256163535Sdes			if (saidx->dst.sin6.sin6_len == 0) {
257163535Sdes				sin6 = (struct sockaddr_in6 *)&saidx->dst;
258163535Sdes				sin6->sin6_len = sizeof(*sin6);
259163535Sdes				sin6->sin6_family = AF_INET6;
260163535Sdes				sin6->sin6_port = IPSEC_PORT_ANY;
261163535Sdes				sin6->sin6_addr = ip6->ip6_dst;
262268069Semaste				if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
263268069Semaste					/* fix scope id for comparing SPD */
264268069Semaste					sin6->sin6_addr.s6_addr16[1] = 0;
265268069Semaste					sin6->sin6_scope_id =
266197379Sdelphij					    ntohs(ip6->ip6_dst.s6_addr16[1]);
267197379Sdelphij				}
268197379Sdelphij			}
269126541Sobrien		}
270126541Sobrien	}
271126541Sobrien
272126541Sobrien	/*
273125461Speter	 * Lookup SA and validate it.
274126541Sobrien	 */
275156354Syar	*error = key_checkrequest(isr, saidx);
276126541Sobrien	if (*error != 0) {
277126541Sobrien		/*
278156354Syar		 * IPsec processing is required, but no SA found.
279126541Sobrien		 * I assume that key_acquire() had been called
280126541Sobrien		 * to get/establish the SA. Here I discard
281125461Speter		 * this packet because it is responsibility for
282125461Speter		 * upper layer to retransmit the packet.
283125461Speter		 */
284125461Speter		newipsecstat.ips_out_nosa++;
285125461Speter		goto bad;
286125461Speter	}
287125461Speter	sav = isr->sav;
288126541Sobrien	if (sav == NULL) {		/* XXX valid return */
289125461Speter		IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
290125461Speter			("no SA found, but required; level %u",
291125461Speter			ipsec_get_reqlevel(isr)));
292171146Snjl		IPSECREQUEST_UNLOCK(isr);
293171146Snjl		isr = isr->next;
294171146Snjl		if (isr == NULL) {
295145132Sanholt			/*XXXstatistic??*/
296145132Sanholt			*error = EINVAL;		/*XXX*/
297153033Sanholt			return isr;
298145132Sanholt		}
299145132Sanholt		IPSECREQUEST_LOCK(isr);
300145132Sanholt		goto again;
301148211Sanholt	}
302152909Sanholt
303145132Sanholt	/*
304145132Sanholt	 * Check system global policy controls.
305203288Srnoland	 */
306145132Sanholt	if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
307125461Speter	    (isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
308125461Speter	    (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
309125461Speter		DPRINTF(("%s: IPsec outbound packet dropped due"
310125461Speter			" to policy (check your sysctls)\n", __func__));
311125461Speter		IPSEC_OSTAT(espstat.esps_pdrops, ahstat.ahs_pdrops,
312255736Sdavidch		    ipcompstat.ipcomps_pdrops);
313255736Sdavidch		*error = EHOSTUNREACH;
314125984Sobrien		goto bad;
315163494Simp	}
316129293Speter
317159549Sjhb	/*
318203691Sbrucec	 * Sanity check the SA contents for the caller
319159549Sjhb	 * before they invoke the xform output method.
320203691Sbrucec	 */
321269992Sgavin	if (sav->tdb_xform == NULL) {
322269992Sgavin		DPRINTF(("%s: no transform for SA\n", __func__));
323203691Sbrucec		IPSEC_OSTAT(espstat.esps_noxform, ahstat.ahs_noxform,
324272022Sbz		    ipcompstat.ipcomps_noxform);
325272022Sbz		*error = EHOSTUNREACH;
326331769Shselasky		goto bad;
327234183Sjhb	}
328329159Shselasky	return isr;
329159967Sobrienbad:
330228085Sphilip	IPSEC_ASSERT(*error != 0, ("error return w/ no error code"));
331255323Sbryanv	IPSECREQUEST_UNLOCK(isr);
332173491Sbenjsc	return NULL;
333203691Sbrucec#undef IPSEC_OSTAT
334125461Speter}
335255736Sdavidch
336233872Sjhb#ifdef INET
337148263Speter/*
338148263Speter * IPsec output logic for IPv4.
339148263Speter */
340233872Sjhbint
341233872Sjhbipsec4_process_packet(
342233872Sjhb	struct mbuf *m,
343272022Sbz	struct ipsecrequest *isr,
344318357Serj	int flags,
345272022Sbz	int tunalready)
346331769Shselasky{
347329159Shselasky	struct secasindex saidx;
348234183Sjhb	struct secasvar *sav;
349329159Shselasky	struct ip *ip;
350233872Sjhb	int error, i, off;
351240098Sjhb
352255323Sbryanv	IPSEC_ASSERT(m != NULL, ("null mbuf"));
353233872Sjhb	IPSEC_ASSERT(isr != NULL, ("null isr"));
354125461Speter
355203691Sbrucec	IPSECREQUEST_LOCK(isr);		/* insure SA contents don't change */
356203691Sbrucec
357203691Sbrucec	isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
358203691Sbrucec	if (isr == NULL)
359203691Sbrucec		goto bad;
360203691Sbrucec
361203691Sbrucec	sav = isr->sav;
362203691Sbrucec
363203691Sbrucec#ifdef DEV_ENC
364203691Sbrucec	/* pass the mbuf to enc0 for packet filtering */
365203691Sbrucec	if ((error = ipsec_filter(&m, 2)) != 0)
366203691Sbrucec		goto bad;
367203691Sbrucec#endif
368269992Sgavin
369269992Sgavin	if (!tunalready) {
370269992Sgavin		union sockaddr_union *dst = &sav->sah->saidx.dst;
371269992Sgavin		int setdf;
372269992Sgavin
373269992Sgavin		/*
374203691Sbrucec		 * Collect IP_DF state from the outer header.
375203691Sbrucec		 */
376203691Sbrucec		if (dst->sa.sa_family == AF_INET) {
377203691Sbrucec			if (m->m_len < sizeof (struct ip) &&
378269992Sgavin			    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
379269992Sgavin				error = ENOBUFS;
380210113Sbschmidt				goto bad;
381203691Sbrucec			}
382203691Sbrucec			ip = mtod(m, struct ip *);
383203691Sbrucec			/* Honor system-wide control of how to handle IP_DF */
384203691Sbrucec			switch (ip4_ipsec_dfbit) {
385203691Sbrucec			case 0:			/* clear in outer header */
386203691Sbrucec			case 1:			/* set in outer header */
387203691Sbrucec				setdf = ip4_ipsec_dfbit;
388203691Sbrucec				break;
389203691Sbrucec			default:		/* propagate to outer header */
390203691Sbrucec				setdf = ntohs(ip->ip_off & IP_DF);
391203691Sbrucec				break;
392269992Sgavin			}
393269992Sgavin		} else {
394269992Sgavin			ip = NULL;		/* keep compiler happy */
395269992Sgavin			setdf = 0;
396269992Sgavin		}
397203691Sbrucec		/* Do the appropriate encapsulation, if necessary */
398203691Sbrucec		if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
399203691Sbrucec		    dst->sa.sa_family != AF_INET ||	    /* PF mismatch */
400203691Sbrucec#if 0
401269992Sgavin		    (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
402269992Sgavin		    sav->tdb_xform->xf_type == XF_IP4 ||    /* ditto */
403210113Sbschmidt#endif
404203691Sbrucec		    (dst->sa.sa_family == AF_INET &&	    /* Proxy */
405203691Sbrucec		     dst->sin.sin_addr.s_addr != INADDR_ANY &&
406323453Smav		     dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
407323453Smav			struct mbuf *mp;
408323453Smav
409323453Smav			/* Fix IPv4 header checksum and length */
410323453Smav			if (m->m_len < sizeof (struct ip) &&
411323453Smav			    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
412323453Smav				error = ENOBUFS;
413323453Smav				goto bad;
414250079Scarl			}
415125461Speter			ip = mtod(m, struct ip *);
416126541Sobrien			ip->ip_len = htons(m->m_pkthdr.len);
417126541Sobrien			ip->ip_sum = 0;
418125461Speter#ifdef _IP_VHL
419126541Sobrien			if (ip->ip_vhl == IP_VHL_BORING)
420144423Sscottl				ip->ip_sum = in_cksum_hdr(ip);
421144423Sscottl			else
422144423Sscottl				ip->ip_sum = in_cksum(m,
423144423Sscottl					_IP_VHL_HL(ip->ip_vhl) << 2);
424144423Sscottl#else
425144423Sscottl			ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
426333417Ssbruno#endif
427333417Ssbruno
428333417Ssbruno			/* Encapsulate the packet */
429333417Ssbruno			error = ipip_output(m, isr, &mp, 0, 0);
430333417Ssbruno			if (mp == NULL && !error) {
431333417Ssbruno				/* Should never happen. */
432333417Ssbruno				DPRINTF(("%s: ipip_output returns no mbuf and "
433129293Speter					"no error!", __func__));
434129293Speter				error = EFAULT;
435129293Speter			}
436142733Sobrien			if (error) {
437142733Sobrien				if (mp) {
438129293Speter					/* XXX: Should never happen! */
439129293Speter					m_freem(mp);
440129293Speter				}
441125461Speter				m = NULL; /* ipip_output() already freed it */
442126541Sobrien				goto bad;
443125984Sobrien			}
444125984Sobrien			m = mp, mp = NULL;
445125984Sobrien			/*
446125461Speter			 * ipip_output clears IP_DF in the new header.  If
447126638Sobrien			 * we need to propagate IP_DF from the outer header,
448126638Sobrien			 * then we have to do it here.
449126638Sobrien			 *
450125984Sobrien			 * XXX shouldn't assume what ipip_output does.
451125461Speter			 */
452125461Speter			if (dst->sa.sa_family == AF_INET && setdf) {
453125461Speter				if (m->m_len < sizeof (struct ip) &&
454125461Speter				    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
455125461Speter					error = ENOBUFS;
456125461Speter					goto bad;
457125461Speter				}
458250963Sachim				ip = mtod(m, struct ip *);
459250963Sachim				ip->ip_off = ntohs(ip->ip_off);
460250963Sachim				ip->ip_off |= IP_DF;
461250963Sachim				ip->ip_off = htons(ip->ip_off);
462228940Sdelphij			}
463228940Sdelphij		}
464228940Sdelphij	}
465228940Sdelphij
466174604Sscottl#ifdef DEV_ENC
467149873Sscottl	/* pass the mbuf to enc0 for bpf processing */
468147687Speter	ipsec_bpf(m, sav, AF_INET);
469147687Speter#endif
470252867Sdelphij
471252867Sdelphij	/*
472252867Sdelphij	 * Dispatch to the appropriate IPsec transform logic.  The
473252867Sdelphij	 * packet will be returned for transmission after crypto
474174604Sscottl	 * processing, etc. are completed.  For encapsulation we
475174604Sscottl	 * bypass this call because of the explicit call done above
476174604Sscottl	 * (necessary to deal with IP_DF handling for IPv4).
477174604Sscottl	 *
478174604Sscottl	 * NB: m & sav are ``passed to caller'' who's reponsible for
479169421Sscottl	 *     for reclaiming their resources.
480169421Sscottl	 */
481169421Sscottl	if (sav->tdb_xform->xf_type != XF_IP4) {
482169421Sscottl		ip = mtod(m, struct ip *);
483125461Speter		i = ip->ip_hl << 2;
484125461Speter		off = offsetof(struct ip, ip_p);
485125461Speter		error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
486125461Speter	} else {
487330679Srpokala		error = ipsec_process_done(m, isr);
488330679Srpokala	}
489330679Srpokala	IPSECREQUEST_UNLOCK(isr);
490330679Srpokala	return error;
491330679Srpokalabad:
492230843Sjimharris	if (isr)
493230843Sjimharris		IPSECREQUEST_UNLOCK(isr);
494263301Simp	if (m)
495230843Sjimharris		m_freem(m);
496230843Sjimharris	return error;
497240618Sjimharris}
498240618Sjimharris#endif
499240618Sjimharris
500240618Sjimharris#ifdef INET6
501240618Sjimharris/*
502285662Sbenno * Chop IP6 header from the payload.
503285662Sbenno */
504285662Sbennostatic struct mbuf *
505285662Sbennoipsec6_splithdr(struct mbuf *m)
506125461Speter{
507125461Speter	struct mbuf *mh;
508125461Speter	struct ip6_hdr *ip6;
509125461Speter	int hlen;
510142733Sobrien
511142733Sobrien	IPSEC_ASSERT(m->m_len >= sizeof (struct ip6_hdr),
512125461Speter		("first mbuf too short, len %u", m->m_len));
513245362Sbryanv	ip6 = mtod(m, struct ip6_hdr *);
514245362Sbryanv	hlen = sizeof(struct ip6_hdr);
515247870Sbryanv	if (m->m_len > hlen) {
516247870Sbryanv		MGETHDR(mh, M_DONTWAIT, MT_DATA);
517247870Sbryanv		if (!mh) {
518260376Sschweikh			m_freem(m);
519247870Sbryanv			return NULL;
520247870Sbryanv		}
521247870Sbryanv		M_MOVE_PKTHDR(mh, m);
522245362Sbryanv		MH_ALIGN(mh, hlen);
523245362Sbryanv		m->m_len -= hlen;
524245362Sbryanv		m->m_data += hlen;
525245362Sbryanv		mh->m_next = m;
526245362Sbryanv		m = mh;
527245362Sbryanv		m->m_len = hlen;
528260847Sbryanv		bcopy((caddr_t)ip6, mtod(m, caddr_t), hlen);
529274065Sbryanv	} else if (m->m_len < hlen) {
530245362Sbryanv		m = m_pullup(m, hlen);
531299010Spfg		if (!m)
532257277Sglebius			return NULL;
533257277Sglebius	}
534257277Sglebius	return m;
535260376Sschweikh}
536257277Sglebius
537257277Sglebius/*
538125461Speter * IPsec output logic for IPv6, transport mode.
539125461Speter */
540125461Speterint
541125461Speteripsec6_output_trans(
542125461Speter	struct ipsec_output_state *state,
543162562Sjhb	u_char *nexthdrp,
544188254Swkoszek	struct mbuf *mprev,
545148264Speter	struct secpolicy *sp,
546148264Speter	int flags,
547174962Srpaulo	int *tun)
548188254Swkoszek{
549212861Snork	struct ipsecrequest *isr;
550125461Speter	struct secasindex saidx;
551125461Speter	int error = 0;
552125461Speter	struct mbuf *m;
553125461Speter
554125461Speter	IPSEC_ASSERT(state != NULL, ("null state"));
555125461Speter	IPSEC_ASSERT(state->m != NULL, ("null m"));
556125461Speter	IPSEC_ASSERT(nexthdrp != NULL, ("null nexthdrp"));
557162562Sjhb	IPSEC_ASSERT(mprev != NULL, ("null mprev"));
558147687Speter	IPSEC_ASSERT(sp != NULL, ("null sp"));
559147687Speter	IPSEC_ASSERT(tun != NULL, ("null tun"));
560147687Speter
561148217Sjkim	KEYDEBUG(KEYDEBUG_IPSEC_DATA,
562148264Speter		printf("%s: applyed SP\n", __func__);
563174962Srpaulo		kdebug_secpolicy(sp));
564270224Sjhb
565212861Snork	isr = sp->req;
566254624Sobrien	if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
567254624Sobrien		/* the rest will be handled by ipsec6_output_tunnel() */
568256053Sjmg		*tun = 1;		/* need tunnel-mode processing */
569287117Scem		return 0;
570188254Swkoszek	}
571125461Speter
572125461Speter	*tun = 0;
573125461Speter	m = state->m;
574125461Speter
575126541Sobrien	isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
576126541Sobrien	if (isr == NULL) {
577126541Sobrien#ifdef notdef
578126541Sobrien		/* XXX should notification be done for all errors ? */
579126541Sobrien		/*
580147687Speter		 * Notify the fact that the packet is discarded
581147687Speter		 * to ourselves. I believe this is better than
582147687Speter		 * just silently discarding. (jinmei@kame.net)
583147687Speter		 * XXX: should we restrict the error to TCP packets?
584199969Savg		 * XXX: should we directly notify sockets via
585228724Sdelphij		 *      pfctlinputs?
586232614Sbz		 */
587147687Speter		icmp6_error(m, ICMP6_DST_UNREACH,
588147687Speter			    ICMP6_DST_UNREACH_ADMIN, 0);
589199969Savg		m = NULL;	/* NB: icmp6_error frees mbuf */
590228431Sfabient#endif
591232614Sbz		goto bad;
592147687Speter	}
593171854Sdes
594171854Sdes	return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL,
595171854Sdes		sizeof (struct ip6_hdr),
596171854Sdes		offsetof(struct ip6_hdr, ip6_nxt));
597189872Sdchaginbad:
598171854Sdes	if (m)
599171854Sdes		m_freem(m);
600189872Sdchagin	state->m = NULL;
601171854Sdes	return error;
602126541Sobrien}
603181430Sstas
604181430Sstasstatic int
605181430Sstasipsec6_encapsulate(struct mbuf *m, struct secasvar *sav)
606181430Sstas{
607181430Sstas	struct ip6_hdr *oip6;
608181430Sstas	struct ip6_hdr *ip6;
609129293Speter	size_t plen;
610129293Speter
611129293Speter	/* can't tunnel between different AFs */
612129293Speter	if (sav->sah->saidx.src.sa.sa_family != AF_INET6 ||
613129293Speter	    sav->sah->saidx.dst.sa.sa_family != AF_INET6) {
614329767Struckman		m_freem(m);
615329767Struckman		return EINVAL;
616329767Struckman	}
617329767Struckman	IPSEC_ASSERT(m->m_len != sizeof (struct ip6_hdr),
618329767Struckman		("mbuf wrong size; len %u", m->m_len));
619225194Sjhb
620225194Sjhb
621225194Sjhb	/*
622225194Sjhb	 * grow the mbuf to accomodate the new IPv6 header.
623225194Sjhb	 */
624225194Sjhb	plen = m->m_pkthdr.len;
625225194Sjhb	if (M_LEADINGSPACE(m->m_next) < sizeof(struct ip6_hdr)) {
626306737Skib		struct mbuf *n;
627306737Skib		MGET(n, M_DONTWAIT, MT_DATA);
628306737Skib		if (!n) {
629125461Speter			m_freem(m);
630125461Speter			return ENOBUFS;
631125461Speter		}
632125461Speter		n->m_len = sizeof(struct ip6_hdr);
633126541Sobrien		n->m_next = m->m_next;
634126541Sobrien		m->m_next = n;
635126541Sobrien		m->m_pkthdr.len += sizeof(struct ip6_hdr);
636133844Sobrien		oip6 = mtod(n, struct ip6_hdr *);
637205014Snwhitehorn	} else {
638133844Sobrien		m->m_next->m_len += sizeof(struct ip6_hdr);
639126541Sobrien		m->m_next->m_data -= sizeof(struct ip6_hdr);
640126541Sobrien		m->m_pkthdr.len += sizeof(struct ip6_hdr);
641126541Sobrien		oip6 = mtod(m->m_next, struct ip6_hdr *);
642126541Sobrien	}
643126541Sobrien	ip6 = mtod(m, struct ip6_hdr *);
644126541Sobrien	bcopy((caddr_t)ip6, (caddr_t)oip6, sizeof(struct ip6_hdr));
645307144Sed
646307144Sed	/* Fake link-local scope-class addresses */
647307144Sed	if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src))
648285746Sed		oip6->ip6_src.s6_addr16[1] = 0;
649285746Sed	if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst))
650285746Sed		oip6->ip6_dst.s6_addr16[1] = 0;
651125461Speter
652126541Sobrien	/* construct new IPv6 header. see RFC 2401 5.1.2.2 */
653125461Speter	/* ECN consideration. */
654337263Smarkj	ip6_ecn_ingress(ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow);
655133819Stjr	if (plen < IPV6_MAXPACKET - sizeof(struct ip6_hdr))
656133819Stjr		ip6->ip6_plen = htons(plen);
657133853Stjr	else {
658125461Speter		/* ip6->ip6_plen will be updated in ip6_output() */
659133853Stjr	}
660125461Speter	ip6->ip6_nxt = IPPROTO_IPV6;
661158381Sambrisko	sav->sah->saidx.src.sin6.sin6_addr = ip6->ip6_src;
662158381Sambrisko	sav->sah->saidx.dst.sin6.sin6_addr = ip6->ip6_dst;
663191954Skuriyama	ip6->ip6_hlim = IPV6_DEFHLIM;
664158381Sambrisko
665126541Sobrien	/* XXX Should ip6_src be updated later ? */
666126541Sobrien
667126541Sobrien	return 0;
668126541Sobrien}
669126541Sobrien
670126541Sobrien/*
671126541Sobrien * IPsec output logic for IPv6, tunnel mode.
672126541Sobrien */
673126541Sobrienint
674126541Sobrienipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int flags)
675126541Sobrien{
676126541Sobrien	struct ip6_hdr *ip6;
677126541Sobrien	struct ipsecrequest *isr;
678126541Sobrien	struct secasindex saidx;
679126541Sobrien	int error;
680126541Sobrien	struct sockaddr_in6* dst6;
681126541Sobrien	struct mbuf *m;
682126930Speter
683126541Sobrien	IPSEC_ASSERT(state != NULL, ("null state"));
684126541Sobrien	IPSEC_ASSERT(state->m != NULL, ("null m"));
685125461Speter	IPSEC_ASSERT(sp != NULL, ("null sp"));
686125461Speter
687125461Speter	KEYDEBUG(KEYDEBUG_IPSEC_DATA,
688125461Speter		printf("%s: applyed SP\n", __func__);
689125461Speter		kdebug_secpolicy(sp));
690125461Speter
691125461Speter	m = state->m;
692219525Savg	/*
693125461Speter	 * transport mode ipsec (before the 1st tunnel mode) is already
694233433Salc	 * processed by ipsec6_output_trans().
695233433Salc	 */
696233433Salc	for (isr = sp->req; isr; isr = isr->next) {
697233433Salc		if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
698125461Speter			break;
699125461Speter	}
700125461Speter	isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
701125461Speter	if (isr == NULL)
702125461Speter		goto bad;
703125461Speter
704125461Speter	/*
705125461Speter	 * There may be the case that SA status will be changed when
706125461Speter	 * we are refering to one. So calling splsoftnet().
707125461Speter	 */
708125461Speter	if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
709125461Speter		/*
710125461Speter		 * build IPsec tunnel.
711125461Speter		 */
712125461Speter		/* XXX should be processed with other familiy */
713125461Speter		if (isr->sav->sah->saidx.src.sa.sa_family != AF_INET6) {
714125461Speter			ipseclog((LOG_ERR, "%s: family mismatched between "
715125461Speter			    "inner and outer, spi=%u\n", __func__,
716125461Speter			    ntohl(isr->sav->spi)));
717132956Smarkm			newipsecstat.ips_out_inval++;
718159549Sjhb			error = EAFNOSUPPORT;
719189497Sthompsa			goto bad;
720189497Sthompsa		}
721
722		m = ipsec6_splithdr(m);
723		if (!m) {
724			newipsecstat.ips_out_nomem++;
725			error = ENOMEM;
726			goto bad;
727		}
728		error = ipsec6_encapsulate(m, isr->sav);
729		if (error) {
730			m = NULL;
731			goto bad;
732		}
733		ip6 = mtod(m, struct ip6_hdr *);
734
735		state->ro = &isr->sav->sah->sa_route;
736		state->dst = (struct sockaddr *)&state->ro->ro_dst;
737		dst6 = (struct sockaddr_in6 *)state->dst;
738		if (state->ro->ro_rt
739		 && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0
740		  || !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))) {
741			RTFREE(state->ro->ro_rt);
742			state->ro->ro_rt = NULL;
743		}
744		if (state->ro->ro_rt == 0) {
745			bzero(dst6, sizeof(*dst6));
746			dst6->sin6_family = AF_INET6;
747			dst6->sin6_len = sizeof(*dst6);
748			dst6->sin6_addr = ip6->ip6_dst;
749			rtalloc(state->ro);
750		}
751		if (state->ro->ro_rt == 0) {
752			ip6stat.ip6s_noroute++;
753			newipsecstat.ips_out_noroute++;
754			error = EHOSTUNREACH;
755			goto bad;
756		}
757
758		/* adjust state->dst if tunnel endpoint is offlink */
759		if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) {
760			state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
761			dst6 = (struct sockaddr_in6 *)state->dst;
762		}
763	}
764
765	m = ipsec6_splithdr(m);
766	if (!m) {
767		newipsecstat.ips_out_nomem++;
768		error = ENOMEM;
769		goto bad;
770	}
771	ip6 = mtod(m, struct ip6_hdr *);
772	return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL,
773		sizeof (struct ip6_hdr),
774		offsetof(struct ip6_hdr, ip6_nxt));
775bad:
776	if (m)
777		m_freem(m);
778	state->m = NULL;
779	return error;
780}
781#endif /*INET6*/
782