summaryrefslogtreecommitdiffstats
path: root/util_lib/compute_ip_checksum.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 02:56:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 02:56:35 +0000
commiteba0cfa6b0bef4f2e73c8630a7efa3944df8b0f8 (patch)
tree74c37eede1f0634cc5de1c63c934edaa1630c6bc /util_lib/compute_ip_checksum.c
parentInitial commit. (diff)
downloadkexec-tools-7bbe6b040c9123991377749057cfc0356c289ceb.tar.xz
kexec-tools-7bbe6b040c9123991377749057cfc0356c289ceb.zip
Adding upstream version 1:2.0.27.upstream/1%2.0.27upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'util_lib/compute_ip_checksum.c')
-rw-r--r--util_lib/compute_ip_checksum.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/util_lib/compute_ip_checksum.c b/util_lib/compute_ip_checksum.c
new file mode 100644
index 0000000..39a371b
--- /dev/null
+++ b/util_lib/compute_ip_checksum.c
@@ -0,0 +1,102 @@
+/*
+ * kexec: Linux boots Linux
+ *
+ * Copyright (C) 2003,2004 Eric Biederman (ebiederm@xmission.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation (version 2 of the License).
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <ip_checksum.h>
+#include <string.h>
+
+unsigned long compute_ip_checksum(void *addr, unsigned long length)
+{
+ uint16_t *ptr;
+ unsigned long sum;
+ unsigned long len;
+ unsigned long laddr;
+ /* compute an ip style checksum */
+ laddr = (unsigned long )addr;
+ sum = 0;
+ if (laddr & 1) {
+ uint16_t buffer;
+ unsigned char *ptr;
+ /* copy the first byte into a 2 byte buffer.
+ * This way automatically handles the endian question
+ * of which byte (low or high) the last byte goes in.
+ */
+ buffer = 0;
+ ptr = addr;
+ memcpy(&buffer, ptr, 1);
+ sum += buffer;
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ length -= 1;
+ addr = ptr +1;
+
+ }
+ len = length >> 1;
+ ptr = addr;
+ while (len--) {
+ sum += *(ptr++);
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ addr = ptr;
+ if (length & 1) {
+ uint16_t buffer;
+ unsigned char *ptr;
+ /* copy the last byte into a 2 byte buffer.
+ * This way automatically handles the endian question
+ * of which byte (low or high) the last byte goes in.
+ */
+ buffer = 0;
+ ptr = addr;
+ memcpy(&buffer, ptr, 1);
+ sum += buffer;
+ if (sum > 0xFFFF)
+ sum -= 0xFFFF;
+ }
+ return (~sum) & 0xFFFF;
+
+}
+
+unsigned long add_ip_checksums(unsigned long offset, unsigned long sum, unsigned long 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;
+}
+
+unsigned long negate_ip_checksum(unsigned long sum)
+{
+ sum = ~sum & 0xFFFF;
+
+ sum = 0xFFFF - sum;
+
+ return ~sum & 0xFFFF;
+}