xref: /openbmc/u-boot/net/checksum.c (revision 3ebd892f)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * This file was originally taken from the FreeBSD project.
4  *
5  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
6  * Copyright (c) 2008 coresystems GmbH
7  * All rights reserved.
8  */
9 
10 #include <common.h>
11 #include <net.h>
12 
13 unsigned compute_ip_checksum(const void *vptr, unsigned nbytes)
14 {
15 	int sum, oddbyte;
16 	const unsigned short *ptr = vptr;
17 
18 	sum = 0;
19 	while (nbytes > 1) {
20 		sum += *ptr++;
21 		nbytes -= 2;
22 	}
23 	if (nbytes == 1) {
24 		oddbyte = 0;
25 		((u8 *)&oddbyte)[0] = *(u8 *)ptr;
26 		((u8 *)&oddbyte)[1] = 0;
27 		sum += oddbyte;
28 	}
29 	sum = (sum >> 16) + (sum & 0xffff);
30 	sum += (sum >> 16);
31 	sum = ~sum & 0xffff;
32 
33 	return sum;
34 }
35 
36 unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new)
37 {
38 	unsigned long checksum;
39 
40 	sum = ~sum & 0xffff;
41 	new = ~new & 0xffff;
42 	if (offset & 1) {
43 		/*
44 		 * byte-swap the sum if it came from an odd offset; since the
45 		 * computation is endian independant this works.
46 		 */
47 		new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
48 	}
49 	checksum = sum + new;
50 	if (checksum > 0xffff)
51 		checksum -= 0xffff;
52 
53 	return (~checksum) & 0xffff;
54 }
55 
56 int ip_checksum_ok(const void *addr, unsigned nbytes)
57 {
58 	return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
59 }
60