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 int /* return checksum in low-order 16 bits */
13 in_cksum(void *parg
, int nbytes
)
15 unsigned short *ptr
= parg
;
16 register long sum
; /* assumes long == 32 bits */
17 unsigned short oddbyte
;
18 register unsigned short answer
; /* assumes unsigned short == 16 bits */
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.
32 /* mop up an odd byte, if necessary */
34 oddbyte
= 0; /* make sure top half is zero */
35 *((uint8_t *)&oddbyte
) = *(uint8_t *)ptr
; /* one byte only */
40 * Add back carry outs from top 16 bits to low 16 bits.
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 */
49 int in_cksum_with_ph4(struct ipv4_ph
*ph
, void *data
, int nbytes
)
51 uint8_t dat
[sizeof(struct ipv4_ph
) + nbytes
];
53 memcpy(dat
, ph
, sizeof(struct ipv4_ph
));
54 memcpy(dat
+ sizeof(struct ipv4_ph
), data
, nbytes
);
55 return in_cksum(dat
, sizeof(dat
));
58 int in_cksum_with_ph6(struct ipv6_ph
*ph
, void *data
, int nbytes
)
60 uint8_t dat
[sizeof(struct ipv6_ph
) + nbytes
];
62 memcpy(dat
, ph
, sizeof(struct ipv6_ph
));
63 memcpy(dat
+ sizeof(struct ipv6_ph
), data
, nbytes
);
64 return in_cksum(dat
, sizeof(dat
));
67 /* Fletcher Checksum -- Refer to RFC1008. */
68 #define MODX 4102U /* 5802 should be fine */
70 /* To be consistent, offset is 0-based index, rather than the 1-based
71 index required in the specification ISO 8473, Annex C.1 */
72 /* calling with offset == FLETCHER_CHECKSUM_VALIDATE will validate the checksum
73 without modifying the buffer; a valid checksum returns 0 */
74 uint16_t fletcher_checksum(uint8_t *buffer
, const size_t len
,
75 const uint16_t offset
)
79 uint16_t checksum
= 0;
81 size_t partial_len
, i
, left
= len
;
83 if (offset
!= FLETCHER_CHECKSUM_VALIDATE
)
84 /* Zero the csum in the packet. */
87 < (len
- 1)); /* account for two bytes of checksum */
88 csum
= (uint16_t *)(buffer
+ offset
);
97 partial_len
= MIN(left
, MODX
);
99 for (i
= 0; i
< partial_len
; i
++) {
110 /* The cast is important, to ensure the mod is taken as a signed value.
112 x
= (int)((len
- offset
- 1) * c0
- c1
) % 255;
120 if (offset
== FLETCHER_CHECKSUM_VALIDATE
) {
121 checksum
= (c1
<< 8) + c0
;
124 * Now we write this to the packet.
125 * We could skip this step too, since the checksum returned
127 * be stored into the checksum field by the caller.
130 buffer
[offset
+ 1] = y
;
132 /* Take care of the endian issue */
133 checksum
= htons((x
<< 8) | (y
& 0xFF));