root/arch/alpha/lib/checksum.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. from64to16
  2. csum_tcpudp_magic
  3. do_csum
  4. ip_fast_csum
  5. csum_partial
  6. csum_partial_copy
  7. ip_compute_csum

   1 /*
   2  * arch/alpha/lib/checksum.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 #include <linux/string.h>
   9 
  10 #include <asm/byteorder.h>
  11 
  12 static inline unsigned short from64to16(unsigned long x)
     /* [previous][next][first][last][top][bottom][index][help] */
  13 {
  14         /* add up 32-bit words for 33 bits */
  15         x = (x & 0xffffffff) + (x >> 32);
  16         /* add up 16-bit and 17-bit words for 17+c bits */
  17         x = (x & 0xffff) + (x >> 16);
  18         /* add up 16-bit and 2-bit for 16+c bit */
  19         x = (x & 0xffff) + (x >> 16);
  20         /* add up carry.. */
  21         x = (x & 0xffff) + (x >> 16);
  22         return x;
  23 }
  24 
  25 /*
  26  * computes the checksum of the TCP/UDP pseudo-header
  27  * returns a 16-bit checksum, already complemented
  28  */
  29 unsigned short int csum_tcpudp_magic(unsigned long saddr,
     /* [previous][next][first][last][top][bottom][index][help] */
  30                                    unsigned long daddr,
  31                                    unsigned short len,
  32                                    unsigned short proto,
  33                                    unsigned int sum)
  34 {
  35         return ~from64to16(saddr + daddr + sum + (ntohs(len) << 16) + (proto << 8));
  36 }
  37 
  38 /*
  39  * Do a 64-bit checksum on an arbitrary memory area..
  40  *
  41  * This isn't a great routine, but it's not _horrible_ either. The
  42  * inner loop could be unrolled a bit further, and there are better
  43  * ways to do the carry, but this is reasonable.
  44  */
  45 static inline unsigned long do_csum(unsigned char * buff, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
  46 {
  47         int odd, count;
  48         unsigned long result = 0;
  49 
  50         if (len <= 0)
  51                 goto out;
  52         odd = 1 & (unsigned long) buff;
  53         if (odd) {
  54                 result = *buff << 8;
  55                 len--;
  56                 buff++;
  57         }
  58         count = len >> 1;               /* nr of 16-bit words.. */
  59         if (count) {
  60                 if (2 & (unsigned long) buff) {
  61                         result += *(unsigned short *) buff;
  62                         count--;
  63                         len -= 2;
  64                         buff += 2;
  65                 }
  66                 count >>= 1;            /* nr of 32-bit words.. */
  67                 if (count) {
  68                         if (4 & (unsigned long) buff) {
  69                                 result += *(unsigned int *) buff;
  70                                 count--;
  71                                 len -= 4;
  72                                 buff += 4;
  73                         }
  74                         count >>= 1;    /* nr of 64-bit words.. */
  75                         if (count) {
  76                                 unsigned long carry = 0;
  77                                 do {
  78                                         unsigned long w = *(unsigned long *) buff;
  79                                         count--;
  80                                         buff += 8;
  81                                         result += carry;
  82                                         result += w;
  83                                         carry = (w > result);
  84                                 } while (count);
  85                                 result += carry;
  86                         }
  87                         if (len & 4) {
  88                                 result += *(unsigned int *) buff;
  89                                 buff += 4;
  90                         }
  91                 }
  92                 if (len & 2) {
  93                         result += *(unsigned short *) buff;
  94                         buff += 2;
  95                 }
  96         }
  97         if (len & 1)
  98                 result += *buff;
  99         result = from64to16(result);
 100         if (odd)
 101                 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
 102 out:
 103         return result;
 104 }
 105 
 106 /*
 107  *      This is a version of ip_compute_csum() optimized for IP headers,
 108  *      which always checksum on 4 octet boundaries.
 109  */
 110 unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112         return ~do_csum(iph,ihl*4);
 113 }
 114 
 115 /*
 116  * computes the checksum of a memory block at buff, length len,
 117  * and adds in "sum" (32-bit)
 118  *
 119  * returns a 32-bit number suitable for feeding into itself
 120  * or csum_tcpudp_magic
 121  *
 122  * this function must be called with even lengths, except
 123  * for the last fragment, which may be odd
 124  *
 125  * it's best to have buff aligned on a 32-bit boundary
 126  */
 127 unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129         unsigned long result = do_csum(buff, len);
 130 
 131         /* add in old sum, and carry.. */
 132         result += sum;
 133         /* 32+c bits -> 32 bits */
 134         result = (result & 0xffffffff) + (result >> 32);
 135         return result;
 136 }
 137 
 138 /*
 139  * the same as csum_partial, but copies from src while it
 140  * checksums
 141  *
 142  * here even more important to align src and dst on a 32-bit (or even
 143  * better 64-bit) boundary
 144  */
 145 
 146 unsigned int csum_partial_copy(char *src, char *dst, int len, int sum)
     /* [previous][next][first][last][top][bottom][index][help] */
 147 {
 148         /*
 149          * The whole idea is to do the copy and the checksum at
 150          * the same time, but we do it the easy way now.
 151          *
 152          * At least csum on the source, not destination, for cache
 153          * reasons..
 154          */
 155         sum = csum_partial(src, len, sum);
 156         memcpy(dst, src, len);
 157         return sum;
 158 }
 159 
 160 /*
 161  * this routine is used for miscellaneous IP-like checksums, mainly
 162  * in icmp.c
 163  */
 164 unsigned short ip_compute_csum(unsigned char * buff, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 165 {
 166         return ~from64to16(do_csum(buff,len));
 167 }

/* [previous][next][first][last][top][bottom][index][help] */