diff options
author | Simon Glass <sjg@chromium.org> | 2015-01-19 22:16:07 -0700 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2015-01-23 21:44:59 -0700 |
commit | 9b0e35cb4889eb04a7ea5dd648d73df0bf37cc68 (patch) | |
tree | 5e3b454e1d4d9a07de41419d56c62b40633adddf /net/checksum.c | |
parent | 5da38086bd6c39efd09e57900702b99541844339 (diff) |
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 <sjg@chromium.org>
Diffstat (limited to 'net/checksum.c')
-rw-r--r-- | net/checksum.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/net/checksum.c b/net/checksum.c new file mode 100644 index 00000000000..a8c9ff5ea45 --- /dev/null +++ b/net/checksum.c @@ -0,0 +1,60 @@ +/* + * This file was originally taken from the FreeBSD project. + * + * Copyright (c) 2001 Charles Mott <cm@linktel.net> + * Copyright (c) 2008 coresystems GmbH + * All rights reserved. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <common.h> +#include <net.h> + +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); +} |