Bug 144529 - [sctp] sctp over ipv6 appears to not calculate checksum
Summary: [sctp] sctp over ipv6 appears to not calculate checksum
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 8.0-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-net (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-03-07 16:00 UTC by Nigel Rumens
Modified: 2010-07-05 01:43 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nigel Rumens 2010-03-07 16:00:02 UTC
testing feng (multimedia streaming server) between freebsd and linux to stream video over ipv6/sctp. Connection never gets to established state

initiator linux running mplayer 
responder freebsd running feng

I took a packet trace at the linux end with wireshark. It seems that the freebsd machine is sending the init_ack with a checksum of 0x00000000 

linux machine also reports sctp checksum errors in proportion to number of init_acks it recieves.

I am new to freebsd so feel free to tell me I'm an idiot if I've missed something or done something daft

Fix: 

Not sure if this is relavent or not but I had a quick look in the code for sctp_output.c and ip_output.c and ip6_output.c - and there appears to code which handles delayed checksum calculation based on a flag in ip_output.c but not in ip6_output.c

Workaround is use ipv4 - I tested over ipv4 without problems
How-To-Repeat: run feng on freebsd configured to use sctp over ipv6
run mplayer with -rtsp-stream-over-sctp option
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2010-03-08 07:17:10 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-net

Over to maintainer(s).
Comment 2 dfilter service freebsd_committer freebsd_triage 2010-03-12 08:10:42 UTC
Author: rrs
Date: Fri Mar 12 08:10:30 2010
New Revision: 205075
URL: http://svn.freebsd.org/changeset/base/205075

Log:
  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.
  
  PR:		144529
  MFC after:	2 weeks

Modified:
  head/sys/netinet6/ip6_output.c

Modified: head/sys/netinet6/ip6_output.c
==============================================================================
--- head/sys/netinet6/ip6_output.c	Fri Mar 12 07:49:10 2010	(r205074)
+++ head/sys/netinet6/ip6_output.c	Fri Mar 12 08:10:30 2010	(r205075)
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
 #include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
+#include "opt_sctp.h"
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -102,6 +103,10 @@ __FBSDID("$FreeBSD$");
 #include <netipsec/key.h>
 #include <netinet6/ip6_ipsec.h>
 #endif /* IPSEC */
+#ifdef SCTP
+#include <netinet/sctp.h>
+#include <netinet/sctp_crc32.h>
+#endif
 
 #include <netinet6/ip6protosw.h>
 #include <netinet6/scope6_var.h>
@@ -208,6 +213,9 @@ ip6_output(struct mbuf *m0, struct ip6_p
 	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);
+		sw_csum &= ~CSUM_SCTP;
+	}
+#endif
 	tlen = m->m_pkthdr.len;
 
 	if (opt && (opt->ip6po_flags & IP6PO_DONTFRAG))
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 3 dfilter service freebsd_committer freebsd_triage 2010-03-12 22:59:06 UTC
Author: rrs
Date: Fri Mar 12 22:58:52 2010
New Revision: 205104
URL: http://svn.freebsd.org/changeset/base/205104

Log:
  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
  MFC after:	2 weeks

Modified:
  head/sys/dev/xen/netback/netback.c
  head/sys/netinet/ip_divert.c
  head/sys/netinet/ip_ipsec.c
  head/sys/netinet/ip_output.c
  head/sys/netinet/sctp_crc32.c
  head/sys/netinet/sctp_crc32.h
  head/sys/netinet6/ip6_output.c

Modified: head/sys/dev/xen/netback/netback.c
==============================================================================
--- head/sys/dev/xen/netback/netback.c	Fri Mar 12 22:39:35 2010	(r205103)
+++ head/sys/dev/xen/netback/netback.c	Fri Mar 12 22:58:52 2010	(r205104)
@@ -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 {

Modified: head/sys/netinet/ip_divert.c
==============================================================================
--- head/sys/netinet/ip_divert.c	Fri Mar 12 22:39:35 2010	(r205103)
+++ head/sys/netinet/ip_divert.c	Fri Mar 12 22:58:52 2010	(r205104)
@@ -227,7 +227,7 @@ divert_packet(struct mbuf *m, int incomi
 #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);
 	}

Modified: head/sys/netinet/ip_ipsec.c
==============================================================================
--- head/sys/netinet/ip_ipsec.c	Fri Mar 12 22:39:35 2010	(r205103)
+++ head/sys/netinet/ip_ipsec.c	Fri Mar 12 22:58:52 2010	(r205104)
@@ -342,7 +342,7 @@ ip_ipsec_output(struct mbuf **m, struct 
 		}
 #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

Modified: head/sys/netinet/ip_output.c
==============================================================================
--- head/sys/netinet/ip_output.c	Fri Mar 12 22:39:35 2010	(r205103)
+++ head/sys/netinet/ip_output.c	Fri Mar 12 22:58:52 2010	(r205104)
@@ -583,7 +583,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
@@ -725,7 +725,7 @@ ip_fragment(struct ip *ip, struct mbuf *
 #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

Modified: head/sys/netinet/sctp_crc32.c
==============================================================================
--- head/sys/netinet/sctp_crc32.c	Fri Mar 12 22:39:35 2010	(r205103)
+++ head/sys/netinet/sctp_crc32.c	Fri Mar 12 22:58:52 2010	(r205104)
@@ -127,14 +127,12 @@ sctp_calculate_cksum(struct mbuf *m, uin
 
 
 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);

Modified: head/sys/netinet/sctp_crc32.h
==============================================================================
--- head/sys/netinet/sctp_crc32.h	Fri Mar 12 22:39:35 2010	(r205103)
+++ head/sys/netinet/sctp_crc32.h	Fri Mar 12 22:58:52 2010	(r205104)
@@ -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 */
 

Modified: head/sys/netinet6/ip6_output.c
==============================================================================
--- head/sys/netinet6/ip6_output.c	Fri Mar 12 22:39:35 2010	(r205103)
+++ head/sys/netinet6/ip6_output.c	Fri Mar 12 22:58:52 2010	(r205104)
@@ -872,7 +872,7 @@ passout:
 #ifdef SCTP
 	sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist;
 	if (sw_csum & CSUM_SCTP) {
-		sctp_delayed_cksum(m);
+		sctp_delayed_cksum(m, sizeof(struct ip6_hdr));
 		sw_csum &= ~CSUM_SCTP;
 	}
 #endif
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 4 dfilter service freebsd_committer freebsd_triage 2010-04-05 14:48:32 UTC
Author: rrs
Date: Mon Apr  5 13:48:23 2010
New Revision: 206181
URL: http://svn.freebsd.org/changeset/base/206181

Log:
  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

Modified:
  stable/8/sys/dev/xen/netback/netback.c
  stable/8/sys/netinet/ip_divert.c
  stable/8/sys/netinet/ip_ipsec.c
  stable/8/sys/netinet/ip_output.c
  stable/8/sys/netinet/sctp_crc32.c
  stable/8/sys/netinet/sctp_crc32.h
  stable/8/sys/netinet6/ip6_output.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/dev/xen/netback/netback.c
==============================================================================
--- stable/8/sys/dev/xen/netback/netback.c	Mon Apr  5 13:33:54 2010	(r206180)
+++ stable/8/sys/dev/xen/netback/netback.c	Mon Apr  5 13:48:23 2010	(r206181)
@@ -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 {

Modified: stable/8/sys/netinet/ip_divert.c
==============================================================================
--- stable/8/sys/netinet/ip_divert.c	Mon Apr  5 13:33:54 2010	(r206180)
+++ stable/8/sys/netinet/ip_divert.c	Mon Apr  5 13:48:23 2010	(r206181)
@@ -234,7 +234,7 @@ divert_packet(struct mbuf *m, int incomi
 #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);
 	}

Modified: stable/8/sys/netinet/ip_ipsec.c
==============================================================================
--- stable/8/sys/netinet/ip_ipsec.c	Mon Apr  5 13:33:54 2010	(r206180)
+++ stable/8/sys/netinet/ip_ipsec.c	Mon Apr  5 13:48:23 2010	(r206181)
@@ -343,7 +343,7 @@ ip_ipsec_output(struct mbuf **m, struct 
 		}
 #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

Modified: stable/8/sys/netinet/ip_output.c
==============================================================================
--- stable/8/sys/netinet/ip_output.c	Mon Apr  5 13:33:54 2010	(r206180)
+++ stable/8/sys/netinet/ip_output.c	Mon Apr  5 13:48:23 2010	(r206181)
@@ -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 *
 #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

Modified: stable/8/sys/netinet/sctp_crc32.c
==============================================================================
--- stable/8/sys/netinet/sctp_crc32.c	Mon Apr  5 13:33:54 2010	(r206180)
+++ stable/8/sys/netinet/sctp_crc32.c	Mon Apr  5 13:48:23 2010	(r206181)
@@ -127,14 +127,12 @@ sctp_calculate_cksum(struct mbuf *m, uin
 
 
 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);

Modified: stable/8/sys/netinet/sctp_crc32.h
==============================================================================
--- stable/8/sys/netinet/sctp_crc32.h	Mon Apr  5 13:33:54 2010	(r206180)
+++ stable/8/sys/netinet/sctp_crc32.h	Mon Apr  5 13:48:23 2010	(r206181)
@@ -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 */
 

Modified: stable/8/sys/netinet6/ip6_output.c
==============================================================================
--- stable/8/sys/netinet6/ip6_output.c	Mon Apr  5 13:33:54 2010	(r206180)
+++ stable/8/sys/netinet6/ip6_output.c	Mon Apr  5 13:48:23 2010	(r206181)
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
 #include "opt_inet.h"
 #include "opt_inet6.h"
 #include "opt_ipsec.h"
+#include "opt_sctp.h"
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -102,6 +103,10 @@ __FBSDID("$FreeBSD$");
 #include <netipsec/key.h>
 #include <netinet6/ip6_ipsec.h>
 #endif /* IPSEC */
+#ifdef SCTP
+#include <netinet/sctp.h>
+#include <netinet/sctp_crc32.h>
+#endif
 
 #include <netinet6/ip6protosw.h>
 #include <netinet6/scope6_var.h>
@@ -208,6 +213,9 @@ ip6_output(struct mbuf *m0, struct ip6_p
 	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))
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
Comment 5 Bruce Cran freebsd_committer freebsd_triage 2010-07-05 01:43:05 UTC
State Changed
From-To: open->closed

Fixed in stable/8 and head.