This introduces support for variable-length checksum in 
DCCP, as it is specified in section 9 of RFC 4340. 

Previously tcpdump was only able to validate full-coverage
checksums, this patch verifies checksums in accordance with
the CsCov header field (sec. 5.3). 

The patch has been tested and verified on DCCPv4 and DCCPv6
connections, checksums were manually validated, and traces
can be supplied.  



In addition, the patch also
        * removes reduplicated code in dccp6_cksum (which 
          just repeated the code of in_cksum)
        * fixes a bug in dccp.h -- the fields of CCVAL and
          CSCOV were swapped (cf. section 5.1 of RFC 4340)
        * fixes a typo in the display of incorrect checksums
          (these were printed as `cksum xDEAD (incorrect (->  xBEEF)',
           it now will print  `cksum xDEAD (incorrect -> xBEEF)'

I would like to see this merged as a Linux kernel patch already
exists for DCCP partial checksum coverage support.

Regards
Gerrit Renker


 dccp.h       |    4 ++--
 print-dccp.c |   34 ++++++++++++++++------------------
 2 files changed, 18 insertions(+), 20 deletions(-)
diff --git a/dccp.h b/dccp.h
index 1afa8c0..8585060 100644
--- a/dccp.h
+++ b/dccp.h
@@ -36,8 +36,8 @@ struct dccp_hdr {
 	}		dccph_xtrs;
 };
 
-#define DCCPH_CCVAL(dh)	(((dh)->dccph_ccval_cscov) & 0x0F)
-#define DCCPH_CSCOV(dh)	(((dh)->dccph_ccval_cscov >> 4) & 0x0F)
+#define DCCPH_CCVAL(dh)	(((dh)->dccph_ccval_cscov >> 4) & 0xF)
+#define DCCPH_CSCOV(dh)	(((dh)->dccph_ccval_cscov) & 0xF)
 
 #define DCCPH_X(dh)	((dh)->dccph_xtrs.dccph_xtr & 1)
 #define DCCPH_TYPE(dh)	(((dh)->dccph_xtrs.dccph_xtr >> 1) & 0xF)
diff --git a/print-dccp.c b/print-dccp.c
index e6bfca6..d19c500 100644
--- a/print-dccp.c
+++ b/print-dccp.c
@@ -60,9 +60,20 @@ static const char *dccp_feature_nums[] =
 	"check data checksum",
 };
 
+static inline int dccp_csum_coverage(const struct dccp_hdr* dh, u_int len)
+{
+	int cov;
+	
+	if (DCCPH_CSCOV(dh) == 0)
+		return len;
+	cov = (dh->dccph_doff + DCCPH_CSCOV(dh) - 1) * sizeof(u_int32_t);
+	return (cov > len)? len : cov;
+}
+
 static int dccp_cksum(const struct ip *ip,
 	const struct dccp_hdr *dh, u_int len)
 {
+	int cov = dccp_csum_coverage(dh, len);
 	union phu {
 		struct phdr {
 			u_int32_t src;
@@ -86,15 +97,15 @@ static int dccp_cksum(const struct ip *i
 		phu.ph.dst = ip_finddst(ip);
 
 	sp = &phu.pa[0];
-	return in_cksum((u_short *)dh, len, sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]);
+	return in_cksum((u_short *)dh, cov, sp[0]+sp[1]+sp[2]+sp[3]+sp[4]+sp[5]);
 }
 
 #ifdef INET6
 static int dccp6_cksum(const struct ip6_hdr *ip6, const struct dccp_hdr *dh, u_int len)
 {
 	size_t i;
-	const u_int16_t *sp;
-	u_int32_t sum;
+	u_int32_t sum = 0;
+	int cov = dccp_csum_coverage(dh, len);
 	union {
 		struct {
 			struct in6_addr ph_src;
@@ -113,23 +124,10 @@ static int dccp6_cksum(const struct ip6_
 	phu.ph.ph_len = htonl(len);
 	phu.ph.ph_nxt = IPPROTO_DCCP;
 
-	sum = 0;
 	for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++)
 		sum += phu.pa[i];
 
-	sp = (const u_int16_t *)dh;
-
-	for (i = 0; i < (len & ~1); i += 2)
-		sum += *sp++;
-
-	if (len & 1)
-		sum += htons((*(const u_int8_t *)sp) << 8);
-
-	while (sum > 0xffff)
-		sum = (sum & 0xffff) + (sum >> 16);
-	sum = ~sum & 0xffff;
-
-	return (sum);
+	return in_cksum((u_short *)dh, cov, sum);
 }
 #endif
 
@@ -288,7 +286,7 @@ #ifdef INET6
 			dccp_sum = EXTRACT_16BITS(&dh->dccph_checksum);		
 			printf("cksum 0x%04x", dccp_sum);		
 			if (sum != 0) {
-				(void)printf(" (incorrect (-> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum));
+				(void)printf(" (incorrect -> 0x%04x), ",in_cksum_shouldbe(dccp_sum, sum));
 			} else
 				(void)printf(" (correct), ");
 		}					
-
This is the tcpdump-workers list.
Visit https://cod.sandelman.ca/ to unsubscribe.

Reply via email to