root/arch/ia64/lib/csum_partial_copy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. from64to16
  2. do_csum_c
  3. csum_partial_copy_from_user
  4. csum_partial_copy_nocheck

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Network Checksum & Copy routine
   4  *
   5  * Copyright (C) 1999, 2003-2004 Hewlett-Packard Co
   6  *      Stephane Eranian <eranian@hpl.hp.com>
   7  *
   8  * Most of the code has been imported from Linux/Alpha
   9  */
  10 
  11 #include <linux/module.h>
  12 #include <linux/types.h>
  13 #include <linux/string.h>
  14 
  15 #include <linux/uaccess.h>
  16 
  17 /*
  18  * XXX Fixme: those 2 inlines are meant for debugging and will go away
  19  */
  20 static inline unsigned
  21 short from64to16(unsigned long x)
  22 {
  23         /* add up 32-bit words for 33 bits */
  24         x = (x & 0xffffffff) + (x >> 32);
  25         /* add up 16-bit and 17-bit words for 17+c bits */
  26         x = (x & 0xffff) + (x >> 16);
  27         /* add up 16-bit and 2-bit for 16+c bit */
  28         x = (x & 0xffff) + (x >> 16);
  29         /* add up carry.. */
  30         x = (x & 0xffff) + (x >> 16);
  31         return x;
  32 }
  33 
  34 static inline
  35 unsigned long do_csum_c(const unsigned char * buff, int len, unsigned int psum)
  36 {
  37         int odd, count;
  38         unsigned long result = (unsigned long)psum;
  39 
  40         if (len <= 0)
  41                 goto out;
  42         odd = 1 & (unsigned long) buff;
  43         if (odd) {
  44                 result = *buff << 8;
  45                 len--;
  46                 buff++;
  47         }
  48         count = len >> 1;               /* nr of 16-bit words.. */
  49         if (count) {
  50                 if (2 & (unsigned long) buff) {
  51                         result += *(unsigned short *) buff;
  52                         count--;
  53                         len -= 2;
  54                         buff += 2;
  55                 }
  56                 count >>= 1;            /* nr of 32-bit words.. */
  57                 if (count) {
  58                         if (4 & (unsigned long) buff) {
  59                                 result += *(unsigned int *) buff;
  60                                 count--;
  61                                 len -= 4;
  62                                 buff += 4;
  63                         }
  64                         count >>= 1;    /* nr of 64-bit words.. */
  65                         if (count) {
  66                                 unsigned long carry = 0;
  67                                 do {
  68                                         unsigned long w = *(unsigned long *) buff;
  69                                         count--;
  70                                         buff += 8;
  71                                         result += carry;
  72                                         result += w;
  73                                         carry = (w > result);
  74                                 } while (count);
  75                                 result += carry;
  76                                 result = (result & 0xffffffff) + (result >> 32);
  77                         }
  78                         if (len & 4) {
  79                                 result += *(unsigned int *) buff;
  80                                 buff += 4;
  81                         }
  82                 }
  83                 if (len & 2) {
  84                         result += *(unsigned short *) buff;
  85                         buff += 2;
  86                 }
  87         }
  88         if (len & 1)
  89                 result += *buff;
  90 
  91         result = from64to16(result);
  92 
  93         if (odd)
  94                 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
  95 
  96 out:
  97         return result;
  98 }
  99 
 100 /*
 101  * XXX Fixme
 102  *
 103  * This is very ugly but temporary. THIS NEEDS SERIOUS ENHANCEMENTS.
 104  * But it's very tricky to get right even in C.
 105  */
 106 extern unsigned long do_csum(const unsigned char *, long);
 107 
 108 __wsum
 109 csum_partial_copy_from_user(const void __user *src, void *dst,
 110                                 int len, __wsum psum, int *errp)
 111 {
 112         unsigned long result;
 113 
 114         /* XXX Fixme
 115          * for now we separate the copy from checksum for obvious
 116          * alignment difficulties. Look at the Alpha code and you'll be
 117          * scared.
 118          */
 119 
 120         if (__copy_from_user(dst, src, len) != 0 && errp)
 121                 *errp = -EFAULT;
 122 
 123         result = do_csum(dst, len);
 124 
 125         /* add in old sum, and carry.. */
 126         result += (__force u32)psum;
 127         /* 32+c bits -> 32 bits */
 128         result = (result & 0xffffffff) + (result >> 32);
 129         return (__force __wsum)result;
 130 }
 131 
 132 EXPORT_SYMBOL(csum_partial_copy_from_user);
 133 
 134 __wsum
 135 csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
 136 {
 137         return csum_partial_copy_from_user((__force const void __user *)src,
 138                                            dst, len, sum, NULL);
 139 }
 140 
 141 EXPORT_SYMBOL(csum_partial_copy_nocheck);

/* [<][>][^][v][top][bottom][index][help] */