Merge branch 'master' of git://git.denx.de/u-boot-sh
[oweals/u-boot.git] / net / checksum.c
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * This file was originally taken from the FreeBSD project.
4  *
5  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
6  * Copyright (c) 2008 coresystems GmbH
7  * All rights reserved.
8  */
9
10 #include <common.h>
11 #include <net.h>
12
13 unsigned compute_ip_checksum(const void *vptr, unsigned nbytes)
14 {
15         int sum, oddbyte;
16         const unsigned short *ptr = vptr;
17
18         sum = 0;
19         while (nbytes > 1) {
20                 sum += *ptr++;
21                 nbytes -= 2;
22         }
23         if (nbytes == 1) {
24                 oddbyte = 0;
25                 ((u8 *)&oddbyte)[0] = *(u8 *)ptr;
26                 ((u8 *)&oddbyte)[1] = 0;
27                 sum += oddbyte;
28         }
29         sum = (sum >> 16) + (sum & 0xffff);
30         sum += (sum >> 16);
31         sum = ~sum & 0xffff;
32
33         return sum;
34 }
35
36 unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new)
37 {
38         unsigned long checksum;
39
40         sum = ~sum & 0xffff;
41         new = ~new & 0xffff;
42         if (offset & 1) {
43                 /*
44                  * byte-swap the sum if it came from an odd offset; since the
45                  * computation is endian independant this works.
46                  */
47                 new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
48         }
49         checksum = sum + new;
50         if (checksum > 0xffff)
51                 checksum -= 0xffff;
52
53         return (~checksum) & 0xffff;
54 }
55
56 int ip_checksum_ok(const void *addr, unsigned nbytes)
57 {
58         return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
59 }