]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - net/checksum.c
Merge branch 'master' of git://git.denx.de/u-boot-blackfin
[karo-tx-uboot.git] / net / checksum.c
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 }