blob: 83f39bcea18beb914564c6e69ab8ec42f64908cd [file] [log] [blame]
/* 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;
}