xref: /openbmc/u-boot/net/checksum.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: BSD-2-Clause
29b0e35cbSSimon Glass /*
39b0e35cbSSimon Glass  * This file was originally taken from the FreeBSD project.
49b0e35cbSSimon Glass  *
59b0e35cbSSimon Glass  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
69b0e35cbSSimon Glass  * Copyright (c) 2008 coresystems GmbH
79b0e35cbSSimon Glass  * All rights reserved.
89b0e35cbSSimon Glass  */
99b0e35cbSSimon Glass 
109b0e35cbSSimon Glass #include <common.h>
119b0e35cbSSimon Glass #include <net.h>
129b0e35cbSSimon Glass 
compute_ip_checksum(const void * vptr,unsigned nbytes)139b0e35cbSSimon Glass unsigned compute_ip_checksum(const void *vptr, unsigned nbytes)
149b0e35cbSSimon Glass {
159b0e35cbSSimon Glass 	int sum, oddbyte;
169b0e35cbSSimon Glass 	const unsigned short *ptr = vptr;
179b0e35cbSSimon Glass 
189b0e35cbSSimon Glass 	sum = 0;
199b0e35cbSSimon Glass 	while (nbytes > 1) {
209b0e35cbSSimon Glass 		sum += *ptr++;
219b0e35cbSSimon Glass 		nbytes -= 2;
229b0e35cbSSimon Glass 	}
239b0e35cbSSimon Glass 	if (nbytes == 1) {
249b0e35cbSSimon Glass 		oddbyte = 0;
259b0e35cbSSimon Glass 		((u8 *)&oddbyte)[0] = *(u8 *)ptr;
269b0e35cbSSimon Glass 		((u8 *)&oddbyte)[1] = 0;
279b0e35cbSSimon Glass 		sum += oddbyte;
289b0e35cbSSimon Glass 	}
299b0e35cbSSimon Glass 	sum = (sum >> 16) + (sum & 0xffff);
309b0e35cbSSimon Glass 	sum += (sum >> 16);
319b0e35cbSSimon Glass 	sum = ~sum & 0xffff;
329b0e35cbSSimon Glass 
339b0e35cbSSimon Glass 	return sum;
349b0e35cbSSimon Glass }
359b0e35cbSSimon Glass 
add_ip_checksums(unsigned offset,unsigned sum,unsigned new)369b0e35cbSSimon Glass unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new)
379b0e35cbSSimon Glass {
389b0e35cbSSimon Glass 	unsigned long checksum;
399b0e35cbSSimon Glass 
409b0e35cbSSimon Glass 	sum = ~sum & 0xffff;
419b0e35cbSSimon Glass 	new = ~new & 0xffff;
429b0e35cbSSimon Glass 	if (offset & 1) {
439b0e35cbSSimon Glass 		/*
449b0e35cbSSimon Glass 		 * byte-swap the sum if it came from an odd offset; since the
459b0e35cbSSimon Glass 		 * computation is endian independant this works.
469b0e35cbSSimon Glass 		 */
479b0e35cbSSimon Glass 		new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
489b0e35cbSSimon Glass 	}
499b0e35cbSSimon Glass 	checksum = sum + new;
509b0e35cbSSimon Glass 	if (checksum > 0xffff)
519b0e35cbSSimon Glass 		checksum -= 0xffff;
529b0e35cbSSimon Glass 
539b0e35cbSSimon Glass 	return (~checksum) & 0xffff;
549b0e35cbSSimon Glass }
559b0e35cbSSimon Glass 
ip_checksum_ok(const void * addr,unsigned nbytes)569b0e35cbSSimon Glass int ip_checksum_ok(const void *addr, unsigned nbytes)
579b0e35cbSSimon Glass {
589b0e35cbSSimon Glass 	return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
599b0e35cbSSimon Glass }
60