summaryrefslogtreecommitdiff
path: root/libbb/inet_cksum.c
blob: 31bf8c4d959c7cf7c1d90e529c7e9527655be899 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
 * Checksum routine for Internet Protocol family headers (C Version)
 *
 * Licensed under GPLv2, see file LICENSE in this source tree.
 */

#include "libbb.h"

uint16_t FAST_FUNC inet_cksum(uint16_t *addr, int nleft)
{
	/*
	 * Our algorithm is simple, using a 32 bit accumulator,
	 * we add sequential 16 bit words to it, and at the end, fold
	 * back all the carry bits from the top 16 bits into the lower
	 * 16 bits.
	 */
	unsigned sum = 0;
	while (nleft > 1) {
		sum += *addr++;
		nleft -= 2;
	}

	/* Mop up an odd byte, if necessary */
	if (nleft)
		sum += *(uint8_t*)addr;

	/* Add back carry outs from top 16 bits to low 16 bits */
	sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
	sum += (sum >> 16);                     /* add carry */

	return (uint16_t)~sum;
}