Module Name:    src
Committed By:   tsutsui
Date:           Sat Sep 18 16:43:51 UTC 2010

Modified Files:
        src/sys/arch/mips/mips: in_cksum.c

Log Message:
Fix wrong checksum calculations of 32 bit unaligned two byte payloads.
Analyzed in PR port-mips/43882, but applied slightly different patch.
Also put some changes for readability.

Note netbsd-5 doesn't use this MD version but netbsd-4 needs a pullup.
(though it's unclear if it's really faster even on modern aggressive gcc4)


To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/mips/mips/in_cksum.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/mips/mips/in_cksum.c
diff -u src/sys/arch/mips/mips/in_cksum.c:1.13 src/sys/arch/mips/mips/in_cksum.c:1.14
--- src/sys/arch/mips/mips/in_cksum.c:1.13	Wed Jan 24 13:08:11 2007
+++ src/sys/arch/mips/mips/in_cksum.c	Sat Sep 18 16:43:50 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: in_cksum.c,v 1.13 2007/01/24 13:08:11 hubertf Exp $ */
+/* $NetBSD: in_cksum.c,v 1.14 2010/09/18 16:43:50 tsutsui Exp $ */
 
 /*
  * Copyright (c) 1993 Regents of the University of California.
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in_cksum.c,v 1.13 2007/01/24 13:08:11 hubertf Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in_cksum.c,v 1.14 2010/09/18 16:43:50 tsutsui Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -56,11 +56,10 @@
 #include <machine/endian.h>
 
 union memptr {
-	unsigned int *i;
-	unsigned long *l;
-	unsigned long u;
-	unsigned short *s;
-	unsigned char *c;
+	uint32_t *l;
+	uintptr_t u;
+	uint16_t *s;
+	uint8_t *c;
 };
 
 static inline uint32_t fastsum(union memptr, int, unsigned int, int);
@@ -83,10 +82,6 @@
 
 	/* Align to 32 bits. */
 	if (buf.u & 0x3) {
-		/* Skip to the end for very small mbufs */
-		if (n < 3)
-			goto verylittleleft;
-
 		/*
 	         * 16-bit-align.
 		 * If buf is odd-byte-aligned, add the byte and toggle
@@ -107,6 +102,9 @@
 			n -= 1;
 			odd_aligned = !odd_aligned;
 		}
+		/* Skip to the end for very small mbufs */
+		if (n <= 2)
+			goto postunaligned;
 
 		/* 32-bit-align */
 		if (buf.u & 0x2) {
@@ -198,7 +196,7 @@
 
  notmuchleft:
 	high = hilo = 0;
-	while (n >= 4) {
+	while (n >= sizeof(uint32_t)) {
 		w0 = *(buf.l++);
 		hilo += w0;
 		high += w0 >> 16;
@@ -208,19 +206,21 @@
 	sum += hilo;
 	sum += high;
 
-	while (n > 1) {
-		n -= sizeof(*buf.s);
+ postunaligned:
+	/* handle post 32bit unaligned payloads */
+	if (n >= sizeof(uint16_t)) {
 		sum += *(buf.s++);
+		n -= sizeof(uint16_t);
 	}
 
- verylittleleft:
-	/* handle trailing byte and short (possibly) unaligned payloads */
-	while (n-- > 0) {
+	/* handle a trailing odd byte */
+	if (n > 0) {
 #if BYTE_ORDER == BIG_ENDIAN
 		sum += *(buf.c++) << 8;
 #else
 		sum += *(buf.c++);
 #endif
+		n = 0;
 	}
 
 	/*

Reply via email to