Line data Source code
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>
10 : #include "checksum.h"
11 :
12 : int /* return checksum in low-order 16 bits */
13 0 : in_cksum(void *parg, int nbytes)
14 : {
15 0 : u_short *ptr = parg;
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 0 : sum = 0;
27 0 : while (nbytes > 1) {
28 0 : sum += *ptr++;
29 0 : nbytes -= 2;
30 : }
31 :
32 : /* mop up an odd byte, if necessary */
33 0 : if (nbytes == 1) {
34 0 : oddbyte = 0; /* make sure top half is zero */
35 0 : *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */
36 0 : sum += oddbyte;
37 : }
38 :
39 : /*
40 : * Add back carry outs from top 16 bits to low 16 bits.
41 : */
42 :
43 0 : sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
44 0 : sum += (sum >> 16); /* add carry */
45 0 : answer = ~sum; /* ones-complement, then truncate to 16 bits */
46 0 : return(answer);
47 : }
48 :
49 : /* Fletcher Checksum -- Refer to RFC1008. */
50 : #define MODX 4102 /* 5802 should be fine */
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 */
54 : /* calling with offset == FLETCHER_CHECKSUM_VALIDATE will validate the checksum
55 : without modifying the buffer; a valid checksum returns 0 */
56 : u_int16_t
57 0 : fletcher_checksum(u_char * buffer, const size_t len, const uint16_t offset)
58 : {
59 : u_int8_t *p;
60 : int x, y, c0, c1;
61 : u_int16_t checksum;
62 : u_int16_t *csum;
63 0 : size_t partial_len, i, left = len;
64 :
65 0 : checksum = 0;
66 :
67 :
68 0 : if (offset != FLETCHER_CHECKSUM_VALIDATE)
69 : /* Zero the csum in the packet. */
70 : {
71 0 : assert (offset < (len - 1)); /* account for two bytes of checksum */
72 0 : csum = (u_int16_t *) (buffer + offset);
73 0 : *(csum) = 0;
74 : }
75 :
76 0 : p = buffer;
77 0 : c0 = 0;
78 0 : c1 = 0;
79 :
80 0 : while (left != 0)
81 : {
82 0 : partial_len = MIN(left, MODX);
83 :
84 0 : for (i = 0; i < partial_len; i++)
85 : {
86 0 : c0 = c0 + *(p++);
87 0 : c1 += c0;
88 : }
89 :
90 0 : c0 = c0 % 255;
91 0 : c1 = c1 % 255;
92 :
93 0 : left -= partial_len;
94 : }
95 :
96 : /* The cast is important, to ensure the mod is taken as a signed value. */
97 0 : x = (int)((len - offset - 1) * c0 - c1) % 255;
98 :
99 0 : if (x <= 0)
100 0 : x += 255;
101 0 : y = 510 - c0 - x;
102 0 : if (y > 255)
103 0 : y -= 255;
104 :
105 0 : if (offset == FLETCHER_CHECKSUM_VALIDATE)
106 : {
107 0 : checksum = (c1 << 8) + c0;
108 : }
109 : else
110 : {
111 : /*
112 : * Now we write this to the packet.
113 : * We could skip this step too, since the checksum returned would
114 : * be stored into the checksum field by the caller.
115 : */
116 0 : buffer[offset] = x;
117 0 : buffer[offset + 1] = y;
118 :
119 : /* Take care of the endian issue */
120 0 : checksum = htons((x << 8) | (y & 0xFF));
121 : }
122 :
123 0 : return checksum;
124 : }
|