From 54bb41671a18fdf3b5d0715ac1d986b397b2c43c Mon Sep 17 00:00:00 2001 From: Randall Stewart Date: Mon, 5 Apr 2010 13:48:23 +0000 Subject: [PATCH] MFC of 2 items to fix the csum for v6 issue: Revision 205075 and 205104: ---------205075---------- With the recent change of the sctp checksum to support offload, no delayed checksum was added to the ip6 output code. This causes cards that do not support SCTP checksum offload to have SCTP packets that are IPv6 NOT have the sctp checksum performed. Thus you could not communicate with a peer. This adds the missing bits to make the checksum happen for these cards. ------------------------- ---------205104---------- The proper fix for the delayed SCTP checksum is to have the delayed function take an argument as to the offset to the SCTP header. This allows it to work for V4 and V6. This of course means changing all callers of the function to either pass the header len, if they have it, or create it (ip_hl << 2 or sizeof(ip6_hdr)). ------------------------- PR: 144529 --- sys/dev/xen/netback/netback.c | 2 +- sys/netinet/ip_divert.c | 2 +- sys/netinet/ip_ipsec.c | 2 +- sys/netinet/ip_output.c | 4 ++-- sys/netinet/sctp_crc32.c | 4 +--- sys/netinet/sctp_crc32.h | 2 +- sys/netinet6/ip6_output.c | 19 +++++++++++++++++++ 7 files changed, 26 insertions(+), 9 deletions(-) diff --git a/sys/dev/xen/netback/netback.c b/sys/dev/xen/netback/netback.c index a6111e265f5..3088ecbdd12 100644 --- a/sys/dev/xen/netback/netback.c +++ b/sys/dev/xen/netback/netback.c @@ -302,7 +302,7 @@ fixup_checksum(struct mbuf *m) m->m_pkthdr.csum_flags &= ~CSUM_TCP; #ifdef SCTP } else if (sw_csum & CSUM_SCTP) { - sctp_delayed_cksum(m); + sctp_delayed_cksum(m, iphlen); sw_csum &= ~CSUM_SCTP; #endif } else { diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c index a2caef54a30..6c48b5b89d6 100644 --- a/sys/netinet/ip_divert.c +++ b/sys/netinet/ip_divert.c @@ -234,7 +234,7 @@ divert_packet(struct mbuf *m, int incoming) #ifdef SCTP if (m->m_pkthdr.csum_flags & CSUM_SCTP) { ip->ip_len = ntohs(ip->ip_len); - sctp_delayed_cksum(m); + sctp_delayed_cksum(m, (uint32_t)(ip->ip_hl << 2)); m->m_pkthdr.csum_flags &= ~CSUM_SCTP; ip->ip_len = htons(ip->ip_len); } diff --git a/sys/netinet/ip_ipsec.c b/sys/netinet/ip_ipsec.c index 0eb4673a038..65ec49eb5a4 100644 --- a/sys/netinet/ip_ipsec.c +++ b/sys/netinet/ip_ipsec.c @@ -343,7 +343,7 @@ ip_ipsec_output(struct mbuf **m, struct inpcb *inp, int *flags, int *error, } #ifdef SCTP if ((*m)->m_pkthdr.csum_flags & CSUM_SCTP) { - sctp_delayed_cksum(*m); + sctp_delayed_cksum(*m, (uint32_t)(ip->ip_hl << 2)); (*m)->m_pkthdr.csum_flags &= ~CSUM_SCTP; } #endif diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 00c3c3ceacf..a10976a06b6 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -589,7 +589,7 @@ passout: } #ifdef SCTP if (sw_csum & CSUM_SCTP) { - sctp_delayed_cksum(m); + sctp_delayed_cksum(m, (uint32_t)(ip->ip_hl << 2)); sw_csum &= ~CSUM_SCTP; } #endif @@ -731,7 +731,7 @@ ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu, #ifdef SCTP if (m0->m_pkthdr.csum_flags & CSUM_SCTP && (if_hwassist_flags & CSUM_IP_FRAGS) == 0) { - sctp_delayed_cksum(m0); + sctp_delayed_cksum(m0, hlen); m0->m_pkthdr.csum_flags &= ~CSUM_SCTP; } #endif diff --git a/sys/netinet/sctp_crc32.c b/sys/netinet/sctp_crc32.c index aeb97153855..d9ae238835f 100644 --- a/sys/netinet/sctp_crc32.c +++ b/sys/netinet/sctp_crc32.c @@ -127,14 +127,12 @@ sctp_calculate_cksum(struct mbuf *m, uint32_t offset) void -sctp_delayed_cksum(struct mbuf *m) +sctp_delayed_cksum(struct mbuf *m, uint32_t offset) { struct ip *ip; uint32_t checksum; - uint32_t offset; ip = mtod(m, struct ip *); - offset = ip->ip_hl << 2; checksum = sctp_calculate_cksum(m, offset); SCTP_STAT_DECR(sctps_sendhwcrc); SCTP_STAT_INCR(sctps_sendswcrc); diff --git a/sys/netinet/sctp_crc32.h b/sys/netinet/sctp_crc32.h index 44196b16abe..e66815ee517 100644 --- a/sys/netinet/sctp_crc32.h +++ b/sys/netinet/sctp_crc32.h @@ -39,7 +39,7 @@ __FBSDID("$FreeBSD$"); #if defined(_KERNEL) || defined(__Userspace__) uint32_t sctp_calculate_cksum(struct mbuf *, uint32_t); -void sctp_delayed_cksum(struct mbuf *); +void sctp_delayed_cksum(struct mbuf *, uint32_t offset); #endif /* _KERNEL */ diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index c2ec49aa350..a878aacf79f 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" +#include "opt_sctp.h" #include #include @@ -102,6 +103,10 @@ __FBSDID("$FreeBSD$"); #include #include #endif /* IPSEC */ +#ifdef SCTP +#include +#include +#endif #include #include @@ -208,6 +213,9 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, struct route_in6 *ro_pmtu = NULL; int hdrsplit = 0; int needipsec = 0; +#ifdef SCTP + int sw_csum; +#endif #ifdef IPSEC struct ipsec_output_state state; struct ip6_rthdr *rh = NULL; @@ -829,6 +837,10 @@ again: } m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED | CSUM_IP_VALID; +#ifdef SCTP + if (m->m_pkthdr.csum_flags & CSUM_SCTP) + m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; +#endif error = netisr_queue(NETISR_IPV6, m); goto done; } else @@ -857,6 +869,13 @@ passout: * 4: if dontfrag == 1 && alwaysfrag == 1 * error, as we cannot handle this conflicting request */ +#ifdef SCTP + sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist; + if (sw_csum & CSUM_SCTP) { + sctp_delayed_cksum(m, sizeof(struct ip6_hdr)); + sw_csum &= ~CSUM_SCTP; + } +#endif tlen = m->m_pkthdr.len; if (opt && (opt->ip6po_flags & IP6PO_DONTFRAG))