diff options
author | fishsoupisgood <github@madingley.org> | 2019-04-29 01:17:54 +0100 |
---|---|---|
committer | fishsoupisgood <github@madingley.org> | 2019-05-27 03:43:43 +0100 |
commit | 3f2546b2ef55b661fd8dd69682b38992225e86f6 (patch) | |
tree | 65ca85f13617aee1dce474596800950f266a456c /roms/openbios/libopenbios/ipchecksum.c | |
download | qemu-master.tar.gz qemu-master.tar.bz2 qemu-master.zip |
Diffstat (limited to 'roms/openbios/libopenbios/ipchecksum.c')
-rw-r--r-- | roms/openbios/libopenbios/ipchecksum.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/roms/openbios/libopenbios/ipchecksum.c b/roms/openbios/libopenbios/ipchecksum.c new file mode 100644 index 00000000..83f39bce --- /dev/null +++ b/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; +} |