diff --git a/CHANGELOG b/CHANGELOG index de3d2980..c460a010 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,15 @@ FUTURE HISTORY + 2005-12-15 Christiaan Simons + * inet.c: Standard checksum routine fixed in proper portable C. + + 2005-12-14 Leon Woestenberg + * inet.c: Duplicate FIN ACK race condition fix by Kelvin Lawson. + Added Curt McDowell's optimized checksumming routine for future + inclusion. Need to create test case for unaliged, aligned, odd, + even length combination of cases on various endianess machines. + 2005-07-17 Leon Woestenberg * inet.c: Fixed unaligned 16-bit access in the standard checksum routine by Peter Jolasson. diff --git a/src/core/inet.c b/src/core/inet.c index b837a741..15ad6ac3 100644 --- a/src/core/inet.c +++ b/src/core/inet.c @@ -80,7 +80,7 @@ lwip_standard_chksum(void *dataptr, u16_t len) octetptr = (u8_t*)dataptr; while (len > 1) { - /* delacre first octet as most significant + /* declare first octet as most significant thus assume network order, ignoring host order */ src = (*octetptr) << 8; octetptr++; @@ -109,6 +109,133 @@ lwip_standard_chksum(void *dataptr, u16_t len) #endif +Curt McDowell +Broadcom Corp. +csm@broadcom.com + +/* + * IP checksum two bytes at a time with support for + * unaligned buffer. + * Works for len up to and including 0x20000. + * by Curt McDowell, Broadcom Corp. 12/08/2005 + */ + +static u16_t +lwip_standard_chksum2(void *dataptr, int len) +{ + u8_t *pb = dataptr; + u16_t *ps, t = 0; + u32_t sum = 0; + int odd = ((u32_t)pb & 1); + + /* Get aligned to u16_t */ + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + /* Add the bulk of the data */ + ps = (u16_t *)pb; + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* Consume left-over byte, if any */ + if (len > 0) + ((u8_t *)&t)[0] = *(u8_t *)ps;; + + /* Add end bytes */ + sum += t; + + /* Fold 32-bit sum to 16 bits */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + /* Swap if alignment was odd */ + if (odd) + sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8); + + return sum; +} + +#if 0 + +/** + * An optimized checksum routine. Basically, it uses loop-unrolling on + * the checksum loop, treating the head and tail bytes specially, whereas + * the inner loop acts on 8 bytes at a time. + * + * @arg start of buffer to be checksummed. May be an odd byte address. + * @len number of bytes in the buffer to be checksummed. + * + * @todo First argument type conflicts with generic checksum routine. + * + * by Curt McDowell, Broadcom Corp. December 8th, 2005 + */ + +static u16_t +lwip_standard_chksum4(u8_t *pb, int len) +{ + u16_t *ps, t = 0; + u32_t *pl; + u32_t sum = 0, tmp; + /* starts at odd byte address? */ + int odd = ((u32_t)pb & 1); + + if (odd && len > 0) { + ((u8_t *)&t)[1] = *pb++; + len--; + } + + ps = (u16_t *)pb; + + if (((u32_t)ps & 3) && len > 1) { + sum += *ps++; + len -= 2; + } + + pl = (u32_t *)ps; + + while (len > 7) { + tmp = sum + *pl++; /* ping */ + if (tmp < sum) + tmp++; /* add back carry */ + + sum = tmp + *pl++; /* pong */ + if (sum < tmp) + sum++; /* add back carry */ + + len -= 8; + } + + /* make room in upper bits */ + sum = (sum >> 16) + (sum & 0xffff); + + ps = (u16_t *)pl; + + /* 16-bit aligned word remaining? */ + while (len > 1) { + sum += *ps++; + len -= 2; + } + + /* dangling tail byte remaining? */ + if (len > 0) /* include odd byte */ + ((u8_t *)&t)[0] = *(u8_t *)ps; + + sum += t; /* add end bytes */ + + while (sum >> 16) /* combine halves */ + sum = (sum >> 16) + (sum & 0xffff); + + if (odd) + sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8); + + return sum; +} +#endif + /* inet_chksum_pseudo: * * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. diff --git a/src/include/ipv4/lwip/inet.h b/src/include/ipv4/lwip/inet.h index 0ae5f698..0d8169e0 100644 --- a/src/include/ipv4/lwip/inet.h +++ b/src/include/ipv4/lwip/inet.h @@ -39,6 +39,9 @@ #include "lwip/ip_addr.h" u16_t inet_chksum(void *dataptr, u16_t len); +#if 0 // optimized routine +u16_t inet_chksum4(u8_t *dataptr, u16_t len); +#endif u16_t inet_chksum_pbuf(struct pbuf *p); u16_t inet_chksum_pseudo(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,