View previous topic :: View next topic |
Author |
Message |
stoyanoff
Joined: 20 Jul 2011 Posts: 375
|
I can't understand what`s happening in this code! Help! |
Posted: Tue Dec 20, 2011 3:51 am |
|
|
The function must calculate the checksum value of TCP package:
Code: |
WORD csum(void *dp, WORD count)
{
register LWORD total=0L;
register WORD n, *p, carries;
n = count / 2;
p = (WORD *)dp;
while (n--)
total += *p++;
if (count & 1)
total += *(BYTE *)p;
while ((carries=(WORD)(total>>16))!=0)
total = (total & 0xffffL) + carries;
return((WORD)total);
}
|
I can't understand how exactly it happens.
In theory I know how to calculate checksum. May be the style of the author is different then main or I just have less experience. I can`t understand what`s happening in rows like
Code: | total += *(BYTE *)p;
|
or
Code: | while ((carries=(WORD)(total>>16))!=0)
|
Can someone explain this function to me? I don't want to know how to calculate a checksum. I just want to know how it's done in this function.
Thanks a lot!!!! |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Dec 20, 2011 4:30 am |
|
|
Assumptions:
BYTE is unsigned 8 bit int
WORD is unsigned 16 bit int
LWORD is unsigned 32 bit int
Code: |
WORD csum(void *dp, WORD count)
{
register LWORD total=0L; // Initial result to zero
register WORD n, *p, carries; // declare 16 bit temporaries, including p: pointer to WORD.
n = count / 2; // n is count of ?WORDs, so is half count of probable BYTES... maybe.
p = (WORD *)dp; // p is copy of void* pointer cast to word *. Presumably the input data is in WORDs.
while (n--) // count down while n is not zero.
total += *p++; // Add WORD p is pointing to to total and increment p to point to the next WORD. Possible problem: Does C assume total is an operand for purposes of casting? If not then total cannot exceed 65535. Safer to explicitly cast as in total += (LWORD)*p++;
// At this stage we've added all the WORDs. Deal with any left over BYTE.
if (count & 1) // If count is odd... (note this is a bit wise and, NOT logical and: &&)
total += *(BYTE *)p; //...add byte p is pointing to to total. This treats the data 16 bit WORDS. Note there's no increment here. Not needed as its not part of the main loop above. {} would have helped to make that clearer.
while ((carries=(WORD)(total>>16))!=0) // Assign the upper word of the total to carries and while its not zero...
total = (total & 0xffffL) + carries; // ...add it into the lower WORD. This is so called end-around carrying. The while is needed in case adding the carries causes a second carry.
return((WORD)total); // return the lower WORD of the result. Which appears to be an end-around sum of 24 bit values preloaded with zero.
}
|
Does that help?
RF Developer |
|
|
stoyanoff
Joined: 20 Jul 2011 Posts: 375
|
|
Posted: Tue Dec 20, 2011 5:44 am |
|
|
Thanks a lot! I think I understood it. I though this is a function for calculating only TCP/IP packages checksum, but it`s universal. The TCP/IP has 8 bytes which must be add. The author of this code had add extra parameter(count) so the function could calculate checksum of any kind of packages. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Dec 20, 2011 6:02 am |
|
|
stoyanoff wrote: | Thanks a lot! I think I understood it. I though this is a function for calculating only TCP/IP packages checksum, but it`s universal. The TCP/IP has 8 bytes which must be add. The author of this code had add extra parameter(count) so the function could calculate checksum of any kind of packages. |
No, this definitely does a *16 bit* end-around checksum ONLY, in other words the TCP & IP protocols' one's compliment checksum. It doesn't do 8 bit two's complement or even 16 bit two compliment summation, or any other variant. They are all different again. There is no "universal" checksum, any more than there is a "universal" CRC which is even more complicated. The principle may be the same, but details, such as preload and end-around, result width all make the checksums different.
RF Developer |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Tue Dec 20, 2011 6:22 am |
|
|
Just a couple of comments to do to do with the addressing...:
Code: |
WORD csum(void *dp, WORD count)
{
register LWORD total=0L; // Initial result to zero
register WORD n, *p, carries; // declare 16 bit temporaries, including p: pointer to WORD.
n = count / 2; // n is count of bytes, so need half this if
//Using words
p = (WORD *)dp; // Just means _we_ are going to work with the
//pointer as if it is to words - hence the half count
while (n--) // count down while n is not zero.
total += *p++; // Add WORD p is pointing to to total and increment p to point to the next WORD. Possible problem: Does C assume total is an operand for purposes of casting? If not then total cannot exceed 65535. Safer to explicitly cast as in total += (LWORD)*p++;
// At this stage we've added all the WORDs. Deal with any left over BYTE.
if (count & 1) // If count is odd... (note this is a bit wise and, NOT logical and: &&)
total += *(BYTE *)p; //...add byte p is pointing to to total. This treats the data 16 bit WORDS. Note there's no increment here. Not needed as its not part of the main loop above. {} would have helped to make that clearer.
//Remember p has already been incremented to point to the next word
//(p++ in the loop) - increment _after_ use.
while ((carries=(WORD)(total>>16))!=0) // Assign the upper word of the total to carries and while its not zero...
total = (total & 0xffffL) + carries; // ...add it into the lower WORD. This is so called end-around carrying. The while is needed in case adding the carries causes a second carry.
return((WORD)total); // return the lower WORD of the result. Which appears to be an end-around sum of 24 bit values preloaded with zero.
}
//Um. Just the 16bit end around sum, not 24bit.
|
Best Wishes |
|
|
|