| /* | |
| * This file was originally taken from the FreeBSD project. | |
| * | |
| * Copyright (c) 2001 Charles Mott <cm@linktel.net> | |
| * Copyright (c) 2008 coresystems GmbH | |
| * All rights reserved. | |
| * | |
| * SPDX-License-Identifier: BSD-2-Clause | |
| */ | |
| #include <common.h> | |
| #include <net.h> | |
| unsigned compute_ip_checksum(const void *vptr, unsigned nbytes) | |
| { | |
| int sum, oddbyte; | |
| const unsigned short *ptr = vptr; | |
| sum = 0; | |
| while (nbytes > 1) { | |
| sum += *ptr++; | |
| nbytes -= 2; | |
| } | |
| if (nbytes == 1) { | |
| oddbyte = 0; | |
| ((u8 *)&oddbyte)[0] = *(u8 *)ptr; | |
| ((u8 *)&oddbyte)[1] = 0; | |
| sum += oddbyte; | |
| } | |
| sum = (sum >> 16) + (sum & 0xffff); | |
| sum += (sum >> 16); | |
| sum = ~sum & 0xffff; | |
| return sum; | |
| } | |
| unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new) | |
| { | |
| unsigned long checksum; | |
| sum = ~sum & 0xffff; | |
| new = ~new & 0xffff; | |
| if (offset & 1) { | |
| /* | |
| * byte-swap the sum if it came from an odd offset; since the | |
| * computation is endian independant this works. | |
| */ | |
| new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00); | |
| } | |
| checksum = sum + new; | |
| if (checksum > 0xffff) | |
| checksum -= 0xffff; | |
| return (~checksum) & 0xffff; | |
| } | |
| int ip_checksum_ok(const void *addr, unsigned nbytes) | |
| { | |
| return !(compute_ip_checksum(addr, nbytes) & 0xfffe); | |
| } |