Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / libopenbios / ipchecksum.c
diff --git a/qemu/roms/openbios/libopenbios/ipchecksum.c b/qemu/roms/openbios/libopenbios/ipchecksum.c
new file mode 100644 (file)
index 0000000..83f39bc
--- /dev/null
@@ -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;
+}