[comp.protocols.tcp-ip] IP Header Checksum Calculation

brian@amc-gw.amc.com (Brian Crowley) (01/30/91)

I wonder if someone can't give me some pointers on what I feel should
be a simple operation, but one that I just can't seem to get a handle on.

I am building an IP packet for transmission over an Ethernet Network.
No problem building the packet, big problems getting the IP header
checksum to come out correctly!

According to the RFC in front of me, the IP header checksum is
calculated by treating the IP header as a sequence of 16-bit values,
which are added together using one's complement arithmetic, and then
the one's complement of the result is used as the checksum.

To test my algorithm, I pulled some IP packets off our local network and 
ran the IP headers through.  Alas, the results of my program do not 
match the checksums stored in the packets!

Would some kind soul please send me their algorithm to accomplish this
feat?  A "C" code fragment, a written algorithm, any help you can give
would be appreciated.

---------------------------------------------------------------------------
|Brian Crowley              |          DNS: brian@amc.com                 |
|Applied Microsystems Corp. |         UUCP: uunet!amc-gw!brian            |
|Redmond, WA                |          ATT: 206-882-2000  Ext. 328        |
---------------------------------------------------------------------------

zweig@cs.uiuc.edu (Johnny Zweig) (01/30/91)

Here is the C++ code from my working IP checksum calculation routine:

Word16
IPChecksum( octet * datagram, int length ) {
	// Add all the 16-bit words (in HOST byte-order!) inside a 32-bit word,
	//   so that the carries can all be added in at the end of the 
	//   calculation. Notice that, regardless of host byte order, if we 
	//   assign the sum to an int16, the byte with the lower address will 
	//   be the one with the high order bits (i.e. we never switched them, 
	//   even though the host might have regarded the high order 
	//   bits as low order when doing the sum -- the end-around carry
	//   takes care of everything!), so casting a pointer to an int16 
	//   as an octet * will cause the assignment to a Word16 to do the
	//   Right Thing. (See RFC 1071 for lots about checksum-computation.)

	int32	sum = 0;
	int16	tmp;
	Word16	num;
	int16 *	foo = (int16 *)datagram;

	// Add in a 32-bit int (won't overflow):
	while ( length > 1 ) {
		sum += *foo++;
		length -= 2;
	}

	// Add left-over byte, if any
	if ( length > 0 ) {
		int16 holder;	// Make it an int16 so alignment is right
		char * holderarray = (char*) & holder;
		holderarray[0] = *foo;
		holderarray[1] = 0x00;
		sum += holder;
			// To make sure there is a zero after that last byte!
	}

	// Fold 32-bit sum to 16 bits (while-loop since may have to add twice
	//   if the first addition causes overflow out of lo-order 16 bits)
	while ( sum >> 16 )
		sum = ( sum & 0x0000ffff ) + ( sum >> 16 );

	tmp = sum;
	tmp = ~tmp;

	num.equals((octet *) &tmp);
		// Here, then, we've basically casted from octet * to int16 *
		//   and back to octet *; it ends up with the right byte order
	return( num );
}

The class Word16 has operations equals(octet *) and val() which assign from a
network-byte-order value pointed to by the point, and return a host byte order
value from the word.  Octet is just unsigned char, int16 is probably unsigned
short int, etc.

-Johnny Checksum

kasten@EUROPA.INTERLAN.COM (Frank Kastenholz) (01/30/91)

Brian,
look at:

RFC 1071  Braden, R.T.; Borman, D.A.; Partridge, C.  Computing the Internet
          checksum.  1988 September; 24 p. (Format: TXT=54941 bytes)  (Updated by
          RFC 1141)
      
Frank Kastenholz
Racal Interlan

braden@VENERA.ISI.EDU (01/31/91)

I suggest you look at RFC-1071, republished in CCR April 89.

Bob Braden