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