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
compute_ip_checksum(const void * vptr,unsigned nbytes)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
add_ip_checksums(unsigned offset,unsigned sum,unsigned new)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
ip_checksum_ok(const void * addr,unsigned nbytes)56 int ip_checksum_ok(const void *addr, unsigned nbytes)
57 {
58 return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
59 }
60