xref: /linux/arch/powerpc/lib/checksum_wrappers.c (revision 03bc8b0fc87616c75c6dd060a2191e7fc8faacb6)
1*03bc8b0fSChristophe Leroy /*
2*03bc8b0fSChristophe Leroy  * This program is free software; you can redistribute it and/or modify
3*03bc8b0fSChristophe Leroy  * it under the terms of the GNU General Public License as published by
4*03bc8b0fSChristophe Leroy  * the Free Software Foundation; either version 2 of the License, or
5*03bc8b0fSChristophe Leroy  * (at your option) any later version.
6*03bc8b0fSChristophe Leroy  *
7*03bc8b0fSChristophe Leroy  * This program is distributed in the hope that it will be useful,
8*03bc8b0fSChristophe Leroy  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9*03bc8b0fSChristophe Leroy  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10*03bc8b0fSChristophe Leroy  * GNU General Public License for more details.
11*03bc8b0fSChristophe Leroy  *
12*03bc8b0fSChristophe Leroy  * You should have received a copy of the GNU General Public License
13*03bc8b0fSChristophe Leroy  * along with this program; if not, write to the Free Software
14*03bc8b0fSChristophe Leroy  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15*03bc8b0fSChristophe Leroy  *
16*03bc8b0fSChristophe Leroy  * Copyright (C) IBM Corporation, 2010
17*03bc8b0fSChristophe Leroy  *
18*03bc8b0fSChristophe Leroy  * Author: Anton Blanchard <anton@au.ibm.com>
19*03bc8b0fSChristophe Leroy  */
20*03bc8b0fSChristophe Leroy #include <linux/export.h>
21*03bc8b0fSChristophe Leroy #include <linux/compiler.h>
22*03bc8b0fSChristophe Leroy #include <linux/types.h>
23*03bc8b0fSChristophe Leroy #include <asm/checksum.h>
24*03bc8b0fSChristophe Leroy #include <asm/uaccess.h>
25*03bc8b0fSChristophe Leroy 
26*03bc8b0fSChristophe Leroy __wsum csum_and_copy_from_user(const void __user *src, void *dst,
27*03bc8b0fSChristophe Leroy 			       int len, __wsum sum, int *err_ptr)
28*03bc8b0fSChristophe Leroy {
29*03bc8b0fSChristophe Leroy 	unsigned int csum;
30*03bc8b0fSChristophe Leroy 
31*03bc8b0fSChristophe Leroy 	might_sleep();
32*03bc8b0fSChristophe Leroy 
33*03bc8b0fSChristophe Leroy 	*err_ptr = 0;
34*03bc8b0fSChristophe Leroy 
35*03bc8b0fSChristophe Leroy 	if (!len) {
36*03bc8b0fSChristophe Leroy 		csum = 0;
37*03bc8b0fSChristophe Leroy 		goto out;
38*03bc8b0fSChristophe Leroy 	}
39*03bc8b0fSChristophe Leroy 
40*03bc8b0fSChristophe Leroy 	if (unlikely((len < 0) || !access_ok(VERIFY_READ, src, len))) {
41*03bc8b0fSChristophe Leroy 		*err_ptr = -EFAULT;
42*03bc8b0fSChristophe Leroy 		csum = (__force unsigned int)sum;
43*03bc8b0fSChristophe Leroy 		goto out;
44*03bc8b0fSChristophe Leroy 	}
45*03bc8b0fSChristophe Leroy 
46*03bc8b0fSChristophe Leroy 	csum = csum_partial_copy_generic((void __force *)src, dst,
47*03bc8b0fSChristophe Leroy 					 len, sum, err_ptr, NULL);
48*03bc8b0fSChristophe Leroy 
49*03bc8b0fSChristophe Leroy 	if (unlikely(*err_ptr)) {
50*03bc8b0fSChristophe Leroy 		int missing = __copy_from_user(dst, src, len);
51*03bc8b0fSChristophe Leroy 
52*03bc8b0fSChristophe Leroy 		if (missing) {
53*03bc8b0fSChristophe Leroy 			memset(dst + len - missing, 0, missing);
54*03bc8b0fSChristophe Leroy 			*err_ptr = -EFAULT;
55*03bc8b0fSChristophe Leroy 		} else {
56*03bc8b0fSChristophe Leroy 			*err_ptr = 0;
57*03bc8b0fSChristophe Leroy 		}
58*03bc8b0fSChristophe Leroy 
59*03bc8b0fSChristophe Leroy 		csum = csum_partial(dst, len, sum);
60*03bc8b0fSChristophe Leroy 	}
61*03bc8b0fSChristophe Leroy 
62*03bc8b0fSChristophe Leroy out:
63*03bc8b0fSChristophe Leroy 	return (__force __wsum)csum;
64*03bc8b0fSChristophe Leroy }
65*03bc8b0fSChristophe Leroy EXPORT_SYMBOL(csum_and_copy_from_user);
66*03bc8b0fSChristophe Leroy 
67*03bc8b0fSChristophe Leroy __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
68*03bc8b0fSChristophe Leroy 			     __wsum sum, int *err_ptr)
69*03bc8b0fSChristophe Leroy {
70*03bc8b0fSChristophe Leroy 	unsigned int csum;
71*03bc8b0fSChristophe Leroy 
72*03bc8b0fSChristophe Leroy 	might_sleep();
73*03bc8b0fSChristophe Leroy 
74*03bc8b0fSChristophe Leroy 	*err_ptr = 0;
75*03bc8b0fSChristophe Leroy 
76*03bc8b0fSChristophe Leroy 	if (!len) {
77*03bc8b0fSChristophe Leroy 		csum = 0;
78*03bc8b0fSChristophe Leroy 		goto out;
79*03bc8b0fSChristophe Leroy 	}
80*03bc8b0fSChristophe Leroy 
81*03bc8b0fSChristophe Leroy 	if (unlikely((len < 0) || !access_ok(VERIFY_WRITE, dst, len))) {
82*03bc8b0fSChristophe Leroy 		*err_ptr = -EFAULT;
83*03bc8b0fSChristophe Leroy 		csum = -1; /* invalid checksum */
84*03bc8b0fSChristophe Leroy 		goto out;
85*03bc8b0fSChristophe Leroy 	}
86*03bc8b0fSChristophe Leroy 
87*03bc8b0fSChristophe Leroy 	csum = csum_partial_copy_generic(src, (void __force *)dst,
88*03bc8b0fSChristophe Leroy 					 len, sum, NULL, err_ptr);
89*03bc8b0fSChristophe Leroy 
90*03bc8b0fSChristophe Leroy 	if (unlikely(*err_ptr)) {
91*03bc8b0fSChristophe Leroy 		csum = csum_partial(src, len, sum);
92*03bc8b0fSChristophe Leroy 
93*03bc8b0fSChristophe Leroy 		if (copy_to_user(dst, src, len)) {
94*03bc8b0fSChristophe Leroy 			*err_ptr = -EFAULT;
95*03bc8b0fSChristophe Leroy 			csum = -1; /* invalid checksum */
96*03bc8b0fSChristophe Leroy 		}
97*03bc8b0fSChristophe Leroy 	}
98*03bc8b0fSChristophe Leroy 
99*03bc8b0fSChristophe Leroy out:
100*03bc8b0fSChristophe Leroy 	return (__force __wsum)csum;
101*03bc8b0fSChristophe Leroy }
102*03bc8b0fSChristophe Leroy EXPORT_SYMBOL(csum_and_copy_to_user);
103