2 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/sys/netipsec/ipsec_output.c,v 1.3.2.2 2003/03/28 20:32:53 sam Exp $
27 * $DragonFly: src/sys/netproto/ipsec/ipsec_output.c,v 1.11 2007/10/20 10:28:44 sephe Exp $
31 * IPsec output processing.
34 #include "opt_inet6.h"
35 #include "opt_ipsec.h"
37 #include <sys/param.h>
38 #include <sys/systm.h>
40 #include <sys/domain.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/errno.h>
44 #include <sys/syslog.h>
45 #include <sys/in_cksum.h>
48 #include <net/route.h>
50 #include <netinet/in.h>
51 #include <netinet/in_systm.h>
52 #include <netinet/ip.h>
53 #include <netinet/ip_var.h>
54 #include <netinet/in_var.h>
55 #include <netinet/ip_ecn.h>
57 #include <netinet6/ip6_ecn.h>
60 #include <netinet/ip6.h>
62 #include <netinet6/ip6_var.h>
64 #include <netinet/in_pcb.h>
66 #include <netinet/icmp6.h>
69 #include <netproto/ipsec/ipsec.h>
71 #include <netproto/ipsec/ipsec6.h>
73 #include <netproto/ipsec/ah_var.h>
74 #include <netproto/ipsec/esp_var.h>
75 #include <netproto/ipsec/ipcomp_var.h>
77 #include <netproto/ipsec/xform.h>
79 #include <netproto/ipsec/key.h>
80 #include <netproto/ipsec/keydb.h>
81 #include <netproto/ipsec/key_debug.h>
84 ipsec_process_done(struct mbuf
*m
, struct ipsecrequest
*isr
)
86 struct tdb_ident
*tdbi
;
89 struct secasindex
*saidx
;
92 KASSERT(m
!= NULL
, ("ipsec_process_done: null mbuf"));
93 KASSERT(isr
!= NULL
, ("ipsec_process_done: null ISR"));
95 KASSERT(sav
!= NULL
, ("ipsec_process_done: null SA"));
96 KASSERT(sav
->sah
!= NULL
, ("ipsec_process_done: null SAH"));
98 saidx
= &sav
->sah
->saidx
;
99 switch (saidx
->dst
.sa
.sa_family
) {
102 /* Fix the header length, for AH processing. */
103 mtod(m
, struct ip
*)->ip_len
= htons(m
->m_pkthdr
.len
);
108 /* Fix the header length, for AH processing. */
109 if (m
->m_pkthdr
.len
< sizeof (struct ip6_hdr
)) {
113 if (m
->m_pkthdr
.len
- sizeof (struct ip6_hdr
) > IPV6_MAXPACKET
) {
114 /* No jumbogram support. */
118 mtod(m
, struct ip6_hdr
*)->ip6_plen
=
119 htons(m
->m_pkthdr
.len
- sizeof(struct ip6_hdr
));
123 DPRINTF(("ipsec_process_done: unknown protocol family %u\n",
124 saidx
->dst
.sa
.sa_family
));
130 * Add a record of what we've done or what needs to be done to the
133 mtag
= m_tag_get(PACKET_TAG_IPSEC_OUT_DONE
,
134 sizeof(struct tdb_ident
), MB_DONTWAIT
);
136 DPRINTF(("ipsec_process_done: could not get packet tag\n"));
141 tdbi
= (struct tdb_ident
*)m_tag_data(mtag
);
142 tdbi
->dst
= saidx
->dst
;
143 tdbi
->proto
= saidx
->proto
;
144 tdbi
->spi
= sav
->spi
;
145 m_tag_prepend(m
, mtag
);
148 * If there's another (bundled) SA to apply, do so.
149 * Note that this puts a burden on the kernel stack size.
150 * If this is a problem we'll need to introduce a queue
151 * to set the packet on so we can unwind the stack before
152 * doing further processing.
155 newipsecstat
.ips_out_bundlesa
++;
156 return ipsec4_process_packet(m
, isr
->next
, 0, 0);
160 * We're done with IPsec processing, transmit the packet using the
161 * appropriate network protocol (IP or IPv6). SPD lookup will be
162 * performed again there.
164 switch (saidx
->dst
.sa
.sa_family
) {
168 ip
= mtod(m
, struct ip
*);
169 ip
->ip_len
= ntohs(ip
->ip_len
);
170 ip
->ip_off
= ntohs(ip
->ip_off
);
172 return ip_output(m
, NULL
, NULL
, IP_RAWOUTPUT
, NULL
, NULL
);
177 * We don't need massage, IPv6 header fields are always in
180 return ip6_output(m
, NULL
, NULL
, 0, NULL
, NULL
, NULL
);
183 panic("ipsec_process_done");
190 static struct ipsecrequest
*
193 struct ipsecrequest
*isr
,
195 struct secasindex
*saidx
,
199 #define IPSEC_OSTAT(x,y,z) (isr->saidx.proto == IPPROTO_ESP ? (x)++ : \
200 isr->saidx.proto == IPPROTO_AH ? (y)++ : (z)++)
201 struct secasvar
*sav
;
203 KASSERT(af
== AF_INET
|| af
== AF_INET6
,
204 ("ipsec_nextisr: invalid address family %u", af
));
207 * Craft SA index to search for proper SA. Note that
208 * we only fillin unspecified SA peers for transport
209 * mode; for tunnel mode they must already be filled in.
212 if (isr
->saidx
.mode
== IPSEC_MODE_TRANSPORT
) {
213 /* Fillin unspecified SA peers only for transport mode */
215 struct sockaddr_in
*sin
;
216 struct ip
*ip
= mtod(m
, struct ip
*);
218 if (saidx
->src
.sa
.sa_len
== 0) {
219 sin
= &saidx
->src
.sin
;
220 sin
->sin_len
= sizeof(*sin
);
221 sin
->sin_family
= AF_INET
;
222 sin
->sin_port
= IPSEC_PORT_ANY
;
223 sin
->sin_addr
= ip
->ip_src
;
225 if (saidx
->dst
.sa
.sa_len
== 0) {
226 sin
= &saidx
->dst
.sin
;
227 sin
->sin_len
= sizeof(*sin
);
228 sin
->sin_family
= AF_INET
;
229 sin
->sin_port
= IPSEC_PORT_ANY
;
230 sin
->sin_addr
= ip
->ip_dst
;
233 struct sockaddr_in6
*sin6
;
234 struct ip6_hdr
*ip6
= mtod(m
, struct ip6_hdr
*);
236 if (saidx
->src
.sin6
.sin6_len
== 0) {
237 sin6
= (struct sockaddr_in6
*)&saidx
->src
;
238 sin6
->sin6_len
= sizeof(*sin6
);
239 sin6
->sin6_family
= AF_INET6
;
240 sin6
->sin6_port
= IPSEC_PORT_ANY
;
241 sin6
->sin6_addr
= ip6
->ip6_src
;
242 if (IN6_IS_SCOPE_LINKLOCAL(&ip6
->ip6_src
)) {
243 /* fix scope id for comparing SPD */
244 sin6
->sin6_addr
.s6_addr16
[1] = 0;
245 sin6
->sin6_scope_id
=
246 ntohs(ip6
->ip6_src
.s6_addr16
[1]);
249 if (saidx
->dst
.sin6
.sin6_len
== 0) {
250 sin6
= (struct sockaddr_in6
*)&saidx
->dst
;
251 sin6
->sin6_len
= sizeof(*sin6
);
252 sin6
->sin6_family
= AF_INET6
;
253 sin6
->sin6_port
= IPSEC_PORT_ANY
;
254 sin6
->sin6_addr
= ip6
->ip6_dst
;
255 if (IN6_IS_SCOPE_LINKLOCAL(&ip6
->ip6_dst
)) {
256 /* fix scope id for comparing SPD */
257 sin6
->sin6_addr
.s6_addr16
[1] = 0;
258 sin6
->sin6_scope_id
=
259 ntohs(ip6
->ip6_dst
.s6_addr16
[1]);
266 * Lookup SA and validate it.
268 *error
= key_checkrequest(isr
, saidx
);
271 * IPsec processing is required, but no SA found.
272 * I assume that key_acquire() had been called
273 * to get/establish the SA. Here I discard
274 * this packet because it is responsibility for
275 * upper layer to retransmit the packet.
277 newipsecstat
.ips_out_nosa
++;
281 if (sav
== NULL
) { /* XXX valid return */
282 KASSERT(ipsec_get_reqlevel(isr
) == IPSEC_LEVEL_USE
,
283 ("ipsec_nextisr: no SA found, but required; level %u",
284 ipsec_get_reqlevel(isr
)));
288 *error
= EINVAL
; /*XXX*/
295 * Check system global policy controls.
297 if ((isr
->saidx
.proto
== IPPROTO_ESP
&& !esp_enable
) ||
298 (isr
->saidx
.proto
== IPPROTO_AH
&& !ah_enable
) ||
299 (isr
->saidx
.proto
== IPPROTO_IPCOMP
&& !ipcomp_enable
)) {
300 DPRINTF(("ipsec_nextisr: IPsec outbound packet dropped due"
301 " to policy (check your sysctls)\n"));
302 IPSEC_OSTAT(espstat
.esps_pdrops
, ahstat
.ahs_pdrops
,
303 ipcompstat
.ipcomps_pdrops
);
304 *error
= EHOSTUNREACH
;
309 * Sanity check the SA contents for the caller
310 * before they invoke the xform output method.
312 if (sav
->tdb_xform
== NULL
) {
313 DPRINTF(("ipsec_nextisr: no transform for SA\n"));
314 IPSEC_OSTAT(espstat
.esps_noxform
, ahstat
.ahs_noxform
,
315 ipcompstat
.ipcomps_noxform
);
316 *error
= EHOSTUNREACH
;
321 KASSERT(*error
!= 0, ("ipsec_nextisr: error return w/ no error code"));
328 * IPsec output logic for IPv4.
331 ipsec4_process_packet(
333 struct ipsecrequest
*isr
,
337 struct secasindex saidx
;
338 struct secasvar
*sav
;
342 KASSERT(m
!= NULL
, ("ipsec4_process_packet: null mbuf"));
343 KASSERT(isr
!= NULL
, ("ipsec4_process_packet: null isr"));
347 isr
= ipsec_nextisr(m
, isr
, AF_INET
, &saidx
, &error
);
353 union sockaddr_union
*dst
= &sav
->sah
->saidx
.dst
;
357 * Collect IP_DF state from the outer header.
359 if (dst
->sa
.sa_family
== AF_INET
) {
360 if (m
->m_len
< sizeof (struct ip
) &&
361 (m
= m_pullup(m
, sizeof (struct ip
))) == NULL
) {
365 ip
= mtod(m
, struct ip
*);
366 /* Honor system-wide control of how to handle IP_DF */
367 switch (ip4_ipsec_dfbit
) {
368 case 0: /* clear in outer header */
369 case 1: /* set in outer header */
370 setdf
= ip4_ipsec_dfbit
;
372 default: /* propagate to outer header */
373 setdf
= ntohs(ip
->ip_off
& IP_DF
);
377 ip
= NULL
; /* keep compiler happy */
380 /* Do the appropriate encapsulation, if necessary */
381 if (isr
->saidx
.mode
== IPSEC_MODE_TUNNEL
|| /* Tunnel requ'd */
382 dst
->sa
.sa_family
!= AF_INET
|| /* PF mismatch */
384 (sav
->flags
& SADB_X_SAFLAGS_TUNNEL
) || /* Tunnel requ'd */
385 sav
->tdb_xform
->xf_type
== XF_IP4
|| /* ditto */
387 (dst
->sa
.sa_family
== AF_INET
&& /* Proxy */
388 dst
->sin
.sin_addr
.s_addr
!= INADDR_ANY
&&
389 dst
->sin
.sin_addr
.s_addr
!= ip
->ip_dst
.s_addr
)) {
392 /* Fix IPv4 header checksum and length */
393 if (m
->m_len
< sizeof (struct ip
) &&
394 (m
= m_pullup(m
, sizeof (struct ip
))) == NULL
) {
398 ip
= mtod(m
, struct ip
*);
399 ip
->ip_len
= htons(m
->m_pkthdr
.len
);
402 if (ip
->ip_vhl
== IP_VHL_BORING
)
403 ip
->ip_sum
= in_cksum_hdr(ip
);
405 ip
->ip_sum
= in_cksum(m
,
406 _IP_VHL_HL(ip
->ip_vhl
) << 2);
408 ip
->ip_sum
= in_cksum(m
, ip
->ip_hl
<< 2);
411 /* Encapsulate the packet */
412 error
= ipip_output(m
, isr
, &mp
, 0, 0);
413 if (mp
== NULL
&& !error
) {
414 /* Should never happen. */
415 DPRINTF(("ipsec4_process_packet: ipip_output "
416 "returns no mbuf and no error!"));
426 * ipip_output clears IP_DF in the new header. If
427 * we need to propagate IP_DF from the outer header,
428 * then we have to do it here.
430 * XXX shouldn't assume what ipip_output does.
432 if (dst
->sa
.sa_family
== AF_INET
&& setdf
) {
433 if (m
->m_len
< sizeof (struct ip
) &&
434 (m
= m_pullup(m
, sizeof (struct ip
))) == NULL
) {
438 ip
= mtod(m
, struct ip
*);
439 ip
->ip_off
= ntohs(ip
->ip_off
);
441 ip
->ip_off
= htons(ip
->ip_off
);
447 * Dispatch to the appropriate IPsec transform logic. The
448 * packet will be returned for transmission after crypto
449 * processing, etc. are completed. For encapsulation we
450 * bypass this call because of the explicit call done above
451 * (necessary to deal with IP_DF handling for IPv4).
453 * NB: m & sav are ``passed to caller'' who's reponsible for
454 * for reclaiming their resources.
456 if (sav
->tdb_xform
->xf_type
!= XF_IP4
) {
457 ip
= mtod(m
, struct ip
*);
459 off
= offsetof(struct ip
, ip_p
);
460 error
= (*sav
->tdb_xform
->xf_output
)(m
, isr
, NULL
, i
, off
);
462 error
= ipsec_process_done(m
, isr
);
476 * Chop IP6 header from the payload.
479 ipsec6_splithdr(struct mbuf
*m
)
485 KASSERT(m
->m_len
>= sizeof (struct ip6_hdr
),
486 ("ipsec6_splithdr: first mbuf too short, len %u", m
->m_len
));
487 ip6
= mtod(m
, struct ip6_hdr
*);
488 hlen
= sizeof(struct ip6_hdr
);
489 if (m
->m_len
> hlen
) {
490 MGETHDR(mh
, MB_DONTWAIT
, MT_HEADER
);
495 M_MOVE_PKTHDR(mh
, m
);
502 bcopy((caddr_t
)ip6
, mtod(m
, caddr_t
), hlen
);
503 } else if (m
->m_len
< hlen
) {
504 m
= m_pullup(m
, hlen
);
512 * IPsec output logic for IPv6, transport mode.
516 struct ipsec_output_state
*state
,
519 struct secpolicy
*sp
,
523 struct ipsecrequest
*isr
;
524 struct secasindex saidx
;
528 KASSERT(state
!= NULL
, ("ipsec6_output: null state"));
529 KASSERT(state
->m
!= NULL
, ("ipsec6_output: null m"));
530 KASSERT(nexthdrp
!= NULL
, ("ipsec6_output: null nexthdrp"));
531 KASSERT(mprev
!= NULL
, ("ipsec6_output: null mprev"));
532 KASSERT(sp
!= NULL
, ("ipsec6_output: null sp"));
533 KASSERT(tun
!= NULL
, ("ipsec6_output: null tun"));
535 KEYDEBUG(KEYDEBUG_IPSEC_DATA
,
536 kprintf("ipsec6_output_trans: applyed SP\n");
537 kdebug_secpolicy(sp
));
540 if (isr
->saidx
.mode
== IPSEC_MODE_TUNNEL
) {
541 /* the rest will be handled by ipsec6_output_tunnel() */
542 *tun
= 1; /* need tunnel-mode processing */
549 isr
= ipsec_nextisr(m
, isr
, AF_INET6
, &saidx
, &error
);
552 /* XXX should notification be done for all errors ? */
554 * Notify the fact that the packet is discarded
555 * to ourselves. I believe this is better than
556 * just silently discarding. (jinmei@kame.net)
557 * XXX: should we restrict the error to TCP packets?
558 * XXX: should we directly notify sockets via
561 icmp6_error(m
, ICMP6_DST_UNREACH
,
562 ICMP6_DST_UNREACH_ADMIN
, 0);
563 m
= NULL
; /* NB: icmp6_error frees mbuf */
568 return (*isr
->sav
->tdb_xform
->xf_output
)(m
, isr
, NULL
,
569 sizeof (struct ip6_hdr
),
570 offsetof(struct ip6_hdr
, ip6_nxt
));
579 ipsec6_encapsulate(struct mbuf
*m
, struct secasvar
*sav
)
581 struct ip6_hdr
*oip6
;
585 /* can't tunnel between different AFs */
586 if (sav
->sah
->saidx
.src
.sa
.sa_family
!= AF_INET6
||
587 sav
->sah
->saidx
.dst
.sa
.sa_family
!= AF_INET6
) {
591 KASSERT(m
->m_len
!= sizeof (struct ip6_hdr
),
592 ("ipsec6_encapsulate: mbuf wrong size; len %u", m
->m_len
));
596 * grow the mbuf to accomodate the new IPv6 header.
598 plen
= m
->m_pkthdr
.len
;
599 if (M_LEADINGSPACE(m
->m_next
) < sizeof(struct ip6_hdr
)) {
601 MGET(n
, MB_DONTWAIT
, MT_DATA
);
606 n
->m_len
= sizeof(struct ip6_hdr
);
607 n
->m_next
= m
->m_next
;
609 m
->m_pkthdr
.len
+= sizeof(struct ip6_hdr
);
610 oip6
= mtod(n
, struct ip6_hdr
*);
612 m
->m_next
->m_len
+= sizeof(struct ip6_hdr
);
613 m
->m_next
->m_data
-= sizeof(struct ip6_hdr
);
614 m
->m_pkthdr
.len
+= sizeof(struct ip6_hdr
);
615 oip6
= mtod(m
->m_next
, struct ip6_hdr
*);
617 ip6
= mtod(m
, struct ip6_hdr
*);
618 ovbcopy((caddr_t
)ip6
, (caddr_t
)oip6
, sizeof(struct ip6_hdr
));
620 /* Fake link-local scope-class addresses */
621 if (IN6_IS_SCOPE_LINKLOCAL(&oip6
->ip6_src
))
622 oip6
->ip6_src
.s6_addr16
[1] = 0;
623 if (IN6_IS_SCOPE_LINKLOCAL(&oip6
->ip6_dst
))
624 oip6
->ip6_dst
.s6_addr16
[1] = 0;
626 /* construct new IPv6 header. see RFC 2401 5.1.2.2 */
627 /* ECN consideration. */
628 ip6_ecn_ingress(ip6_ipsec_ecn
, &ip6
->ip6_flow
, &oip6
->ip6_flow
);
629 if (plen
< IPV6_MAXPACKET
- sizeof(struct ip6_hdr
))
630 ip6
->ip6_plen
= htons(plen
);
632 /* ip6->ip6_plen will be updated in ip6_output() */
634 ip6
->ip6_nxt
= IPPROTO_IPV6
;
635 sav
->sah
->saidx
.src
.sin6
.sin6_addr
= ip6
->ip6_src
;
636 sav
->sah
->saidx
.dst
.sin6
.sin6_addr
= ip6
->ip6_dst
;
637 ip6
->ip6_hlim
= IPV6_DEFHLIM
;
639 /* XXX Should ip6_src be updated later ? */
645 * IPsec output logic for IPv6, tunnel mode.
648 ipsec6_output_tunnel(struct ipsec_output_state
*state
, struct secpolicy
*sp
, int flags
)
651 struct ipsecrequest
*isr
;
652 struct secasindex saidx
;
654 struct sockaddr_in6
* dst6
;
657 KASSERT(state
!= NULL
, ("ipsec6_output: null state"));
658 KASSERT(state
->m
!= NULL
, ("ipsec6_output: null m"));
659 KASSERT(sp
!= NULL
, ("ipsec6_output: null sp"));
661 KEYDEBUG(KEYDEBUG_IPSEC_DATA
,
662 kprintf("ipsec6_output_tunnel: applyed SP\n");
663 kdebug_secpolicy(sp
));
667 * transport mode ipsec (before the 1st tunnel mode) is already
668 * processed by ipsec6_output_trans().
670 for (isr
= sp
->req
; isr
; isr
= isr
->next
) {
671 if (isr
->saidx
.mode
== IPSEC_MODE_TUNNEL
)
674 isr
= ipsec_nextisr(m
, isr
, AF_INET6
, &saidx
, &error
);
679 * There may be the case that SA status will be changed when
680 * we are refering to one. So calling splsoftnet().
682 if (isr
->saidx
.mode
== IPSEC_MODE_TUNNEL
) {
684 * build IPsec tunnel.
686 /* XXX should be processed with other familiy */
687 if (isr
->sav
->sah
->saidx
.src
.sa
.sa_family
!= AF_INET6
) {
688 ipseclog((LOG_ERR
, "ipsec6_output_tunnel: "
689 "family mismatched between inner and outer, spi=%u\n",
690 ntohl(isr
->sav
->spi
)));
691 newipsecstat
.ips_out_inval
++;
692 error
= EAFNOSUPPORT
;
696 m
= ipsec6_splithdr(m
);
698 newipsecstat
.ips_out_nomem
++;
702 error
= ipsec6_encapsulate(m
, isr
->sav
);
707 ip6
= mtod(m
, struct ip6_hdr
*);
709 state
->ro
= &isr
->sav
->sah
->sa_route
;
710 state
->dst
= (struct sockaddr
*)&state
->ro
->ro_dst
;
711 dst6
= (struct sockaddr_in6
*)state
->dst
;
713 && ((state
->ro
->ro_rt
->rt_flags
& RTF_UP
) == 0
714 || !IN6_ARE_ADDR_EQUAL(&dst6
->sin6_addr
, &ip6
->ip6_dst
))) {
715 RTFREE(state
->ro
->ro_rt
);
716 state
->ro
->ro_rt
= NULL
;
718 if (state
->ro
->ro_rt
== 0) {
719 bzero(dst6
, sizeof(*dst6
));
720 dst6
->sin6_family
= AF_INET6
;
721 dst6
->sin6_len
= sizeof(*dst6
);
722 dst6
->sin6_addr
= ip6
->ip6_dst
;
725 if (state
->ro
->ro_rt
== 0) {
726 ip6stat
.ip6s_noroute
++;
727 newipsecstat
.ips_out_noroute
++;
728 error
= EHOSTUNREACH
;
732 /* adjust state->dst if tunnel endpoint is offlink */
733 if (state
->ro
->ro_rt
->rt_flags
& RTF_GATEWAY
) {
734 state
->dst
= (struct sockaddr
*)state
->ro
->ro_rt
->rt_gateway
;
735 dst6
= (struct sockaddr_in6
*)state
->dst
;
739 m
= ipsec6_splithdr(m
);
741 newipsecstat
.ips_out_nomem
++;
745 ip6
= mtod(m
, struct ip6_hdr
*);
746 return (*isr
->sav
->tdb_xform
->xf_output
)(m
, isr
, NULL
,
747 sizeof (struct ip6_hdr
),
748 offsetof(struct ip6_hdr
, ip6_nxt
));