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