blob: 16ef41635676e1cf7673aaca8a0ae5e019e2c36c [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: BSD-2-Clause
Simon Glass9b0e35c2015-01-19 22:16:07 -07002/*
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.
Simon Glass9b0e35c2015-01-19 22:16:07 -07008 */
9
10#include <common.h>
11#include <net.h>
12
13unsigned 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
36unsigned 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
56int ip_checksum_ok(const void *addr, unsigned nbytes)
57{
58 return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
59}