diff options
Diffstat (limited to 'qemu/roms/openbios/libopenbios/ipchecksum.c')
-rw-r--r-- | qemu/roms/openbios/libopenbios/ipchecksum.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/qemu/roms/openbios/libopenbios/ipchecksum.c b/qemu/roms/openbios/libopenbios/ipchecksum.c new file mode 100644 index 000000000..83f39bcea --- /dev/null +++ b/qemu/roms/openbios/libopenbios/ipchecksum.c @@ -0,0 +1,55 @@ +/* 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; +} |