blob: 913f25c10cc12da04f78274db707fa5b2879f2bb [file] [log] [blame]
Martin Rothfb8876d2022-08-07 15:12:12 -06001/* SPDX-License-Identifier: GPL-2.0-only */
2
Eric Biederman8ca8d762003-04-22 19:02:15 +00003#include <stdint.h>
4#include <ip_checksum.h>
5
Aaron Durbin30c64be2016-12-03 21:05:53 -06006unsigned long compute_ip_checksum(const void *addr, unsigned long length)
Eric Biederman8ca8d762003-04-22 19:02:15 +00007{
Aaron Durbin30c64be2016-12-03 21:05:53 -06008 const uint8_t *ptr;
Eric Biederman8ca8d762003-04-22 19:02:15 +00009 volatile union {
10 uint8_t byte[2];
11 uint16_t word;
12 } value;
13 unsigned long sum;
14 unsigned long i;
15 /* In the most straight forward way possible,
16 * compute an ip style checksum.
17 */
18 sum = 0;
19 ptr = addr;
Lee Leahy45fde702017-03-08 18:02:24 -080020 for (i = 0; i < length; i++) {
Stefan Reinauer45dffef2009-03-31 16:42:57 +000021 unsigned long v;
22 v = ptr[i];
Lee Leahy2f919ec2017-03-08 17:37:06 -080023 if (i & 1)
Stefan Reinauer45dffef2009-03-31 16:42:57 +000024 v <<= 8;
Eric Biederman8ca8d762003-04-22 19:02:15 +000025 /* Add the new value */
Stefan Reinauer45dffef2009-03-31 16:42:57 +000026 sum += v;
Eric Biederman8ca8d762003-04-22 19:02:15 +000027 /* Wrap around the carry */
Lee Leahy2f919ec2017-03-08 17:37:06 -080028 if (sum > 0xFFFF)
Eric Biederman8ca8d762003-04-22 19:02:15 +000029 sum = (sum + (sum >> 16)) & 0xFFFF;
Eric Biederman8ca8d762003-04-22 19:02:15 +000030 }
31 value.byte[0] = sum & 0xff;
32 value.byte[1] = (sum >> 8) & 0xff;
33 return (~value.word) & 0xFFFF;
34}
35
Lee Leahy73402172017-03-10 15:23:24 -080036unsigned long add_ip_checksums(unsigned long offset, unsigned long sum,
37 unsigned long new)
Eric Biederman8ca8d762003-04-22 19:02:15 +000038{
39 unsigned long checksum;
40 sum = ~sum & 0xFFFF;
41 new = ~new & 0xFFFF;
42 if (offset & 1) {
Stefan Reinauer14e22772010-04-27 06:56:47 +000043 /* byte swap the sum if it came from an odd offset
Martin Rothcbf2bd72013-07-09 21:51:14 -060044 * since the computation is endian independent this
Eric Biederman8ca8d762003-04-22 19:02:15 +000045 * works.
46 */
47 new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
48 }
49 checksum = sum + new;
Lee Leahy2f919ec2017-03-08 17:37:06 -080050 if (checksum > 0xFFFF)
Eric Biederman8ca8d762003-04-22 19:02:15 +000051 checksum -= 0xFFFF;
Eric Biederman8ca8d762003-04-22 19:02:15 +000052 return (~checksum) & 0xFFFF;
53}