]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
2 | * Checksum routine for Internet Protocol family headers (C Version). | |
3 | * | |
4 | * Refer to "Computing the Internet Checksum" by R. Braden, D. Borman and | |
5 | * C. Partridge, Computer Communication Review, Vol. 19, No. 2, April 1989, | |
6 | * pp. 86-101, for additional details on computing this checksum. | |
7 | */ | |
8 | ||
9 | #include <zebra.h> | |
34204aac | 10 | #include "checksum.h" |
718e3744 | 11 | |
d62a17ae | 12 | int /* return checksum in low-order 16 bits */ |
9d303b37 | 13 | in_cksum(void *parg, int nbytes) |
718e3744 | 14 | { |
d7c0a89a | 15 | unsigned short *ptr = parg; |
d62a17ae | 16 | register long sum; /* assumes long == 32 bits */ |
d7c0a89a QY |
17 | unsigned short oddbyte; |
18 | register unsigned short answer; /* assumes unsigned short == 16 bits */ | |
718e3744 | 19 | |
20 | /* | |
21 | * Our algorithm is simple, using a 32-bit accumulator (sum), | |
22 | * we add sequential 16-bit words to it, and at the end, fold back | |
23 | * all the carry bits from the top 16 bits into the lower 16 bits. | |
24 | */ | |
25 | ||
26 | sum = 0; | |
d62a17ae | 27 | while (nbytes > 1) { |
718e3744 | 28 | sum += *ptr++; |
29 | nbytes -= 2; | |
30 | } | |
31 | ||
d62a17ae | 32 | /* mop up an odd byte, if necessary */ |
718e3744 | 33 | if (nbytes == 1) { |
d62a17ae | 34 | oddbyte = 0; /* make sure top half is zero */ |
d7c0a89a | 35 | *((uint8_t *)&oddbyte) = *(uint8_t *)ptr; /* one byte only */ |
718e3744 | 36 | sum += oddbyte; |
37 | } | |
38 | ||
39 | /* | |
40 | * Add back carry outs from top 16 bits to low 16 bits. | |
41 | */ | |
42 | ||
d62a17ae | 43 | sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */ |
44 | sum += (sum >> 16); /* add carry */ | |
45 | answer = ~sum; /* ones-complement, then truncate to 16 bits */ | |
46 | return (answer); | |
718e3744 | 47 | } |
efda3bb8 JD |
48 | |
49 | /* Fletcher Checksum -- Refer to RFC1008. */ | |
6b143a68 | 50 | #define MODX 4102U /* 5802 should be fine */ |
efda3bb8 | 51 | |
d62a17ae | 52 | /* To be consistent, offset is 0-based index, rather than the 1-based |
efda3bb8 | 53 | index required in the specification ISO 8473, Annex C.1 */ |
d8a4e42b JR |
54 | /* calling with offset == FLETCHER_CHECKSUM_VALIDATE will validate the checksum |
55 | without modifying the buffer; a valid checksum returns 0 */ | |
d7c0a89a QY |
56 | uint16_t fletcher_checksum(uint8_t *buffer, const size_t len, |
57 | const uint16_t offset) | |
efda3bb8 | 58 | { |
d7c0a89a | 59 | uint8_t *p; |
d62a17ae | 60 | int x, y, c0, c1; |
d7c0a89a QY |
61 | uint16_t checksum = 0; |
62 | uint16_t *csum; | |
d62a17ae | 63 | size_t partial_len, i, left = len; |
64 | ||
65 | if (offset != FLETCHER_CHECKSUM_VALIDATE) | |
66 | /* Zero the csum in the packet. */ | |
efda3bb8 | 67 | { |
d62a17ae | 68 | assert(offset |
69 | < (len - 1)); /* account for two bytes of checksum */ | |
d7c0a89a | 70 | csum = (uint16_t *)(buffer + offset); |
d62a17ae | 71 | *(csum) = 0; |
efda3bb8 JD |
72 | } |
73 | ||
d62a17ae | 74 | p = buffer; |
75 | c0 = 0; | |
76 | c1 = 0; | |
77 | ||
78 | while (left != 0) { | |
79 | partial_len = MIN(left, MODX); | |
80 | ||
81 | for (i = 0; i < partial_len; i++) { | |
82 | c0 = c0 + *(p++); | |
83 | c1 += c0; | |
84 | } | |
85 | ||
86 | c0 = c0 % 255; | |
87 | c1 = c1 % 255; | |
88 | ||
89 | left -= partial_len; | |
90 | } | |
91 | ||
92 | /* The cast is important, to ensure the mod is taken as a signed value. | |
93 | */ | |
94 | x = (int)((len - offset - 1) * c0 - c1) % 255; | |
95 | ||
96 | if (x <= 0) | |
97 | x += 255; | |
98 | y = 510 - c0 - x; | |
99 | if (y > 255) | |
100 | y -= 255; | |
101 | ||
102 | if (offset == FLETCHER_CHECKSUM_VALIDATE) { | |
103 | checksum = (c1 << 8) + c0; | |
104 | } else { | |
105 | /* | |
106 | * Now we write this to the packet. | |
107 | * We could skip this step too, since the checksum returned | |
108 | * would | |
109 | * be stored into the checksum field by the caller. | |
110 | */ | |
111 | buffer[offset] = x; | |
112 | buffer[offset + 1] = y; | |
113 | ||
114 | /* Take care of the endian issue */ | |
115 | checksum = htons((x << 8) | (y & 0xFF)); | |
116 | } | |
117 | ||
118 | return checksum; | |
efda3bb8 | 119 | } |