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