Skip to contentSkip to conversation

: Fix invalid IP checksums on 64bit

PATCH In review Patrick McHardy 1 participant 2 messages Jan 6, 2005 – Jan 7, 2005 netfilter

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 : Fix invalid IP checksums on 64bit

IP checksums are calculated wrong on 64 bit because too large types are used. This patch fixes them and a couple of unrelated snprintf-sizeof-warnings in the same file. I still get invalid TCP checksums, but couldn't locate the problem yet.

ipv4/ipv4.c +6 -6
Index: core/ipv4/ipv4.c
===================================================================
@@ -565,7 +565,7 @@
 	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 }
 
-static inline unsigned short from32to16(unsigned long x)
+static inline unsigned short from32to16(unsigned int x)
 {
 	/* add up 16-bit and 16-bit for 16+c bit */
 	x = (x & 0xffff) + (x >> 16);
@@ -574,10 +574,10 @@
 	return x;
 }
 
-static unsigned long do_csum(const unsigned char * buff, int len)
+static unsigned int do_csum(const unsigned char * buff, int len)
 {
 	int odd, count;
-	unsigned long result = 0;
+	unsigned int result = 0;
 
 	if (len <= 0)
 		return 0;
@@ -819,7 +819,7 @@
 	switch (iph->protocol) {
 	case IPPROTO_ICMP:
 		icmph = (struct icmphdr *)(iph + 1);
-		ptr += sprintf(ptr, "%u %u ",
+		ptr += sprintf(ptr, "%Zu %u ",
 		       iplen - sizeof(struct icmphdr), iph->protocol);
 
 		if (len < sizeof(struct icmphdr)) {
@@ -855,7 +855,7 @@
 
 	case IPPROTO_UDP:
 		udph = (struct udphdr *)(iph + 1);
-		ptr += sprintf(ptr, "%u %u ",
+		ptr += sprintf(ptr, "%Zu %u ",
 		       iplen - sizeof(struct udphdr), iph->protocol);
 
 		if (len < sizeof(struct udphdr)) {
@@ -891,7 +891,7 @@
 		tcph = (struct tcphdr *)(iph + 1);
 		if (len < sizeof(struct tcphdr)) {
 			/* Assume no tcp options... */
-			ptr += sprintf(ptr, "%u %u ",
+			ptr += sprintf(ptr, "%Zu %u ",
 				       iplen - sizeof(*tcph), iph->protocol);
 
 			ptr += sprintf(ptr, "-TRUNCATED-");
#1 lore raw
Quoted 4 lines · Patrick McHardy

IP checksums are calculated wrong on 64 bit because too large types are used. This patch fixes them and a couple of unrelated snprintf-sizeof-warnings in the same file. I still get invalid TCP checksums, but couldn't locate the problem yet.

I found the real bug, my previous fix just hid it. This patch fixes all checksum problems, the calculated checksum are equal to the ones of a 32-bit binary.

ipv4/ipv4.c +4 -4
Index: core/ipv4/ipv4.c
===================================================================
@@ -600,7 +600,7 @@
 		if (count) {
 		        unsigned long carry = 0;
 			do {
-				unsigned long w = *(unsigned long *) buff;
+				unsigned int w = *(unsigned int *) buff;
 				count--;
 				buff += 4;
 				result += carry;
@@ -819,7 +819,7 @@
 	switch (iph->protocol) {
 	case IPPROTO_ICMP:
 		icmph = (struct icmphdr *)(iph + 1);
-		ptr += sprintf(ptr, "%u %u ",
+		ptr += sprintf(ptr, "%Zu %u ",
 		       iplen - sizeof(struct icmphdr), iph->protocol);
 
 		if (len < sizeof(struct icmphdr)) {
@@ -855,7 +855,7 @@
 
 	case IPPROTO_UDP:
 		udph = (struct udphdr *)(iph + 1);
-		ptr += sprintf(ptr, "%u %u ",
+		ptr += sprintf(ptr, "%Zu %u ",
 		       iplen - sizeof(struct udphdr), iph->protocol);
 
 		if (len < sizeof(struct udphdr)) {
@@ -891,7 +891,7 @@
 		tcph = (struct tcphdr *)(iph + 1);
 		if (len < sizeof(struct tcphdr)) {
 			/* Assume no tcp options... */
-			ptr += sprintf(ptr, "%u %u ",
+			ptr += sprintf(ptr, "%Zu %u ",
 				       iplen - sizeof(*tcph), iph->protocol);
 
 			ptr += sprintf(ptr, "-TRUNCATED-");