root/arch/parisc/lib/checksum.c

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

DEFINITIONS

This source file includes following definitions.
  1. from32to16
  2. do_csum
  3. csum_partial
  4. csum_partial_copy_nocheck
  5. csum_partial_copy_from_user

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * INET         An implementation of the TCP/IP protocol suite for the LINUX
   4  *              operating system.  INET is implemented using the  BSD Socket
   5  *              interface as the means of communication with the user level.
   6  *
   7  *              MIPS specific IP/TCP/UDP checksumming routines
   8  *
   9  * Authors:     Ralf Baechle, <ralf@waldorf-gmbh.de>
  10  *              Lots of code moved from tcp.c and ip.c; see those files
  11  *              for more names.
  12  */
  13 #include <linux/module.h>
  14 #include <linux/types.h>
  15 
  16 #include <net/checksum.h>
  17 #include <asm/byteorder.h>
  18 #include <asm/string.h>
  19 #include <linux/uaccess.h>
  20 
  21 #define addc(_t,_r)                     \
  22         __asm__ __volatile__ (          \
  23 "       add             %0, %1, %0\n"   \
  24 "       addc            %0, %%r0, %0\n" \
  25         : "=r"(_t)                      \
  26         : "r"(_r), "0"(_t));
  27 
  28 static inline unsigned short from32to16(unsigned int x)
  29 {
  30         /* 32 bits --> 16 bits + carry */
  31         x = (x & 0xffff) + (x >> 16);
  32         /* 16 bits + carry --> 16 bits including carry */
  33         x = (x & 0xffff) + (x >> 16);
  34         return (unsigned short)x;
  35 }
  36 
  37 static inline unsigned int do_csum(const unsigned char * buff, int len)
  38 {
  39         int odd, count;
  40         unsigned int result = 0;
  41 
  42         if (len <= 0)
  43                 goto out;
  44         odd = 1 & (unsigned long) buff;
  45         if (odd) {
  46                 result = be16_to_cpu(*buff);
  47                 len--;
  48                 buff++;
  49         }
  50         count = len >> 1;               /* nr of 16-bit words.. */
  51         if (count) {
  52                 if (2 & (unsigned long) buff) {
  53                         result += *(unsigned short *) buff;
  54                         count--;
  55                         len -= 2;
  56                         buff += 2;
  57                 }
  58                 count >>= 1;            /* nr of 32-bit words.. */
  59                 if (count) {
  60                         while (count >= 4) {
  61                                 unsigned int r1, r2, r3, r4;
  62                                 r1 = *(unsigned int *)(buff + 0);
  63                                 r2 = *(unsigned int *)(buff + 4);
  64                                 r3 = *(unsigned int *)(buff + 8);
  65                                 r4 = *(unsigned int *)(buff + 12);
  66                                 addc(result, r1);
  67                                 addc(result, r2);
  68                                 addc(result, r3);
  69                                 addc(result, r4);
  70                                 count -= 4;
  71                                 buff += 16;
  72                         }
  73                         while (count) {
  74                                 unsigned int w = *(unsigned int *) buff;
  75                                 count--;
  76                                 buff += 4;
  77                                 addc(result, w);
  78                         }
  79                         result = (result & 0xffff) + (result >> 16);
  80                 }
  81                 if (len & 2) {
  82                         result += *(unsigned short *) buff;
  83                         buff += 2;
  84                 }
  85         }
  86         if (len & 1)
  87                 result += le16_to_cpu(*buff);
  88         result = from32to16(result);
  89         if (odd)
  90                 result = swab16(result);
  91 out:
  92         return result;
  93 }
  94 
  95 /*
  96  * computes a partial checksum, e.g. for TCP/UDP fragments
  97  */
  98 /*
  99  * why bother folding?
 100  */
 101 __wsum csum_partial(const void *buff, int len, __wsum sum)
 102 {
 103         unsigned int result = do_csum(buff, len);
 104         addc(result, sum);
 105         return (__force __wsum)from32to16(result);
 106 }
 107 
 108 EXPORT_SYMBOL(csum_partial);
 109 
 110 /*
 111  * copy while checksumming, otherwise like csum_partial
 112  */
 113 __wsum csum_partial_copy_nocheck(const void *src, void *dst,
 114                                        int len, __wsum sum)
 115 {
 116         /*
 117          * It's 2:30 am and I don't feel like doing it real ...
 118          * This is lots slower than the real thing (tm)
 119          */
 120         sum = csum_partial(src, len, sum);
 121         memcpy(dst, src, len);
 122 
 123         return sum;
 124 }
 125 EXPORT_SYMBOL(csum_partial_copy_nocheck);
 126 
 127 /*
 128  * Copy from userspace and compute checksum.  If we catch an exception
 129  * then zero the rest of the buffer.
 130  */
 131 __wsum csum_partial_copy_from_user(const void __user *src,
 132                                         void *dst, int len,
 133                                         __wsum sum, int *err_ptr)
 134 {
 135         int missing;
 136 
 137         missing = copy_from_user(dst, src, len);
 138         if (missing) {
 139                 memset(dst + len - missing, 0, missing);
 140                 *err_ptr = -EFAULT;
 141         }
 142                 
 143         return csum_partial(dst, len, sum);
 144 }
 145 EXPORT_SYMBOL(csum_partial_copy_from_user);

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