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