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 } 61