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