blob: 0b8eb90f858cf2a2f475bc75c5014e3d86ffb089 [file] [log] [blame]
Eric Biederman8ca8d762003-04-22 19:02:15 +00001#include <stdint.h>
2#include <ip_checksum.h>
3
4unsigned long compute_ip_checksum(void *addr, unsigned long length)
5{
6 uint8_t *ptr;
7 volatile union {
8 uint8_t byte[2];
9 uint16_t word;
10 } value;
11 unsigned long sum;
12 unsigned long i;
13 /* In the most straight forward way possible,
14 * compute an ip style checksum.
15 */
16 sum = 0;
17 ptr = addr;
18 for(i = 0; i < length; i++) {
19 unsigned long value;
20 value = ptr[i];
21 if (i & 1) {
22 value <<= 8;
23 }
24 /* Add the new value */
25 sum += value;
26 /* Wrap around the carry */
27 if (sum > 0xFFFF) {
28 sum = (sum + (sum >> 16)) & 0xFFFF;
29 }
30 }
31 value.byte[0] = sum & 0xff;
32 value.byte[1] = (sum >> 8) & 0xff;
33 return (~value.word) & 0xFFFF;
34}
35
36unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long new)
37{
38 unsigned long checksum;
39 sum = ~sum & 0xFFFF;
40 new = ~new & 0xFFFF;
41 if (offset & 1) {
42 /* byte swap the sum if it came from an odd offset
43 * since the computation is endian independant this
44 * works.
45 */
46 new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
47 }
48 checksum = sum + new;
49 if (checksum > 0xFFFF) {
50 checksum -= 0xFFFF;
51 }
52 return (~checksum) & 0xFFFF;
53}