Newsgroups: comp.protocols.tcp-ip Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!think.com!mintaka!mintaka.lcs.mit.edu!sra From: sra@lcs.mit.edu (Rob Austein) Subject: Re: TCP checksums In-Reply-To: zweig@parc.xerox.com's message of 30 May 91 20:10:04 GMT Message-ID: <1991Jun2.204825.14065@mintaka.lcs.mit.edu> Sender: news@mintaka.lcs.mit.edu Organization: ITS Lamentation Society References: <3270025@hpctdlb.HP.COM> <1991May28.221045.27724@Think.COM> Date: Sun, 2 Jun 91 20:48:25 GMT Lines: 57 One algorithm for computing the ones-complement checksum on a twos-complement machine works by explictly computing a sum modulo 0xFFFF. The actual summation can be done in a larger word, and the properties of the ones-complement sum can be preserved by occasionally subtracting some large multiple of 0xFFFF. The final step of this algorithm returns the ones-complement of the quantity (sum mod 0xFFFF). Thus, this algorithm will always return 0xFFFF instead of 0x0000. So, at least in this case, making 0x0000 the excluded value makes sense. On certain machines (eg, the PDP-10, where normal fixed-point arithmetic operates on 36-bit words) this is by far the easiest way to compute the checksum, because the loop can sum 32-bit quantities instead of 16-bit quantities without changing the result. For those interested in the nitty-gritty, here's the UDP checksum code from the CHIVES domain resolver. The macro L32INT() obtains a 32-bit integer from a 36-bit word; this involves some bit-shifting, but you can think of it as a simple array reference. ZERO_MOD_0xFFFF is the largest multiple of 0xFFFF which can be represented as a positive 36-bit twos-complement quantity. The basic algorithm is from the checksum routine in the ITS monitor. int udp_chksum(pkt) char *pkt; { int n, sum, *u; struct ip_header *ip_h; struct udp_header *udp_h; /* Initialize pointers, compute data length */ ip_h = IP_HEADER(pkt); u = (int *) (udp_h = UDP_HEADER(pkt)); n = ip_h->len - (ip_h->ihl * 4); /* * Initial sum is pseudo-header: * IP source and destination addresses * IP protocol number * UDP data length (which gets added again part of UDP header!) * plus whatever bytes are in the last word of the packet buffer. */ sum = ip_h->sh + ip_h->dh + ip_h->pro + udp_h->ln + (L32INT(u[n/4]) & (~0 << (8 * (4 - (n % 4))))); /* Sum everything else, folding when necessary. */ n /= 4; while(--n >= 0) if((sum += L32INT(*u++)) < 0) /* Carried into the sign bit? */ sum -= ZERO_MOD_0xFFFF; /* Yeah, fix that */ /* Final folding, return complement. */ return((sum % 0xFFFF) ^ 0xFFFF); } --Rob Austein