tags:

views:

2678

answers:

1

Hi,

The UDP header struct defined at /usr/include/netinet/udp.h is as follows

struct udphdr
{
  u_int16_t source;
  u_int16_t dest;
  u_int16_t len;
  u_int16_t check;
};

What value is stored in the check field of the header? How to verify if the checksum is correct? I meant on what data is the checksum computed? (Is it just the udp header or udp header plus the payload that follows it?)

Thanks.

+8  A: 

The UDP checksum is performed over the entire payload, and the other fields in the header, and some fields from the IP header. A pseudo-header is constructed from the IP header in order to perform the calculation (which is done over this pseudo-header, the UDP header and the payload). The reason the pseudo-header is included is to catch packets that have been routed to the wrong IP address.

Basically, at the receiving end, all the 16-bit words of the headers plus data area are added together (wrapping at 16 bits) and the result is checked against 0xffff.

On the sending side, it's a little more complex. A one's complement sum is performed on all the 16-bit values then the one's complement (i.e., invert all bits) is taken of that value to populate the checksum field.

Unlike my earlier answer (which was wrong, and thanks to Jim Hunziker for setting me straight), the one's complement sum is not just the sum of all the one's complement values. It's a little more complex.

Basically, you have a running 16-bit accumulator starting at zero and you add every 16-bit value to that. Whenever one of those additions results in a carry, the value is wrapped around and you add one to the value again. This effectively takes the carry bit of the 16-bit addition and adds it to the value.


As an aside, and this is pure conjecture on my part but this could probably be efficiently done by use of the ADC (add with carry) instruction rather than ADD (surprisingly enough, add), or whatever equivalent instructions were available on your CPU at the time.

If there were no carry, ADC would just add the zero bit from the carry. In the days when this stuff was done (and yes, unfortunately, I am that old), memory was far more of a constraint than speed, not so much the case nowadays, so saving a few bytes in your code could well elevate you to the level of demi-god-emperor-of-the-universe :-)


Note that you never had to worry about carry the second time around (or a carry of two with the next ADC if you're using that method mentioned in the previous paragraph) since the two largest 16-bit values, when summed, produce (truncated from 0x1fffe) 0xfffe - adding one to that will never cause another carry.

Once the calculated one's complement sum is calculated, has its bits inverted and is inserted into the packet, that will cause the calculation at the receiving end to produce 0xffff, assuming no errors in transmission of course.

It's worth noting that the payload is always padded to ensure there's an integral number of 16-bit words. If it was padded, the length field tells you the actual length.

RFC768 is the specification which details this.

paxdiablo
Thanks for that. I was a bit confused about the Pseudo-Header part..but then the RFC cleared the air.
Deepak Konidena
"All the 16-bit words of the headers (where the UDP checksum is zero) are added and the one's complement (i.e., invert all bits) is what gets put into the checksum field." No, what the RFC says would lead to "All the one's complements (i.e., invert all bits) of the 16-bit words of the headers (where the UDP checksum is zero) are added and the one's complement of that is what gets put into the checksum field."Otherwise perfect answer +1.
Joren
Right you are, @Joren, adjusted, and thanks.
paxdiablo
This isn't right. "One's complement sum" doesn't mean take the one's complement of each word and add them together. It means that you add the words together, and when a carry bit is produced, you add 1 to the running sum. See http://mathforum.org/library/drmath/view/54379.html .
Jim Hunziker
Thanks, @Jim, a bit more research turns up that you're dead right. I was going to say that I was dead wrong but my ego stepped in at the last minute and disallowed it :-). If you think the updated answer is still wrong, please let me know. Cheers.
paxdiablo
Looks good now - upvoted.
Jim Hunziker