2 * arch/sh/lib/csum_parial.c
4 * This file contains network checksum routines that are better done
5 * in an architecture-specific manner due to speed..
8 #include <linux/config.h>
9 #include <linux/string.h>
10 #include <linux/errno.h>
11 #include <asm/byteorder.h>
12 #include <asm/uaccess.h>
17 #define dprintk(x...) printk(x)
20 static inline unsigned short from64to16(unsigned long long x)
22 /* add up 32-bit words for 33 bits */
23 x = (x & 0xffffffff) + (x >> 32);
24 /* add up 16-bit and 17-bit words for 17+c bits */
25 x = (x & 0xffff) + (x >> 16);
26 /* add up 16-bit and 2-bit for 16+c bit */
27 x = (x & 0xffff) + (x >> 16);
29 x = (x & 0xffff) + (x >> 16);
33 static inline unsigned short foldto16(unsigned long x)
35 /* add up 16-bit for 17 bits */
36 x = (x & 0xffff) + (x >> 16);
38 x = (x & 0xffff) + (x >> 16);
42 static inline unsigned short myfoldto16(unsigned long long x)
44 /* Fold down to 32-bits so we don't loose in the typedef-less
47 x = (x & 0xffffffff) + (x >> 32);
49 x = (x & 0xffffffff) + (x >> 32);
51 /* add up 16-bit for 17 bits */
52 x = (x & 0xffff) + (x >> 16);
54 x = (x & 0xffff) + (x >> 16);
58 #define odd(x) ((x)&1)
60 typedef unsigned short u16;
63 #define U16(x) ntohs(x)
65 static unsigned long do_moronic_csum(const unsigned char *a16p, int cnt)
70 /* This algorithm is correct only for those values of cnt < 65536 */
73 cnt >>= 1; /* convert to a word count */
74 sum = 0; /* do a straight two's complement sum */
77 if (oddb) /* pick up the odd byte */
78 sum += U16(*a16p++) & (u16) 0xFF00;
79 /* add in the sum of the `carry' bits, making this one's complement */
80 sum = (sum & (u32) 0xFFFF) + ((sum >> 16) & (u32) 0xFFFF);
81 if (sum & (u32) 0x10000) /* one last possible carry */
82 sum = (sum + 1) & (u32) 0xFFFF;
83 if (sum == (u32) 0xFFFF) /* remove the -0 ambiguity */
90 static inline unsigned long do_csum(const unsigned char *buff, int len)
93 unsigned long long result = 0;
97 odd = 1 & (unsigned long) buff;
103 count = len >> 1; /* nr of 16-bit words.. */
105 if (2 & (unsigned long) buff) {
106 result += *(unsigned short *) buff;
111 count >>= 1; /* nr of 32-bit words.. */
113 if (4 & (unsigned long) buff) {
114 result += *(unsigned int *) buff;
119 count >>= 1; /* nr of 64-bit words.. */
121 unsigned long carry = 0;
124 *(unsigned long *) buff;
129 carry = (w > result);
132 result = (result & 0xffffffff) + (result >> 32);
135 result += *(unsigned int *) buff;
140 result += *(unsigned short *) buff;
146 result = from64to16(result);
148 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
155 static unsigned long do_csum(const unsigned char *buff, int len)
158 unsigned long result = 0;
160 dprintk("do_csum buff %p, len %d (0x%x)\n", buff, len, len);
162 for (i = 0; i < len; i++) {
165 printk("%02X ", buff[i]);
172 odd = 1 & (unsigned long) buff;
178 count = len >> 1; /* nr of 16-bit words.. */
180 if (2 & (unsigned long) buff) {
181 result += *(unsigned short *) buff;
186 count >>= 1; /* nr of 32-bit words.. */
188 unsigned long carry = 0;
190 unsigned long w = *(unsigned long *) buff;
195 carry = (w > result);
198 result = (result & 0xffff) + (result >> 16);
201 result += *(unsigned short *) buff;
207 result = foldto16(result);
209 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
211 dprintk("\nCHECKSUM is 0x%x\n", result);
219 /* computes the checksum of a memory block at buff, length len,
220 and adds in "sum" (32-bit) */
221 unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
223 unsigned long long result = do_csum(buff, len);
225 /* add in old sum, and carry.. */
227 /* 32+c bits -> 32 bits */
228 result = (result & 0xffffffff) + (result >> 32);
230 dprintk("csum_partial, buff %p len %d sum 0x%x result=0x%016Lx\n",
231 buff, len, sum, result);
236 /* Copy while checksumming, otherwise like csum_partial. */
238 csum_partial_copy(const char *src, char *dst, int len, unsigned int sum)
240 sum = csum_partial(src, len, sum);
241 memcpy(dst, src, len);
246 /* Copy from userspace and compute checksum. If we catch an exception
247 then zero the rest of the buffer. */
249 csum_partial_copy_from_user(const char *src, char *dst, int len,
250 unsigned int sum, int *err_ptr)
255 ("csum_partial_copy_from_user src %p, dest %p, len %d, sum %08x, err_ptr %p\n",
256 src, dst, len, sum, err_ptr);
257 missing = copy_from_user(dst, src, len);
258 dprintk(" access_ok %d\n", __access_ok((unsigned long) src, len));
259 dprintk(" missing %d\n", missing);
261 memset(dst + len - missing, 0, missing);
265 return csum_partial(dst, len, sum);
268 /* Copy to userspace and compute checksum. */
270 csum_partial_copy_to_user(const char *src, char *dst, int len,
271 unsigned int sum, int *err_ptr)
273 sum = csum_partial(src, len, sum);
275 if (copy_to_user(dst, src, len))
282 * This is a version of ip_compute_csum() optimized for IP headers,
283 * which always checksum on 4 octet boundaries.
285 unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
287 dprintk("ip_fast_csum %p,%d\n", iph, ihl);
289 return ~do_csum(iph, ihl * 4);
292 unsigned int csum_tcpudp_nofold(unsigned long saddr,
295 unsigned short proto, unsigned int sum)
297 unsigned long long result;
299 dprintk("ntohs(0x%x)=0x%x\n", 0xdead, ntohs(0xdead));
300 dprintk("htons(0x%x)=0x%x\n", 0xdead, htons(0xdead));
302 result = ((unsigned long long) saddr +
303 (unsigned long long) daddr +
304 (unsigned long long) sum +
305 ((unsigned long long) ntohs(len) << 16) +
306 ((unsigned long long) proto << 8));
308 /* Fold down to 32-bits so we don't loose in the typedef-less
311 result = (result & 0xffffffff) + (result >> 32);
313 result = (result & 0xffffffff) + (result >> 32);
315 dprintk("%s saddr %x daddr %x len %x proto %x sum %x result %08Lx\n",
316 __FUNCTION__, saddr, daddr, len, proto, sum, result);
323 csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum)
326 dprintk("csum_partial_copy_nocheck src %p dst %p len %d\n", src, dst,
329 return csum_partial_copy(src, dst, len, sum);