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 --- include/net.h | 30 +++++++++++++++++++++++++++++ net/Makefile | 1 + net/checksum.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 net/checksum.c diff --git a/include/net.h b/include/net.h index 3da35fe981..73ea88b42d 100644 --- a/include/net.h +++ b/include/net.h @@ -482,6 +482,36 @@ extern void net_set_ip_header(uchar *pkt, IPaddr_t dest, IPaddr_t source); extern void net_set_udp_header(uchar *pkt, IPaddr_t dest, int dport, int sport, int len); +/** + * compute_ip_checksum() - Compute IP checksum + * + * @addr: Address to check (must be 16-bit aligned) + * @nbytes: Number of bytes to check (normally a multiple of 2) + * @return 16-bit IP checksum + */ +unsigned compute_ip_checksum(const void *addr, unsigned nbytes); + +/** + * add_ip_checksums() - add two IP checksums + * + * @offset: Offset of first sum (if odd we do a byte-swap) + * @sum: First checksum + * @new_sum: New checksum to add + * @return updated 16-bit IP checksum + */ +unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum); + +/** + * ip_checksum_ok() - check if a checksum is correct + * + * This works by making sure the checksum sums to 0 + * + * @addr: Address to check (must be 16-bit aligned) + * @nbytes: Number of bytes to check (normally a multiple of 2) + * @return true if the checksum matches, false if not + */ +int ip_checksum_ok(const void *addr, unsigned nbytes); + /* Checksum */ extern int NetCksumOk(uchar *, int); /* Return true if cksum OK */ extern uint NetCksum(uchar *, int); /* Calculate the checksum */ 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