]>
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 | |
34204aac | 12 | int /* return checksum in low-order 16 bits */ |
13 | in_cksum(void *parg, int nbytes) | |
718e3744 | 14 | { |
34204aac | 15 | u_short *ptr = parg; |
718e3744 | 16 | register long sum; /* assumes long == 32 bits */ |
17 | u_short oddbyte; | |
18 | register u_short answer; /* assumes u_short == 16 bits */ | |
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; | |
27 | while (nbytes > 1) { | |
28 | sum += *ptr++; | |
29 | nbytes -= 2; | |
30 | } | |
31 | ||
32 | /* mop up an odd byte, if necessary */ | |
33 | if (nbytes == 1) { | |
34 | oddbyte = 0; /* make sure top half is zero */ | |
35 | *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */ | |
36 | sum += oddbyte; | |
37 | } | |
38 | ||
39 | /* | |
40 | * Add back carry outs from top 16 bits to low 16 bits. | |
41 | */ | |
42 | ||
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); | |
47 | } | |
efda3bb8 JD |
48 | |
49 | /* Fletcher Checksum -- Refer to RFC1008. */ | |
6b143a68 | 50 | #define MODX 4102U /* 5802 should be fine */ |
efda3bb8 JD |
51 | |
52 | /* To be consistent, offset is 0-based index, rather than the 1-based | |
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 */ | |
efda3bb8 | 56 | u_int16_t |
5d4b8cf2 | 57 | fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset) |
efda3bb8 JD |
58 | { |
59 | u_int8_t *p; | |
5d4b8cf2 | 60 | int x, y, c0, c1; |
f48f65d2 | 61 | u_int16_t checksum = 0; |
efda3bb8 | 62 | u_int16_t *csum; |
5d4b8cf2 PJ |
63 | size_t partial_len, i, left = len; |
64 | ||
d8a4e42b JR |
65 | if (offset != FLETCHER_CHECKSUM_VALIDATE) |
66 | /* Zero the csum in the packet. */ | |
67 | { | |
68 | assert (offset < (len - 1)); /* account for two bytes of checksum */ | |
69 | csum = (u_int16_t *) (buffer + offset); | |
70 | *(csum) = 0; | |
71 | } | |
efda3bb8 JD |
72 | |
73 | p = buffer; | |
74 | c0 = 0; | |
75 | c1 = 0; | |
efda3bb8 | 76 | |
5d4b8cf2 | 77 | while (left != 0) |
efda3bb8 | 78 | { |
5d4b8cf2 | 79 | partial_len = MIN(left, MODX); |
efda3bb8 JD |
80 | |
81 | for (i = 0; i < partial_len; i++) | |
82 | { | |
83 | c0 = c0 + *(p++); | |
84 | c1 += c0; | |
85 | } | |
86 | ||
87 | c0 = c0 % 255; | |
88 | c1 = c1 % 255; | |
89 | ||
5d4b8cf2 | 90 | left -= partial_len; |
efda3bb8 | 91 | } |
d8a4e42b | 92 | |
5d4b8cf2 | 93 | /* The cast is important, to ensure the mod is taken as a signed value. */ |
6e907dd4 | 94 | x = (int)((len - offset - 1) * c0 - c1) % 255; |
5d4b8cf2 PJ |
95 | |
96 | if (x <= 0) | |
97 | x += 255; | |
98 | y = 510 - c0 - x; | |
99 | if (y > 255) | |
100 | y -= 255; | |
d8a4e42b JR |
101 | |
102 | if (offset == FLETCHER_CHECKSUM_VALIDATE) | |
103 | { | |
104 | checksum = (c1 << 8) + c0; | |
105 | } | |
106 | else | |
107 | { | |
108 | /* | |
109 | * Now we write this to the packet. | |
110 | * We could skip this step too, since the checksum returned would | |
111 | * be stored into the checksum field by the caller. | |
112 | */ | |
113 | buffer[offset] = x; | |
114 | buffer[offset + 1] = y; | |
115 | ||
116 | /* Take care of the endian issue */ | |
117 | checksum = htons((x << 8) | (y & 0xFF)); | |
118 | } | |
efda3bb8 JD |
119 | |
120 | return checksum; | |
121 | } |