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" 35bdea400fSAndrew Thompson #include "opt_enc.h" 3688768458SSam Leffler 3788768458SSam Leffler #include <sys/param.h> 3888768458SSam Leffler #include <sys/systm.h> 3988768458SSam Leffler #include <sys/mbuf.h> 4088768458SSam Leffler #include <sys/domain.h> 4188768458SSam Leffler #include <sys/protosw.h> 4288768458SSam Leffler #include <sys/socket.h> 4388768458SSam Leffler #include <sys/errno.h> 4488768458SSam Leffler #include <sys/syslog.h> 4588768458SSam Leffler 4688768458SSam Leffler #include <net/if.h> 4776039bc8SGleb Smirnoff #include <net/if_var.h> 48b28cd334SBjoern A. Zeeb #include <net/pfil.h> 4988768458SSam Leffler #include <net/route.h> 50eddfbb76SRobert Watson #include <net/vnet.h> 5188768458SSam Leffler 5288768458SSam Leffler #include <netinet/in.h> 5388768458SSam Leffler #include <netinet/in_systm.h> 5488768458SSam Leffler #include <netinet/ip.h> 5588768458SSam Leffler #include <netinet/ip_var.h> 5688768458SSam Leffler #include <netinet/in_var.h> 5788768458SSam Leffler #include <netinet/ip_ecn.h> 5888768458SSam Leffler #ifdef INET6 5988768458SSam Leffler #include <netinet6/ip6_ecn.h> 6088768458SSam Leffler #endif 6188768458SSam Leffler 6288768458SSam Leffler #include <netinet/ip6.h> 6388768458SSam Leffler #ifdef INET6 6488768458SSam Leffler #include <netinet6/ip6_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 9197c2a697SVANHULLEBUS Yvan #ifdef DEV_ENC 9297c2a697SVANHULLEBUS Yvan #include <net/if_enc.h> 9397c2a697SVANHULLEBUS Yvan #endif 9497c2a697SVANHULLEBUS Yvan 9597c2a697SVANHULLEBUS Yvan 9688768458SSam Leffler int 9788768458SSam Leffler ipsec_process_done(struct mbuf *m, struct ipsecrequest *isr) 9888768458SSam Leffler { 9988768458SSam Leffler struct tdb_ident *tdbi; 10088768458SSam Leffler struct m_tag *mtag; 10188768458SSam Leffler struct secasvar *sav; 10288768458SSam Leffler struct secasindex *saidx; 10388768458SSam Leffler int error; 10488768458SSam Leffler 1059ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 1069ffa9677SSam Leffler IPSEC_ASSERT(isr != NULL, ("null ISR")); 10788768458SSam Leffler sav = isr->sav; 1089ffa9677SSam Leffler IPSEC_ASSERT(sav != NULL, ("null SA")); 1099ffa9677SSam Leffler IPSEC_ASSERT(sav->sah != NULL, ("null SAH")); 11088768458SSam Leffler 11188768458SSam Leffler saidx = &sav->sah->saidx; 11288768458SSam Leffler switch (saidx->dst.sa.sa_family) { 11388768458SSam Leffler #ifdef INET 11488768458SSam Leffler case AF_INET: 11588768458SSam Leffler /* Fix the header length, for AH processing. */ 11688768458SSam Leffler mtod(m, struct ip *)->ip_len = htons(m->m_pkthdr.len); 11788768458SSam Leffler break; 11888768458SSam Leffler #endif /* INET */ 11988768458SSam Leffler #ifdef INET6 12088768458SSam Leffler case AF_INET6: 12188768458SSam Leffler /* Fix the header length, for AH processing. */ 12288768458SSam Leffler if (m->m_pkthdr.len < sizeof (struct ip6_hdr)) { 12388768458SSam Leffler error = ENXIO; 12488768458SSam Leffler goto bad; 12588768458SSam Leffler } 12688768458SSam Leffler if (m->m_pkthdr.len - sizeof (struct ip6_hdr) > IPV6_MAXPACKET) { 12788768458SSam Leffler /* No jumbogram support. */ 12888768458SSam Leffler error = ENXIO; /*?*/ 12988768458SSam Leffler goto bad; 13088768458SSam Leffler } 13188768458SSam Leffler mtod(m, struct ip6_hdr *)->ip6_plen = 13288768458SSam Leffler htons(m->m_pkthdr.len - sizeof(struct ip6_hdr)); 13388768458SSam Leffler break; 13488768458SSam Leffler #endif /* INET6 */ 13588768458SSam Leffler default: 1369ffa9677SSam Leffler DPRINTF(("%s: unknown protocol family %u\n", __func__, 13788768458SSam Leffler saidx->dst.sa.sa_family)); 13888768458SSam Leffler error = ENXIO; 13988768458SSam Leffler goto bad; 14088768458SSam Leffler } 14188768458SSam Leffler 14288768458SSam Leffler /* 14388768458SSam Leffler * Add a record of what we've done or what needs to be done to the 14488768458SSam Leffler * packet. 14588768458SSam Leffler */ 14688768458SSam Leffler mtag = m_tag_get(PACKET_TAG_IPSEC_OUT_DONE, 14788768458SSam Leffler sizeof(struct tdb_ident), M_NOWAIT); 14888768458SSam Leffler if (mtag == NULL) { 1499ffa9677SSam Leffler DPRINTF(("%s: could not get packet tag\n", __func__)); 15088768458SSam Leffler error = ENOMEM; 15188768458SSam Leffler goto bad; 15288768458SSam Leffler } 15388768458SSam Leffler 15488768458SSam Leffler tdbi = (struct tdb_ident *)(mtag + 1); 15588768458SSam Leffler tdbi->dst = saidx->dst; 15688768458SSam Leffler tdbi->proto = saidx->proto; 15788768458SSam Leffler tdbi->spi = sav->spi; 15888768458SSam Leffler m_tag_prepend(m, mtag); 15988768458SSam Leffler 16088768458SSam Leffler /* 16188768458SSam Leffler * If there's another (bundled) SA to apply, do so. 16288768458SSam Leffler * Note that this puts a burden on the kernel stack size. 16388768458SSam Leffler * If this is a problem we'll need to introduce a queue 16488768458SSam Leffler * to set the packet on so we can unwind the stack before 16588768458SSam Leffler * doing further processing. 16688768458SSam Leffler */ 16788768458SSam Leffler if (isr->next) { 168174b0d41SBjoern A. Zeeb /* XXX-BZ currently only support same AF bundles. */ 169db178eb8SBjoern A. Zeeb switch (saidx->dst.sa.sa_family) { 170db178eb8SBjoern A. Zeeb #ifdef INET 171db178eb8SBjoern A. Zeeb case AF_INET: 172*f9d8f665SAndrey V. Elsukov IPSECSTAT_INC(ips_out_bundlesa); 17388768458SSam Leffler return ipsec4_process_packet(m, isr->next, 0, 0); 174db178eb8SBjoern A. Zeeb /* NOTREACHED */ 175db178eb8SBjoern A. Zeeb #endif 176db178eb8SBjoern A. Zeeb #ifdef notyet 177db178eb8SBjoern A. Zeeb #ifdef INET6 178db178eb8SBjoern A. Zeeb case AF_INET6: 179db178eb8SBjoern A. Zeeb /* XXX */ 180*f9d8f665SAndrey V. Elsukov IPSEC6STAT_INC(ips_out_bundlesa); 181aaf2cfc0SVANHULLEBUS Yvan return ipsec6_process_packet(m, isr->next); 182db178eb8SBjoern A. Zeeb /* NOTREACHED */ 183db178eb8SBjoern A. Zeeb #endif /* INET6 */ 184db178eb8SBjoern A. Zeeb #endif 185db178eb8SBjoern A. Zeeb default: 186db178eb8SBjoern A. Zeeb DPRINTF(("%s: unknown protocol family %u\n", __func__, 187db178eb8SBjoern A. Zeeb saidx->dst.sa.sa_family)); 188db178eb8SBjoern A. Zeeb error = ENXIO; 189db178eb8SBjoern A. Zeeb goto bad; 190db178eb8SBjoern A. Zeeb } 19188768458SSam Leffler } 1925d1dbc0eSSam Leffler key_sa_recordxfer(sav, m); /* record data transfer */ 19388768458SSam Leffler 19488768458SSam Leffler /* 19588768458SSam Leffler * We're done with IPsec processing, transmit the packet using the 19688768458SSam Leffler * appropriate network protocol (IP or IPv6). SPD lookup will be 19788768458SSam Leffler * performed again there. 19888768458SSam Leffler */ 19988768458SSam Leffler switch (saidx->dst.sa.sa_family) { 20088768458SSam Leffler #ifdef INET 20188768458SSam Leffler case AF_INET: 2027b495c44SVANHULLEBUS Yvan #ifdef IPSEC_NAT_T 2037b495c44SVANHULLEBUS Yvan /* 2047b495c44SVANHULLEBUS Yvan * If NAT-T is enabled, now that all IPsec processing is done 2057b495c44SVANHULLEBUS Yvan * insert UDP encapsulation header after IP header. 2067b495c44SVANHULLEBUS Yvan */ 2077b495c44SVANHULLEBUS Yvan if (sav->natt_type) { 20820472bceSGleb Smirnoff struct ip *ip = mtod(m, struct ip *); 2097b495c44SVANHULLEBUS Yvan const int hlen = (ip->ip_hl << 2); 2107b495c44SVANHULLEBUS Yvan int size, off; 2117b495c44SVANHULLEBUS Yvan struct mbuf *mi; 2127b495c44SVANHULLEBUS Yvan struct udphdr *udp; 2137b495c44SVANHULLEBUS Yvan 2147b495c44SVANHULLEBUS Yvan size = sizeof(struct udphdr); 2157b495c44SVANHULLEBUS Yvan if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) { 2167b495c44SVANHULLEBUS Yvan /* 2177b495c44SVANHULLEBUS Yvan * draft-ietf-ipsec-nat-t-ike-0[01].txt and 2187b495c44SVANHULLEBUS Yvan * draft-ietf-ipsec-udp-encaps-(00/)01.txt, 2197b495c44SVANHULLEBUS Yvan * ignoring possible AH mode 2207b495c44SVANHULLEBUS Yvan * non-IKE marker + non-ESP marker 2217b495c44SVANHULLEBUS Yvan * from draft-ietf-ipsec-udp-encaps-00.txt. 2227b495c44SVANHULLEBUS Yvan */ 2237b495c44SVANHULLEBUS Yvan size += sizeof(u_int64_t); 2247b495c44SVANHULLEBUS Yvan } 2257b495c44SVANHULLEBUS Yvan mi = m_makespace(m, hlen, size, &off); 2267b495c44SVANHULLEBUS Yvan if (mi == NULL) { 2277b495c44SVANHULLEBUS Yvan DPRINTF(("%s: m_makespace for udphdr failed\n", 2287b495c44SVANHULLEBUS Yvan __func__)); 2297b495c44SVANHULLEBUS Yvan error = ENOBUFS; 2307b495c44SVANHULLEBUS Yvan goto bad; 2317b495c44SVANHULLEBUS Yvan } 2327b495c44SVANHULLEBUS Yvan 2337b495c44SVANHULLEBUS Yvan udp = (struct udphdr *)(mtod(mi, caddr_t) + off); 2347b495c44SVANHULLEBUS Yvan if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) 2357b495c44SVANHULLEBUS Yvan udp->uh_sport = htons(UDP_ENCAP_ESPINUDP_PORT); 2367b495c44SVANHULLEBUS Yvan else 2377b495c44SVANHULLEBUS Yvan udp->uh_sport = 2387b495c44SVANHULLEBUS Yvan KEY_PORTFROMSADDR(&sav->sah->saidx.src); 2397b495c44SVANHULLEBUS Yvan udp->uh_dport = KEY_PORTFROMSADDR(&sav->sah->saidx.dst); 2407b495c44SVANHULLEBUS Yvan udp->uh_sum = 0; 2417b495c44SVANHULLEBUS Yvan udp->uh_ulen = htons(m->m_pkthdr.len - hlen); 24220472bceSGleb Smirnoff ip->ip_len = htons(m->m_pkthdr.len); 2437b495c44SVANHULLEBUS Yvan ip->ip_p = IPPROTO_UDP; 2447b495c44SVANHULLEBUS Yvan 2457b495c44SVANHULLEBUS Yvan if (sav->natt_type == UDP_ENCAP_ESPINUDP_NON_IKE) 2467b495c44SVANHULLEBUS Yvan *(u_int64_t *)(udp + 1) = 0; 2477b495c44SVANHULLEBUS Yvan } 2487b495c44SVANHULLEBUS Yvan #endif /* IPSEC_NAT_T */ 2497b495c44SVANHULLEBUS Yvan 25088768458SSam Leffler return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL); 25188768458SSam Leffler #endif /* INET */ 25288768458SSam Leffler #ifdef INET6 25388768458SSam Leffler case AF_INET6: 25488768458SSam Leffler /* 25588768458SSam Leffler * We don't need massage, IPv6 header fields are always in 25688768458SSam Leffler * net endian. 25788768458SSam Leffler */ 25888768458SSam Leffler return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); 25988768458SSam Leffler #endif /* INET6 */ 26088768458SSam Leffler } 26188768458SSam Leffler panic("ipsec_process_done"); 26288768458SSam Leffler bad: 26388768458SSam Leffler m_freem(m); 26488768458SSam Leffler return (error); 26588768458SSam Leffler } 26688768458SSam Leffler 26788768458SSam Leffler static struct ipsecrequest * 26888768458SSam Leffler ipsec_nextisr( 26988768458SSam Leffler struct mbuf *m, 27088768458SSam Leffler struct ipsecrequest *isr, 27188768458SSam Leffler int af, 27288768458SSam Leffler struct secasindex *saidx, 27388768458SSam Leffler int *error 27488768458SSam Leffler ) 27588768458SSam Leffler { 276a04d64d8SAndrey V. Elsukov #define IPSEC_OSTAT(name) do { \ 277a04d64d8SAndrey V. Elsukov if (isr->saidx.proto == IPPROTO_ESP) \ 278a04d64d8SAndrey V. Elsukov ESPSTAT_INC(esps_##name); \ 279a04d64d8SAndrey V. Elsukov else if (isr->saidx.proto == IPPROTO_AH)\ 280a04d64d8SAndrey V. Elsukov AHSTAT_INC(ahs_##name); \ 281a04d64d8SAndrey V. Elsukov else \ 282a04d64d8SAndrey V. Elsukov IPCOMPSTAT_INC(ipcomps_##name); \ 283a04d64d8SAndrey V. Elsukov } while (0) 28488768458SSam Leffler struct secasvar *sav; 28588768458SSam Leffler 2869ffa9677SSam Leffler IPSECREQUEST_LOCK_ASSERT(isr); 2879ffa9677SSam Leffler 2889ffa9677SSam Leffler IPSEC_ASSERT(af == AF_INET || af == AF_INET6, 2899ffa9677SSam Leffler ("invalid address family %u", af)); 29088768458SSam Leffler again: 29188768458SSam Leffler /* 29288768458SSam Leffler * Craft SA index to search for proper SA. Note that 29388768458SSam Leffler * we only fillin unspecified SA peers for transport 29488768458SSam Leffler * mode; for tunnel mode they must already be filled in. 29588768458SSam Leffler */ 29688768458SSam Leffler *saidx = isr->saidx; 29788768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TRANSPORT) { 29888768458SSam Leffler /* Fillin unspecified SA peers only for transport mode */ 29988768458SSam Leffler if (af == AF_INET) { 30088768458SSam Leffler struct sockaddr_in *sin; 30188768458SSam Leffler struct ip *ip = mtod(m, struct ip *); 30288768458SSam Leffler 30388768458SSam Leffler if (saidx->src.sa.sa_len == 0) { 30488768458SSam Leffler sin = &saidx->src.sin; 30588768458SSam Leffler sin->sin_len = sizeof(*sin); 30688768458SSam Leffler sin->sin_family = AF_INET; 30788768458SSam Leffler sin->sin_port = IPSEC_PORT_ANY; 30888768458SSam Leffler sin->sin_addr = ip->ip_src; 30988768458SSam Leffler } 31088768458SSam Leffler if (saidx->dst.sa.sa_len == 0) { 31188768458SSam Leffler sin = &saidx->dst.sin; 31288768458SSam Leffler sin->sin_len = sizeof(*sin); 31388768458SSam Leffler sin->sin_family = AF_INET; 31488768458SSam Leffler sin->sin_port = IPSEC_PORT_ANY; 31588768458SSam Leffler sin->sin_addr = ip->ip_dst; 31688768458SSam Leffler } 31788768458SSam Leffler } else { 31888768458SSam Leffler struct sockaddr_in6 *sin6; 31988768458SSam Leffler struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 32088768458SSam Leffler 32188768458SSam Leffler if (saidx->src.sin6.sin6_len == 0) { 32288768458SSam Leffler sin6 = (struct sockaddr_in6 *)&saidx->src; 32388768458SSam Leffler sin6->sin6_len = sizeof(*sin6); 32488768458SSam Leffler sin6->sin6_family = AF_INET6; 32588768458SSam Leffler sin6->sin6_port = IPSEC_PORT_ANY; 32688768458SSam Leffler sin6->sin6_addr = ip6->ip6_src; 32788768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) { 32888768458SSam Leffler /* fix scope id for comparing SPD */ 32988768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 33088768458SSam Leffler sin6->sin6_scope_id = 33188768458SSam Leffler ntohs(ip6->ip6_src.s6_addr16[1]); 33288768458SSam Leffler } 33388768458SSam Leffler } 33488768458SSam Leffler if (saidx->dst.sin6.sin6_len == 0) { 33588768458SSam Leffler sin6 = (struct sockaddr_in6 *)&saidx->dst; 33688768458SSam Leffler sin6->sin6_len = sizeof(*sin6); 33788768458SSam Leffler sin6->sin6_family = AF_INET6; 33888768458SSam Leffler sin6->sin6_port = IPSEC_PORT_ANY; 33988768458SSam Leffler sin6->sin6_addr = ip6->ip6_dst; 34088768458SSam Leffler if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) { 34188768458SSam Leffler /* fix scope id for comparing SPD */ 34288768458SSam Leffler sin6->sin6_addr.s6_addr16[1] = 0; 34388768458SSam Leffler sin6->sin6_scope_id = 34488768458SSam Leffler ntohs(ip6->ip6_dst.s6_addr16[1]); 34588768458SSam Leffler } 34688768458SSam Leffler } 34788768458SSam Leffler } 34888768458SSam Leffler } 34988768458SSam Leffler 35088768458SSam Leffler /* 35188768458SSam Leffler * Lookup SA and validate it. 35288768458SSam Leffler */ 35388768458SSam Leffler *error = key_checkrequest(isr, saidx); 35488768458SSam Leffler if (*error != 0) { 35588768458SSam Leffler /* 35688768458SSam Leffler * IPsec processing is required, but no SA found. 35788768458SSam Leffler * I assume that key_acquire() had been called 35888768458SSam Leffler * to get/establish the SA. Here I discard 35988768458SSam Leffler * this packet because it is responsibility for 36088768458SSam Leffler * upper layer to retransmit the packet. 36188768458SSam Leffler */ 362f3c93842SAndrey V. Elsukov switch(af) { 363f3c93842SAndrey V. Elsukov case AF_INET: 3646659296cSAndrey V. Elsukov IPSECSTAT_INC(ips_out_nosa); 365f3c93842SAndrey V. Elsukov break; 366f3c93842SAndrey V. Elsukov #ifdef INET6 367f3c93842SAndrey V. Elsukov case AF_INET6: 368f3c93842SAndrey V. Elsukov IPSEC6STAT_INC(ips_out_nosa); 369f3c93842SAndrey V. Elsukov break; 370f3c93842SAndrey V. Elsukov #endif 371f3c93842SAndrey V. Elsukov } 37288768458SSam Leffler goto bad; 37388768458SSam Leffler } 37488768458SSam Leffler sav = isr->sav; 3759e3bdedeSBjoern A. Zeeb if (sav == NULL) { 3769ffa9677SSam Leffler IPSEC_ASSERT(ipsec_get_reqlevel(isr) == IPSEC_LEVEL_USE, 3779ffa9677SSam Leffler ("no SA found, but required; level %u", 37888768458SSam Leffler ipsec_get_reqlevel(isr))); 3799ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 38088768458SSam Leffler isr = isr->next; 3819e3bdedeSBjoern A. Zeeb /* 3829e3bdedeSBjoern A. Zeeb * If isr is NULL, we found a 'use' policy w/o SA. 3839e3bdedeSBjoern A. Zeeb * Return w/o error and w/o isr so we can drop out 3849e3bdedeSBjoern A. Zeeb * and continue w/o IPsec processing. 3859e3bdedeSBjoern A. Zeeb */ 3869e3bdedeSBjoern A. Zeeb if (isr == NULL) 38788768458SSam Leffler return isr; 3889ffa9677SSam Leffler IPSECREQUEST_LOCK(isr); 38988768458SSam Leffler goto again; 39088768458SSam Leffler } 39188768458SSam Leffler 39288768458SSam Leffler /* 39388768458SSam Leffler * Check system global policy controls. 39488768458SSam Leffler */ 395603724d3SBjoern A. Zeeb if ((isr->saidx.proto == IPPROTO_ESP && !V_esp_enable) || 396603724d3SBjoern A. Zeeb (isr->saidx.proto == IPPROTO_AH && !V_ah_enable) || 397603724d3SBjoern A. Zeeb (isr->saidx.proto == IPPROTO_IPCOMP && !V_ipcomp_enable)) { 3989ffa9677SSam Leffler DPRINTF(("%s: IPsec outbound packet dropped due" 3999ffa9677SSam Leffler " to policy (check your sysctls)\n", __func__)); 400a04d64d8SAndrey V. Elsukov IPSEC_OSTAT(pdrops); 40188768458SSam Leffler *error = EHOSTUNREACH; 40288768458SSam Leffler goto bad; 40388768458SSam Leffler } 40488768458SSam Leffler 40588768458SSam Leffler /* 40688768458SSam Leffler * Sanity check the SA contents for the caller 40788768458SSam Leffler * before they invoke the xform output method. 40888768458SSam Leffler */ 40988768458SSam Leffler if (sav->tdb_xform == NULL) { 4109ffa9677SSam Leffler DPRINTF(("%s: no transform for SA\n", __func__)); 411a04d64d8SAndrey V. Elsukov IPSEC_OSTAT(noxform); 41288768458SSam Leffler *error = EHOSTUNREACH; 41388768458SSam Leffler goto bad; 41488768458SSam Leffler } 41588768458SSam Leffler return isr; 41688768458SSam Leffler bad: 4179ffa9677SSam Leffler IPSEC_ASSERT(*error != 0, ("error return w/ no error code")); 4189ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 41988768458SSam Leffler return NULL; 42088768458SSam Leffler #undef IPSEC_OSTAT 42188768458SSam Leffler } 42288768458SSam Leffler 42388768458SSam Leffler #ifdef INET 42488768458SSam Leffler /* 42588768458SSam Leffler * IPsec output logic for IPv4. 42688768458SSam Leffler */ 42788768458SSam Leffler int 42888768458SSam Leffler ipsec4_process_packet( 42988768458SSam Leffler struct mbuf *m, 43088768458SSam Leffler struct ipsecrequest *isr, 43188768458SSam Leffler int flags, 43288768458SSam Leffler int tunalready) 43388768458SSam Leffler { 43488768458SSam Leffler struct secasindex saidx; 43588768458SSam Leffler struct secasvar *sav; 43688768458SSam Leffler struct ip *ip; 4376464079fSSam Leffler int error, i, off; 43888768458SSam Leffler 4399ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 4409ffa9677SSam Leffler IPSEC_ASSERT(isr != NULL, ("null isr")); 44188768458SSam Leffler 4429ffa9677SSam Leffler IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 44388768458SSam Leffler 44488768458SSam Leffler isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); 4459e3bdedeSBjoern A. Zeeb if (isr == NULL) { 4469e3bdedeSBjoern A. Zeeb if (error != 0) 44788768458SSam Leffler goto bad; 4489e3bdedeSBjoern A. Zeeb return EJUSTRETURN; 4499e3bdedeSBjoern A. Zeeb } 45088768458SSam Leffler 45188768458SSam Leffler sav = isr->sav; 452bdea400fSAndrew Thompson 453bdea400fSAndrew Thompson #ifdef DEV_ENC 4546ff8af1cSGleb Smirnoff if_inc_counter(encif, IFCOUNTER_OPACKETS, 1); 4556ff8af1cSGleb Smirnoff if_inc_counter(encif, IFCOUNTER_OBYTES, m->m_pkthdr.len); 45697c2a697SVANHULLEBUS Yvan 45719ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for bpf processing */ 45819ad9831SBjoern A. Zeeb ipsec_bpf(m, sav, AF_INET, ENC_OUT|ENC_BEFORE); 459bdea400fSAndrew Thompson /* pass the mbuf to enc0 for packet filtering */ 46019ad9831SBjoern A. Zeeb if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0) 461bdea400fSAndrew Thompson goto bad; 462bdea400fSAndrew Thompson #endif 463bdea400fSAndrew Thompson 46488768458SSam Leffler if (!tunalready) { 46588768458SSam Leffler union sockaddr_union *dst = &sav->sah->saidx.dst; 46688768458SSam Leffler int setdf; 46788768458SSam Leffler 46888768458SSam Leffler /* 46988768458SSam Leffler * Collect IP_DF state from the outer header. 47088768458SSam Leffler */ 47188768458SSam Leffler if (dst->sa.sa_family == AF_INET) { 47288768458SSam Leffler if (m->m_len < sizeof (struct ip) && 47388768458SSam Leffler (m = m_pullup(m, sizeof (struct ip))) == NULL) { 47488768458SSam Leffler error = ENOBUFS; 47588768458SSam Leffler goto bad; 47688768458SSam Leffler } 47788768458SSam Leffler ip = mtod(m, struct ip *); 47888768458SSam Leffler /* Honor system-wide control of how to handle IP_DF */ 479603724d3SBjoern A. Zeeb switch (V_ip4_ipsec_dfbit) { 48088768458SSam Leffler case 0: /* clear in outer header */ 48188768458SSam Leffler case 1: /* set in outer header */ 482603724d3SBjoern A. Zeeb setdf = V_ip4_ipsec_dfbit; 48388768458SSam Leffler break; 48488768458SSam Leffler default: /* propagate to outer header */ 48588768458SSam Leffler setdf = ntohs(ip->ip_off & IP_DF); 48688768458SSam Leffler break; 48788768458SSam Leffler } 48888768458SSam Leffler } else { 48988768458SSam Leffler ip = NULL; /* keep compiler happy */ 49088768458SSam Leffler setdf = 0; 49188768458SSam Leffler } 49288768458SSam Leffler /* Do the appropriate encapsulation, if necessary */ 49388768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 49488768458SSam Leffler dst->sa.sa_family != AF_INET || /* PF mismatch */ 49588768458SSam Leffler #if 0 49688768458SSam Leffler (sav->flags & SADB_X_SAFLAGS_TUNNEL) || /* Tunnel requ'd */ 49788768458SSam Leffler sav->tdb_xform->xf_type == XF_IP4 || /* ditto */ 49888768458SSam Leffler #endif 49988768458SSam Leffler (dst->sa.sa_family == AF_INET && /* Proxy */ 50088768458SSam Leffler dst->sin.sin_addr.s_addr != INADDR_ANY && 50188768458SSam Leffler dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { 50288768458SSam Leffler struct mbuf *mp; 50388768458SSam Leffler 50488768458SSam Leffler /* Fix IPv4 header checksum and length */ 50588768458SSam Leffler if (m->m_len < sizeof (struct ip) && 50688768458SSam Leffler (m = m_pullup(m, sizeof (struct ip))) == NULL) { 50788768458SSam Leffler error = ENOBUFS; 50888768458SSam Leffler goto bad; 50988768458SSam Leffler } 51088768458SSam Leffler ip = mtod(m, struct ip *); 511b01e3d08SMarko Zec if (ip->ip_v == IPVERSION) { 51288768458SSam Leffler ip->ip_len = htons(m->m_pkthdr.len); 51388768458SSam Leffler ip->ip_sum = 0; 51488768458SSam Leffler ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 515b01e3d08SMarko Zec } 51688768458SSam Leffler 51788768458SSam Leffler /* Encapsulate the packet */ 51888768458SSam Leffler error = ipip_output(m, isr, &mp, 0, 0); 51988768458SSam Leffler if (mp == NULL && !error) { 52088768458SSam Leffler /* Should never happen. */ 5219ffa9677SSam Leffler DPRINTF(("%s: ipip_output returns no mbuf and " 5229ffa9677SSam Leffler "no error!", __func__)); 52388768458SSam Leffler error = EFAULT; 52488768458SSam Leffler } 52588768458SSam Leffler if (error) { 526b5b47bc6SSam Leffler if (mp) { 527b5b47bc6SSam Leffler /* XXX: Should never happen! */ 52888768458SSam Leffler m_freem(mp); 529b5b47bc6SSam Leffler } 530b5b47bc6SSam Leffler m = NULL; /* ipip_output() already freed it */ 53188768458SSam Leffler goto bad; 53288768458SSam Leffler } 53388768458SSam Leffler m = mp, mp = NULL; 53488768458SSam Leffler /* 53588768458SSam Leffler * ipip_output clears IP_DF in the new header. If 53688768458SSam Leffler * we need to propagate IP_DF from the outer header, 53788768458SSam Leffler * then we have to do it here. 53888768458SSam Leffler * 53988768458SSam Leffler * XXX shouldn't assume what ipip_output does. 54088768458SSam Leffler */ 54188768458SSam Leffler if (dst->sa.sa_family == AF_INET && setdf) { 54288768458SSam Leffler if (m->m_len < sizeof (struct ip) && 54388768458SSam Leffler (m = m_pullup(m, sizeof (struct ip))) == NULL) { 54488768458SSam Leffler error = ENOBUFS; 54588768458SSam Leffler goto bad; 54688768458SSam Leffler } 54788768458SSam Leffler ip = mtod(m, struct ip *); 54888768458SSam Leffler ip->ip_off = ntohs(ip->ip_off); 54988768458SSam Leffler ip->ip_off |= IP_DF; 55088768458SSam Leffler ip->ip_off = htons(ip->ip_off); 55188768458SSam Leffler } 55288768458SSam Leffler } 55388768458SSam Leffler } 55488768458SSam Leffler 555bdea400fSAndrew Thompson #ifdef DEV_ENC 556bdea400fSAndrew Thompson /* pass the mbuf to enc0 for bpf processing */ 557aaf2cfc0SVANHULLEBUS Yvan ipsec_bpf(m, sav, sav->sah->saidx.dst.sa.sa_family, ENC_OUT|ENC_AFTER); 55819ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for packet filtering */ 55919ad9831SBjoern A. Zeeb if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0) 56019ad9831SBjoern A. Zeeb goto bad; 561bdea400fSAndrew Thompson #endif 562bdea400fSAndrew Thompson 56388768458SSam Leffler /* 56488768458SSam Leffler * Dispatch to the appropriate IPsec transform logic. The 56588768458SSam Leffler * packet will be returned for transmission after crypto 56688768458SSam Leffler * processing, etc. are completed. For encapsulation we 56788768458SSam Leffler * bypass this call because of the explicit call done above 56888768458SSam Leffler * (necessary to deal with IP_DF handling for IPv4). 56988768458SSam Leffler * 57088768458SSam Leffler * NB: m & sav are ``passed to caller'' who's reponsible for 57188768458SSam Leffler * for reclaiming their resources. 57288768458SSam Leffler */ 57388768458SSam Leffler if (sav->tdb_xform->xf_type != XF_IP4) { 574aaf2cfc0SVANHULLEBUS Yvan union sockaddr_union *dst = &sav->sah->saidx.dst; 575aaf2cfc0SVANHULLEBUS Yvan switch(dst->sa.sa_family) { 576aaf2cfc0SVANHULLEBUS Yvan case AF_INET: 57788768458SSam Leffler ip = mtod(m, struct ip *); 57888768458SSam Leffler i = ip->ip_hl << 2; 57988768458SSam Leffler off = offsetof(struct ip, ip_p); 580aaf2cfc0SVANHULLEBUS Yvan break; 581aaf2cfc0SVANHULLEBUS Yvan #ifdef INET6 582aaf2cfc0SVANHULLEBUS Yvan case AF_INET6: 583aaf2cfc0SVANHULLEBUS Yvan i = sizeof(struct ip6_hdr); 584aaf2cfc0SVANHULLEBUS Yvan off = offsetof(struct ip6_hdr, ip6_nxt); 585aaf2cfc0SVANHULLEBUS Yvan break; 586aaf2cfc0SVANHULLEBUS Yvan #endif /* INET6 */ 587aaf2cfc0SVANHULLEBUS Yvan default: 588aaf2cfc0SVANHULLEBUS Yvan DPRINTF(("%s: unsupported protocol family %u\n", 589aaf2cfc0SVANHULLEBUS Yvan __func__, dst->sa.sa_family)); 590aaf2cfc0SVANHULLEBUS Yvan error = EPFNOSUPPORT; 5916d120f90SBjoern A. Zeeb IPSECSTAT_INC(ips_out_inval); 592aaf2cfc0SVANHULLEBUS Yvan goto bad; 593aaf2cfc0SVANHULLEBUS Yvan } 59488768458SSam Leffler error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); 59588768458SSam Leffler } else { 59688768458SSam Leffler error = ipsec_process_done(m, isr); 59788768458SSam Leffler } 5989ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 59988768458SSam Leffler return error; 60088768458SSam Leffler bad: 6019ffa9677SSam Leffler if (isr) 6029ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 60388768458SSam Leffler if (m) 60488768458SSam Leffler m_freem(m); 60588768458SSam Leffler return error; 60688768458SSam Leffler } 60788768458SSam Leffler #endif 60888768458SSam Leffler 609aaf2cfc0SVANHULLEBUS Yvan 61088768458SSam Leffler #ifdef INET6 61188768458SSam Leffler static int 612aaf2cfc0SVANHULLEBUS Yvan in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia) 61388768458SSam Leffler { 614aaf2cfc0SVANHULLEBUS Yvan struct in6_addr ia2; 61588768458SSam Leffler 616aaf2cfc0SVANHULLEBUS Yvan memcpy(&ia2, &sa->sin6_addr, sizeof(ia2)); 617aaf2cfc0SVANHULLEBUS Yvan if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr)) 618aaf2cfc0SVANHULLEBUS Yvan ia2.s6_addr16[1] = htons(sa->sin6_scope_id); 61988768458SSam Leffler 620aaf2cfc0SVANHULLEBUS Yvan return IN6_ARE_ADDR_EQUAL(ia, &ia2); 62188768458SSam Leffler } 62288768458SSam Leffler 62388768458SSam Leffler /* 624aaf2cfc0SVANHULLEBUS Yvan * IPsec output logic for IPv6. 62588768458SSam Leffler */ 62688768458SSam Leffler int 627aaf2cfc0SVANHULLEBUS Yvan ipsec6_process_packet( 628aaf2cfc0SVANHULLEBUS Yvan struct mbuf *m, 629aaf2cfc0SVANHULLEBUS Yvan struct ipsecrequest *isr 630aaf2cfc0SVANHULLEBUS Yvan ) 63188768458SSam Leffler { 63288768458SSam Leffler struct secasindex saidx; 633aaf2cfc0SVANHULLEBUS Yvan struct secasvar *sav; 634aaf2cfc0SVANHULLEBUS Yvan struct ip6_hdr *ip6; 635aaf2cfc0SVANHULLEBUS Yvan int error, i, off; 636aaf2cfc0SVANHULLEBUS Yvan union sockaddr_union *dst; 63788768458SSam Leffler 638aaf2cfc0SVANHULLEBUS Yvan IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf")); 639aaf2cfc0SVANHULLEBUS Yvan IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr")); 640923e1044SBjoern A. Zeeb 641923e1044SBjoern A. Zeeb IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 642aaf2cfc0SVANHULLEBUS Yvan 64388768458SSam Leffler isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); 6449e3bdedeSBjoern A. Zeeb if (isr == NULL) { 6459e3bdedeSBjoern A. Zeeb if (error != 0) 64688768458SSam Leffler goto bad; 6479e3bdedeSBjoern A. Zeeb return EJUSTRETURN; 6489e3bdedeSBjoern A. Zeeb } 64988768458SSam Leffler 650aaf2cfc0SVANHULLEBUS Yvan sav = isr->sav; 651aaf2cfc0SVANHULLEBUS Yvan dst = &sav->sah->saidx.dst; 652aaf2cfc0SVANHULLEBUS Yvan 65367fd1727SAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 65467fd1727SAndrey V. Elsukov ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); 65519ad9831SBjoern A. Zeeb #ifdef DEV_ENC 6566ff8af1cSGleb Smirnoff if_inc_counter(encif, IFCOUNTER_OPACKETS, 1); 6576ff8af1cSGleb Smirnoff if_inc_counter(encif, IFCOUNTER_OBYTES, m->m_pkthdr.len); 65897c2a697SVANHULLEBUS Yvan 65919ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for bpf processing */ 66019ad9831SBjoern A. Zeeb ipsec_bpf(m, isr->sav, AF_INET6, ENC_OUT|ENC_BEFORE); 66119ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for packet filtering */ 66219ad9831SBjoern A. Zeeb if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0) 66319ad9831SBjoern A. Zeeb goto bad; 664aaf2cfc0SVANHULLEBUS Yvan #endif /* DEV_ENC */ 66519ad9831SBjoern A. Zeeb 666aaf2cfc0SVANHULLEBUS Yvan /* Do the appropriate encapsulation, if necessary */ 667aaf2cfc0SVANHULLEBUS Yvan if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 668aaf2cfc0SVANHULLEBUS Yvan dst->sa.sa_family != AF_INET6 || /* PF mismatch */ 669aaf2cfc0SVANHULLEBUS Yvan ((dst->sa.sa_family == AF_INET6) && 670aaf2cfc0SVANHULLEBUS Yvan (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && 671aaf2cfc0SVANHULLEBUS Yvan (!in6_sa_equal_addrwithscope(&dst->sin6, 672aaf2cfc0SVANHULLEBUS Yvan &ip6->ip6_dst)))) { 673aaf2cfc0SVANHULLEBUS Yvan struct mbuf *mp; 674aaf2cfc0SVANHULLEBUS Yvan 675aaf2cfc0SVANHULLEBUS Yvan /* Fix IPv6 header payload length. */ 676aaf2cfc0SVANHULLEBUS Yvan if (m->m_len < sizeof(struct ip6_hdr)) 677aaf2cfc0SVANHULLEBUS Yvan if ((m = m_pullup(m,sizeof(struct ip6_hdr))) == NULL) { 678aaf2cfc0SVANHULLEBUS Yvan error = ENOBUFS; 67988768458SSam Leffler goto bad; 68088768458SSam Leffler } 68188768458SSam Leffler 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 } 687aaf2cfc0SVANHULLEBUS Yvan 688aaf2cfc0SVANHULLEBUS Yvan /* Encapsulate the packet */ 689aaf2cfc0SVANHULLEBUS Yvan error = ipip_output(m, isr, &mp, 0, 0); 690aaf2cfc0SVANHULLEBUS Yvan if (mp == NULL && !error) { 691aaf2cfc0SVANHULLEBUS Yvan /* Should never happen. */ 692aaf2cfc0SVANHULLEBUS Yvan DPRINTF(("ipsec6_process_packet: ipip_output " 693aaf2cfc0SVANHULLEBUS Yvan "returns no mbuf and no error!")); 694aaf2cfc0SVANHULLEBUS Yvan error = EFAULT; 695aaf2cfc0SVANHULLEBUS Yvan goto bad; 696aaf2cfc0SVANHULLEBUS Yvan } 697aaf2cfc0SVANHULLEBUS Yvan 69888768458SSam Leffler if (error) { 699aaf2cfc0SVANHULLEBUS Yvan if (mp) { 700aaf2cfc0SVANHULLEBUS Yvan /* XXX: Should never happen! */ 701aaf2cfc0SVANHULLEBUS Yvan m_freem(mp); 70288768458SSam Leffler } 703aaf2cfc0SVANHULLEBUS Yvan m = NULL; /* ipip_output() already freed it */ 70488768458SSam Leffler goto bad; 70588768458SSam Leffler } 70688768458SSam Leffler 707aaf2cfc0SVANHULLEBUS Yvan m = mp; 708aaf2cfc0SVANHULLEBUS Yvan mp = NULL; 70988768458SSam Leffler } 71088768458SSam Leffler 71119ad9831SBjoern A. Zeeb #ifdef DEV_ENC 712aaf2cfc0SVANHULLEBUS Yvan ipsec_bpf(m, isr->sav, dst->sa.sa_family, ENC_OUT|ENC_AFTER); 71319ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for packet filtering */ 71419ad9831SBjoern A. Zeeb if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0) 71519ad9831SBjoern A. Zeeb goto bad; 716aaf2cfc0SVANHULLEBUS Yvan #endif /* DEV_ENC */ 71719ad9831SBjoern A. Zeeb 718aaf2cfc0SVANHULLEBUS Yvan switch(dst->sa.sa_family) { 719aaf2cfc0SVANHULLEBUS Yvan #ifdef INET 720aaf2cfc0SVANHULLEBUS Yvan case AF_INET: 721aaf2cfc0SVANHULLEBUS Yvan { 722aaf2cfc0SVANHULLEBUS Yvan struct ip *ip; 723aaf2cfc0SVANHULLEBUS Yvan ip = mtod(m, struct ip *); 724aaf2cfc0SVANHULLEBUS Yvan i = ip->ip_hl << 2; 725aaf2cfc0SVANHULLEBUS Yvan off = offsetof(struct ip, ip_p); 726aaf2cfc0SVANHULLEBUS Yvan } 727aaf2cfc0SVANHULLEBUS Yvan break; 728aaf2cfc0SVANHULLEBUS Yvan #endif /* AF_INET */ 729aaf2cfc0SVANHULLEBUS Yvan case AF_INET6: 730aaf2cfc0SVANHULLEBUS Yvan i = sizeof(struct ip6_hdr); 731aaf2cfc0SVANHULLEBUS Yvan off = offsetof(struct ip6_hdr, ip6_nxt); 732aaf2cfc0SVANHULLEBUS Yvan break; 733aaf2cfc0SVANHULLEBUS Yvan default: 734aaf2cfc0SVANHULLEBUS Yvan DPRINTF(("%s: unsupported protocol family %u\n", 735aaf2cfc0SVANHULLEBUS Yvan __func__, dst->sa.sa_family)); 736aaf2cfc0SVANHULLEBUS Yvan error = EPFNOSUPPORT; 737aaf2cfc0SVANHULLEBUS Yvan IPSEC6STAT_INC(ips_out_inval); 738aaf2cfc0SVANHULLEBUS Yvan goto bad; 739aaf2cfc0SVANHULLEBUS Yvan } 740aaf2cfc0SVANHULLEBUS Yvan error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); 741923e1044SBjoern A. Zeeb IPSECREQUEST_UNLOCK(isr); 742923e1044SBjoern A. Zeeb return error; 74388768458SSam Leffler bad: 744aaf2cfc0SVANHULLEBUS Yvan 745923e1044SBjoern A. Zeeb if (isr) 746923e1044SBjoern A. Zeeb IPSECREQUEST_UNLOCK(isr); 74788768458SSam Leffler if (m) 74888768458SSam Leffler m_freem(m); 74988768458SSam Leffler return error; 75088768458SSam Leffler } 75188768458SSam Leffler #endif /*INET6*/ 752