1aaea26efSSam Leffler /*- 2aaea26efSSam Leffler * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3aaea26efSSam Leffler * All rights reserved. 4aaea26efSSam Leffler * 5aaea26efSSam Leffler * Redistribution and use in source and binary forms, with or without 6aaea26efSSam Leffler * modification, are permitted provided that the following conditions 7aaea26efSSam Leffler * are met: 8aaea26efSSam Leffler * 1. Redistributions of source code must retain the above copyright 9aaea26efSSam Leffler * notice, this list of conditions and the following disclaimer. 10aaea26efSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 11aaea26efSSam Leffler * notice, this list of conditions and the following disclaimer in the 12aaea26efSSam Leffler * documentation and/or other materials provided with the distribution. 13aaea26efSSam Leffler * 14aaea26efSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15aaea26efSSam Leffler * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16aaea26efSSam Leffler * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17aaea26efSSam Leffler * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18aaea26efSSam Leffler * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19aaea26efSSam Leffler * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20aaea26efSSam Leffler * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21aaea26efSSam Leffler * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22aaea26efSSam Leffler * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23aaea26efSSam Leffler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24aaea26efSSam Leffler * SUCH DAMAGE. 25aaea26efSSam Leffler * 26aaea26efSSam Leffler * $FreeBSD$ 27aaea26efSSam Leffler */ 2888768458SSam Leffler 2988768458SSam Leffler /* 3088768458SSam Leffler * IPsec output processing. 3188768458SSam Leffler */ 3288768458SSam Leffler #include "opt_inet.h" 3388768458SSam Leffler #include "opt_inet6.h" 3488768458SSam Leffler #include "opt_ipsec.h" 3588768458SSam Leffler 3688768458SSam Leffler #include <sys/param.h> 3788768458SSam Leffler #include <sys/systm.h> 3888768458SSam Leffler #include <sys/mbuf.h> 3988768458SSam Leffler #include <sys/domain.h> 4088768458SSam Leffler #include <sys/protosw.h> 4188768458SSam Leffler #include <sys/socket.h> 4288768458SSam Leffler #include <sys/errno.h> 43*ef91a976SAndrey V. Elsukov #include <sys/hhook.h> 4488768458SSam Leffler #include <sys/syslog.h> 4588768458SSam Leffler 4688768458SSam Leffler #include <net/if.h> 47*ef91a976SAndrey V. Elsukov #include <net/if_enc.h> 4876039bc8SGleb Smirnoff #include <net/if_var.h> 49eddfbb76SRobert Watson #include <net/vnet.h> 5088768458SSam Leffler 5188768458SSam Leffler #include <netinet/in.h> 5288768458SSam Leffler #include <netinet/in_systm.h> 5388768458SSam Leffler #include <netinet/ip.h> 5488768458SSam Leffler #include <netinet/ip_var.h> 5588768458SSam Leffler #include <netinet/in_var.h> 5688768458SSam Leffler #include <netinet/ip_ecn.h> 5788768458SSam Leffler #ifdef INET6 5888768458SSam Leffler #include <netinet6/ip6_ecn.h> 5988768458SSam Leffler #endif 6088768458SSam Leffler 6188768458SSam Leffler #include <netinet/ip6.h> 6288768458SSam Leffler #ifdef INET6 6388768458SSam Leffler #include <netinet6/ip6_var.h> 6461f37615SAndrey V. Elsukov #include <netinet6/scope6_var.h> 6588768458SSam Leffler #endif 6688768458SSam Leffler #include <netinet/in_pcb.h> 6788768458SSam Leffler #ifdef INET6 6888768458SSam Leffler #include <netinet/icmp6.h> 6988768458SSam Leffler #endif 7088768458SSam Leffler 7188768458SSam Leffler #include <netipsec/ipsec.h> 7288768458SSam Leffler #ifdef INET6 7388768458SSam Leffler #include <netipsec/ipsec6.h> 7488768458SSam Leffler #endif 7588768458SSam Leffler #include <netipsec/ah_var.h> 7688768458SSam Leffler #include <netipsec/esp_var.h> 7788768458SSam Leffler #include <netipsec/ipcomp_var.h> 7888768458SSam Leffler 7988768458SSam Leffler #include <netipsec/xform.h> 8088768458SSam Leffler 8188768458SSam Leffler #include <netipsec/key.h> 8288768458SSam Leffler #include <netipsec/keydb.h> 8388768458SSam Leffler #include <netipsec/key_debug.h> 8488768458SSam Leffler 8588768458SSam Leffler #include <machine/in_cksum.h> 8688768458SSam Leffler 877b495c44SVANHULLEBUS Yvan #ifdef IPSEC_NAT_T 887b495c44SVANHULLEBUS Yvan #include <netinet/udp.h> 897b495c44SVANHULLEBUS Yvan #endif 907b495c44SVANHULLEBUS Yvan 9188768458SSam Leffler int 9288768458SSam Leffler ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) 9388768458SSam Leffler { 9488768458SSam Leffler struct tdb_ident *tdbi; 9588768458SSam Leffler struct m_tag *mtag; 9688768458SSam Leffler struct secasvar *sav; 9788768458SSam Leffler struct secasindex *saidx; 9888768458SSam Leffler int error; 9988768458SSam Leffler 1009ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 1019ffa9677SSam Leffler IPSEC_ASSERT(isr != NULL, ("null ISR")); 1023d80e82dSAndrey V. Elsukov IPSEC_ASSERT(isr->sp != NULL, ("NULL isr->sp")); 10388768458SSam Leffler sav = isr->sav; 1049ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("null SA")); 1059ffa9677SSam Leffler IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 10688768458SSam Leffler 10788768458SSam Leffler saidx = &sav->sah->saidx; 10888768458SSam Leffler switch (saidx->dst.sa.sa_family) { 10988768458SSam Leffler #ifdef INET 11088768458SSam Leffler case AF_INET: 11188768458SSam Leffler /* Fix the header length, for AH processing. */ 11288768458SSam Leffler mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len); 11388768458SSam Leffler break; 11488768458SSam Leffler #endif /* INET */ 11588768458SSam Leffler #ifdef INET6 11688768458SSam Leffler case AF_INET6: 11788768458SSam Leffler /* Fix the header length, for AH processing. */ 11888768458SSam Leffler if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) { 11988768458SSam Leffler error = ENXIO; 12088768458SSam Leffler goto bad; 12188768458SSam Leffler } 12288768458SSam Leffler if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) { 12388768458SSam Leffler /* No jumbogram support. */ 12488768458SSam Leffler error = ENXIO; /*?*/ 12588768458SSam Leffler goto bad; 12688768458SSam Leffler } 12788768458SSam Leffler mtod(m, struct ip6_hdr *)->ip6_plen = 12888768458SSam Leffler htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 12988768458SSam Leffler break; 13088768458SSam Leffler #endif /* INET6 */ 13188768458SSam Leffler default: 1329ffa9677SSam Leffler DPRINTF(("%s: unknown protocol family %u\n", __func__, 13388768458SSam Leffler saidx->dst.sa.sa_family)); 13488768458SSam Leffler error = ENXIO; 13588768458SSam Leffler goto bad; 13688768458SSam Leffler } 13788768458SSam Leffler 13888768458SSam Leffler /* 13988768458SSam Leffler * Add a record of what we've done or what needs to be done to the 14088768458SSam Leffler * packet. 14188768458SSam Leffler */ 14288768458SSam Leffler mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 14388768458SSam Leffler sizeof(struct tdb_ident), M_NOWAIT); 14488768458SSam Leffler if (mtag == NULL) { 1459ffa9677SSam Leffler DPRINTF(("%s: could not get packet tag\n", __func__)); 14688768458SSam Leffler error = ENOMEM; 14788768458SSam Leffler goto bad; 14888768458SSam Leffler } 14988768458SSam Leffler 15088768458SSam Leffler tdbi = (struct tdb_ident *)(mtag + 1); 15188768458SSam Leffler tdbi->dst = saidx->dst; 15288768458SSam Leffler tdbi->proto = saidx->proto; 15388768458SSam Leffler tdbi->spi = sav->spi; 15488768458SSam Leffler m_tag_prepend(m, mtag); 15588768458SSam Leffler 15659959de5SErmal Luçi key_sa_recordxfer(sav, m); /* record data transfer */ 15759959de5SErmal Luçi 15888768458SSam Leffler /* 15988768458SSam Leffler * If there's another (bundled) SA to apply, do so. 16088768458SSam Leffler * Note that this puts a burden on the kernel stack size. 16188768458SSam Leffler * If this is a problem we'll need to introduce a queue 16288768458SSam Leffler * to set the packet on so we can unwind the stack before 16388768458SSam Leffler * doing further processing. 16488768458SSam Leffler */ 16588768458SSam Leffler if (isr->next) { 166174b0d41SBjoern A. Zeeb /* XXX-BZ currently only support same AF bundles. */ 167db178eb8SBjoern A. Zeeb switch (saidx->dst.sa.sa_family) { 168db178eb8SBjoern A. Zeeb #ifdef INET 169db178eb8SBjoern A. Zeeb case AF_INET: 170f9d8f665SAndrey V. Elsukov IPSECSTAT_INC(ips_out_bundlesa); 171f3677984SAndrey V. Elsukov return (ipsec4_process_packet(m, isr->next)); 172db178eb8SBjoern A. Zeeb /* NOTREACHED */ 173db178eb8SBjoern A. Zeeb #endif 174db178eb8SBjoern A. Zeeb #ifdef notyet 175db178eb8SBjoern A. Zeeb #ifdef INET6 176db178eb8SBjoern A. Zeeb case AF_INET6: 177db178eb8SBjoern A. Zeeb /* XXX */ 178f9d8f665SAndrey V. Elsukov IPSEC6STAT_INC(ips_out_bundlesa); 179f3677984SAndrey V. Elsukov return (ipsec6_process_packet(m, isr->next)); 180db178eb8SBjoern A. Zeeb /* NOTREACHED */ 181db178eb8SBjoern A. Zeeb #endif /* INET6 */ 182db178eb8SBjoern A. Zeeb #endif 183db178eb8SBjoern A. Zeeb default: 184db178eb8SBjoern A. Zeeb DPRINTF(("%s: unknown protocol family %u\n", __func__, 185db178eb8SBjoern A. Zeeb saidx->dst.sa.sa_family)); 186db178eb8SBjoern A. Zeeb error = ENXIO; 187db178eb8SBjoern A. Zeeb goto bad; 188db178eb8SBjoern A. Zeeb } 18988768458SSam Leffler } 19088768458SSam Leffler 19188768458SSam Leffler /* 19288768458SSam Leffler * We're done with IPsec processing, transmit the packet using the 1936508929bSAndrey V. Elsukov * appropriate network protocol (IP or IPv6). 19488768458SSam Leffler */ 19588768458SSam Leffler switch (saidx->dst.sa.sa_family) { 19688768458SSam Leffler #ifdef INET 19788768458SSam Leffler case AF_INET: 1987b495c44SVANHULLEBUS Yvan #ifdef IPSEC_NAT_T 1997b495c44SVANHULLEBUS Yvan /* 2007b495c44SVANHULLEBUS Yvan * If NAT-T is enabled, now that all IPsec processing is done 2017b495c44SVANHULLEBUS Yvan * insert UDP encapsulation header after IP header. 2027b495c44SVANHULLEBUS Yvan */ 2037b495c44SVANHULLEBUS Yvan if (sav->natt_type) { 20420472bceSGleb Smirnoff struct ip *ip = mtod(m, struct ip *); 2057b495c44SVANHULLEBUS Yvan const int hlen = (ip->ip_hl << 2); 2067b495c44SVANHULLEBUS Yvan int size, off; 2077b495c44SVANHULLEBUS Yvan struct mbuf *mi; 2087b495c44SVANHULLEBUS Yvan struct udphdr *udp; 2097b495c44SVANHULLEBUS Yvan 2107b495c44SVANHULLEBUS Yvan size = sizeof(struct udphdr); 2117b495c44SVANHULLEBUS Yvan if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) { 2127b495c44SVANHULLEBUS Yvan /* 2137b495c44SVANHULLEBUS Yvan * draft-ietf-ipsec-nat-t-ike-0[01].txt and 2147b495c44SVANHULLEBUS Yvan * draft-ietf-ipsec-udp-encaps-(00/)01.txt, 2157b495c44SVANHULLEBUS Yvan * ignoring possible AH mode 2167b495c44SVANHULLEBUS Yvan * non-IKE marker + non-ESP marker 2177b495c44SVANHULLEBUS Yvan * from draft-ietf-ipsec-udp-encaps-00.txt. 2187b495c44SVANHULLEBUS Yvan */ 2197b495c44SVANHULLEBUS Yvan size += sizeof(u_int64_t); 2207b495c44SVANHULLEBUS Yvan } 2217b495c44SVANHULLEBUS Yvan mi = m_makespace(m, hlen, size, &off); 2227b495c44SVANHULLEBUS Yvan if (mi == NULL) { 2237b495c44SVANHULLEBUS Yvan DPRINTF(("%s: m_makespace for udphdr failed\n", 2247b495c44SVANHULLEBUS Yvan __func__)); 2257b495c44SVANHULLEBUS Yvan error = ENOBUFS; 2267b495c44SVANHULLEBUS Yvan goto bad; 2277b495c44SVANHULLEBUS Yvan } 2287b495c44SVANHULLEBUS Yvan 2297b495c44SVANHULLEBUS Yvan udp = (struct udphdr *)(mtod(mi, caddr_t) + off); 2307b495c44SVANHULLEBUS Yvan if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) 2317b495c44SVANHULLEBUS Yvan udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT); 2327b495c44SVANHULLEBUS Yvan else 2337b495c44SVANHULLEBUS Yvan udp->uh_sport = 2347b495c44SVANHULLEBUS Yvan KEY_PORTFROMSADDR(&sav->sah->saidx.src); 2357b495c44SVANHULLEBUS Yvan udp->uh_dport = KEY_PORTFROMSADDR(&sav->sah->saidx.dst); 2367b495c44SVANHULLEBUS Yvan udp->uh_sum = 0; 2377b495c44SVANHULLEBUS Yvan udp->uh_ulen = htons(m->m_pkthdr.len - hlen); 23820472bceSGleb Smirnoff ip->ip_len = htons(m->m_pkthdr.len); 2397b495c44SVANHULLEBUS Yvan ip->ip_p = IPPROTO_UDP; 2407b495c44SVANHULLEBUS Yvan 2417b495c44SVANHULLEBUS Yvan if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) 2427b495c44SVANHULLEBUS Yvan *(u_int64_t *)(udp + 1) = 0; 2437b495c44SVANHULLEBUS Yvan } 2447b495c44SVANHULLEBUS Yvan #endif /* IPSEC_NAT_T */ 2457b495c44SVANHULLEBUS Yvan 24688768458SSam Leffler return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL); 24788768458SSam Leffler #endif /* INET */ 24888768458SSam Leffler #ifdef INET6 24988768458SSam Leffler case AF_INET6: 25088768458SSam Leffler /* 25188768458SSam Leffler * We don't need massage, IPv6 header fields are always in 25288768458SSam Leffler * net endian. 25388768458SSam Leffler */ 25488768458SSam Leffler return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 25588768458SSam Leffler #endif /* INET6 */ 25688768458SSam Leffler } 25788768458SSam Leffler panic("ipsec_process_done"); 25888768458SSam Leffler bad: 25988768458SSam Leffler m_freem(m); 26088768458SSam Leffler return (error); 26188768458SSam Leffler } 26288768458SSam Leffler 26388768458SSam Leffler static struct ipsecrequest * 26488768458SSam Leffler ipsec_nextisr( 26588768458SSam Leffler struct mbuf *m, 26688768458SSam Leffler struct ipsecrequest *isr, 26788768458SSam Leffler int af, 26888768458SSam Leffler struct secasindex *saidx, 26988768458SSam Leffler int *error 27088768458SSam Leffler ) 27188768458SSam Leffler { 272a04d64d8SAndrey V. Elsukov #define IPSEC_OSTAT(name) do { \ 273a04d64d8SAndrey V. Elsukov if (isr->saidx.proto == IPPROTO_ESP) \ 274a04d64d8SAndrey V. Elsukov ESPSTAT_INC(esps_##name); \ 275a04d64d8SAndrey V. Elsukov else if (isr->saidx.proto == IPPROTO_AH)\ 276a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_##name); \ 277a04d64d8SAndrey V. Elsukov else \ 278a04d64d8SAndrey V. Elsukov IPCOMPSTAT_INC(ipcomps_##name); \ 279a04d64d8SAndrey V. Elsukov } while (0) 28088768458SSam Leffler struct secasvar *sav; 28188768458SSam Leffler 2829ffa9677SSam Leffler IPSECREQUEST_LOCK_ASSERT(isr); 2839ffa9677SSam Leffler 2849ffa9677SSam Leffler IPSEC_ASSERT(af == AF_INET || af == AF_INET6, 2859ffa9677SSam Leffler ("invalid address family %u", af)); 28688768458SSam Leffler again: 28788768458SSam Leffler /* 28888768458SSam Leffler * Craft SA index to search for proper SA. Note that 28988768458SSam Leffler * we only fillin unspecified SA peers for transport 29088768458SSam Leffler * mode; for tunnel mode they must already be filled in. 29188768458SSam Leffler */ 29288768458SSam Leffler *saidx = isr->saidx; 29388768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) { 29488768458SSam Leffler /* Fillin unspecified SA peers only for transport mode */ 29588768458SSam Leffler if (af == AF_INET) { 29688768458SSam Leffler struct sockaddr_in *sin; 29788768458SSam Leffler struct ip *ip = mtod(m, struct ip *); 29888768458SSam Leffler 29988768458SSam Leffler if (saidx->src.sa.sa_len == 0) { 30088768458SSam Leffler sin = &saidx->src.sin; 30188768458SSam Leffler sin->sin_len = sizeof(*sin); 30288768458SSam Leffler sin->sin_family = AF_INET; 30388768458SSam Leffler sin->sin_port = IPSEC_PORT_ANY; 30488768458SSam Leffler sin->sin_addr = ip->ip_src; 30588768458SSam Leffler } 30688768458SSam Leffler if (saidx->dst.sa.sa_len == 0) { 30788768458SSam Leffler sin = &saidx->dst.sin; 30888768458SSam Leffler sin->sin_len = sizeof(*sin); 30988768458SSam Leffler sin->sin_family = AF_INET; 31088768458SSam Leffler sin->sin_port = IPSEC_PORT_ANY; 31188768458SSam Leffler sin->sin_addr = ip->ip_dst; 31288768458SSam Leffler } 31388768458SSam Leffler } else { 31488768458SSam Leffler struct sockaddr_in6 *sin6; 31588768458SSam Leffler struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 31688768458SSam Leffler 31788768458SSam Leffler if (saidx->src.sin6.sin6_len == 0) { 31888768458SSam Leffler sin6 = (struct sockaddr_in6 *)&saidx->src; 31988768458SSam Leffler sin6->sin6_len = sizeof(*sin6); 32088768458SSam Leffler sin6->sin6_family = AF_INET6; 32188768458SSam Leffler sin6->sin6_port = IPSEC_PORT_ANY; 32288768458SSam Leffler sin6->sin6_addr = ip6->ip6_src; 32388768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { 32488768458SSam Leffler /* fix scope id for comparing SPD */ 32588768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 32688768458SSam Leffler sin6->sin6_scope_id = 32788768458SSam Leffler ntohs(ip6->ip6_src.s6_addr16[1]); 32888768458SSam Leffler } 32988768458SSam Leffler } 33088768458SSam Leffler if (saidx->dst.sin6.sin6_len == 0) { 33188768458SSam Leffler sin6 = (struct sockaddr_in6 *)&saidx->dst; 33288768458SSam Leffler sin6->sin6_len = sizeof(*sin6); 33388768458SSam Leffler sin6->sin6_family = AF_INET6; 33488768458SSam Leffler sin6->sin6_port = IPSEC_PORT_ANY; 33588768458SSam Leffler sin6->sin6_addr = ip6->ip6_dst; 33688768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 33788768458SSam Leffler /* fix scope id for comparing SPD */ 33888768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 33988768458SSam Leffler sin6->sin6_scope_id = 34088768458SSam Leffler ntohs(ip6->ip6_dst.s6_addr16[1]); 34188768458SSam Leffler } 34288768458SSam Leffler } 34388768458SSam Leffler } 34488768458SSam Leffler } 34588768458SSam Leffler 34688768458SSam Leffler /* 34788768458SSam Leffler * Lookup SA and validate it. 34888768458SSam Leffler */ 34988768458SSam Leffler *error = key_checkrequest(isr, saidx); 35088768458SSam Leffler if (*error != 0) { 35188768458SSam Leffler /* 35288768458SSam Leffler * IPsec processing is required, but no SA found. 35388768458SSam Leffler * I assume that key_acquire() had been called 35488768458SSam Leffler * to get/establish the SA. Here I discard 35588768458SSam Leffler * this packet because it is responsibility for 35688768458SSam Leffler * upper layer to retransmit the packet. 35788768458SSam Leffler */ 358f3c93842SAndrey V. Elsukov switch(af) { 359f3c93842SAndrey V. Elsukov case AF_INET: 3606659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_out_nosa); 361f3c93842SAndrey V. Elsukov break; 362f3c93842SAndrey V. Elsukov #ifdef INET6 363f3c93842SAndrey V. Elsukov case AF_INET6: 364f3c93842SAndrey V. Elsukov IPSEC6STAT_INC(ips_out_nosa); 365f3c93842SAndrey V. Elsukov break; 366f3c93842SAndrey V. Elsukov #endif 367f3c93842SAndrey V. Elsukov } 36888768458SSam Leffler goto bad; 36988768458SSam Leffler } 37088768458SSam Leffler sav = isr->sav; 3719e3bdedeSBjoern A. Zeeb if (sav == NULL) { 3729ffa9677SSam Leffler IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE, 3739ffa9677SSam Leffler ("no SA found, but required; level %u", 37488768458SSam Leffler ipsec_get_reqlevel(isr))); 3759ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 37688768458SSam Leffler isr = isr->next; 3779e3bdedeSBjoern A. Zeeb /* 3789e3bdedeSBjoern A. Zeeb * If isr is NULL, we found a 'use' policy w/o SA. 3799e3bdedeSBjoern A. Zeeb * Return w/o error and w/o isr so we can drop out 3809e3bdedeSBjoern A. Zeeb * and continue w/o IPsec processing. 3819e3bdedeSBjoern A. Zeeb */ 3829e3bdedeSBjoern A. Zeeb if (isr == NULL) 38388768458SSam Leffler return isr; 3849ffa9677SSam Leffler IPSECREQUEST_LOCK(isr); 38588768458SSam Leffler goto again; 38688768458SSam Leffler } 38788768458SSam Leffler 38888768458SSam Leffler /* 38988768458SSam Leffler * Check system global policy controls. 39088768458SSam Leffler */ 391603724d3SBjoern A. Zeeb if ((isr->saidx.proto == IPPROTO_ESP && !V_esp_enable) || 392603724d3SBjoern A. Zeeb (isr->saidx.proto == IPPROTO_AH && !V_ah_enable) || 393603724d3SBjoern A. Zeeb (isr->saidx.proto == IPPROTO_IPCOMP && !V_ipcomp_enable)) { 3949ffa9677SSam Leffler DPRINTF(("%s: IPsec outbound packet dropped due" 3959ffa9677SSam Leffler " to policy (check your sysctls)\n", __func__)); 396a04d64d8SAndrey V. Elsukov IPSEC_OSTAT(pdrops); 39788768458SSam Leffler *error = EHOSTUNREACH; 39888768458SSam Leffler goto bad; 39988768458SSam Leffler } 40088768458SSam Leffler 40188768458SSam Leffler /* 40288768458SSam Leffler * Sanity check the SA contents for the caller 40388768458SSam Leffler * before they invoke the xform output method. 40488768458SSam Leffler */ 40588768458SSam Leffler if (sav->tdb_xform == NULL) { 4069ffa9677SSam Leffler DPRINTF(("%s: no transform for SA\n", __func__)); 407a04d64d8SAndrey V. Elsukov IPSEC_OSTAT(noxform); 40888768458SSam Leffler *error = EHOSTUNREACH; 40988768458SSam Leffler goto bad; 41088768458SSam Leffler } 41188768458SSam Leffler return isr; 41288768458SSam Leffler bad: 4139ffa9677SSam Leffler IPSEC_ASSERT(*error != 0, ("error return w/ no error code")); 4149ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 41588768458SSam Leffler return NULL; 41688768458SSam Leffler #undef IPSEC_OSTAT 41788768458SSam Leffler } 41888768458SSam Leffler 41961f37615SAndrey V. Elsukov static int 42061f37615SAndrey V. Elsukov ipsec_encap(struct mbuf **mp, struct secasindex *saidx) 42161f37615SAndrey V. Elsukov { 42261f37615SAndrey V. Elsukov #ifdef INET6 42361f37615SAndrey V. Elsukov struct ip6_hdr *ip6; 42461f37615SAndrey V. Elsukov #endif 42561f37615SAndrey V. Elsukov struct ip *ip; 42661f37615SAndrey V. Elsukov int setdf; 42761f37615SAndrey V. Elsukov uint8_t itos, proto; 42861f37615SAndrey V. Elsukov 42961f37615SAndrey V. Elsukov ip = mtod(*mp, struct ip *); 43061f37615SAndrey V. Elsukov switch (ip->ip_v) { 43161f37615SAndrey V. Elsukov #ifdef INET 43261f37615SAndrey V. Elsukov case IPVERSION: 43361f37615SAndrey V. Elsukov proto = IPPROTO_IPIP; 43461f37615SAndrey V. Elsukov /* 43561f37615SAndrey V. Elsukov * Collect IP_DF state from the inner header 43661f37615SAndrey V. Elsukov * and honor system-wide control of how to handle it. 43761f37615SAndrey V. Elsukov */ 43861f37615SAndrey V. Elsukov switch (V_ip4_ipsec_dfbit) { 43961f37615SAndrey V. Elsukov case 0: /* clear in outer header */ 44061f37615SAndrey V. Elsukov case 1: /* set in outer header */ 44161f37615SAndrey V. Elsukov setdf = V_ip4_ipsec_dfbit; 44261f37615SAndrey V. Elsukov break; 44361f37615SAndrey V. Elsukov default:/* propagate to outer header */ 44461f37615SAndrey V. Elsukov setdf = (ip->ip_off & ntohs(IP_DF)) != 0; 44561f37615SAndrey V. Elsukov } 44661f37615SAndrey V. Elsukov itos = ip->ip_tos; 44761f37615SAndrey V. Elsukov break; 44861f37615SAndrey V. Elsukov #endif 44961f37615SAndrey V. Elsukov #ifdef INET6 45061f37615SAndrey V. Elsukov case (IPV6_VERSION >> 4): 45161f37615SAndrey V. Elsukov proto = IPPROTO_IPV6; 45261f37615SAndrey V. Elsukov ip6 = mtod(*mp, struct ip6_hdr *); 45361f37615SAndrey V. Elsukov itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 45461f37615SAndrey V. Elsukov setdf = V_ip4_ipsec_dfbit ? 1: 0; 45561f37615SAndrey V. Elsukov /* scoped address handling */ 45661f37615SAndrey V. Elsukov in6_clearscope(&ip6->ip6_src); 45761f37615SAndrey V. Elsukov in6_clearscope(&ip6->ip6_dst); 45861f37615SAndrey V. Elsukov break; 45961f37615SAndrey V. Elsukov #endif 46061f37615SAndrey V. Elsukov default: 46161f37615SAndrey V. Elsukov return (EAFNOSUPPORT); 46261f37615SAndrey V. Elsukov } 46361f37615SAndrey V. Elsukov switch (saidx->dst.sa.sa_family) { 46461f37615SAndrey V. Elsukov #ifdef INET 46561f37615SAndrey V. Elsukov case AF_INET: 46661f37615SAndrey V. Elsukov if (saidx->src.sa.sa_family != AF_INET || 46761f37615SAndrey V. Elsukov saidx->src.sin.sin_addr.s_addr == INADDR_ANY || 46861f37615SAndrey V. Elsukov saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) 46961f37615SAndrey V. Elsukov return (EINVAL); 47061f37615SAndrey V. Elsukov M_PREPEND(*mp, sizeof(struct ip), M_NOWAIT); 47161f37615SAndrey V. Elsukov if (*mp == NULL) 47261f37615SAndrey V. Elsukov return (ENOBUFS); 47361f37615SAndrey V. Elsukov ip = mtod(*mp, struct ip *); 47461f37615SAndrey V. Elsukov ip->ip_v = IPVERSION; 47561f37615SAndrey V. Elsukov ip->ip_hl = sizeof(struct ip) >> 2; 47661f37615SAndrey V. Elsukov ip->ip_p = proto; 47761f37615SAndrey V. Elsukov ip->ip_len = htons((*mp)->m_pkthdr.len); 47861f37615SAndrey V. Elsukov ip->ip_ttl = V_ip_defttl; 47961f37615SAndrey V. Elsukov ip->ip_sum = 0; 48061f37615SAndrey V. Elsukov ip->ip_off = setdf ? htons(IP_DF): 0; 48161f37615SAndrey V. Elsukov ip->ip_src = saidx->src.sin.sin_addr; 48261f37615SAndrey V. Elsukov ip->ip_dst = saidx->dst.sin.sin_addr; 48361f37615SAndrey V. Elsukov ip_ecn_ingress(V_ip4_ipsec_ecn, &ip->ip_tos, &itos); 48461f37615SAndrey V. Elsukov ip_fillid(ip); 48561f37615SAndrey V. Elsukov break; 48661f37615SAndrey V. Elsukov #endif /* INET */ 48761f37615SAndrey V. Elsukov #ifdef INET6 48861f37615SAndrey V. Elsukov case AF_INET6: 48961f37615SAndrey V. Elsukov if (saidx->src.sa.sa_family != AF_INET6 || 49061f37615SAndrey V. Elsukov IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr) || 49161f37615SAndrey V. Elsukov IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr)) 49261f37615SAndrey V. Elsukov return (EINVAL); 49361f37615SAndrey V. Elsukov M_PREPEND(*mp, sizeof(struct ip6_hdr), M_NOWAIT); 49461f37615SAndrey V. Elsukov if (*mp == NULL) 49561f37615SAndrey V. Elsukov return (ENOBUFS); 49661f37615SAndrey V. Elsukov ip6 = mtod(*mp, struct ip6_hdr *); 49761f37615SAndrey V. Elsukov ip6->ip6_flow = 0; 49861f37615SAndrey V. Elsukov ip6->ip6_vfc = IPV6_VERSION; 49961f37615SAndrey V. Elsukov ip6->ip6_hlim = V_ip6_defhlim; 50061f37615SAndrey V. Elsukov ip6->ip6_nxt = proto; 50161f37615SAndrey V. Elsukov ip6->ip6_dst = saidx->dst.sin6.sin6_addr; 5021ae800e7SAndrey V. Elsukov /* For link-local address embed scope zone id */ 5031ae800e7SAndrey V. Elsukov if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) 5041ae800e7SAndrey V. Elsukov ip6->ip6_dst.s6_addr16[1] = 5051ae800e7SAndrey V. Elsukov htons(saidx->dst.sin6.sin6_scope_id & 0xffff); 50661f37615SAndrey V. Elsukov ip6->ip6_src = saidx->src.sin6.sin6_addr; 5071ae800e7SAndrey V. Elsukov if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) 5081ae800e7SAndrey V. Elsukov ip6->ip6_src.s6_addr16[1] = 5091ae800e7SAndrey V. Elsukov htons(saidx->src.sin6.sin6_scope_id & 0xffff); 51061f37615SAndrey V. Elsukov ip6->ip6_plen = htons((*mp)->m_pkthdr.len - sizeof(*ip6)); 51161f37615SAndrey V. Elsukov ip_ecn_ingress(V_ip6_ipsec_ecn, &proto, &itos); 51261f37615SAndrey V. Elsukov ip6->ip6_flow |= htonl((uint32_t)proto << 20); 51361f37615SAndrey V. Elsukov break; 51461f37615SAndrey V. Elsukov #endif /* INET6 */ 51561f37615SAndrey V. Elsukov default: 51661f37615SAndrey V. Elsukov return (EAFNOSUPPORT); 51761f37615SAndrey V. Elsukov } 51861f37615SAndrey V. Elsukov return (0); 51961f37615SAndrey V. Elsukov } 52061f37615SAndrey V. Elsukov 52188768458SSam Leffler #ifdef INET 52288768458SSam Leffler /* 52388768458SSam Leffler * IPsec output logic for IPv4. 52488768458SSam Leffler */ 52588768458SSam Leffler int 526619764beSAndrey V. Elsukov ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr) 52788768458SSam Leffler { 528962ac6c7SAndrey V. Elsukov char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN]; 529*ef91a976SAndrey V. Elsukov struct ipsec_ctx_data ctx; 530619764beSAndrey V. Elsukov union sockaddr_union *dst; 53188768458SSam Leffler struct secasindex saidx; 53288768458SSam Leffler struct secasvar *sav; 53388768458SSam Leffler struct ip *ip; 53461f37615SAndrey V. Elsukov int error, i, off; 53588768458SSam Leffler 5369ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 5379ffa9677SSam Leffler IPSEC_ASSERT(isr != NULL, ("null isr")); 53888768458SSam Leffler 5399ffa9677SSam Leffler IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 54088768458SSam Leffler 54188768458SSam Leffler isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); 5429e3bdedeSBjoern A. Zeeb if (isr == NULL) { 5439e3bdedeSBjoern A. Zeeb if (error != 0) 54488768458SSam Leffler goto bad; 5459e3bdedeSBjoern A. Zeeb return EJUSTRETURN; 5469e3bdedeSBjoern A. Zeeb } 54788768458SSam Leffler 54888768458SSam Leffler sav = isr->sav; 549619764beSAndrey V. Elsukov if (m->m_len < sizeof(struct ip) && 550619764beSAndrey V. Elsukov (m = m_pullup(m, sizeof (struct ip))) == NULL) { 551619764beSAndrey V. Elsukov error = ENOBUFS; 552619764beSAndrey V. Elsukov goto bad; 553619764beSAndrey V. Elsukov } 554*ef91a976SAndrey V. Elsukov 555*ef91a976SAndrey V. Elsukov IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET, IPSEC_ENC_BEFORE); 556*ef91a976SAndrey V. Elsukov if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0) 557*ef91a976SAndrey V. Elsukov goto bad; 558*ef91a976SAndrey V. Elsukov 559619764beSAndrey V. Elsukov ip = mtod(m, struct ip *); 560619764beSAndrey V. Elsukov dst = &sav->sah->saidx.dst; 56188768458SSam Leffler /* Do the appropriate encapsulation, if necessary */ 56288768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 56388768458SSam Leffler dst->sa.sa_family != AF_INET || /* PF mismatch */ 56488768458SSam Leffler (dst->sa.sa_family == AF_INET && /* Proxy */ 56588768458SSam Leffler dst->sin.sin_addr.s_addr != INADDR_ANY && 56688768458SSam Leffler dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { 56788768458SSam Leffler /* Fix IPv4 header checksum and length */ 56888768458SSam Leffler ip->ip_len = htons(m->m_pkthdr.len); 56988768458SSam Leffler ip->ip_sum = 0; 57088768458SSam Leffler ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 57161f37615SAndrey V. Elsukov error = ipsec_encap(&m, &sav->sah->saidx); 572619764beSAndrey V. Elsukov if (error != 0) { 57361f37615SAndrey V. Elsukov DPRINTF(("%s: encapsulation for SA %s->%s " 57461f37615SAndrey V. Elsukov "SPI 0x%08x failed with error %d\n", __func__, 575962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.src, sbuf, 576962ac6c7SAndrey V. Elsukov sizeof(sbuf)), 577962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst, dbuf, 578962ac6c7SAndrey V. Elsukov sizeof(dbuf)), ntohl(sav->spi), error)); 57988768458SSam Leffler goto bad; 58088768458SSam Leffler } 58188768458SSam Leffler } 582*ef91a976SAndrey V. Elsukov 583*ef91a976SAndrey V. Elsukov IPSEC_INIT_CTX(&ctx, &m, sav, dst->sa.sa_family, IPSEC_ENC_AFTER); 584*ef91a976SAndrey V. Elsukov if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0) 58519ad9831SBjoern A. Zeeb goto bad; 586bdea400fSAndrew Thompson 58788768458SSam Leffler /* 58888768458SSam Leffler * Dispatch to the appropriate IPsec transform logic. The 58988768458SSam Leffler * packet will be returned for transmission after crypto 59061f37615SAndrey V. Elsukov * processing, etc. are completed. 59188768458SSam Leffler * 59288768458SSam Leffler * NB: m & sav are ``passed to caller'' who's reponsible for 59388768458SSam Leffler * for reclaiming their resources. 59488768458SSam Leffler */ 595aaf2cfc0SVANHULLEBUS Yvan switch(dst->sa.sa_family) { 596aaf2cfc0SVANHULLEBUS Yvan case AF_INET: 59788768458SSam Leffler ip = mtod(m, struct ip *); 59888768458SSam Leffler i = ip->ip_hl << 2; 59988768458SSam Leffler off = offsetof(struct ip, ip_p); 600aaf2cfc0SVANHULLEBUS Yvan break; 601aaf2cfc0SVANHULLEBUS Yvan #ifdef INET6 602aaf2cfc0SVANHULLEBUS Yvan case AF_INET6: 603aaf2cfc0SVANHULLEBUS Yvan i = sizeof(struct ip6_hdr); 604aaf2cfc0SVANHULLEBUS Yvan off = offsetof(struct ip6_hdr, ip6_nxt); 605aaf2cfc0SVANHULLEBUS Yvan break; 606aaf2cfc0SVANHULLEBUS Yvan #endif /* INET6 */ 607aaf2cfc0SVANHULLEBUS Yvan default: 608aaf2cfc0SVANHULLEBUS Yvan DPRINTF(("%s: unsupported protocol family %u\n", 609aaf2cfc0SVANHULLEBUS Yvan __func__, dst->sa.sa_family)); 610aaf2cfc0SVANHULLEBUS Yvan error = EPFNOSUPPORT; 6116d120f90SBjoern A. Zeeb IPSECSTAT_INC(ips_out_inval); 612aaf2cfc0SVANHULLEBUS Yvan goto bad; 613aaf2cfc0SVANHULLEBUS Yvan } 61488768458SSam Leffler error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); 6159ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 61661f37615SAndrey V. Elsukov return (error); 61788768458SSam Leffler bad: 6189ffa9677SSam Leffler if (isr) 6199ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 62088768458SSam Leffler if (m) 62188768458SSam Leffler m_freem(m); 62288768458SSam Leffler return error; 62388768458SSam Leffler } 62488768458SSam Leffler #endif 62588768458SSam Leffler 626aaf2cfc0SVANHULLEBUS Yvan 62788768458SSam Leffler #ifdef INET6 62888768458SSam Leffler static int 629aaf2cfc0SVANHULLEBUS Yvan in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia) 63088768458SSam Leffler { 631aaf2cfc0SVANHULLEBUS Yvan struct in6_addr ia2; 63288768458SSam Leffler 633aaf2cfc0SVANHULLEBUS Yvan memcpy(&ia2, &sa->sin6_addr, sizeof(ia2)); 634aaf2cfc0SVANHULLEBUS Yvan if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr)) 635aaf2cfc0SVANHULLEBUS Yvan ia2.s6_addr16[1] = htons(sa->sin6_scope_id); 63688768458SSam Leffler 637aaf2cfc0SVANHULLEBUS Yvan return IN6_ARE_ADDR_EQUAL(ia, &ia2); 63888768458SSam Leffler } 63988768458SSam Leffler 64088768458SSam Leffler /* 641aaf2cfc0SVANHULLEBUS Yvan * IPsec output logic for IPv6. 64288768458SSam Leffler */ 64388768458SSam Leffler int 644962ac6c7SAndrey V. Elsukov ipsec6_process_packet(struct mbuf *m, struct ipsecrequest *isr) 64588768458SSam Leffler { 646962ac6c7SAndrey V. Elsukov char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN]; 647*ef91a976SAndrey V. Elsukov struct ipsec_ctx_data ctx; 64888768458SSam Leffler struct secasindex saidx; 649aaf2cfc0SVANHULLEBUS Yvan struct secasvar *sav; 650aaf2cfc0SVANHULLEBUS Yvan struct ip6_hdr *ip6; 651aaf2cfc0SVANHULLEBUS Yvan int error, i, off; 652aaf2cfc0SVANHULLEBUS Yvan union sockaddr_union *dst; 65388768458SSam Leffler 654aaf2cfc0SVANHULLEBUS Yvan IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf")); 655aaf2cfc0SVANHULLEBUS Yvan IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr")); 656923e1044SBjoern A. Zeeb 657923e1044SBjoern A. Zeeb IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 658aaf2cfc0SVANHULLEBUS Yvan 65988768458SSam Leffler isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); 6609e3bdedeSBjoern A. Zeeb if (isr == NULL) { 6619e3bdedeSBjoern A. Zeeb if (error != 0) 66288768458SSam Leffler goto bad; 6639e3bdedeSBjoern A. Zeeb return EJUSTRETURN; 6649e3bdedeSBjoern A. Zeeb } 665aaf2cfc0SVANHULLEBUS Yvan sav = isr->sav; 666aaf2cfc0SVANHULLEBUS Yvan dst = &sav->sah->saidx.dst; 667aaf2cfc0SVANHULLEBUS Yvan 668*ef91a976SAndrey V. Elsukov IPSEC_INIT_CTX(&ctx, &m, sav, AF_INET6, IPSEC_ENC_BEFORE); 669*ef91a976SAndrey V. Elsukov if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0) 670*ef91a976SAndrey V. Elsukov goto bad; 671*ef91a976SAndrey V. Elsukov 67267fd1727SAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 67367fd1727SAndrey V. Elsukov ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); 67419ad9831SBjoern A. Zeeb 675aaf2cfc0SVANHULLEBUS Yvan /* Do the appropriate encapsulation, if necessary */ 676aaf2cfc0SVANHULLEBUS Yvan if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 677aaf2cfc0SVANHULLEBUS Yvan dst->sa.sa_family != AF_INET6 || /* PF mismatch */ 678aaf2cfc0SVANHULLEBUS Yvan ((dst->sa.sa_family == AF_INET6) && 679aaf2cfc0SVANHULLEBUS Yvan (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && 680aaf2cfc0SVANHULLEBUS Yvan (!in6_sa_equal_addrwithscope(&dst->sin6, 681aaf2cfc0SVANHULLEBUS Yvan &ip6->ip6_dst)))) { 682aaf2cfc0SVANHULLEBUS Yvan if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { 683aaf2cfc0SVANHULLEBUS Yvan /* No jumbogram support. */ 684aaf2cfc0SVANHULLEBUS Yvan error = ENXIO; /*XXX*/ 68588768458SSam Leffler goto bad; 68688768458SSam Leffler } 68761f37615SAndrey V. Elsukov error = ipsec_encap(&m, &sav->sah->saidx); 68861f37615SAndrey V. Elsukov if (error != 0) { 68961f37615SAndrey V. Elsukov DPRINTF(("%s: encapsulation for SA %s->%s " 69061f37615SAndrey V. Elsukov "SPI 0x%08x failed with error %d\n", __func__, 691962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.src, sbuf, 692962ac6c7SAndrey V. Elsukov sizeof(sbuf)), 693962ac6c7SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst, dbuf, 694962ac6c7SAndrey V. Elsukov sizeof(dbuf)), ntohl(sav->spi), error)); 695aaf2cfc0SVANHULLEBUS Yvan goto bad; 696aaf2cfc0SVANHULLEBUS Yvan } 69788768458SSam Leffler } 69888768458SSam Leffler 699*ef91a976SAndrey V. Elsukov IPSEC_INIT_CTX(&ctx, &m, sav, dst->sa.sa_family, IPSEC_ENC_AFTER); 700*ef91a976SAndrey V. Elsukov if ((error = ipsec_run_hhooks(&ctx, HHOOK_TYPE_IPSEC_OUT)) != 0) 70119ad9831SBjoern A. Zeeb goto bad; 70219ad9831SBjoern A. Zeeb 703aaf2cfc0SVANHULLEBUS Yvan switch(dst->sa.sa_family) { 704aaf2cfc0SVANHULLEBUS Yvan #ifdef INET 705aaf2cfc0SVANHULLEBUS Yvan case AF_INET: 706aaf2cfc0SVANHULLEBUS Yvan { 707aaf2cfc0SVANHULLEBUS Yvan struct ip *ip; 708aaf2cfc0SVANHULLEBUS Yvan ip = mtod(m, struct ip *); 709aaf2cfc0SVANHULLEBUS Yvan i = ip->ip_hl << 2; 710aaf2cfc0SVANHULLEBUS Yvan off = offsetof(struct ip, ip_p); 711aaf2cfc0SVANHULLEBUS Yvan } 712aaf2cfc0SVANHULLEBUS Yvan break; 713aaf2cfc0SVANHULLEBUS Yvan #endif /* AF_INET */ 714aaf2cfc0SVANHULLEBUS Yvan case AF_INET6: 715aaf2cfc0SVANHULLEBUS Yvan i = sizeof(struct ip6_hdr); 716aaf2cfc0SVANHULLEBUS Yvan off = offsetof(struct ip6_hdr, ip6_nxt); 717aaf2cfc0SVANHULLEBUS Yvan break; 718aaf2cfc0SVANHULLEBUS Yvan default: 719aaf2cfc0SVANHULLEBUS Yvan DPRINTF(("%s: unsupported protocol family %u\n", 720aaf2cfc0SVANHULLEBUS Yvan __func__, dst->sa.sa_family)); 721aaf2cfc0SVANHULLEBUS Yvan error = EPFNOSUPPORT; 722aaf2cfc0SVANHULLEBUS Yvan goto bad; 723aaf2cfc0SVANHULLEBUS Yvan } 724aaf2cfc0SVANHULLEBUS Yvan error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); 725923e1044SBjoern A. Zeeb IPSECREQUEST_UNLOCK(isr); 726923e1044SBjoern A. Zeeb return error; 72788768458SSam Leffler bad: 728*ef91a976SAndrey V. Elsukov IPSEC6STAT_INC(ips_out_inval); 729923e1044SBjoern A. Zeeb if (isr) 730923e1044SBjoern A. Zeeb IPSECREQUEST_UNLOCK(isr); 73188768458SSam Leffler if (m) 73288768458SSam Leffler m_freem(m); 73388768458SSam Leffler return error; 73488768458SSam Leffler } 73588768458SSam Leffler #endif /*INET6*/ 736