2 * Checksum routine for Internet Protocol family headers (C Version).
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.
12 #define add_carry(dst, add) \
14 typeof(dst) _add = (add); \
20 uint16_t in_cksumv(const struct iovec
*iov
, size_t iov_len
)
22 const struct iovec
*iov_end
;
29 bool have_oddbyte
= false;
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.
37 for (iov_end
= iov
+ iov_len
; iov
< iov_end
; iov
++) {
38 const uint8_t *ptr
, *end
;
40 ptr
= (const uint8_t *)iov
->iov_base
;
41 end
= ptr
+ iov
->iov_len
;
47 wordbuf
.bytes
[1] = *ptr
++;
49 add_carry(sum
, wordbuf
.word
);
52 while (ptr
+ 8 <= end
) {
53 add_carry(sum
, *(const uint32_t *)(ptr
+ 0));
54 add_carry(sum
, *(const uint32_t *)(ptr
+ 4));
58 while (ptr
+ 2 <= end
) {
59 add_carry(sum
, *(const uint16_t *)ptr
);
64 wordbuf
.bytes
[0] = *ptr
++;
69 /* mop up an odd byte, if necessary */
72 add_carry(sum
, wordbuf
.word
);
76 * Add back carry outs from top 16 bits to low 16 bits.
79 sum
= (sum
>> 16) + (sum
& 0xffff); /* add high-16 to low-16 */
80 sum
+= (sum
>> 16); /* add carry */
84 /* Fletcher Checksum -- Refer to RFC1008. */
85 #define MODX 4102U /* 5802 should be fine */
87 /* To be consistent, offset is 0-based index, rather than the 1-based
88 index required in the specification ISO 8473, Annex C.1 */
89 /* calling with offset == FLETCHER_CHECKSUM_VALIDATE will validate the checksum
90 without modifying the buffer; a valid checksum returns 0 */
91 uint16_t fletcher_checksum(uint8_t *buffer
, const size_t len
,
92 const uint16_t offset
)
96 uint16_t checksum
= 0;
98 size_t partial_len
, i
, left
= len
;
100 if (offset
!= FLETCHER_CHECKSUM_VALIDATE
)
101 /* Zero the csum in the packet. */
104 < (len
- 1)); /* account for two bytes of checksum */
105 csum
= (uint16_t *)(buffer
+ offset
);
114 partial_len
= MIN(left
, MODX
);
116 for (i
= 0; i
< partial_len
; i
++) {
127 /* The cast is important, to ensure the mod is taken as a signed value.
129 x
= (int)((len
- offset
- 1) * c0
- c1
) % 255;
137 if (offset
== FLETCHER_CHECKSUM_VALIDATE
) {
138 checksum
= (c1
<< 8) + c0
;
141 * Now we write this to the packet.
142 * We could skip this step too, since the checksum returned
144 * be stored into the checksum field by the caller.
147 buffer
[offset
+ 1] = y
;
149 /* Take care of the endian issue */
150 checksum
= htons((x
<< 8) | (y
& 0xFF));