1*83d290c5STom Rini // SPDX-License-Identifier: BSD-2-Clause
29b0e35cbSSimon Glass /*
39b0e35cbSSimon Glass * This file was originally taken from the FreeBSD project.
49b0e35cbSSimon Glass *
59b0e35cbSSimon Glass * Copyright (c) 2001 Charles Mott <cm@linktel.net>
69b0e35cbSSimon Glass * Copyright (c) 2008 coresystems GmbH
79b0e35cbSSimon Glass * All rights reserved.
89b0e35cbSSimon Glass */
99b0e35cbSSimon Glass
109b0e35cbSSimon Glass #include <common.h>
119b0e35cbSSimon Glass #include <net.h>
129b0e35cbSSimon Glass
compute_ip_checksum(const void * vptr,unsigned nbytes)139b0e35cbSSimon Glass unsigned compute_ip_checksum(const void *vptr, unsigned nbytes)
149b0e35cbSSimon Glass {
159b0e35cbSSimon Glass int sum, oddbyte;
169b0e35cbSSimon Glass const unsigned short *ptr = vptr;
179b0e35cbSSimon Glass
189b0e35cbSSimon Glass sum = 0;
199b0e35cbSSimon Glass while (nbytes > 1) {
209b0e35cbSSimon Glass sum += *ptr++;
219b0e35cbSSimon Glass nbytes -= 2;
229b0e35cbSSimon Glass }
239b0e35cbSSimon Glass if (nbytes == 1) {
249b0e35cbSSimon Glass oddbyte = 0;
259b0e35cbSSimon Glass ((u8 *)&oddbyte)[0] = *(u8 *)ptr;
269b0e35cbSSimon Glass ((u8 *)&oddbyte)[1] = 0;
279b0e35cbSSimon Glass sum += oddbyte;
289b0e35cbSSimon Glass }
299b0e35cbSSimon Glass sum = (sum >> 16) + (sum & 0xffff);
309b0e35cbSSimon Glass sum += (sum >> 16);
319b0e35cbSSimon Glass sum = ~sum & 0xffff;
329b0e35cbSSimon Glass
339b0e35cbSSimon Glass return sum;
349b0e35cbSSimon Glass }
359b0e35cbSSimon Glass
add_ip_checksums(unsigned offset,unsigned sum,unsigned new)369b0e35cbSSimon Glass unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new)
379b0e35cbSSimon Glass {
389b0e35cbSSimon Glass unsigned long checksum;
399b0e35cbSSimon Glass
409b0e35cbSSimon Glass sum = ~sum & 0xffff;
419b0e35cbSSimon Glass new = ~new & 0xffff;
429b0e35cbSSimon Glass if (offset & 1) {
439b0e35cbSSimon Glass /*
449b0e35cbSSimon Glass * byte-swap the sum if it came from an odd offset; since the
459b0e35cbSSimon Glass * computation is endian independant this works.
469b0e35cbSSimon Glass */
479b0e35cbSSimon Glass new = ((new >> 8) & 0xff) | ((new << 8) & 0xff00);
489b0e35cbSSimon Glass }
499b0e35cbSSimon Glass checksum = sum + new;
509b0e35cbSSimon Glass if (checksum > 0xffff)
519b0e35cbSSimon Glass checksum -= 0xffff;
529b0e35cbSSimon Glass
539b0e35cbSSimon Glass return (~checksum) & 0xffff;
549b0e35cbSSimon Glass }
559b0e35cbSSimon Glass
ip_checksum_ok(const void * addr,unsigned nbytes)569b0e35cbSSimon Glass int ip_checksum_ok(const void *addr, unsigned nbytes)
579b0e35cbSSimon Glass {
589b0e35cbSSimon Glass return !(compute_ip_checksum(addr, nbytes) & 0xfffe);
599b0e35cbSSimon Glass }
60