summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2015-01-19 22:16:07 -0700
committerSimon Glass <sjg@chromium.org>2015-01-23 21:44:59 -0700
commit9b0e35cb4889eb04a7ea5dd648d73df0bf37cc68 (patch)
tree5e3b454e1d4d9a07de41419d56c62b40633adddf /net
parent5da38086bd6c39efd09e57900702b99541844339 (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')
-rw-r--r--net/Makefile1
-rw-r--r--net/checksum.c60
2 files changed, 61 insertions, 0 deletions
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 <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);
+}