ipsec_output.c revision 1.10 1 /* $NetBSD: ipsec_output.c,v 1.10 2004/03/16 22:48:29 jonathan 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.10 2004/03/16 22:48:29 jonathan 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 #include <netinet6/ip6_ecn.h>
63 #endif
64
65 #include <netinet/ip6.h>
66 #ifdef INET6
67 #include <netinet6/ip6_var.h>
68 #endif
69 #include <netinet/in_pcb.h>
70 #ifdef INET6
71 #include <netinet/icmp6.h>
72 #endif
73
74 #include <netipsec/ipsec.h>
75 #ifdef INET6
76 #include <netipsec/ipsec6.h>
77 #endif
78 #include <netipsec/ah_var.h>
79 #include <netipsec/esp_var.h>
80 #include <netipsec/ipcomp_var.h>
81
82 #include <netipsec/xform.h>
83
84 #include <netipsec/key.h>
85 #include <netipsec/keydb.h>
86 #include <netipsec/key_debug.h>
87 #include <netipsec/ipsec_osdep.h>
88
89 #include <net/net_osdep.h> /* ovbcopy() in ipsec6_encapsulate() */
90
91 int
92 ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr)
93 {
94 struct tdb_ident *tdbi;
95 struct m_tag *mtag;
96 struct secasvar *sav;
97 struct secasindex *saidx;
98 int error;
99
100 IPSEC_SPLASSERT_SOFTNET("ipsec_process_done");
101
102 IPSEC_ASSERT(m != NULL, ("ipsec_process_done: null mbuf"));
103 IPSEC_ASSERT(isr != NULL, ("ipsec_process_done: null ISR"));
104 sav = isr->sav;
105 IPSEC_ASSERT(sav != NULL, ("ipsec_process_done: null SA"));
106 IPSEC_ASSERT(sav->sah != NULL, ("ipsec_process_done: null SAH"));
107
108 saidx = &sav->sah->saidx;
109 switch (saidx->dst.sa.sa_family) {
110 #ifdef INET
111 case AF_INET:
112 /* Fix the header length, for AH processing. */
113 mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len);
114 break;
115 #endif /* INET */
116 #ifdef INET6
117 case AF_INET6:
118 /* Fix the header length, for AH processing. */
119 if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) {
120 error = ENXIO;
121 goto bad;
122 }
123 if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) {
124 /* No jumbogram support. */
125 error = ENXIO; /*?*/
126 goto bad;
127 }
128 mtod(m, struct ip6_hdr *)->ip6_plen =
129 htons(m->m_pkthdr.len - sizeof(struct ip6_hdr));
130 break;
131 #endif /* INET6 */
132 default:
133 DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
134 saidx->dst.sa.sa_family));
135 error = ENXIO;
136 goto bad;
137 }
138
139 /*
140 * Add a record of what we've done or what needs to be done to the
141 * packet.
142 */
143 mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE,
144 sizeof(struct tdb_ident), M_NOWAIT);
145 if (mtag == NULL) {
146 DPRINTF(("ipsec_process_done: could not get packet tag\n"));
147 error = ENOMEM;
148 goto bad;
149 }
150
151 tdbi = (struct tdb_ident *)(mtag + 1);
152 tdbi->dst = saidx->dst;
153 tdbi->proto = saidx->proto;
154 tdbi->spi = sav->spi;
155 m_tag_prepend(m, mtag);
156
157 /*
158 * If there's another (bundled) SA to apply, do so.
159 * Note that this puts a burden on the kernel stack size.
160 * If this is a problem we'll need to introduce a queue
161 * to set the packet on so we can unwind the stack before
162 * doing further processing.
163 */
164 if (isr->next) {
165 newipsecstat.ips_out_bundlesa++;
166 return ipsec4_process_packet(m, isr->next, 0, 0);
167 }
168
169 /*
170 * We're done with IPsec processing, transmit the packet using the
171 * appropriate network protocol (IP or IPv6). SPD lookup will be
172 * performed again there.
173 */
174 switch (saidx->dst.sa.sa_family) {
175 #ifdef INET
176 struct ip *ip;
177 case AF_INET:
178 ip = mtod(m, struct ip *);
179 #ifdef __FreeBSD__
180 /* FreeBSD ip_output() expects ip_len, ip_off in host endian */
181 ip->ip_len = ntohs(ip->ip_len);
182 ip->ip_off = ntohs(ip->ip_off);
183 #endif /* __FreeBSD_ */
184 return ip_output(m, NULL, NULL, IP_RAWOUTPUT,
185 (struct ip_moptions *)NULL, (struct socket *)NULL);
186
187 #endif /* INET */
188 #ifdef INET6
189 case AF_INET6:
190 /*
191 * We don't need massage, IPv6 header fields are always in
192 * net endian.
193 */
194 return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
195 #endif /* INET6 */
196 }
197 panic("ipsec_process_done");
198 bad:
199 m_freem(m);
200 KEY_FREESAV(&sav);
201 return (error);
202 }
203
204 static struct ipsecrequest *
205 ipsec_nextisr(
206 struct mbuf *m,
207 struct ipsecrequest *isr,
208 int af,
209 struct secasindex *saidx,
210 int *error
211 )
212 {
213 #define IPSEC_OSTAT(x,y,z) (isr->saidx.proto == IPPROTO_ESP ? (x)++ : \
214 isr->saidx.proto == IPPROTO_AH ? (y)++ : (z)++)
215 struct secasvar *sav;
216
217 IPSEC_SPLASSERT_SOFTNET("ipsec_nextisr");
218 IPSEC_ASSERT(af == AF_INET || af == AF_INET6,
219 ("ipsec_nextisr: invalid address family %u", af));
220 again:
221 /*
222 * Craft SA index to search for proper SA. Note that
223 * we only fillin unspecified SA peers for transport
224 * mode; for tunnel mode they must already be filled in.
225 */
226 *saidx = isr->saidx;
227 if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) {
228 /* Fillin unspecified SA peers only for transport mode */
229 if (af == AF_INET) {
230 struct sockaddr_in *sin;
231 struct ip *ip = mtod(m, struct ip *);
232
233 if (saidx->src.sa.sa_len == 0) {
234 sin = &saidx->src.sin;
235 sin->sin_len = sizeof(*sin);
236 sin->sin_family = AF_INET;
237 sin->sin_port = IPSEC_PORT_ANY;
238 sin->sin_addr = ip->ip_src;
239 }
240 if (saidx->dst.sa.sa_len == 0) {
241 sin = &saidx->dst.sin;
242 sin->sin_len = sizeof(*sin);
243 sin->sin_family = AF_INET;
244 sin->sin_port = IPSEC_PORT_ANY;
245 sin->sin_addr = ip->ip_dst;
246 }
247 } else {
248 struct sockaddr_in6 *sin6;
249 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
250
251 if (saidx->src.sin6.sin6_len == 0) {
252 sin6 = (struct sockaddr_in6 *)&saidx->src;
253 sin6->sin6_len = sizeof(*sin6);
254 sin6->sin6_family = AF_INET6;
255 sin6->sin6_port = IPSEC_PORT_ANY;
256 sin6->sin6_addr = ip6->ip6_src;
257 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
258 /* fix scope id for comparing SPD */
259 sin6->sin6_addr.s6_addr16[1] = 0;
260 sin6->sin6_scope_id =
261 ntohs(ip6->ip6_src.s6_addr16[1]);
262 }
263 }
264 if (saidx->dst.sin6.sin6_len == 0) {
265 sin6 = (struct sockaddr_in6 *)&saidx->dst;
266 sin6->sin6_len = sizeof(*sin6);
267 sin6->sin6_family = AF_INET6;
268 sin6->sin6_port = IPSEC_PORT_ANY;
269 sin6->sin6_addr = ip6->ip6_dst;
270 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
271 /* fix scope id for comparing SPD */
272 sin6->sin6_addr.s6_addr16[1] = 0;
273 sin6->sin6_scope_id =
274 ntohs(ip6->ip6_dst.s6_addr16[1]);
275 }
276 }
277 }
278 }
279
280 /*
281 * Lookup SA and validate it.
282 */
283 *error = key_checkrequest(isr, saidx);
284 if (*error != 0) {
285 /*
286 * IPsec processing is required, but no SA found.
287 * I assume that key_acquire() had been called
288 * to get/establish the SA. Here I discard
289 * this packet because it is responsibility for
290 * upper layer to retransmit the packet.
291 */
292 newipsecstat.ips_out_nosa++;
293 goto bad;
294 }
295 sav = isr->sav;
296 if (sav == NULL) { /* XXX valid return */
297 IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE,
298 ("ipsec_nextisr: no SA found, but required; level %u",
299 ipsec_get_reqlevel(isr)));
300 isr = isr->next;
301 if (isr == NULL) {
302 /*XXXstatistic??*/
303 *error = EINVAL; /*XXX*/
304 return isr;
305 }
306 goto again;
307 }
308
309 /*
310 * Check system global policy controls.
311 */
312 if ((isr->saidx.proto == IPPROTO_ESP && !esp_enable) ||
313 (isr->saidx.proto == IPPROTO_AH && !ah_enable) ||
314 (isr->saidx.proto == IPPROTO_IPCOMP && !ipcomp_enable)) {
315 DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due"
316 " to policy (check your sysctls)\n"));
317 IPSEC_OSTAT(espstat.esps_pdrops, ahstat.ahs_pdrops,
318 ipcompstat.ipcomps_pdrops);
319 *error = EHOSTUNREACH;
320 goto bad;
321 }
322
323 /*
324 * Sanity check the SA contents for the caller
325 * before they invoke the xform output method.
326 */
327 if (sav->tdb_xform == NULL) {
328 DPRINTF(("ipsec_nextisr: no transform for SA\n"));
329 IPSEC_OSTAT(espstat.esps_noxform, ahstat.ahs_noxform,
330 ipcompstat.ipcomps_noxform);
331 *error = EHOSTUNREACH;
332 goto bad;
333 }
334 return isr;
335 bad:
336 IPSEC_ASSERT(*error != 0, ("ipsec_nextisr: error return w/ no error code"));
337 return NULL;
338 #undef IPSEC_OSTAT
339 }
340
341 #ifdef INET
342 /*
343 * IPsec output logic for IPv4.
344 */
345 int
346 ipsec4_process_packet(
347 struct mbuf *m,
348 struct ipsecrequest *isr,
349 int flags,
350 int tunalready)
351 {
352 struct secasindex saidx;
353 struct secasvar *sav;
354 struct ip *ip;
355 int s, error, i, off;
356
357 IPSEC_ASSERT(m != NULL, ("ipsec4_process_packet: null mbuf"));
358 IPSEC_ASSERT(isr != NULL, ("ipsec4_process_packet: null isr"));
359
360 s = splsoftnet(); /* insure SA contents don't change */
361
362 isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error);
363 if (isr == NULL)
364 goto bad;
365
366 sav = isr->sav;
367 if (!tunalready) {
368 union sockaddr_union *dst = &sav->sah->saidx.dst;
369 int setdf;
370
371 /*
372 * Collect IP_DF state from the outer header.
373 */
374 if (dst->sa.sa_family == AF_INET) {
375 if (m->m_len < sizeof (struct ip) &&
376 (m = m_pullup(m, sizeof (struct ip))) == NULL) {
377 error = ENOBUFS;
378 goto bad;
379 }
380 ip = mtod(m, struct ip *);
381 /* Honor system-wide control of how to handle IP_DF */
382 switch (ip4_ipsec_dfbit) {
383 case 0: /* clear in outer header */
384 case 1: /* set in outer header */
385 setdf = ip4_ipsec_dfbit;
386 break;
387 default: /* propagate to outer header */
388 setdf = ip->ip_off;
389 #ifndef __FreeBSD__
390 /* On FreeBSD, ip_off and ip_len assumed in host endian. */
391 setdf = ntohs(setdf);
392 #endif
393 setdf = htons(setdf & IP_DF);
394 break;
395 }
396 } else {
397 ip = NULL; /* keep compiler happy */
398 setdf = 0;
399 }
400 /* Do the appropriate encapsulation, if necessary */
401 if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */
402 dst->sa.sa_family != AF_INET || /* PF mismatch */
403 #if 0
404 (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */
405 sav->tdb_xform->xf_type == XF_IP4 || /* ditto */
406 #endif
407 (dst->sa.sa_family == AF_INET && /* Proxy */
408 dst->sin.sin_addr.s_addr != INADDR_ANY &&
409 dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) {
410 struct mbuf *mp;
411
412 /* Fix IPv4 header checksum and length */
413 if (m->m_len < sizeof (struct ip) &&
414 (m = m_pullup(m, sizeof (struct ip))) == NULL) {
415 error = ENOBUFS;
416 goto bad;
417 }
418 ip = mtod(m, struct ip *);
419 ip->ip_len = htons(m->m_pkthdr.len);
420 ip->ip_sum = 0;
421 #ifdef _IP_VHL
422 if (ip->ip_vhl == IP_VHL_BORING)
423 ip->ip_sum = in_cksum_hdr(ip);
424 else
425 ip->ip_sum = in_cksum(m,
426 _IP_VHL_HL(ip->ip_vhl) << 2);
427 #else
428 ip->ip_sum = in_cksum(m, ip->ip_hl << 2);
429 #endif
430
431 /* Encapsulate the packet */
432 error = ipip_output(m, isr, &mp, 0, 0);
433 if (mp == NULL && !error) {
434 /* Should never happen. */
435 DPRINTF(("ipsec4_process_packet: ipip_output "
436 "returns no mbuf and no error!"));
437 error = EFAULT;
438 }
439 if (error) {
440 if (mp) {
441 /* XXX: Should never happen! */
442 m_freem(mp);
443 }
444 m = NULL; /* ipip_output() already freed it */
445 goto bad;
446 }
447 m = mp, mp = NULL;
448 /*
449 * ipip_output clears IP_DF in the new header. If
450 * we need to propagate IP_DF from the outer header,
451 * then we have to do it here.
452 *
453 * XXX shouldn't assume what ipip_output does.
454 */
455 if (dst->sa.sa_family == AF_INET && setdf) {
456 if (m->m_len < sizeof (struct ip) &&
457 (m = m_pullup(m, sizeof (struct ip))) == NULL) {
458 error = ENOBUFS;
459 goto bad;
460 }
461 ip = mtod(m, struct ip *);
462 ip->ip_off = ntohs(ip->ip_off);
463 ip->ip_off |= IP_DF;
464 ip->ip_off = htons(ip->ip_off);
465 }
466 }
467 }
468
469 /*
470 * Dispatch to the appropriate IPsec transform logic. The
471 * packet will be returned for transmission after crypto
472 * processing, etc. are completed. For encapsulation we
473 * bypass this call because of the explicit call done above
474 * (necessary to deal with IP_DF handling for IPv4).
475 *
476 * NB: m & sav are ``passed to caller'' who's reponsible for
477 * for reclaiming their resources.
478 */
479 if (sav->tdb_xform->xf_type != XF_IP4) {
480 ip = mtod(m, struct ip *);
481 i = ip->ip_hl << 2;
482 off = offsetof(struct ip, ip_p);
483 error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off);
484 } else {
485 error = ipsec_process_done(m, isr);
486 }
487 splx(s);
488 return error;
489 bad:
490 splx(s);
491 if (m)
492 m_freem(m);
493 return error;
494 }
495 #endif
496
497 #ifdef INET6
498 /*
499 * Chop IP6 header from the payload.
500 */
501 static struct mbuf *
502 ipsec6_splithdr(struct mbuf *m)
503 {
504 struct mbuf *mh;
505 struct ip6_hdr *ip6;
506 int hlen;
507
508 IPSEC_ASSERT(m->m_len >= sizeof (struct ip6_hdr),
509 ("ipsec6_splithdr: first mbuf too short, len %u", m->m_len));
510 ip6 = mtod(m, struct ip6_hdr *);
511 hlen = sizeof(struct ip6_hdr);
512 if (m->m_len > hlen) {
513 MGETHDR(mh, M_DONTWAIT, MT_HEADER);
514 if (!mh) {
515 m_freem(m);
516 return NULL;
517 }
518 M_MOVE_PKTHDR(mh, m);
519 MH_ALIGN(mh, hlen);
520 m->m_len -= hlen;
521 m->m_data += hlen;
522 mh->m_next = m;
523 m = mh;
524 m->m_len = hlen;
525 bcopy((caddr_t)ip6, mtod(m, caddr_t), hlen);
526 } else if (m->m_len < hlen) {
527 m = m_pullup(m, hlen);
528 if (!m)
529 return NULL;
530 }
531 return m;
532 }
533
534 /*
535 * IPsec output logic for IPv6, transport mode.
536 */
537 int
538 ipsec6_output_trans(
539 struct ipsec_output_state *state,
540 u_char *nexthdrp,
541 struct mbuf *mprev,
542 struct secpolicy *sp,
543 int flags,
544 int *tun)
545 {
546 struct ipsecrequest *isr;
547 struct secasindex saidx;
548 int error = 0;
549 struct mbuf *m;
550
551 IPSEC_ASSERT(state != NULL, ("ipsec6_output: null state"));
552 IPSEC_ASSERT(state->m != NULL, ("ipsec6_output: null m"));
553 IPSEC_ASSERT(nexthdrp != NULL, ("ipsec6_output: null nexthdrp"));
554 IPSEC_ASSERT(mprev != NULL, ("ipsec6_output: null mprev"));
555 IPSEC_ASSERT(sp != NULL, ("ipsec6_output: null sp"));
556 IPSEC_ASSERT(tun != NULL, ("ipsec6_output: null tun"));
557
558 KEYDEBUG(KEYDEBUG_IPSEC_DATA,
559 printf("ipsec6_output_trans: applyed SP\n");
560 kdebug_secpolicy(sp));
561
562 isr = sp->req;
563 if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
564 /* the rest will be handled by ipsec6_output_tunnel() */
565 *tun = 1; /* need tunnel-mode processing */
566 return 0;
567 }
568
569 *tun = 0;
570 m = state->m;
571
572 isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
573 if (isr == NULL) {
574 #ifdef notdef
575 /* XXX should notification be done for all errors ? */
576 /*
577 * Notify the fact that the packet is discarded
578 * to ourselves. I believe this is better than
579 * just silently discarding. (jinmei (at) kame.net)
580 * XXX: should we restrict the error to TCP packets?
581 * XXX: should we directly notify sockets via
582 * pfctlinputs?
583 */
584 icmp6_error(m, ICMP6_DST_UNREACH,
585 ICMP6_DST_UNREACH_ADMIN, 0);
586 m = NULL; /* NB: icmp6_error frees mbuf */
587 #endif
588 goto bad;
589 }
590
591 return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL,
592 sizeof (struct ip6_hdr),
593 offsetof(struct ip6_hdr, ip6_nxt));
594 bad:
595 if (m)
596 m_freem(m);
597 state->m = NULL;
598 return error;
599 }
600
601 static int
602 ipsec6_encapsulate(struct mbuf *m, struct secasvar *sav)
603 {
604 struct ip6_hdr *oip6;
605 struct ip6_hdr *ip6;
606 size_t plen;
607
608 /* can't tunnel between different AFs */
609 if (sav->sah->saidx.src.sa.sa_family != AF_INET6 ||
610 sav->sah->saidx.dst.sa.sa_family != AF_INET6) {
611 m_freem(m);
612 return EINVAL;
613 }
614 IPSEC_ASSERT(m->m_len != sizeof (struct ip6_hdr),
615 ("ipsec6_encapsulate: mbuf wrong size; len %u", m->m_len));
616
617
618 /*
619 * grow the mbuf to accomodate the new IPv6 header.
620 */
621 plen = m->m_pkthdr.len;
622 if (M_LEADINGSPACE(m->m_next) < sizeof(struct ip6_hdr)) {
623 struct mbuf *n;
624 MGET(n, M_DONTWAIT, MT_DATA);
625 if (!n) {
626 m_freem(m);
627 return ENOBUFS;
628 }
629 n->m_len = sizeof(struct ip6_hdr);
630 n->m_next = m->m_next;
631 m->m_next = n;
632 m->m_pkthdr.len += sizeof(struct ip6_hdr);
633 oip6 = mtod(n, struct ip6_hdr *);
634 } else {
635 m->m_next->m_len += sizeof(struct ip6_hdr);
636 m->m_next->m_data -= sizeof(struct ip6_hdr);
637 m->m_pkthdr.len += sizeof(struct ip6_hdr);
638 oip6 = mtod(m->m_next, struct ip6_hdr *);
639 }
640 ip6 = mtod(m, struct ip6_hdr *);
641 ovbcopy((caddr_t)ip6, (caddr_t)oip6, sizeof(struct ip6_hdr));
642
643 /* Fake link-local scope-class addresses */
644 if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_src))
645 oip6->ip6_src.s6_addr16[1] = 0;
646 if (IN6_IS_SCOPE_LINKLOCAL(&oip6->ip6_dst))
647 oip6->ip6_dst.s6_addr16[1] = 0;
648
649 /* construct new IPv6 header. see RFC 2401 5.1.2.2 */
650 /* ECN consideration. */
651 ip6_ecn_ingress(ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow);
652 if (plen < IPV6_MAXPACKET - sizeof(struct ip6_hdr))
653 ip6->ip6_plen = htons(plen);
654 else {
655 /* ip6->ip6_plen will be updated in ip6_output() */
656 }
657 ip6->ip6_nxt = IPPROTO_IPV6;
658 sav->sah->saidx.src.sin6.sin6_addr = ip6->ip6_src;
659 sav->sah->saidx.dst.sin6.sin6_addr = ip6->ip6_dst;
660 ip6->ip6_hlim = IPV6_DEFHLIM;
661
662 /* XXX Should ip6_src be updated later ? */
663
664 return 0;
665 }
666
667 /*
668 * IPsec output logic for IPv6, tunnel mode.
669 */
670 int
671 ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int flags)
672 {
673 struct ip6_hdr *ip6;
674 struct ipsecrequest *isr;
675 struct secasindex saidx;
676 int error;
677 struct sockaddr_in6* dst6;
678 struct mbuf *m;
679
680 IPSEC_ASSERT(state != NULL, ("ipsec6_output: null state"));
681 IPSEC_ASSERT(state->m != NULL, ("ipsec6_output: null m"));
682 IPSEC_ASSERT(sp != NULL, ("ipsec6_output: null sp"));
683
684 KEYDEBUG(KEYDEBUG_IPSEC_DATA,
685 printf("ipsec6_output_tunnel: applyed SP\n");
686 kdebug_secpolicy(sp));
687
688 m = state->m;
689 /*
690 * transport mode ipsec (before the 1st tunnel mode) is already
691 * processed by ipsec6_output_trans().
692 */
693 for (isr = sp->req; isr; isr = isr->next) {
694 if (isr->saidx.mode == IPSEC_MODE_TUNNEL)
695 break;
696 }
697 isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error);
698 if (isr == NULL)
699 goto bad;
700
701 /*
702 * There may be the case that SA status will be changed when
703 * we are refering to one. So calling splsoftnet().
704 */
705 if (isr->saidx.mode == IPSEC_MODE_TUNNEL) {
706 /*
707 * build IPsec tunnel.
708 */
709 /* XXX should be processed with other familiy */
710 if (isr->sav->sah->saidx.src.sa.sa_family != AF_INET6) {
711 ipseclog((LOG_ERR, "ipsec6_output_tunnel: "
712 "family mismatched between inner and outer, spi=%lu\n",
713 ntohl(isr->sav->spi)));
714 newipsecstat.ips_out_inval++;
715 error = EAFNOSUPPORT;
716 goto bad;
717 }
718
719 m = ipsec6_splithdr(m);
720 if (!m) {
721 newipsecstat.ips_out_nomem++;
722 error = ENOMEM;
723 goto bad;
724 }
725 error = ipsec6_encapsulate(m, isr->sav);
726 if (error) {
727 m = NULL;
728 goto bad;
729 }
730 ip6 = mtod(m, struct ip6_hdr *);
731
732 state->ro = &isr->sav->sah->sa_route;
733 state->dst = (struct sockaddr *)&state->ro->ro_dst;
734 dst6 = (struct sockaddr_in6 *)state->dst;
735 if (state->ro->ro_rt
736 && ((state->ro->ro_rt->rt_flags & RTF_UP) == 0
737 || !IN6_ARE_ADDR_EQUAL(&dst6->sin6_addr, &ip6->ip6_dst))) {
738 RTFREE(state->ro->ro_rt);
739 state->ro->ro_rt = NULL;
740 }
741 if (state->ro->ro_rt == 0) {
742 bzero(dst6, sizeof(*dst6));
743 dst6->sin6_family = AF_INET6;
744 dst6->sin6_len = sizeof(*dst6);
745 dst6->sin6_addr = ip6->ip6_dst;
746 rtalloc(state->ro);
747 }
748 if (state->ro->ro_rt == 0) {
749 ip6stat.ip6s_noroute++;
750 newipsecstat.ips_out_noroute++;
751 error = EHOSTUNREACH;
752 goto bad;
753 }
754
755 /* adjust state->dst if tunnel endpoint is offlink */
756 if (state->ro->ro_rt->rt_flags & RTF_GATEWAY) {
757 state->dst = (struct sockaddr *)state->ro->ro_rt->rt_gateway;
758 dst6 = (struct sockaddr_in6 *)state->dst;
759 }
760 }
761
762 m = ipsec6_splithdr(m);
763 if (!m) {
764 newipsecstat.ips_out_nomem++;
765 error = ENOMEM;
766 goto bad;
767 }
768 ip6 = mtod(m, struct ip6_hdr *);
769 return (*isr->sav->tdb_xform->xf_output)(m, isr, NULL,
770 sizeof (struct ip6_hdr),
771 offsetof(struct ip6_hdr, ip6_nxt));
772 bad:
773 if (m)
774 m_freem(m);
775 state->m = NULL;
776 return error;
777 }
778 #endif /*INET6*/
779