linux-bk/arch/sh64/lib/c-checksum.c
<<
>>
Prefs
   1/*
   2 * arch/sh/lib/csum_parial.c
   3 *
   4 * This file contains network checksum routines that are better done
   5 * in an architecture-specific manner due to speed..
   6 */
   7
   8#undef DEBUG
   9
  10#include <linux/config.h>
  11#include <linux/string.h>
  12#include <linux/errno.h>
  13#include <linux/kernel.h>
  14#include <asm/byteorder.h>
  15#include <asm/uaccess.h>
  16
  17static inline unsigned short from64to16(unsigned long long x)
  18{
  19        /* add up 32-bit words for 33 bits */
  20        x = (x & 0xffffffff) + (x >> 32);
  21        /* add up 16-bit and 17-bit words for 17+c bits */
  22        x = (x & 0xffff) + (x >> 16);
  23        /* add up 16-bit and 2-bit for 16+c bit */
  24        x = (x & 0xffff) + (x >> 16);
  25        /* add up carry.. */
  26        x = (x & 0xffff) + (x >> 16);
  27        return x;
  28}
  29
  30static inline unsigned short foldto16(unsigned long x)
  31{
  32        /* add up 16-bit for 17 bits */
  33        x = (x & 0xffff) + (x >> 16);
  34        /* add up carry.. */
  35        x = (x & 0xffff) + (x >> 16);
  36        return x;
  37}
  38
  39static inline unsigned short myfoldto16(unsigned long long x)
  40{
  41        /* Fold down to 32-bits so we don't loose in the typedef-less
  42           network stack.  */
  43        /* 64 to 33 */
  44        x = (x & 0xffffffff) + (x >> 32);
  45        /* 33 to 32 */
  46        x = (x & 0xffffffff) + (x >> 32);
  47
  48        /* add up 16-bit for 17 bits */
  49        x = (x & 0xffff) + (x >> 16);
  50        /* add up carry.. */
  51        x = (x & 0xffff) + (x >> 16);
  52        return x;
  53}
  54
  55#define odd(x) ((x)&1)
  56#define U16(x) ntohs(x)
  57
  58static unsigned long do_csum(const unsigned char *buff, int len)
  59{
  60        int odd, count;
  61        unsigned long result = 0;
  62
  63        pr_debug("do_csum buff %p, len %d (0x%x)\n", buff, len, len);
  64#ifdef DEBUG
  65        for (i = 0; i < len; i++) {
  66                if ((i % 26) == 0)
  67                        printk("\n");
  68                printk("%02X ", buff[i]);
  69        }
  70#endif
  71
  72        if (len <= 0)
  73                goto out;
  74
  75        odd = 1 & (unsigned long) buff;
  76        if (odd) {
  77                result = *buff << 8;
  78                len--;
  79                buff++;
  80        }
  81        count = len >> 1;       /* nr of 16-bit words.. */
  82        if (count) {
  83                if (2 & (unsigned long) buff) {
  84                        result += *(unsigned short *) buff;
  85                        count--;
  86                        len -= 2;
  87                        buff += 2;
  88                }
  89                count >>= 1;    /* nr of 32-bit words.. */
  90                if (count) {
  91                        unsigned long carry = 0;
  92                        do {
  93                                unsigned long w = *(unsigned long *) buff;
  94                                buff += 4;
  95                                count--;
  96                                result += carry;
  97                                result += w;
  98                                carry = (w > result);
  99                        } while (count);
 100                        result += carry;
 101                        result = (result & 0xffff) + (result >> 16);
 102                }
 103                if (len & 2) {
 104                        result += *(unsigned short *) buff;
 105                        buff += 2;
 106                }
 107        }
 108        if (len & 1)
 109                result += *buff;
 110        result = foldto16(result);
 111        if (odd)
 112                result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
 113
 114        pr_debug("\nCHECKSUM is 0x%x\n", result);
 115
 116      out:
 117        return result;
 118}
 119
 120/* computes the checksum of a memory block at buff, length len,
 121   and adds in "sum" (32-bit)  */
 122unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
 123{
 124        unsigned long long result = do_csum(buff, len);
 125
 126        /* add in old sum, and carry.. */
 127        result += sum;
 128        /* 32+c bits -> 32 bits */
 129        result = (result & 0xffffffff) + (result >> 32);
 130
 131        pr_debug("csum_partial, buff %p len %d sum 0x%x result=0x%016Lx\n",
 132                buff, len, sum, result);
 133
 134        return result;
 135}
 136
 137/* Copy while checksumming, otherwise like csum_partial.  */
 138unsigned int
 139csum_partial_copy(const char *src, char *dst, int len, unsigned int sum)
 140{
 141        sum = csum_partial(src, len, sum);
 142        memcpy(dst, src, len);
 143
 144        return sum;
 145}
 146
 147/* Copy from userspace and compute checksum.  If we catch an exception
 148   then zero the rest of the buffer.  */
 149unsigned int
 150csum_partial_copy_from_user(const char *src, char *dst, int len,
 151                            unsigned int sum, int *err_ptr)
 152{
 153        int missing;
 154
 155        pr_debug
 156            ("csum_partial_copy_from_user src %p, dest %p, len %d, sum %08x, err_ptr %p\n",
 157             src, dst, len, sum, err_ptr);
 158        missing = copy_from_user(dst, src, len);
 159        pr_debug("  access_ok %d\n", __access_ok((unsigned long) src, len));
 160        pr_debug("  missing %d\n", missing);
 161        if (missing) {
 162                memset(dst + len - missing, 0, missing);
 163                *err_ptr = -EFAULT;
 164        }
 165
 166        return csum_partial(dst, len, sum);
 167}
 168
 169/* Copy to userspace and compute checksum.  */
 170unsigned int
 171csum_partial_copy_to_user(const char *src, char *dst, int len,
 172                          unsigned int sum, int *err_ptr)
 173{
 174        sum = csum_partial(src, len, sum);
 175
 176        if (copy_to_user(dst, src, len))
 177                *err_ptr = -EFAULT;
 178
 179        return sum;
 180}
 181
 182/*
 183 *      This is a version of ip_compute_csum() optimized for IP headers,
 184 *      which always checksum on 4 octet boundaries.
 185 */
 186unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
 187{
 188        pr_debug("ip_fast_csum %p,%d\n", iph, ihl);
 189
 190        return ~do_csum(iph, ihl * 4);
 191}
 192
 193unsigned int csum_tcpudp_nofold(unsigned long saddr,
 194                                unsigned long daddr,
 195                                unsigned short len,
 196                                unsigned short proto, unsigned int sum)
 197{
 198        unsigned long long result;
 199
 200        pr_debug("ntohs(0x%x)=0x%x\n", 0xdead, ntohs(0xdead));
 201        pr_debug("htons(0x%x)=0x%x\n", 0xdead, htons(0xdead));
 202
 203        result = ((unsigned long long) saddr +
 204                  (unsigned long long) daddr +
 205                  (unsigned long long) sum +
 206                  ((unsigned long long) ntohs(len) << 16) +
 207                  ((unsigned long long) proto << 8));
 208
 209        /* Fold down to 32-bits so we don't loose in the typedef-less
 210           network stack.  */
 211        /* 64 to 33 */
 212        result = (result & 0xffffffff) + (result >> 32);
 213        /* 33 to 32 */
 214        result = (result & 0xffffffff) + (result >> 32);
 215
 216        pr_debug("%s saddr %x daddr %x len %x proto %x sum %x result %08Lx\n",
 217                __FUNCTION__, saddr, daddr, len, proto, sum, result);
 218
 219        return result;
 220}
 221
 222// Post SIM:
 223unsigned int
 224csum_partial_copy_nocheck(const char *src, char *dst, int len, unsigned int sum)
 225{
 226        //  unsigned dummy;
 227        pr_debug("csum_partial_copy_nocheck src %p dst %p len %d\n", src, dst,
 228                len);
 229
 230        return csum_partial_copy(src, dst, len, sum);
 231}
 232
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.