56 lines
1.2 KiB
C
56 lines
1.2 KiB
C
|
/* Taken from Etherboot */
|
||
|
|
||
|
#include "libopenbios/ipchecksum.h"
|
||
|
|
||
|
unsigned short ipchksum(const void *data, unsigned long length)
|
||
|
{
|
||
|
unsigned long sum;
|
||
|
unsigned long i;
|
||
|
const unsigned char *ptr;
|
||
|
union {
|
||
|
unsigned char byte[2];
|
||
|
unsigned short word;
|
||
|
} u;
|
||
|
|
||
|
/* In the most straight forward way possible,
|
||
|
* compute an ip style checksum.
|
||
|
*/
|
||
|
sum = 0;
|
||
|
ptr = data;
|
||
|
for(i = 0; i < length; i++) {
|
||
|
unsigned long value;
|
||
|
value = ptr[i];
|
||
|
if (i & 1) {
|
||
|
value <<= 8;
|
||
|
}
|
||
|
/* Add the new value */
|
||
|
sum += value;
|
||
|
/* Wrap around the carry */
|
||
|
if (sum > 0xFFFF) {
|
||
|
sum = (sum + (sum >> 16)) & 0xFFFF;
|
||
|
}
|
||
|
}
|
||
|
u.byte[0] = (unsigned char) sum;
|
||
|
u.byte[1] = (unsigned char) (sum >> 8);
|
||
|
return (unsigned short) ~u.word;
|
||
|
}
|
||
|
|
||
|
unsigned short add_ipchksums(unsigned long offset, unsigned short sum, unsigned short new)
|
||
|
{
|
||
|
unsigned long checksum;
|
||
|
sum = ~sum & 0xFFFF;
|
||
|
new = ~new & 0xFFFF;
|
||
|
if (offset & 1) {
|
||
|
/* byte swap the sum if it came from an odd offset
|
||
|
* since the computation is endian independant this
|
||
|
* works.
|
||
|
*/
|
||
|
new = (new << 8) | (new >> 8);
|
||
|
}
|
||
|
checksum = sum + new;
|
||
|
if (checksum > 0xFFFF) {
|
||
|
checksum -= 0xFFFF;
|
||
|
}
|
||
|
return (~checksum) & 0xFFFF;
|
||
|
}
|