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

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