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