1
2
3
4
5
6
7#include <asm/checksum.h>
8#include <linux/module.h>
9
10
11
12
13
14
15
16
17
18
19
20
21__wsum
22csum_partial_copy_from_user(const void __user *src, void *dst,
23 int len, __wsum isum, int *errp)
24{
25 might_sleep();
26 *errp = 0;
27 if (likely(access_ok(VERIFY_READ,src, len))) {
28
29
30
31
32
33
34 if (unlikely((unsigned long)src & 6)) {
35 while (((unsigned long)src & 6) && len >= 2) {
36 __u16 val16;
37 *errp = __get_user(val16, (const __u16 __user *)src);
38 if (*errp)
39 return isum;
40 *(__u16 *)dst = val16;
41 isum = (__force __wsum)add32_with_carry(
42 (__force unsigned)isum, val16);
43 src += 2;
44 dst += 2;
45 len -= 2;
46 }
47 }
48 isum = csum_partial_copy_generic((__force const void *)src,
49 dst, len, isum, errp, NULL);
50 if (likely(*errp == 0))
51 return isum;
52 }
53 *errp = -EFAULT;
54 memset(dst,0,len);
55 return isum;
56}
57
58EXPORT_SYMBOL(csum_partial_copy_from_user);
59
60
61
62
63
64
65
66
67
68
69
70
71__wsum
72csum_partial_copy_to_user(const void *src, void __user *dst,
73 int len, __wsum isum, int *errp)
74{
75 might_sleep();
76 if (unlikely(!access_ok(VERIFY_WRITE, dst, len))) {
77 *errp = -EFAULT;
78 return 0;
79 }
80
81 if (unlikely((unsigned long)dst & 6)) {
82 while (((unsigned long)dst & 6) && len >= 2) {
83 __u16 val16 = *(__u16 *)src;
84 isum = (__force __wsum)add32_with_carry(
85 (__force unsigned)isum, val16);
86 *errp = __put_user(val16, (__u16 __user *)dst);
87 if (*errp)
88 return isum;
89 src += 2;
90 dst += 2;
91 len -= 2;
92 }
93 }
94
95 *errp = 0;
96 return csum_partial_copy_generic(src, (void __force *)dst,len,isum,NULL,errp);
97}
98
99EXPORT_SYMBOL(csum_partial_copy_to_user);
100
101
102
103
104
105
106
107
108
109
110__wsum
111csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
112{
113 return csum_partial_copy_generic(src,dst,len,sum,NULL,NULL);
114}
115EXPORT_SYMBOL(csum_partial_copy_nocheck);
116
117__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
118 const struct in6_addr *daddr,
119 __u32 len, unsigned short proto, __wsum sum)
120{
121 __u64 rest, sum64;
122
123 rest = (__force __u64)htonl(len) + (__force __u64)htons(proto) +
124 (__force __u64)sum;
125 asm(" addq (%[saddr]),%[sum]\n"
126 " adcq 8(%[saddr]),%[sum]\n"
127 " adcq (%[daddr]),%[sum]\n"
128 " adcq 8(%[daddr]),%[sum]\n"
129 " adcq $0,%[sum]\n"
130 : [sum] "=r" (sum64)
131 : "[sum]" (rest),[saddr] "r" (saddr), [daddr] "r" (daddr));
132 return csum_fold((__force __wsum)add32_with_carry(sum64 & 0xffffffff, sum64>>32));
133}
134
135EXPORT_SYMBOL(csum_ipv6_magic);
136