[comp.dcom.lans] Internet Protocol header checksum implementation problem

david@dcl-cs.UUCP (04/07/87)

I'm posting this on behalf of a project student so if anyone
has any thoughts on it, could they channel them through me. Thanks.
--

INTERNET HEADER CHECKSUM

I am having a no doubt trivial problem calculating the header checksum
within an internet packet and would be grateful if someone could enlighten
me as to my mistake.

To calculate the checksum I take each 16-bits within the header  
( starting with the version/IHL octet and ending with the octet immediately
preceding the data portion of the Internet packet).  To each of these
I take the 16-bit one's complement and add them all up giving an 
unsigned 16-bit value.  This is then one's complemented to give me 
the header checksum which is placed in the internet header checksum field
(as per the IP spec).

When calculating the checksum the checksum field is taken as containing zero.

I have applied this procedure to packets taken directly from the network,
the final checksum is nothing like what it should be, however, the value
before taking the final one's complement is sometimes 7 sometimes 8 lower
than what is in the checksum field of the packet read.

Any clues? Thanks.
-- 
janet:  david@uk.ac.lancs.comp           Department of Computing
arpa:   david@comp.lancs.ac.uk           University of Lancaster
uucp:   ...!mcvax!ukc!dcl-cs!david       Bailrigg, Lancaster, LA1 4YR, UK

hans@umd5.UUCP (04/08/87)

In article <328@dcl-csvax.comp.lancs.ac.uk> david@comp.lancs.ac.uk (David Coffield) writes:
>
>INTERNET HEADER CHECKSUM
>
>I am having a no doubt trivial problem calculating the header checksum
>within an internet packet and would be grateful if someone could enlighten
>me as to my mistake.
>
> ...
>
>
>I have applied this procedure to packets taken directly from the network,
>the final checksum is nothing like what it should be, however, the value
>before taking the final one's complement is sometimes 7 sometimes 8 lower
>than what is in the checksum field of the packet read.
>
>Any clues? Thanks.
>-- 


You are probably using twos complement addition instead of one's complement
addition when computing the sum.  The difference lies in what happens to the
carry when doing addition:  in two's complement it is ignored, in one's com-
plement it is added to the sum.  For example the sum of the 16-bit octal
numbers 07776 and 3 works as follows:
  Two's complement:  07776 is -2,  -2 plus 3 gives 1
         07776 + 00003 = 00001 plus carry (which gets ignored)
  One's complement:  07776 is -1,  -1 plus 3 gives 2
         07776 + 00003 = 00001 plus carry
                         00001 + carry = 00002
If you are working on a 32-bit machine, you can just add all the numbers,
and then add the two 16-bit fields of the result (plus any carry you get
from that addition).
  There is an additional problem with simulating one's complement in this
fashion:  If the result is zero, it will usually be minus zero (i.e. 07777)
and not plus zero.  One's complement hardware usually works by subtracting
the complement instead of adding, in which case you get minus zero results
only if you start out with a minus zero.  I don't know if you have to
worry about this special case in IP header checksums.

ron@brl-sem.ARPA (Ron Natalie <ron>) (04/09/87)

In article <328@dcl-csvax.comp.lancs.ac.uk>, david@comp.lancs.ac.uk (David Coffield) writes:
> 
> To calculate the checksum I take each 16-bits within the header  
> ( starting with the version/IHL octet and ending with the octet immediately
> preceding the data portion of the Internet packet).  To each of these
> I take the 16-bit one's complement and add them all up giving an 
> unsigned 16-bit value.  This is then one's complemented to give me 
> the header checksum which is placed in the internet header checksum field
> (as per the IP spec).

You read the spec wrong.  The checksum is the ones complement of the
ones complement sum of all the values.  The ones complement sum is not
the twos complement sum of all the numbers ones complemented.  When a
ones complement number reaches the value 0xFFFF (-0) it must be incremented
to 0 (+0) before adding another number to it.  In assembler this is easy
(if you don't already have ones complement instructions already), if the
carry bit it set after an addition, add one to the result.  A crude C
function would look like this....

(assuming, 16 bit shorts, and > 16 bit longs, I know, silly assumption,
 but I'm just doing this for illustration)

	unsigned short header[N];
	long  tmpsum;
	int   i;
	short   sum;

	for(i = 0, tmpsum = 0; i < N; i++)  {
		tmpsum += header[i];
		if(tmpsum & 0x10000L)
			tmpsum = (tmpsum & 0xFFFF) + 1;
	}
	sum = ~tmpsum;

-Ron

henry@utzoo.UUCP (Henry Spencer) (04/12/87)

> To calculate the checksum I take each 16-bits within the header  ...
> To each of these
> I take the 16-bit one's complement and add them all up giving an 
> unsigned 16-bit value.  This is then one's complemented to give me 
> the header checksum ... (as per the IP spec).

The problem is that you have misunderstooding the meaning of the term
"one's-complement addition".  This does not mean adding the complements
of the numbers.  One's-complement addition is addition done by treating
the 16-bit lumps as numbers in the obsolete one's-complement number
representation, rather than the two's-complement representation that
most modern computers use.  See any good book on digital systems design
for the details of what one's-complement representation is all about.
The simple way to fake one's-complement addition on a two's-complement
machine is to do a regular add and then add the carry to the result; on a
32-bit machine it's often better to do a 32-bit sum of all the 16-bit
values and then add the top 16 bits to the bottom 16 (repeating this
until the top 16 are zero).
-- 
"We must choose: the stars or	Henry Spencer @ U of Toronto Zoology
the dust.  Which shall it be?"	{allegra,ihnp4,decvax,pyramid}!utzoo!henry