From 9b0e35cb4889eb04a7ea5dd648d73df0bf37cc68 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 19 Jan 2015 22:16:07 -0700 Subject: net: Add a separate file for IP checksumming Move the checksum code out into its own file so it can be used elsewhere. Also use a new version which supports a length which is not a multiple of 2 and add a new function to add two checksums. Signed-off-by: Simon Glass --- net/Makefile | 1 + net/checksum.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 net/checksum.c (limited to 'net') diff --git a/net/Makefile b/net/Makefile index 942595021d..e9cc8ada96 100644 --- a/net/Makefile +++ b/net/Makefile @@ -7,6 +7,7 @@ #ccflags-y += -DDEBUG +obj-y += checksum.o obj-$(CONFIG_CMD_NET) += arp.o obj-$(CONFIG_CMD_NET) += bootp.o obj-$(CONFIG_CMD_CDP) += cdp.o diff --git a/net/checksum.c b/net/checksum.c new file mode 100644 index 0000000000..a8c9ff5ea4 --- /dev/null +++ b/net/checksum.c @@ -0,0 +1,60 @@ +/* + * This file was originally taken from the FreeBSD project. + * + * Copyright (c) 2001 Charles Mott + * Copyright (c) 2008 coresystems GmbH + * All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +unsigned compute_ip_checksum(const void *vptr, unsigned nbytes) +{ + int sum, oddbyte; + const unsigned short *ptr = vptr; + + sum = 0; + while (nbytes > 1) { + sum += *ptr++; + nbytes -= 2; + } + if (nbytes == 1) { + oddbyte = 0; + ((u8 *)&oddbyte)[0] = *(u8 *)ptr; + ((u8 *)&oddbyte)[1] = 0; + sum += oddbyte; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + sum = ~sum & 0xffff; + + return sum; +} + +unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new) +{ + unsigned long checksum; + + sum = ~sum & 0xffff; + new = ~new & 0xffff; + if (offset & 1) { + /* + * byte-swap the sum if it came from an odd offset; since the + * computation is endian independant this works. + */ + new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00); + } + checksum = sum + new; + if (checksum > 0xffff) + checksum -= 0xffff; + + return (~checksum) & 0xffff; +} + +int ip_checksum_ok(const void *addr, unsigned nbytes) +{ + return !(compute_ip_checksum(addr, nbytes) & 0xfffe); +} -- cgit v1.2.1