From 80044c785cb040a2cf73779d23f9e1e81a00c6c3 Mon Sep 17 00:00:00 2001 From: Xavier Beaudouin Date: Tue, 16 Jan 2024 20:44:34 +0000 Subject: [PATCH] Add UDP encapsulation of ESP in IPv6 This patch provides UDP encapsulation of ESP packets over IPv6. Ports the IPv4 code to IPv6 and adds support for IPv6 in udpencap.c As required by the RFC and unlike in IPv4 encapsulation, UDP checksums are calculated. Co-authored-by: Aurelien Cazuc Sponsored-by: Stormshield Sponsored-by: Wiktel Sponsored-by: Klara, Inc. --- sys/conf/files | 2 +- sys/netinet/udp_usrreq.c | 68 +++++++++----- sys/netinet6/udp6_usrreq.c | 12 ++- sys/netipsec/ipsec_input.c | 9 ++ sys/netipsec/ipsec_mod.c | 2 + sys/netipsec/ipsec_output.c | 4 +- sys/netipsec/ipsec_support.h | 16 ++-- sys/netipsec/key.c | 130 ++++++++++++++++++++------- sys/netipsec/udpencap.c | 170 +++++++++++++++++++++++++++++------ 9 files changed, 322 insertions(+), 91 deletions(-) diff --git a/sys/conf/files b/sys/conf/files index 9f0b3cf3831a..c91b1f89f921 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -4429,7 +4429,7 @@ netipsec/keysock.c optional ipsec inet | ipsec inet6 | \ ipsec_support inet | ipsec_support inet6 netipsec/subr_ipsec.c optional ipsec inet | ipsec inet6 | \ ipsec_support inet | ipsec_support inet6 -netipsec/udpencap.c optional ipsec inet +netipsec/udpencap.c optional ipsec inet | ipsec inet6 netipsec/xform_ah.c optional ipsec inet | ipsec inet6 netipsec/xform_esp.c optional ipsec inet | ipsec inet6 netipsec/xform_ipcomp.c optional ipsec inet | ipsec inet6 diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index b68ec95a923a..24bc3403b0f7 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -267,7 +267,7 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off, } if (up->u_flags & UF_ESPINUDP) {/* IPSec UDP encaps. */ if (IPSEC_ENABLED(ipv4) && - UDPENCAP_INPUT(n, off, AF_INET) != 0) + UDPENCAP_INPUT(ipv4, n, off, AF_INET) != 0) return (0); /* Consumed. */ } #endif /* IPSEC */ @@ -893,19 +893,32 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt) case SOPT_SET: switch (sopt->sopt_name) { #if defined(IPSEC) || defined(IPSEC_SUPPORT) -#ifdef INET +#if defined(INET) || defined(INET6) case UDP_ENCAP: - if (!INP_CHECK_SOCKAF(so, AF_INET)) { - INP_WUNLOCK(inp); - return (EINVAL); +#ifdef INET + if (INP_SOCKAF(so) == AF_INET) { + if (!IPSEC_ENABLED(ipv4)) { + INP_WUNLOCK(inp); + return (ENOPROTOOPT); + } + error = UDPENCAP_PCBCTL(ipv4, inp, sopt); + break; } - if (!IPSEC_ENABLED(ipv4)) { - INP_WUNLOCK(inp); - return (ENOPROTOOPT); - } - error = UDPENCAP_PCBCTL(inp, sopt); - break; #endif /* INET */ +#ifdef INET6 + if (INP_SOCKAF(so) == AF_INET6) { + if (!IPSEC_ENABLED(ipv6)) { + INP_WUNLOCK(inp); + return (ENOPROTOOPT); + } + error = UDPENCAP_PCBCTL(ipv6, inp, sopt); + break; + } +#endif /* INET6 */ + INP_WUNLOCK(inp); + return (EINVAL); +#endif /* INET || INET6 */ + #endif /* IPSEC */ case UDPLITE_SEND_CSCOV: case UDPLITE_RECV_CSCOV: @@ -944,19 +957,32 @@ udp_ctloutput(struct socket *so, struct sockopt *sopt) case SOPT_GET: switch (sopt->sopt_name) { #if defined(IPSEC) || defined(IPSEC_SUPPORT) -#ifdef INET +#if defined(INET) || defined(INET6) case UDP_ENCAP: - if (!INP_CHECK_SOCKAF(so, AF_INET)) { - INP_WUNLOCK(inp); - return (EINVAL); +#ifdef INET + if (INP_SOCKAF(so) == AF_INET) { + if (!IPSEC_ENABLED(ipv4)) { + INP_WUNLOCK(inp); + return (ENOPROTOOPT); + } + error = UDPENCAP_PCBCTL(ipv4, inp, sopt); + break; } - if (!IPSEC_ENABLED(ipv4)) { - INP_WUNLOCK(inp); - return (ENOPROTOOPT); - } - error = UDPENCAP_PCBCTL(inp, sopt); - break; #endif /* INET */ +#ifdef INET6 + if (INP_SOCKAF(so) == AF_INET6) { + if (!IPSEC_ENABLED(ipv6)) { + INP_WUNLOCK(inp); + return (ENOPROTOOPT); + } + error = UDPENCAP_PCBCTL(ipv6, inp, sopt); + break; + } +#endif /* INET6 */ + INP_WUNLOCK(inp); + return (EINVAL); +#endif /* INET || INET6 */ + #endif /* IPSEC */ case UDPLITE_SEND_CSCOV: case UDPLITE_RECV_CSCOV: diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index bbd7ba9477d6..414be35b5bef 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -75,6 +75,7 @@ #include "opt_rss.h" #include +#include #include #include #include @@ -158,6 +159,9 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off, if (filtered) return (in_pcbrele_rlocked(inp)); } + + off += sizeof(struct udphdr); + #if defined(IPSEC) || defined(IPSEC_SUPPORT) /* Check AH/ESP integrity. */ if (IPSEC_ENABLED(ipv6)) { @@ -165,6 +169,12 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off, m_freem(n); return (0); } + + /* IPSec UDP encaps. */ + if ((up->u_flags & UF_ESPINUDP) != 0 && + UDPENCAP_INPUT(ipv6, n, off, AF_INET6) != 0) { + return (0); /* Consumed. */ + } } #endif /* IPSEC */ #ifdef MAC @@ -189,7 +199,7 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off, opts = tmp_opts; } } - m_adj(n, off + sizeof(struct udphdr)); + m_adj(n, off); so = inp->inp_socket; SOCKBUF_LOCK(&so->so_rcv); diff --git a/sys/netipsec/ipsec_input.c b/sys/netipsec/ipsec_input.c index 472216392949..1150f3f470d3 100644 --- a/sys/netipsec/ipsec_input.c +++ b/sys/netipsec/ipsec_input.c @@ -628,6 +628,15 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip, m_copydata(m, protoff, 1, &nxt8); prot = nxt8; + /* + * Check that we have NAT-T enabled and apply transport mode + * decapsulation NAT procedure (RFC3948). + * Do this before invoking into the PFIL. + */ + if (sav->natt != NULL && + (prot == IPPROTO_UDP || prot == IPPROTO_TCP)) + udp_ipsec_adjust_cksum(m, sav, prot, skip); + /* IPv6-in-IP encapsulation */ if (prot == IPPROTO_IPV6 && saidx->mode != IPSEC_MODE_TRANSPORT) { diff --git a/sys/netipsec/ipsec_mod.c b/sys/netipsec/ipsec_mod.c index c5976723b4d5..eea2898b5359 100644 --- a/sys/netipsec/ipsec_mod.c +++ b/sys/netipsec/ipsec_mod.c @@ -84,6 +84,8 @@ static const struct ipsec_methods ipv6_methods = { .check_policy = ipsec6_in_reject, .ctlinput = ipsec6_ctlinput, .hdrsize = ipsec_hdrsiz_inpcb, + .udp_input = udp_ipsec_input, + .udp_pcbctl = udp_ipsec_pcbctl, }; #ifndef KLD_MODULE static const struct ipsec_support ipv6_ipsec = { diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c index caf3c3f74433..707fe3421c97 100644 --- a/sys/netipsec/ipsec_output.c +++ b/sys/netipsec/ipsec_output.c @@ -935,7 +935,7 @@ ipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav, } key_freesp(&sp), sp = NULL; /* Release reference to SP */ -#ifdef INET +#if defined(INET) || defined(INET6) /* * Do UDP encapsulation if SA requires it. */ @@ -944,7 +944,7 @@ ipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav, if (error != 0) goto bad; } -#endif /* INET */ +#endif /* INET || INET6 */ /* * We're done with IPsec processing, transmit the packet using the * appropriate network protocol (IP or IPv6). diff --git a/sys/netipsec/ipsec_support.h b/sys/netipsec/ipsec_support.h index c437879e3a2c..905b2b6cd764 100644 --- a/sys/netipsec/ipsec_support.h +++ b/sys/netipsec/ipsec_support.h @@ -164,10 +164,10 @@ extern const struct ipsec_support * const ipv6_ipsec_support; #define IPSEC_CTLINPUT(proto, param) \ (*(proto ## _ipsec_support)->methods->ctlinput)(param) -#define UDPENCAP_INPUT(m, ...) \ - (*ipv4_ipsec_support->methods->udp_input)(m, __VA_ARGS__) -#define UDPENCAP_PCBCTL(inp, sopt) \ - (*ipv4_ipsec_support->methods->udp_pcbctl)(inp, sopt) +#define UDPENCAP_INPUT(proto, m, ...) \ + (*(proto ## _ipsec_support)->methods->udp_input)(m, __VA_ARGS__) +#define UDPENCAP_PCBCTL(proto, inp, sopt) \ + (*(proto ## _ipsec_support)->methods->udp_pcbctl)(inp, sopt) #elif defined(IPSEC_SUPPORT) struct ipsec_support { @@ -196,10 +196,10 @@ int ipsec_kmod_udp_input(struct ipsec_support * const, struct mbuf *, int, int); int ipsec_kmod_udp_pcbctl(struct ipsec_support * const, struct inpcb *, struct sockopt *); -#define UDPENCAP_INPUT(m, ...) \ - ipsec_kmod_udp_input(ipv4_ipsec_support, m, __VA_ARGS__) -#define UDPENCAP_PCBCTL(inp, sopt) \ - ipsec_kmod_udp_pcbctl(ipv4_ipsec_support, inp, sopt) +#define UDPENCAP_INPUT(proto, m, ...) \ + ipsec_kmod_udp_input(proto ## _ipsec_support, m, __VA_ARGS__) +#define UDPENCAP_PCBCTL(proto, inp, sopt) \ + ipsec_kmod_udp_pcbctl(proto ## _ipsec_support, inp, sopt) #define IPSEC_INPUT(proto, ...) \ ipsec_kmod_input(proto ## _ipsec_support, __VA_ARGS__) diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c index 772602eeea90..a077f8007e47 100644 --- a/sys/netipsec/key.c +++ b/sys/netipsec/key.c @@ -5752,6 +5752,7 @@ key_setnatt(struct secasvar *sav, const struct sadb_msghdr *mhp) struct sockaddr *sa; uint32_t addr; uint16_t cksum; + int i; IPSEC_ASSERT(sav->natt == NULL, ("natt is already initialized")); /* @@ -5838,52 +5839,117 @@ key_setnatt(struct secasvar *sav, const struct sadb_msghdr *mhp) if (sav->sah->saidx.mode != IPSEC_MODE_TUNNEL) { cksum = 0; if (oai != NULL) { - /* Currently we support only AF_INET */ sa = (struct sockaddr *)(oai + 1); - if (sa->sa_family != AF_INET || - sa->sa_len != sizeof(struct sockaddr_in)) { + switch (sa->sa_family) { +#ifdef AF_INET + case AF_INET: + if (sa->sa_len != sizeof(struct sockaddr_in)) { + ipseclog((LOG_DEBUG, + "%s: wrong NAT-OAi header.\n", + __func__)); + return (EINVAL); + } + /* Ignore address if it the same */ + if (((struct sockaddr_in *)sa)->sin_addr.s_addr != + sav->sah->saidx.src.sin.sin_addr.s_addr) { + bcopy(sa, &sav->natt->oai.sa, sa->sa_len); + sav->natt->flags |= IPSEC_NATT_F_OAI; + /* Calculate checksum delta */ + addr = sav->sah->saidx.src.sin.sin_addr.s_addr; + cksum = in_addword(cksum, ~addr >> 16); + cksum = in_addword(cksum, ~addr & 0xffff); + addr = sav->natt->oai.sin.sin_addr.s_addr; + cksum = in_addword(cksum, addr >> 16); + cksum = in_addword(cksum, addr & 0xffff); + } + break; +#endif +#ifdef AF_INET6 + case AF_INET6: + if (sa->sa_len != sizeof(struct sockaddr_in6)) { + ipseclog((LOG_DEBUG, + "%s: wrong NAT-OAi header.\n", + __func__)); + return (EINVAL); + } + /* Ignore address if it the same */ + if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr, + &sav->sah->saidx.src.sin6.sin6_addr.s6_addr, + sizeof(struct in6_addr)) != 0) { + bcopy(sa, &sav->natt->oai.sa, sa->sa_len); + sav->natt->flags |= IPSEC_NATT_F_OAI; + /* Calculate checksum delta */ + for (i = 0; i < 8; i++) { + cksum = in_addword(cksum, + ~sav->sah->saidx.src.sin6.sin6_addr.s6_addr16[i]); + cksum = in_addword(cksum, + sav->natt->oai.sin6.sin6_addr.s6_addr16[i]); + } + } + break; +#endif + default: ipseclog((LOG_DEBUG, "%s: wrong NAT-OAi header.\n", __func__)); return (EINVAL); } - /* Ignore address if it the same */ - if (((struct sockaddr_in *)sa)->sin_addr.s_addr != - sav->sah->saidx.src.sin.sin_addr.s_addr) { - bcopy(sa, &sav->natt->oai.sa, sa->sa_len); - sav->natt->flags |= IPSEC_NATT_F_OAI; - /* Calculate checksum delta */ - addr = sav->sah->saidx.src.sin.sin_addr.s_addr; - cksum = in_addword(cksum, ~addr >> 16); - cksum = in_addword(cksum, ~addr & 0xffff); - addr = sav->natt->oai.sin.sin_addr.s_addr; - cksum = in_addword(cksum, addr >> 16); - cksum = in_addword(cksum, addr & 0xffff); - } } if (oar != NULL) { - /* Currently we support only AF_INET */ sa = (struct sockaddr *)(oar + 1); - if (sa->sa_family != AF_INET || - sa->sa_len != sizeof(struct sockaddr_in)) { + switch (sa->sa_family) { +#ifdef AF_INET + case AF_INET: + if (sa->sa_len != sizeof(struct sockaddr_in)) { + ipseclog((LOG_DEBUG, + "%s: wrong NAT-OAr header.\n", + __func__)); + return (EINVAL); + } + /* Ignore address if it the same */ + if (((struct sockaddr_in *)sa)->sin_addr.s_addr != + sav->sah->saidx.dst.sin.sin_addr.s_addr) { + bcopy(sa, &sav->natt->oar.sa, sa->sa_len); + sav->natt->flags |= IPSEC_NATT_F_OAR; + /* Calculate checksum delta */ + addr = sav->sah->saidx.dst.sin.sin_addr.s_addr; + cksum = in_addword(cksum, ~addr >> 16); + cksum = in_addword(cksum, ~addr & 0xffff); + addr = sav->natt->oar.sin.sin_addr.s_addr; + cksum = in_addword(cksum, addr >> 16); + cksum = in_addword(cksum, addr & 0xffff); + } + break; +#endif +#ifdef AF_INET6 + case AF_INET6: + if (sa->sa_len != sizeof(struct sockaddr_in6)) { + ipseclog((LOG_DEBUG, + "%s: wrong NAT-OAr header.\n", + __func__)); + return (EINVAL); + } + /* Ignore address if it the same */ + if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr, + &sav->sah->saidx.dst.sin6.sin6_addr.s6_addr, 16) != 0) { + bcopy(sa, &sav->natt->oar.sa, sa->sa_len); + sav->natt->flags |= IPSEC_NATT_F_OAR; + /* Calculate checksum delta */ + for (i = 0; i < 8; i++) { + cksum = in_addword(cksum, + ~sav->sah->saidx.dst.sin6.sin6_addr.s6_addr16[i]); + cksum = in_addword(cksum, + sav->natt->oar.sin6.sin6_addr.s6_addr16[i]); + } + } + break; +#endif + default: ipseclog((LOG_DEBUG, "%s: wrong NAT-OAr header.\n", __func__)); return (EINVAL); } - /* Ignore address if it the same */ - if (((struct sockaddr_in *)sa)->sin_addr.s_addr != - sav->sah->saidx.dst.sin.sin_addr.s_addr) { - bcopy(sa, &sav->natt->oar.sa, sa->sa_len); - sav->natt->flags |= IPSEC_NATT_F_OAR; - /* Calculate checksum delta */ - addr = sav->sah->saidx.dst.sin.sin_addr.s_addr; - cksum = in_addword(cksum, ~addr >> 16); - cksum = in_addword(cksum, ~addr & 0xffff); - addr = sav->natt->oar.sin.sin_addr.s_addr; - cksum = in_addword(cksum, addr >> 16); - cksum = in_addword(cksum, addr & 0xffff); - } } sav->natt->cksum = cksum; } diff --git a/sys/netipsec/udpencap.c b/sys/netipsec/udpencap.c index 118e0be317a0..960e7d3d1c9f 100644 --- a/sys/netipsec/udpencap.c +++ b/sys/netipsec/udpencap.c @@ -26,6 +26,7 @@ #include #include "opt_inet.h" +#include "opt_inet6.h" #include "opt_ipsec.h" #include @@ -42,11 +43,14 @@ #include #include #include +#include #include #include #include #include +#include + #include #include @@ -116,7 +120,6 @@ udp_ipsec_input(struct mbuf *m, int off, int af) union sockaddr_union dst; struct secasvar *sav; struct udphdr *udp; - struct ip *ip; uint32_t spi; int hlen; @@ -141,7 +144,9 @@ udp_ipsec_input(struct mbuf *m, int off, int af) dst.sa.sa_family = af; switch (af) { #ifdef INET - case AF_INET: + case AF_INET: { + struct ip *ip; + dst.sin.sin_len = sizeof(struct sockaddr_in); ip = mtod(m, struct ip *); ip->ip_p = IPPROTO_ESP; @@ -149,11 +154,20 @@ udp_ipsec_input(struct mbuf *m, int off, int af) hlen = ip->ip_hl << 2; dst.sin.sin_addr = ip->ip_dst; break; + } #endif #ifdef INET6 - case AF_INET6: - /* Not yet */ - /* FALLTHROUGH */ + case AF_INET6: { + struct ip6_hdr *ip6; + + dst.sin6.sin6_len = sizeof(struct sockaddr_in6); + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_nxt = IPPROTO_ESP; + off = offsetof(struct ip6_hdr, ip6_nxt); + hlen = sizeof(struct ip6_hdr); + dst.sin6.sin6_addr = ip6->ip6_dst; + break; + } #endif default: ESPSTAT_INC(esps_nopf); @@ -192,12 +206,30 @@ udp_ipsec_input(struct mbuf *m, int off, int af) * <-skip-> */ m_striphdr(m, hlen, sizeof(*udp)); + /* * We cannot yet update the cksums so clear any h/w cksum flags * as they are no longer valid. */ - if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) - m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID | CSUM_PSEUDO_HDR); + switch (af) { +#ifdef INET + case AF_INET: + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) + m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID | CSUM_PSEUDO_HDR); + break; +#endif /* INET */ +#ifdef INET6 + case AF_INET6: + if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID_IPV6) + m->m_pkthdr.csum_flags &= ~(CSUM_DATA_VALID_IPV6 | CSUM_PSEUDO_HDR); + break; +#endif /* INET6 */ + default: + ESPSTAT_INC(esps_nopf); + m_freem(m); + return (EPFNOSUPPORT); + } + /* * We can update ip_len and ip_sum here, but ipsec4_input_cb() * will do this anyway, so don't touch them here. @@ -212,16 +244,31 @@ udp_ipsec_output(struct mbuf *m, struct secasvar *sav) { struct udphdr *udp; struct mbuf *n; - struct ip *ip; int hlen, off; IPSEC_ASSERT(sav->natt != NULL, ("UDP encapsulation isn't required.")); - if (sav->sah->saidx.dst.sa.sa_family == AF_INET6) + switch (sav->sah->saidx.dst.sa.sa_family) { +#ifdef INET + case AF_INET: { + struct ip *ip; + ip = mtod(m, struct ip *); + hlen = ip->ip_hl << 2; + break; + } +#endif +#ifdef INET6 + case AF_INET6: + KASSERT(ip6->ip6_nxt == IPPROTO_ESP, + ("unexpected next header type %d", ip->ip6_nxt)); + hlen = sizeof(struct ip6_hdr); + break; +#endif + default: + ESPSTAT_INC(esps_nopf); return (EAFNOSUPPORT); + } - ip = mtod(m, struct ip *); - hlen = ip->ip_hl << 2; n = m_makespace(m, hlen, sizeof(*udp), &off); if (n == NULL) { DPRINTF(("%s: m_makespace for udphdr failed\n", __func__)); @@ -234,9 +281,36 @@ udp_ipsec_output(struct mbuf *m, struct secasvar *sav) udp->uh_sum = 0; udp->uh_ulen = htons(m->m_pkthdr.len - hlen); - ip = mtod(m, struct ip *); - ip->ip_len = htons(m->m_pkthdr.len); - ip->ip_p = IPPROTO_UDP; + switch (sav->sah->saidx.dst.sa.sa_family) { +#ifdef INET + case AF_INET: { + struct ip *ip; + + ip = mtod(m, struct ip *); + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_p = IPPROTO_UDP; + break; + } +#endif +#ifdef INET6 + case AF_INET6: { + struct ip6_hdr *ip6; + + ip6 = mtod(m, struct ip6_hdr *); + ip6->ip6_plen = htons(m->m_pkthdr.len); + ip6->ip6_nxt = IPPROTO_UDP; + udp->uh_sum = in6_cksum_pseudo(ip6, + m->m_pkthdr.len - hlen, ip6->ip6_nxt, 0); + m->m_pkthdr.csum_flags = CSUM_UDP_IPV6; + m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum); + break; + } +#endif + default: + ESPSTAT_INC(esps_nopf); + return (EAFNOSUPPORT); + } + return (0); } @@ -244,7 +318,6 @@ void udp_ipsec_adjust_cksum(struct mbuf *m, struct secasvar *sav, int proto, int skip) { - struct ip *ip; uint16_t cksum, off; IPSEC_ASSERT(sav->natt != NULL, ("NAT-T isn't required")); @@ -270,22 +343,67 @@ udp_ipsec_adjust_cksum(struct mbuf *m, struct secasvar *sav, int proto, if (proto == IPPROTO_TCP) { /* Ignore for TCP. */ m->m_pkthdr.csum_data = 0xffff; - m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID | - CSUM_PSEUDO_HDR); + switch (sav->sah->saidx.dst.sa.sa_family) { +#ifdef INET + case AF_INET: + m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID | + CSUM_PSEUDO_HDR); + break; +#endif +#ifdef INET6 + case AF_INET6: + m->m_pkthdr.csum_flags |= (CSUM_DATA_VALID_IPV6 | + CSUM_PSEUDO_HDR); + break; +#endif + default: + break; + } return; } cksum = 0; /* Reset for UDP. */ } m_copyback(m, skip + off, sizeof(cksum), (caddr_t)&cksum); } else { /* Fully recompute */ - ip = mtod(m, struct ip *); - cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, - htons(m->m_pkthdr.len - skip + proto)); - m_copyback(m, skip + off, sizeof(cksum), (caddr_t)&cksum); - m->m_pkthdr.csum_flags = - (proto == IPPROTO_UDP) ? CSUM_UDP: CSUM_TCP; - m->m_pkthdr.csum_data = off; - in_delayed_cksum(m); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + switch (sav->sah->saidx.dst.sa.sa_family) { +#ifdef INET + case AF_INET: { + struct ip *ip; + + ip = mtod(m, struct ip *); + cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htons(m->m_pkthdr.len - skip + proto)); + m_copyback(m, skip + off, sizeof(cksum), + (caddr_t)&cksum); + m->m_pkthdr.csum_flags = + (proto == IPPROTO_UDP) ? CSUM_UDP : CSUM_TCP; + m->m_pkthdr.csum_data = off; + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + break; + } +#endif +#ifdef INET6 + case AF_INET6: { + struct ip6_hdr *ip6; + + ip6 = mtod(m, struct ip6_hdr *); + cksum = in6_cksum_pseudo(ip6, m->m_pkthdr.len - skip, + proto, 0); + m_copyback(m, skip + off, sizeof(cksum), + (caddr_t)&cksum); + m->m_pkthdr.csum_flags = + (proto == IPPROTO_UDP) ? CSUM_UDP_IPV6 : CSUM_TCP_IPV6; + m->m_pkthdr.csum_data = off; + in6_delayed_cksum(m, + m->m_pkthdr.len - sizeof(struct ip6_hdr), + sizeof(struct ip6_hdr)); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; + break; + } +#endif + default: + break; + } } }