]> git.proxmox.com Git - mirror_frr.git/blame - lib/checksum.c
Merge pull request #10816 from anlancs/fix-bgdp-local-es-rt
[mirror_frr.git] / lib / checksum.c
CommitLineData
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
89087f23
DL
12#define add_carry(dst, add) \
13 do { \
14 typeof(dst) _add = (add); \
15 dst += _add; \
16 if (dst < _add) \
17 dst++; \
18 } while (0)
19
20uint16_t in_cksumv(const struct iovec *iov, size_t iov_len)
718e3744 21{
89087f23
DL
22 const struct iovec *iov_end;
23 uint32_t sum = 0;
24
25 union {
26 uint8_t bytes[2];
27 uint16_t word;
28 } wordbuf;
29 bool have_oddbyte = false;
718e3744 30
31 /*
32 * Our algorithm is simple, using a 32-bit accumulator (sum),
33 * we add sequential 16-bit words to it, and at the end, fold back
34 * all the carry bits from the top 16 bits into the lower 16 bits.
35 */
36
89087f23
DL
37 for (iov_end = iov + iov_len; iov < iov_end; iov++) {
38 const uint8_t *ptr, *end;
39
40 ptr = (const uint8_t *)iov->iov_base;
41 end = ptr + iov->iov_len;
42 if (ptr == end)
43 continue;
44
45 if (have_oddbyte) {
46 have_oddbyte = false;
47 wordbuf.bytes[1] = *ptr++;
48
49 add_carry(sum, wordbuf.word);
50 }
51
52 while (ptr + 8 <= end) {
53 add_carry(sum, *(const uint32_t *)(ptr + 0));
54 add_carry(sum, *(const uint32_t *)(ptr + 4));
55 ptr += 8;
56 }
57
58 while (ptr + 2 <= end) {
59 add_carry(sum, *(const uint16_t *)ptr);
60 ptr += 2;
61 }
62
63 if (ptr + 1 <= end) {
64 wordbuf.bytes[0] = *ptr++;
65 have_oddbyte = true;
66 }
718e3744 67 }
68
d62a17ae 69 /* mop up an odd byte, if necessary */
89087f23
DL
70 if (have_oddbyte) {
71 wordbuf.bytes[1] = 0;
72 add_carry(sum, wordbuf.word);
718e3744 73 }
74
75 /*
76 * Add back carry outs from top 16 bits to low 16 bits.
77 */
78
d62a17ae 79 sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
80 sum += (sum >> 16); /* add carry */
89087f23 81 return ~sum;
17b48d7d
QY
82}
83
efda3bb8 84/* Fletcher Checksum -- Refer to RFC1008. */
6b143a68 85#define MODX 4102U /* 5802 should be fine */
efda3bb8 86
d62a17ae 87/* To be consistent, offset is 0-based index, rather than the 1-based
efda3bb8 88 index required in the specification ISO 8473, Annex C.1 */
d8a4e42b
JR
89/* calling with offset == FLETCHER_CHECKSUM_VALIDATE will validate the checksum
90 without modifying the buffer; a valid checksum returns 0 */
d7c0a89a
QY
91uint16_t fletcher_checksum(uint8_t *buffer, const size_t len,
92 const uint16_t offset)
efda3bb8 93{
d7c0a89a 94 uint8_t *p;
d62a17ae 95 int x, y, c0, c1;
d7c0a89a
QY
96 uint16_t checksum = 0;
97 uint16_t *csum;
d62a17ae 98 size_t partial_len, i, left = len;
99
100 if (offset != FLETCHER_CHECKSUM_VALIDATE)
101 /* Zero the csum in the packet. */
efda3bb8 102 {
d62a17ae 103 assert(offset
104 < (len - 1)); /* account for two bytes of checksum */
d7c0a89a 105 csum = (uint16_t *)(buffer + offset);
d62a17ae 106 *(csum) = 0;
efda3bb8
JD
107 }
108
d62a17ae 109 p = buffer;
110 c0 = 0;
111 c1 = 0;
112
113 while (left != 0) {
114 partial_len = MIN(left, MODX);
115
116 for (i = 0; i < partial_len; i++) {
117 c0 = c0 + *(p++);
118 c1 += c0;
119 }
120
121 c0 = c0 % 255;
122 c1 = c1 % 255;
123
124 left -= partial_len;
125 }
126
127 /* The cast is important, to ensure the mod is taken as a signed value.
128 */
129 x = (int)((len - offset - 1) * c0 - c1) % 255;
130
131 if (x <= 0)
132 x += 255;
133 y = 510 - c0 - x;
134 if (y > 255)
135 y -= 255;
136
137 if (offset == FLETCHER_CHECKSUM_VALIDATE) {
138 checksum = (c1 << 8) + c0;
139 } else {
140 /*
141 * Now we write this to the packet.
142 * We could skip this step too, since the checksum returned
143 * would
144 * be stored into the checksum field by the caller.
145 */
146 buffer[offset] = x;
147 buffer[offset + 1] = y;
148
149 /* Take care of the endian issue */
150 checksum = htons((x << 8) | (y & 0xFF));
151 }
152
153 return checksum;
efda3bb8 154}