1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35#include <linux/module.h>
36#include <net/checksum.h>
37
38#include <asm/byteorder.h>
39
40#ifndef do_csum
41static inline unsigned short from32to16(unsigned int x)
42{
43
44 x = (x & 0xffff) + (x >> 16);
45
46 x = (x & 0xffff) + (x >> 16);
47 return x;
48}
49
50static unsigned int do_csum(const unsigned char *buff, int len)
51{
52 int odd, count;
53 unsigned int result = 0;
54
55 if (len <= 0)
56 goto out;
57 odd = 1 & (unsigned long) buff;
58 if (odd) {
59#ifdef __LITTLE_ENDIAN
60 result += (*buff << 8);
61#else
62 result = *buff;
63#endif
64 len--;
65 buff++;
66 }
67 count = len >> 1;
68 if (count) {
69 if (2 & (unsigned long) buff) {
70 result += *(unsigned short *) buff;
71 count--;
72 len -= 2;
73 buff += 2;
74 }
75 count >>= 1;
76 if (count) {
77 unsigned int carry = 0;
78 do {
79 unsigned int w = *(unsigned int *) buff;
80 count--;
81 buff += 4;
82 result += carry;
83 result += w;
84 carry = (w > result);
85 } while (count);
86 result += carry;
87 result = (result & 0xffff) + (result >> 16);
88 }
89 if (len & 2) {
90 result += *(unsigned short *) buff;
91 buff += 2;
92 }
93 }
94 if (len & 1)
95#ifdef __LITTLE_ENDIAN
96 result += *buff;
97#else
98 result += (*buff << 8);
99#endif
100 result = from32to16(result);
101 if (odd)
102 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
103out:
104 return result;
105}
106#endif
107
108
109
110
111
112__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
113{
114 return (__force __sum16)~do_csum(iph, ihl*4);
115}
116EXPORT_SYMBOL(ip_fast_csum);
117
118
119
120
121
122
123
124
125
126
127
128
129
130__wsum csum_partial(const void *buff, int len, __wsum wsum)
131{
132 unsigned int sum = (__force unsigned int)wsum;
133 unsigned int result = do_csum(buff, len);
134
135
136 result += sum;
137 if (sum > result)
138 result += 1;
139 return (__force __wsum)result;
140}
141EXPORT_SYMBOL(csum_partial);
142
143
144
145
146
147__sum16 ip_compute_csum(const void *buff, int len)
148{
149 return (__force __sum16)~do_csum(buff, len);
150}
151EXPORT_SYMBOL(ip_compute_csum);
152
153
154
155
156__wsum
157csum_partial_copy_from_user(const void __user *src, void *dst, int len,
158 __wsum sum, int *csum_err)
159{
160 int missing;
161
162 missing = __copy_from_user(dst, src, len);
163 if (missing) {
164 memset(dst + len - missing, 0, missing);
165 *csum_err = -EFAULT;
166 } else
167 *csum_err = 0;
168
169 return csum_partial(dst, len, sum);
170}
171EXPORT_SYMBOL(csum_partial_copy_from_user);
172
173
174
175
176__wsum
177csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
178{
179 memcpy(dst, src, len);
180 return csum_partial(dst, len, sum);
181}
182EXPORT_SYMBOL(csum_partial_copy);
183
184#ifndef csum_tcpudp_nofold
185__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
186 unsigned short len,
187 unsigned short proto,
188 __wsum sum)
189{
190 unsigned long long s = (__force u32)sum;
191
192 s += (__force u32)saddr;
193 s += (__force u32)daddr;
194#ifdef __BIG_ENDIAN
195 s += proto + len;
196#else
197 s += (proto + len) << 8;
198#endif
199 s += (s >> 32);
200 return (__force __wsum)s;
201}
202EXPORT_SYMBOL(csum_tcpudp_nofold);
203#endif
204