1/*	$NetBSD: ipsec_output.c,v 1.37 2011/08/31 18:31:03 plunky Exp $	*/
2
3/*-
4 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/ipsec_output.c,v 1.3.2.2 2003/03/28 20:32:53 sam Exp $
29 */
30
31#include <sys/cdefs.h>
32__KERNEL_RCSID(0, "$NetBSD: ipsec_output.c,v 1.37 2011/08/31 18:31:03 plunky Exp $");
33
34/*
35 * IPsec output processing.
36 */
37#include "opt_inet.h"
38#ifdef __FreeBSD__
39#include "opt_inet6.h"
40#endif
41#include "opt_ipsec.h"
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/mbuf.h>
46#include <sys/domain.h>
47#include <sys/protosw.h>
48#include <sys/socket.h>
49#include <sys/errno.h>
50#include <sys/syslog.h>
51
52#include <net/if.h>
53#include <net/route.h>
54
55#include <netinet/in.h>
56#include <netinet/in_systm.h>
57#include <netinet/ip.h>
58#include <netinet/ip_var.h>
59#include <netinet/in_var.h>
60#include <netinet/ip_ecn.h>
61#ifdef INET6
62#  ifdef __FreeBSD__
63#  include <netinet6/ip6_ecn.h>
64#  endif
65#endif
66
67#include <netinet/ip6.h>
68#ifdef INET6
69#include <netinet6/ip6_var.h>
70#endif
71#include <netinet/in_pcb.h>
72#ifdef INET6
73#include <netinet/icmp6.h>
74#endif
75#ifdef IPSEC_NAT_T
76#include <netinet/udp.h>
77#endif
78
79#include <netipsec/ipsec.h>
80#include <netipsec/ipsec_var.h>
81#include <netipsec/ipsec_private.h>
82#ifdef INET6
83#include <netipsec/ipsec6.h>
84#endif
85#include <netipsec/ah_var.h>
86#include <netipsec/esp_var.h>
87#include <netipsec/ipcomp_var.h>
88
89#include <netipsec/xform.h>
90
91#include <netipsec/key.h>
92#include <netipsec/keydb.h>
93#include <netipsec/key_debug.h>
94#include <netipsec/ipsec_osdep.h>
95
96#include <net/net_osdep.h>		/* ovbcopy() in ipsec6_encapsulate() */
97
98
99/*
100 * Add a IPSEC_OUT_DONE tag to mark that we have finished the ipsec processing
101 * It will be used by ip{,6}_output to check if we have already or not
102 * processed this packet.
103 */
104static int
105ipsec_register_done(struct mbuf *m, int * error)
106{
107	struct m_tag *mtag;
108
109	mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 0, M_NOWAIT);
110	if (mtag == NULL) {
111		DPRINTF(("ipsec_register_done: could not get packet tag\n"));
112		*error = ENOMEM;
113		return -1;
114	}
115
116	m_tag_prepend(m, mtag);
117	return 0;
118}
119
120static int
121ipsec_reinject_ipstack(struct mbuf *m, int af)
122{
123#ifdef INET
124	struct ip * ip;
125#endif /* INET */
126#if defined(INET) || defined(INET6)
127	int rv;
128#endif
129
130	switch (af) {
131#ifdef INET
132	case AF_INET:
133		ip = mtod(m, struct ip *);
134#ifdef __FreeBSD__
135		/* FreeBSD ip_output() expects ip_len, ip_off in host endian */
136		ip->ip_len = ntohs(ip->ip_len);
137		ip->ip_off = ntohs(ip->ip_off);
138#endif /* __FreeBSD_ */
139		KERNEL_LOCK(1, NULL);
140		rv = ip_output(m, NULL, NULL, IP_RAWOUTPUT|IP_NOIPNEWID,
141		    NULL, NULL);
142		KERNEL_UNLOCK_ONE(NULL);
143		return rv;
144
145#endif /* INET */
146#ifdef INET6
147	case AF_INET6:
148		/*
149		 * We don't need massage, IPv6 header fields are always in
150		 * net endian.
151		 */
152		KERNEL_LOCK(1, NULL);
153		rv = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
154		KERNEL_UNLOCK_ONE(NULL);
155		return rv;
156#endif /* INET6 */
157	}
158
159	panic("ipsec_reinject_ipstack : iunknown protocol family %u\n", af);
160	return -1; /* NOTREACHED */
161}
162
163int
164ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
165{
166	struct secasvar *sav;
167	struct secasindex *saidx;
168	int error;
169#ifdef INET
170	struct ip * ip;
171#endif /* INET */
172#ifdef INET6
173	struct ip6_hdr * ip6;
174#endif /* INET6 */
175#ifdef IPSEC_NAT_T
176	struct mbuf * mo;
177	struct udphdr *udp = NULL;
178	uint64_t * data = NULL;
179	int hlen, roff;
180#endif /* IPSEC_NAT_T */
181
182	IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
183
184	IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf"));
185	IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR"));
186	sav = isr->sav;
187	IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA"));
188	IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
189
190	saidx = &sav->sah->saidx;
191
192#ifdef IPSEC_NAT_T
193	if(sav->natt_type != 0) {
194		ip = mtod(m, struct ip *);
195
196		hlen = sizeof(struct udphdr);
197		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
198			hlen += sizeof(uint64_t);
199
200		mo = m_makespace(m, sizeof(struct ip), hlen, &roff);
201		if (mo == NULL) {
202			DPRINTF(("ipsec_process_done : failed to inject"
203				 "%u byte UDP for SA %s/%08lx\n",
204					 hlen, ipsec_address(&saidx->dst),
205					 (u_long) ntohl(sav->spi)));
206			error = ENOBUFS;
207			goto bad;
208		}
209
210		udp = (struct udphdr*) (mtod(mo, char*) + roff);
211		data = (uint64_t*) (udp + 1);
212
213		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
214			*data = 0; /* NON-IKE Marker */
215
216		if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE)
217			udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT);
218		else
219			udp->uh_sport = key_portfromsaddr(&saidx->src);
220
221		udp->uh_dport = key_portfromsaddr(&saidx->dst);
222		udp->uh_sum = 0;
223		udp->uh_ulen = htons(m->m_pkthdr.len - (ip->ip_hl << 2));
224	}
225#endif /* IPSEC_NAT_T */
226
227	switch (saidx->dst.sa.sa_family) {
228#ifdef INET
229	case AF_INET:
230		/* Fix the header length, for AH processing. */
231		ip = mtod(m, struct ip *);
232		ip->ip_len = htons(m->m_pkthdr.len);
233#ifdef IPSEC_NAT_T
234		if (sav->natt_type != 0)
235			ip->ip_p = IPPROTO_UDP;
236#endif /* IPSEC_NAT_T */
237		break;
238#endif /* INET */
239#ifdef INET6
240	case AF_INET6:
241		/* Fix the header length, for AH processing. */
242		if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
243			error = ENXIO;
244			goto bad;
245		}
246		if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
247			/* No jumbogram support. */
248			error = ENXIO;	/*?*/
249			goto bad;
250		}
251		ip6 = mtod(m, struct ip6_hdr *);
252		ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
253#ifdef IPSEC_NAT_T
254		if (sav->natt_type != 0)
255			ip6->ip6_nxt = IPPROTO_UDP;
256#endif /* IPSEC_NAT_T */
257		break;
258#endif /* INET6 */
259	default:
260		DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
261		    saidx->dst.sa.sa_family));
262		error = ENXIO;
263		goto bad;
264	}
265
266	key_sa_recordxfer(sav, m);
267
268	/*
269	 * If there's another (bundled) SA to apply, do so.
270	 * Note that this puts a burden on the kernel stack size.
271	 * If this is a problem we'll need to introduce a queue
272	 * to set the packet on so we can unwind the stack before
273	 * doing further processing.
274	 */
275	if (isr->next) {
276		IPSEC_STATINC(IPSEC_STAT_OUT_BUNDLESA);
277		switch ( saidx->dst.sa.sa_family ) {
278#ifdef INET
279		case AF_INET:
280			return ipsec4_process_packet(m, isr->next, 0,0);
281#endif /* INET */
282#ifdef INET6
283		case AF_INET6:
284			return ipsec6_process_packet(m,isr->next);
285#endif /* INET6 */
286		default :
287			DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
288			       saidx->dst.sa.sa_family));
289			error = ENXIO;
290			goto bad;
291		}
292	}
293
294	/*
295	 * We're done with IPsec processing,
296	 * mark that we have already processed the packet
297	 * transmit it packet using the appropriate network protocol (IP or IPv6).
298	 */
299
300	if (ipsec_register_done(m, &error) < 0)
301		goto bad;
302
303	return ipsec_reinject_ipstack(m, saidx->dst.sa.sa_family);
304bad:
305	m_freem(m);
306	KEY_FREESAV(&sav);
307	return (error);
308}
309
310/*
311 * ipsec_nextisr can return :
312 * - isr == NULL and error != 0 => something is bad : the packet must be
313 *   discarded
314 * - isr == NULL and error == 0 => no more rules to apply, ipsec processing
315 *   is done, reinject it in ip stack
316 * - isr != NULL (error == 0) => we need to apply one rule to the packet
317 */
318static struct ipsecrequest *
319ipsec_nextisr(
320	struct mbuf *m,
321	struct ipsecrequest *isr,
322	int af,
323	struct secasindex *saidx,
324	int *error
325)
326{
327#define	IPSEC_OSTAT(x, y, z)						\
328do {									\
329	switch (isr->saidx.proto) {					\
330	case IPPROTO_ESP:						\
331		ESP_STATINC(x);						\
332		break;							\
333	case IPPROTO_AH:						\
334		AH_STATINC(y);						\
335		break;							\
336	default:							\
337		IPCOMP_STATINC(z);					\
338		break;							\
339	}								\
340} while (/*CONSTCOND*/0)
341
342	struct secasvar *sav;
343
344	IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr");
345	IPSEC_ASSERT(af == AF_INET || af == AF_INET6,
346		("ipsec_nextisr: invalid address family %u", af));
347again:
348	/*
349	 * Craft SA index to search for proper SA.  Note that
350	 * we only fillin unspecified SA peers for transport
351	 * mode; for tunnel mode they must already be filled in.
352	 */
353	*saidx = isr->saidx;
354	if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
355		/* Fillin unspecified SA peers only for transport mode */
356		if (af == AF_INET) {
357			struct sockaddr_in *sin;
358			struct ip *ip = mtod(m, struct ip *);
359
360			if (saidx->src.sa.sa_len == 0) {
361				sin = &saidx->src.sin;
362				sin->sin_len = sizeof(*sin);
363				sin->sin_family = AF_INET;
364				sin->sin_port = IPSEC_PORT_ANY;
365				sin->sin_addr = ip->ip_src;
366			}
367			if (saidx->dst.sa.sa_len == 0) {
368				sin = &saidx->dst.sin;
369				sin->sin_len = sizeof(*sin);
370				sin->sin_family = AF_INET;
371				sin->sin_port = IPSEC_PORT_ANY;
372				sin->sin_addr = ip->ip_dst;
373			}
374		} else {
375			struct sockaddr_in6 *sin6;
376			struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
377
378			if (saidx->src.sin6.sin6_len == 0) {
379				sin6 = (struct sockaddr_in6 *)&saidx->src;
380				sin6->sin6_len = sizeof(*sin6);
381				sin6->sin6_family = AF_INET6;
382				sin6->sin6_port = IPSEC_PORT_ANY;
383				sin6->sin6_addr = ip6->ip6_src;
384				if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
385					/* fix scope id for comparing SPD */
386					sin6->sin6_addr.s6_addr16[1] = 0;
387					sin6->sin6_scope_id =
388					    ntohs(ip6->ip6_src.s6_addr16[1]);
389				}
390			}
391			if (saidx->dst.sin6.sin6_len == 0) {
392				sin6 = (struct sockaddr_in6 *)&saidx->dst;
393				sin6->sin6_len = sizeof(*sin6);
394				sin6->sin6_family = AF_INET6;
395				sin6->sin6_port = IPSEC_PORT_ANY;
396				sin6->sin6_addr = ip6->ip6_dst;
397				if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
398					/* fix scope id for comparing SPD */
399					sin6->sin6_addr.s6_addr16[1] = 0;
400					sin6->sin6_scope_id =
401					    ntohs(ip6->ip6_dst.s6_addr16[1]);
402				}
403			}
404		}
405	}
406
407	/*
408	 * Lookup SA and validate it.
409	 */
410	*error = key_checkrequest(isr, saidx);
411	if (*error != 0) {
412		/*
413		 * IPsec processing is required, but no SA found.
414		 * I assume that key_acquire() had been called
415		 * to get/establish the SA. Here I discard
416		 * this packet because it is responsibility for
417		 * upper layer to retransmit the packet.
418		 */
419		IPSEC_STATINC(IPSEC_STAT_OUT_NOSA);
420		goto bad;
421	}
422	sav = isr->sav;
423	/* sav may be NULL here if we have an USE rule */
424	if (sav == NULL) {
425		IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
426			("ipsec_nextisr: no SA found, but required; level %u",
427			ipsec_get_reqlevel(isr)));
428		isr = isr->next;
429		/*
430		 * No more rules to apply, return NULL isr and no error
431		 * It can happen when the last rules are USE rules
432		 * */
433		if (isr == NULL) {
434			*error = 0;
435			return isr;
436		}
437		goto again;
438	}
439
440	/*
441	 * Check system global policy controls.
442	 */
443	if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
444	    (isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
445	    (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
446		DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due"
447			" to policy (check your sysctls)\n"));
448		IPSEC_OSTAT(ESP_STAT_PDROPS, AH_STAT_PDROPS,
449		    IPCOMP_STAT_PDROPS);
450		*error = EHOSTUNREACH;
451		goto bad;
452	}
453
454	/*
455	 * Sanity check the SA contents for the caller
456	 * before they invoke the xform output method.
457	 */
458	if (sav->tdb_xform == NULL) {
459		DPRINTF(("ipsec_nextisr: no transform for SA\n"));
460		IPSEC_OSTAT(ESP_STAT_NOXFORM, AH_STAT_NOXFORM,
461		    IPCOMP_STAT_NOXFORM);
462		*error = EHOSTUNREACH;
463		goto bad;
464	}
465	return isr;
466bad:
467	IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code"));
468	return NULL;
469#undef IPSEC_OSTAT
470}
471
472#ifdef INET
473/*
474 * IPsec output logic for IPv4.
475 */
476int
477ipsec4_process_packet(
478    struct mbuf *m,
479    struct ipsecrequest *isr,
480    int flags,
481    int tunalready
482)
483{
484	struct secasindex saidx;
485	struct secasvar *sav;
486	struct ip *ip;
487	int s, error, i, off;
488
489	IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf"));
490	IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr"));
491
492	s = splsoftnet();			/* insure SA contents don't change */
493
494	isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
495	if (isr == NULL) {
496		if (error != 0) {
497			goto bad;
498		} else {
499			if (ipsec_register_done(m, &error) < 0)
500				goto bad;
501
502			splx(s);
503			return ipsec_reinject_ipstack(m, AF_INET);
504		}
505	}
506
507	sav = isr->sav;
508	if (!tunalready) {
509		union sockaddr_union *dst = &sav->sah->saidx.dst;
510		int setdf;
511
512		/*
513		 * Collect IP_DF state from the outer header.
514		 */
515		if (dst->sa.sa_family == AF_INET) {
516			if (m->m_len < sizeof (struct ip) &&
517			    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
518				error = ENOBUFS;
519				goto bad;
520			}
521			ip = mtod(m, struct ip *);
522			/* Honor system-wide control of how to handle IP_DF */
523			switch (ip4_ipsec_dfbit) {
524			case 0:			/* clear in outer header */
525			case 1:			/* set in outer header */
526				setdf = ip4_ipsec_dfbit;
527				break;
528			default:		/* propagate to outer header */
529				setdf = ip->ip_off;
530#ifndef __FreeBSD__
531		/* On FreeBSD, ip_off and ip_len assumed in host endian. */
532				setdf = ntohs(setdf);
533#endif
534				setdf = htons(setdf & IP_DF);
535				break;
536			}
537		} else {
538			ip = NULL;		/* keep compiler happy */
539			setdf = 0;
540		}
541		/* Do the appropriate encapsulation, if necessary */
542		if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
543		    dst->sa.sa_family != AF_INET ||	    /* PF mismatch */
544#if 0
545		    (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
546		    sav->tdb_xform->xf_type == XF_IP4 ||    /* ditto */
547#endif
548		    (dst->sa.sa_family == AF_INET &&	    /* Proxy */
549		     dst->sin.sin_addr.s_addr != INADDR_ANY &&
550		     dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
551			struct mbuf *mp;
552
553			/* Fix IPv4 header checksum and length */
554			if (m->m_len < sizeof (struct ip) &&
555			    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
556				error = ENOBUFS;
557				goto bad;
558			}
559			ip = mtod(m, struct ip *);
560			ip->ip_len = htons(m->m_pkthdr.len);
561			ip->ip_sum = 0;
562			ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
563
564			/* Encapsulate the packet */
565			error = ipip_output(m, isr, &mp, 0, 0);
566			if (mp == NULL && !error) {
567				/* Should never happen. */
568				DPRINTF(("ipsec4_process_packet: ipip_output "
569					"returns no mbuf and no error!"));
570				error = EFAULT;
571			}
572			if (error) {
573				if (mp) {
574					/* XXX: Should never happen! */
575					m_freem(mp);
576				}
577				m = NULL; /* ipip_output() already freed it */
578				goto bad;
579			}
580			m = mp, mp = NULL;
581			/*
582			 * ipip_output clears IP_DF in the new header.  If
583			 * we need to propagate IP_DF from the outer header,
584			 * then we have to do it here.
585			 *
586			 * XXX shouldn't assume what ipip_output does.
587			 */
588			if (dst->sa.sa_family == AF_INET && setdf) {
589				if (m->m_len < sizeof (struct ip) &&
590				    (m = m_pullup(m, sizeof (struct ip))) == NULL) {
591					error = ENOBUFS;
592					goto bad;
593				}
594				ip = mtod(m, struct ip *);
595				ip->ip_off |= IP_OFF_CONVERT(IP_DF);
596			}
597		}
598	}
599
600	/*
601	 * Dispatch to the appropriate IPsec transform logic.  The
602	 * packet will be returned for transmission after crypto
603	 * processing, etc. are completed.  For encapsulation we
604	 * bypass this call because of the explicit call done above
605	 * (necessary to deal with IP_DF handling for IPv4).
606	 *
607	 * NB: m & sav are ``passed to caller'' who's reponsible for
608	 *     for reclaiming their resources.
609	 */
610	if (sav->tdb_xform->xf_type != XF_IP4) {
611		union sockaddr_union *dst = &sav->sah->saidx.dst;
612		if (dst->sa.sa_family == AF_INET) {
613			ip = mtod(m, struct ip *);
614			i = ip->ip_hl << 2;
615			off = offsetof(struct ip, ip_p);
616		} else {
617			i = sizeof(struct ip6_hdr);
618			off = offsetof(struct ip6_hdr, ip6_nxt);
619		}
620		error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
621	} else {
622		error = ipsec_process_done(m, isr);
623	}
624	splx(s);
625	return error;
626bad:
627	splx(s);
628	if (m)
629		m_freem(m);
630	return error;
631}
632#endif
633
634#ifdef INET6
635static void
636compute_ipsec_pos(struct mbuf *m, int *i, int *off)
637{
638	int nxt;
639	struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr*);
640	struct ip6_ext ip6e;
641	int dstopt = 0;
642
643	*i = sizeof(struct ip6_hdr);
644	*off = offsetof(struct ip6_hdr, ip6_nxt);
645	nxt = ip6->ip6_nxt;
646
647	/*
648	 * chase mbuf chain to find the appropriate place to
649	 * put AH/ESP/IPcomp header.
650	 *  IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
651	 */
652	do {
653		switch (nxt) {
654		case IPPROTO_AH:
655		case IPPROTO_ESP:
656		case IPPROTO_IPCOMP:
657		/*
658		 * we should not skip security header added
659		 * beforehand.
660		 */
661			return;
662
663		case IPPROTO_HOPOPTS:
664		case IPPROTO_DSTOPTS:
665		case IPPROTO_ROUTING:
666		/*
667		 * if we see 2nd destination option header,
668		 * we should stop there.
669		 */
670			if (nxt == IPPROTO_DSTOPTS && dstopt)
671				return;
672
673			if (nxt == IPPROTO_DSTOPTS) {
674				/*
675				 * seen 1st or 2nd destination option.
676				 * next time we see one, it must be 2nd.
677				 */
678				dstopt = 1;
679			} else if (nxt == IPPROTO_ROUTING) {
680				/*
681				 * if we see destionation option next
682				 * time, it must be dest2.
683				 */
684				dstopt = 2;
685			}
686
687			/* skip this header */
688			m_copydata(m, *i, sizeof(ip6e), &ip6e);
689			nxt = ip6e.ip6e_nxt;
690			*off = *i + offsetof(struct ip6_ext, ip6e_nxt);
691			/*
692			 * we will never see nxt == IPPROTO_AH
693			 * so it is safe to omit AH case.
694			 */
695			*i += (ip6e.ip6e_len + 1) << 3;
696			break;
697		default:
698			return;
699		}
700	} while (*i < m->m_pkthdr.len);
701}
702
703static int
704in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia)
705{
706	struct in6_addr ia2;
707
708	memcpy(&ia2, &sa->sin6_addr, sizeof(ia2));
709	if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr))
710		ia2.s6_addr16[1] = htons(sa->sin6_scope_id);
711
712	return IN6_ARE_ADDR_EQUAL(ia, &ia2);
713}
714
715int
716ipsec6_process_packet(
717	struct mbuf *m,
718 	struct ipsecrequest *isr
719    )
720{
721	struct secasindex saidx;
722	struct secasvar *sav;
723	struct ip6_hdr *ip6;
724	int s, error, i, off;
725	union sockaddr_union *dst;
726
727	IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf"));
728	IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr"));
729
730	s = splsoftnet();   /* insure SA contents don't change */
731
732	isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
733	if (isr == NULL) {
734		if (error != 0) {
735			/* XXX Should we send a notification ? */
736			goto bad;
737		} else {
738			if (ipsec_register_done(m, &error) < 0)
739				goto bad;
740
741			splx(s);
742			return ipsec_reinject_ipstack(m, AF_INET6);
743		}
744	}
745
746	sav = isr->sav;
747	dst = &sav->sah->saidx.dst;
748
749	ip6 = mtod(m, struct ip6_hdr *); /* XXX */
750
751	/* Do the appropriate encapsulation, if necessary */
752	if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
753	    dst->sa.sa_family != AF_INET6 ||        /* PF mismatch */
754	    ((dst->sa.sa_family == AF_INET6) &&
755	     (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) &&
756	     (!in6_sa_equal_addrwithscope(&dst->sin6,
757				  &ip6->ip6_dst)))) {
758		struct mbuf *mp;
759
760		/* Fix IPv6 header payload length. */
761		if (m->m_len < sizeof(struct ip6_hdr))
762			if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL)
763				return ENOBUFS;
764
765		if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) {
766			/* No jumbogram support. */
767			m_freem(m);
768			return ENXIO;   /*XXX*/
769		}
770
771		ip6 = mtod(m, struct ip6_hdr *);
772		ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6));
773
774		/* Encapsulate the packet */
775		error = ipip_output(m, isr, &mp, 0, 0);
776		if (mp == NULL && !error) {
777			/* Should never happen. */
778			DPRINTF(("ipsec6_process_packet: ipip_output "
779				 "returns no mbuf and no error!"));
780			error = EFAULT;
781		}
782
783		if (error) {
784			if (mp) {
785				/* XXX: Should never happen! */
786				m_freem(mp);
787			}
788			m = NULL; /* ipip_output() already freed it */
789			goto bad;
790		}
791
792		m = mp;
793		mp = NULL;
794	}
795
796	if (dst->sa.sa_family == AF_INET) {
797		struct ip *ip;
798		ip = mtod(m, struct ip *);
799		i = ip->ip_hl << 2;
800		off = offsetof(struct ip, ip_p);
801	} else {
802		compute_ipsec_pos(m, &i, &off);
803	}
804	error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
805	splx(s);
806	return error;
807bad:
808	splx(s);
809	if (m)
810		m_freem(m);
811	return error;
812}
813#endif /*INET6*/
814