blob: a8c9ff5ea456a76c59591aac9f52e118f2d89ba9 [file] [log] [blame]
Simon Glass9b0e35c2015-01-19 22:16:07 -07001/*
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
14unsigned 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
37unsigned 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
57int ip_checksum_ok(const void *addr, unsigned nbytes)
58{
59 return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
60}