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> 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 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: 172f9d8f665SAndrey V. Elsukov IPSECSTAT_INC(ips_out_bundlesa); 173619764beSAndrey V. Elsukov return ipsec4_process_packet(m, isr->next); 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 */ 180f9d8f665SAndrey 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 42361f37615SAndrey V. Elsukov static int 42461f37615SAndrey V. Elsukov ipsec_encap(struct mbuf **mp, struct secasindex *saidx) 42561f37615SAndrey V. Elsukov { 42661f37615SAndrey V. Elsukov #ifdef INET6 42761f37615SAndrey V. Elsukov struct ip6_hdr *ip6; 42861f37615SAndrey V. Elsukov #endif 42961f37615SAndrey V. Elsukov struct ip *ip; 43061f37615SAndrey V. Elsukov int setdf; 43161f37615SAndrey V. Elsukov uint8_t itos, proto; 43261f37615SAndrey V. Elsukov 43361f37615SAndrey V. Elsukov ip = mtod(*mp, struct ip *); 43461f37615SAndrey V. Elsukov switch (ip->ip_v) { 43561f37615SAndrey V. Elsukov #ifdef INET 43661f37615SAndrey V. Elsukov case IPVERSION: 43761f37615SAndrey V. Elsukov proto = IPPROTO_IPIP; 43861f37615SAndrey V. Elsukov /* 43961f37615SAndrey V. Elsukov * Collect IP_DF state from the inner header 44061f37615SAndrey V. Elsukov * and honor system-wide control of how to handle it. 44161f37615SAndrey V. Elsukov */ 44261f37615SAndrey V. Elsukov switch (V_ip4_ipsec_dfbit) { 44361f37615SAndrey V. Elsukov case 0: /* clear in outer header */ 44461f37615SAndrey V. Elsukov case 1: /* set in outer header */ 44561f37615SAndrey V. Elsukov setdf = V_ip4_ipsec_dfbit; 44661f37615SAndrey V. Elsukov break; 44761f37615SAndrey V. Elsukov default:/* propagate to outer header */ 44861f37615SAndrey V. Elsukov setdf = (ip->ip_off & ntohs(IP_DF)) != 0; 44961f37615SAndrey V. Elsukov } 45061f37615SAndrey V. Elsukov itos = ip->ip_tos; 45161f37615SAndrey V. Elsukov break; 45261f37615SAndrey V. Elsukov #endif 45361f37615SAndrey V. Elsukov #ifdef INET6 45461f37615SAndrey V. Elsukov case (IPV6_VERSION >> 4): 45561f37615SAndrey V. Elsukov proto = IPPROTO_IPV6; 45661f37615SAndrey V. Elsukov ip6 = mtod(*mp, struct ip6_hdr *); 45761f37615SAndrey V. Elsukov itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 45861f37615SAndrey V. Elsukov setdf = V_ip4_ipsec_dfbit ? 1: 0; 45961f37615SAndrey V. Elsukov /* scoped address handling */ 46061f37615SAndrey V. Elsukov in6_clearscope(&ip6->ip6_src); 46161f37615SAndrey V. Elsukov in6_clearscope(&ip6->ip6_dst); 46261f37615SAndrey V. Elsukov break; 46361f37615SAndrey V. Elsukov #endif 46461f37615SAndrey V. Elsukov default: 46561f37615SAndrey V. Elsukov return (EAFNOSUPPORT); 46661f37615SAndrey V. Elsukov } 46761f37615SAndrey V. Elsukov switch (saidx->dst.sa.sa_family) { 46861f37615SAndrey V. Elsukov #ifdef INET 46961f37615SAndrey V. Elsukov case AF_INET: 47061f37615SAndrey V. Elsukov if (saidx->src.sa.sa_family != AF_INET || 47161f37615SAndrey V. Elsukov saidx->src.sin.sin_addr.s_addr == INADDR_ANY || 47261f37615SAndrey V. Elsukov saidx->dst.sin.sin_addr.s_addr == INADDR_ANY) 47361f37615SAndrey V. Elsukov return (EINVAL); 47461f37615SAndrey V. Elsukov M_PREPEND(*mp, sizeof(struct ip), M_NOWAIT); 47561f37615SAndrey V. Elsukov if (*mp == NULL) 47661f37615SAndrey V. Elsukov return (ENOBUFS); 47761f37615SAndrey V. Elsukov ip = mtod(*mp, struct ip *); 47861f37615SAndrey V. Elsukov ip->ip_v = IPVERSION; 47961f37615SAndrey V. Elsukov ip->ip_hl = sizeof(struct ip) >> 2; 48061f37615SAndrey V. Elsukov ip->ip_p = proto; 48161f37615SAndrey V. Elsukov ip->ip_len = htons((*mp)->m_pkthdr.len); 48261f37615SAndrey V. Elsukov ip->ip_ttl = V_ip_defttl; 48361f37615SAndrey V. Elsukov ip->ip_sum = 0; 48461f37615SAndrey V. Elsukov ip->ip_off = setdf ? htons(IP_DF): 0; 48561f37615SAndrey V. Elsukov ip->ip_src = saidx->src.sin.sin_addr; 48661f37615SAndrey V. Elsukov ip->ip_dst = saidx->dst.sin.sin_addr; 48761f37615SAndrey V. Elsukov ip_ecn_ingress(V_ip4_ipsec_ecn, &ip->ip_tos, &itos); 48861f37615SAndrey V. Elsukov ip_fillid(ip); 48961f37615SAndrey V. Elsukov break; 49061f37615SAndrey V. Elsukov #endif /* INET */ 49161f37615SAndrey V. Elsukov #ifdef INET6 49261f37615SAndrey V. Elsukov case AF_INET6: 49361f37615SAndrey V. Elsukov if (saidx->src.sa.sa_family != AF_INET6 || 49461f37615SAndrey V. Elsukov IN6_IS_ADDR_UNSPECIFIED(&saidx->src.sin6.sin6_addr) || 49561f37615SAndrey V. Elsukov IN6_IS_ADDR_UNSPECIFIED(&saidx->dst.sin6.sin6_addr)) 49661f37615SAndrey V. Elsukov return (EINVAL); 49761f37615SAndrey V. Elsukov M_PREPEND(*mp, sizeof(struct ip6_hdr), M_NOWAIT); 49861f37615SAndrey V. Elsukov if (*mp == NULL) 49961f37615SAndrey V. Elsukov return (ENOBUFS); 50061f37615SAndrey V. Elsukov ip6 = mtod(*mp, struct ip6_hdr *); 50161f37615SAndrey V. Elsukov ip6->ip6_flow = 0; 50261f37615SAndrey V. Elsukov ip6->ip6_vfc = IPV6_VERSION; 50361f37615SAndrey V. Elsukov ip6->ip6_hlim = V_ip6_defhlim; 50461f37615SAndrey V. Elsukov ip6->ip6_nxt = proto; 50561f37615SAndrey V. Elsukov ip6->ip6_dst = saidx->dst.sin6.sin6_addr; 506*1ae800e7SAndrey V. Elsukov /* For link-local address embed scope zone id */ 507*1ae800e7SAndrey V. Elsukov if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) 508*1ae800e7SAndrey V. Elsukov ip6->ip6_dst.s6_addr16[1] = 509*1ae800e7SAndrey V. Elsukov htons(saidx->dst.sin6.sin6_scope_id & 0xffff); 51061f37615SAndrey V. Elsukov ip6->ip6_src = saidx->src.sin6.sin6_addr; 511*1ae800e7SAndrey V. Elsukov if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) 512*1ae800e7SAndrey V. Elsukov ip6->ip6_src.s6_addr16[1] = 513*1ae800e7SAndrey V. Elsukov htons(saidx->src.sin6.sin6_scope_id & 0xffff); 51461f37615SAndrey V. Elsukov ip6->ip6_plen = htons((*mp)->m_pkthdr.len - sizeof(*ip6)); 51561f37615SAndrey V. Elsukov ip_ecn_ingress(V_ip6_ipsec_ecn, &proto, &itos); 51661f37615SAndrey V. Elsukov ip6->ip6_flow |= htonl((uint32_t)proto << 20); 51761f37615SAndrey V. Elsukov break; 51861f37615SAndrey V. Elsukov #endif /* INET6 */ 51961f37615SAndrey V. Elsukov default: 52061f37615SAndrey V. Elsukov return (EAFNOSUPPORT); 52161f37615SAndrey V. Elsukov } 52261f37615SAndrey V. Elsukov return (0); 52361f37615SAndrey V. Elsukov } 52461f37615SAndrey V. Elsukov 52588768458SSam Leffler #ifdef INET 52688768458SSam Leffler /* 52788768458SSam Leffler * IPsec output logic for IPv4. 52888768458SSam Leffler */ 52988768458SSam Leffler int 530619764beSAndrey V. Elsukov ipsec4_process_packet(struct mbuf *m, struct ipsecrequest *isr) 53188768458SSam Leffler { 532619764beSAndrey V. Elsukov union sockaddr_union *dst; 53388768458SSam Leffler struct secasindex saidx; 53488768458SSam Leffler struct secasvar *sav; 53588768458SSam Leffler struct ip *ip; 53661f37615SAndrey V. Elsukov int error, i, off; 53788768458SSam Leffler 5389ffa9677SSam Leffler IPSEC_ASSERT(m != NULL, ("null mbuf")); 5399ffa9677SSam Leffler IPSEC_ASSERT(isr != NULL, ("null isr")); 54088768458SSam Leffler 5419ffa9677SSam Leffler IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 54288768458SSam Leffler 54388768458SSam Leffler isr = ipsec_nextisr(m, isr, AF_INET, &saidx, &error); 5449e3bdedeSBjoern A. Zeeb if (isr == NULL) { 5459e3bdedeSBjoern A. Zeeb if (error != 0) 54688768458SSam Leffler goto bad; 5479e3bdedeSBjoern A. Zeeb return EJUSTRETURN; 5489e3bdedeSBjoern A. Zeeb } 54988768458SSam Leffler 55088768458SSam Leffler sav = isr->sav; 551619764beSAndrey V. Elsukov if (m->m_len < sizeof(struct ip) && 552619764beSAndrey V. Elsukov (m = m_pullup(m, sizeof (struct ip))) == NULL) { 553619764beSAndrey V. Elsukov error = ENOBUFS; 554619764beSAndrey V. Elsukov goto bad; 555619764beSAndrey V. Elsukov } 556619764beSAndrey V. Elsukov ip = mtod(m, struct ip *); 557619764beSAndrey V. Elsukov dst = &sav->sah->saidx.dst; 558bdea400fSAndrew Thompson #ifdef DEV_ENC 5596ff8af1cSGleb Smirnoff if_inc_counter(encif, IFCOUNTER_OPACKETS, 1); 5606ff8af1cSGleb Smirnoff if_inc_counter(encif, IFCOUNTER_OBYTES, m->m_pkthdr.len); 56197c2a697SVANHULLEBUS Yvan 56219ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for bpf processing */ 56319ad9831SBjoern A. Zeeb ipsec_bpf(m, sav, AF_INET, ENC_OUT|ENC_BEFORE); 564bdea400fSAndrew Thompson /* pass the mbuf to enc0 for packet filtering */ 56519ad9831SBjoern A. Zeeb if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0) 566bdea400fSAndrew Thompson goto bad; 567bdea400fSAndrew Thompson #endif 56888768458SSam Leffler /* Do the appropriate encapsulation, if necessary */ 56988768458SSam Leffler if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 57088768458SSam Leffler dst->sa.sa_family != AF_INET || /* PF mismatch */ 57188768458SSam Leffler (dst->sa.sa_family == AF_INET && /* Proxy */ 57288768458SSam Leffler dst->sin.sin_addr.s_addr != INADDR_ANY && 57388768458SSam Leffler dst->sin.sin_addr.s_addr != ip->ip_dst.s_addr)) { 57488768458SSam Leffler /* Fix IPv4 header checksum and length */ 57588768458SSam Leffler ip->ip_len = htons(m->m_pkthdr.len); 57688768458SSam Leffler ip->ip_sum = 0; 57788768458SSam Leffler ip->ip_sum = in_cksum(m, ip->ip_hl << 2); 57861f37615SAndrey V. Elsukov error = ipsec_encap(&m, &sav->sah->saidx); 579619764beSAndrey V. Elsukov if (error != 0) { 58061f37615SAndrey V. Elsukov DPRINTF(("%s: encapsulation for SA %s->%s " 58161f37615SAndrey V. Elsukov "SPI 0x%08x failed with error %d\n", __func__, 58261f37615SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.src), 58361f37615SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst), 58461f37615SAndrey V. Elsukov ntohl(sav->spi), error)); 58588768458SSam Leffler goto bad; 58688768458SSam Leffler } 58788768458SSam Leffler } 588bdea400fSAndrew Thompson #ifdef DEV_ENC 589bdea400fSAndrew Thompson /* pass the mbuf to enc0 for bpf processing */ 590aaf2cfc0SVANHULLEBUS Yvan ipsec_bpf(m, sav, sav->sah->saidx.dst.sa.sa_family, ENC_OUT|ENC_AFTER); 59119ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for packet filtering */ 59219ad9831SBjoern A. Zeeb if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0) 59319ad9831SBjoern A. Zeeb goto bad; 594bdea400fSAndrew Thompson #endif 595bdea400fSAndrew Thompson 59688768458SSam Leffler /* 59788768458SSam Leffler * Dispatch to the appropriate IPsec transform logic. The 59888768458SSam Leffler * packet will be returned for transmission after crypto 59961f37615SAndrey V. Elsukov * processing, etc. are completed. 60088768458SSam Leffler * 60188768458SSam Leffler * NB: m & sav are ``passed to caller'' who's reponsible for 60288768458SSam Leffler * for reclaiming their resources. 60388768458SSam Leffler */ 604aaf2cfc0SVANHULLEBUS Yvan switch(dst->sa.sa_family) { 605aaf2cfc0SVANHULLEBUS Yvan case AF_INET: 60688768458SSam Leffler ip = mtod(m, struct ip *); 60788768458SSam Leffler i = ip->ip_hl << 2; 60888768458SSam Leffler off = offsetof(struct ip, ip_p); 609aaf2cfc0SVANHULLEBUS Yvan break; 610aaf2cfc0SVANHULLEBUS Yvan #ifdef INET6 611aaf2cfc0SVANHULLEBUS Yvan case AF_INET6: 612aaf2cfc0SVANHULLEBUS Yvan i = sizeof(struct ip6_hdr); 613aaf2cfc0SVANHULLEBUS Yvan off = offsetof(struct ip6_hdr, ip6_nxt); 614aaf2cfc0SVANHULLEBUS Yvan break; 615aaf2cfc0SVANHULLEBUS Yvan #endif /* INET6 */ 616aaf2cfc0SVANHULLEBUS Yvan default: 617aaf2cfc0SVANHULLEBUS Yvan DPRINTF(("%s: unsupported protocol family %u\n", 618aaf2cfc0SVANHULLEBUS Yvan __func__, dst->sa.sa_family)); 619aaf2cfc0SVANHULLEBUS Yvan error = EPFNOSUPPORT; 6206d120f90SBjoern A. Zeeb IPSECSTAT_INC(ips_out_inval); 621aaf2cfc0SVANHULLEBUS Yvan goto bad; 622aaf2cfc0SVANHULLEBUS Yvan } 62388768458SSam Leffler error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); 6249ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 62561f37615SAndrey V. Elsukov return (error); 62688768458SSam Leffler bad: 6279ffa9677SSam Leffler if (isr) 6289ffa9677SSam Leffler IPSECREQUEST_UNLOCK(isr); 62988768458SSam Leffler if (m) 63088768458SSam Leffler m_freem(m); 63188768458SSam Leffler return error; 63288768458SSam Leffler } 63388768458SSam Leffler #endif 63488768458SSam Leffler 635aaf2cfc0SVANHULLEBUS Yvan 63688768458SSam Leffler #ifdef INET6 63788768458SSam Leffler static int 638aaf2cfc0SVANHULLEBUS Yvan in6_sa_equal_addrwithscope(const struct sockaddr_in6 *sa, const struct in6_addr *ia) 63988768458SSam Leffler { 640aaf2cfc0SVANHULLEBUS Yvan struct in6_addr ia2; 64188768458SSam Leffler 642aaf2cfc0SVANHULLEBUS Yvan memcpy(&ia2, &sa->sin6_addr, sizeof(ia2)); 643aaf2cfc0SVANHULLEBUS Yvan if (IN6_IS_SCOPE_LINKLOCAL(&sa->sin6_addr)) 644aaf2cfc0SVANHULLEBUS Yvan ia2.s6_addr16[1] = htons(sa->sin6_scope_id); 64588768458SSam Leffler 646aaf2cfc0SVANHULLEBUS Yvan return IN6_ARE_ADDR_EQUAL(ia, &ia2); 64788768458SSam Leffler } 64888768458SSam Leffler 64988768458SSam Leffler /* 650aaf2cfc0SVANHULLEBUS Yvan * IPsec output logic for IPv6. 65188768458SSam Leffler */ 65288768458SSam Leffler int 653aaf2cfc0SVANHULLEBUS Yvan ipsec6_process_packet( 654aaf2cfc0SVANHULLEBUS Yvan struct mbuf *m, 655aaf2cfc0SVANHULLEBUS Yvan struct ipsecrequest *isr 656aaf2cfc0SVANHULLEBUS Yvan ) 65788768458SSam Leffler { 65888768458SSam Leffler struct secasindex saidx; 659aaf2cfc0SVANHULLEBUS Yvan struct secasvar *sav; 660aaf2cfc0SVANHULLEBUS Yvan struct ip6_hdr *ip6; 661aaf2cfc0SVANHULLEBUS Yvan int error, i, off; 662aaf2cfc0SVANHULLEBUS Yvan union sockaddr_union *dst; 66388768458SSam Leffler 664aaf2cfc0SVANHULLEBUS Yvan IPSEC_ASSERT(m != NULL, ("ipsec6_process_packet: null mbuf")); 665aaf2cfc0SVANHULLEBUS Yvan IPSEC_ASSERT(isr != NULL, ("ipsec6_process_packet: null isr")); 666923e1044SBjoern A. Zeeb 667923e1044SBjoern A. Zeeb IPSECREQUEST_LOCK(isr); /* insure SA contents don't change */ 668aaf2cfc0SVANHULLEBUS Yvan 66988768458SSam Leffler isr = ipsec_nextisr(m, isr, AF_INET6, &saidx, &error); 6709e3bdedeSBjoern A. Zeeb if (isr == NULL) { 6719e3bdedeSBjoern A. Zeeb if (error != 0) 67288768458SSam Leffler goto bad; 6739e3bdedeSBjoern A. Zeeb return EJUSTRETURN; 6749e3bdedeSBjoern A. Zeeb } 675aaf2cfc0SVANHULLEBUS Yvan sav = isr->sav; 676aaf2cfc0SVANHULLEBUS Yvan dst = &sav->sah->saidx.dst; 677aaf2cfc0SVANHULLEBUS Yvan 67867fd1727SAndrey V. Elsukov ip6 = mtod(m, struct ip6_hdr *); 67967fd1727SAndrey V. Elsukov ip6->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6)); 68019ad9831SBjoern A. Zeeb #ifdef DEV_ENC 6816ff8af1cSGleb Smirnoff if_inc_counter(encif, IFCOUNTER_OPACKETS, 1); 6826ff8af1cSGleb Smirnoff if_inc_counter(encif, IFCOUNTER_OBYTES, m->m_pkthdr.len); 68397c2a697SVANHULLEBUS Yvan 68419ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for bpf processing */ 68519ad9831SBjoern A. Zeeb ipsec_bpf(m, isr->sav, AF_INET6, ENC_OUT|ENC_BEFORE); 68619ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for packet filtering */ 68719ad9831SBjoern A. Zeeb if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_BEFORE)) != 0) 68819ad9831SBjoern A. Zeeb goto bad; 689aaf2cfc0SVANHULLEBUS Yvan #endif /* DEV_ENC */ 69019ad9831SBjoern A. Zeeb 691aaf2cfc0SVANHULLEBUS Yvan /* Do the appropriate encapsulation, if necessary */ 692aaf2cfc0SVANHULLEBUS Yvan if (isr->saidx.mode == IPSEC_MODE_TUNNEL || /* Tunnel requ'd */ 693aaf2cfc0SVANHULLEBUS Yvan dst->sa.sa_family != AF_INET6 || /* PF mismatch */ 694aaf2cfc0SVANHULLEBUS Yvan ((dst->sa.sa_family == AF_INET6) && 695aaf2cfc0SVANHULLEBUS Yvan (!IN6_IS_ADDR_UNSPECIFIED(&dst->sin6.sin6_addr)) && 696aaf2cfc0SVANHULLEBUS Yvan (!in6_sa_equal_addrwithscope(&dst->sin6, 697aaf2cfc0SVANHULLEBUS Yvan &ip6->ip6_dst)))) { 698aaf2cfc0SVANHULLEBUS Yvan if (m->m_pkthdr.len - sizeof(*ip6) > IPV6_MAXPACKET) { 699aaf2cfc0SVANHULLEBUS Yvan /* No jumbogram support. */ 700aaf2cfc0SVANHULLEBUS Yvan error = ENXIO; /*XXX*/ 70188768458SSam Leffler goto bad; 70288768458SSam Leffler } 70361f37615SAndrey V. Elsukov error = ipsec_encap(&m, &sav->sah->saidx); 70461f37615SAndrey V. Elsukov if (error != 0) { 70561f37615SAndrey V. Elsukov DPRINTF(("%s: encapsulation for SA %s->%s " 70661f37615SAndrey V. Elsukov "SPI 0x%08x failed with error %d\n", __func__, 70761f37615SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.src), 70861f37615SAndrey V. Elsukov ipsec_address(&sav->sah->saidx.dst), 70961f37615SAndrey V. Elsukov ntohl(sav->spi), error)); 710aaf2cfc0SVANHULLEBUS Yvan goto bad; 711aaf2cfc0SVANHULLEBUS Yvan } 71288768458SSam Leffler } 71388768458SSam Leffler 71419ad9831SBjoern A. Zeeb #ifdef DEV_ENC 715aaf2cfc0SVANHULLEBUS Yvan ipsec_bpf(m, isr->sav, dst->sa.sa_family, ENC_OUT|ENC_AFTER); 71619ad9831SBjoern A. Zeeb /* pass the mbuf to enc0 for packet filtering */ 71719ad9831SBjoern A. Zeeb if ((error = ipsec_filter(&m, PFIL_OUT, ENC_OUT|ENC_AFTER)) != 0) 71819ad9831SBjoern A. Zeeb goto bad; 719aaf2cfc0SVANHULLEBUS Yvan #endif /* DEV_ENC */ 72019ad9831SBjoern A. Zeeb 721aaf2cfc0SVANHULLEBUS Yvan switch(dst->sa.sa_family) { 722aaf2cfc0SVANHULLEBUS Yvan #ifdef INET 723aaf2cfc0SVANHULLEBUS Yvan case AF_INET: 724aaf2cfc0SVANHULLEBUS Yvan { 725aaf2cfc0SVANHULLEBUS Yvan struct ip *ip; 726aaf2cfc0SVANHULLEBUS Yvan ip = mtod(m, struct ip *); 727aaf2cfc0SVANHULLEBUS Yvan i = ip->ip_hl << 2; 728aaf2cfc0SVANHULLEBUS Yvan off = offsetof(struct ip, ip_p); 729aaf2cfc0SVANHULLEBUS Yvan } 730aaf2cfc0SVANHULLEBUS Yvan break; 731aaf2cfc0SVANHULLEBUS Yvan #endif /* AF_INET */ 732aaf2cfc0SVANHULLEBUS Yvan case AF_INET6: 733aaf2cfc0SVANHULLEBUS Yvan i = sizeof(struct ip6_hdr); 734aaf2cfc0SVANHULLEBUS Yvan off = offsetof(struct ip6_hdr, ip6_nxt); 735aaf2cfc0SVANHULLEBUS Yvan break; 736aaf2cfc0SVANHULLEBUS Yvan default: 737aaf2cfc0SVANHULLEBUS Yvan DPRINTF(("%s: unsupported protocol family %u\n", 738aaf2cfc0SVANHULLEBUS Yvan __func__, dst->sa.sa_family)); 739aaf2cfc0SVANHULLEBUS Yvan error = EPFNOSUPPORT; 740aaf2cfc0SVANHULLEBUS Yvan IPSEC6STAT_INC(ips_out_inval); 741aaf2cfc0SVANHULLEBUS Yvan goto bad; 742aaf2cfc0SVANHULLEBUS Yvan } 743aaf2cfc0SVANHULLEBUS Yvan error = (*sav->tdb_xform->xf_output)(m, isr, NULL, i, off); 744923e1044SBjoern A. Zeeb IPSECREQUEST_UNLOCK(isr); 745923e1044SBjoern A. Zeeb return error; 74688768458SSam Leffler bad: 747aaf2cfc0SVANHULLEBUS Yvan 748923e1044SBjoern A. Zeeb if (isr) 749923e1044SBjoern A. Zeeb IPSECREQUEST_UNLOCK(isr); 75088768458SSam Leffler if (m) 75188768458SSam Leffler m_freem(m); 75288768458SSam Leffler return error; 75388768458SSam Leffler } 75488768458SSam Leffler #endif /*INET6*/ 755