From 4525ea16327a142113abdfaadd3133b8aa6c9ce2 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Wed, 9 Nov 2011 16:08:14 +0100 Subject: tune chksumming towards the simple packets we have MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- ldra.c | 55 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/ldra.c b/ldra.c index a6074d9..d588a02 100644 --- a/ldra.c +++ b/ldra.c @@ -119,27 +119,13 @@ int print_hex(const char *buf, size_t len) { } -/* creating an UDP checksum isn't all that magic. you can checksum - parts individually and add up the result and carry later, provided - that all parts except possibly the last one has an even number of - bytes. -*/ - -/* fixup carry and complement the sum, returning it in network byte order */ -u_int16_t complement(u_int32_t sum) { - /* carry adjustment */ - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); +/* calulate a possibly partial checksum from a stream of 16bit + numbers in network byte order. - /* return the complement sum in network byte order */ - return htons(~sum); -} - -/* calulate a possibly partial checksum - We consider buf a stream of 16bit numbers in network byte order. - Just sum them up, and leave the carry adjustment for later + Just sum them up, leaving the carry for later adjustments */ -u_int32_t chksum(u_int8_t *buf, size_t n) { +u_int32_t chksum(char *buf, size_t n) +{ u_int32_t sum = 0; int i; @@ -154,6 +140,28 @@ u_int32_t chksum(u_int8_t *buf, size_t n) { return sum; } +/* calculate IPv6 udp chksum, blindly assuming that there are no other headers in the packet */ +u_int16_t udp6chksum(struct ip6_hdr *ip6) +{ + int len = ntohs(ip6->ip6_plen); + struct udphdr *udp = (struct udphdr *)((char *)ip6 + sizeof(struct ip6_hdr)); + u_int32_t sum = chksum((char *)udp, len); /* udp header + packet data */ + + /* add the pseudo header: src + dst + nxtheader + length */ + sum += chksum((char *)&ip6->ip6_src, 2 * sizeof(ip6->ip6_src)); + sum += IPPROTO_UDP + len; + + /* subtract the old checksum instead of resetting it to 0 */ + sum -= ntohs(udp->check); + + /* adjust for carry */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + /* return the complement sum */ + return ~sum; +} + int main(int argc, char *argv[]) { int domain, s, i; @@ -558,13 +566,8 @@ Steven McCanne and Van Jacobson of Lawrence Berkeley Laboratory. udp->len = ip6->ip6_plen; udp->dest = htons(546); - /* calculate UDP checksum */ - udp->check = 0; /* reset before calculating new checksum */ - - udp->check = complement(chksum((u_int8_t *)udp, sizeof(struct udphdr) + datalen) + /* udp header + packet data */ - chksum((u_int8_t *)&ip6->ip6_src, 2 * sizeof(ip6->ip6_src)) + /* src + dst address */ - IPPROTO_UDP + (u_int32_t)ntohs(udp->len)); /* final part of pseudo header */ - + /* update UDP checksum */ + udp->check = htons(udp6chksum(ip6)); packetlen = sizeof(struct ethhdr) + VLANTAGZ + sizeof(struct ip6_hdr) + ntohs(udp->len); fprintf(stderr, "packetlen=%d bytes\n", packetlen); -- cgit v1.2.3