* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / arch / alpha / lib / checksum.c
blob5165279f0da2098e8e86779d86c2039a893bf861
1 /*
2 * arch/alpha/lib/checksum.c
4 * This file contains network checksum routines that are better done
5 * in an architecture-specific manner due to speed..
6 */
8 #include <linux/string.h>
10 #include <asm/byteorder.h>
12 static inline unsigned short from64to16(unsigned long x)
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;
26 * computes the checksum of the TCP/UDP pseudo-header
27 * returns a 16-bit checksum, already complemented.
29 unsigned short int csum_tcpudp_magic(unsigned long saddr,
30 unsigned long daddr,
31 unsigned short len,
32 unsigned short proto,
33 unsigned int sum)
35 return ~from64to16(saddr + daddr + sum +
36 ((unsigned long) ntohs(len) << 16) +
37 ((unsigned long) proto << 8));
40 unsigned int csum_tcpudp_nofold(unsigned long saddr,
41 unsigned long daddr,
42 unsigned short len,
43 unsigned short proto,
44 unsigned int sum)
46 unsigned long result;
48 result = (saddr + daddr + sum +
49 ((unsigned long) ntohs(len) << 16) +
50 ((unsigned long) proto << 8));
52 /* Fold down to 32-bits so we don't loose in the typedef-less
53 network stack. */
54 /* 64 to 33 */
55 result = (result & 0xffffffff) + (result >> 32);
56 /* 33 to 32 */
57 result = (result & 0xffffffff) + (result >> 32);
58 return result;
62 * Do a 64-bit checksum on an arbitrary memory area..
64 * This isn't a great routine, but it's not _horrible_ either. The
65 * inner loop could be unrolled a bit further, and there are better
66 * ways to do the carry, but this is reasonable.
68 static inline unsigned long do_csum(const unsigned char * buff, int len)
70 int odd, count;
71 unsigned long result = 0;
73 if (len <= 0)
74 goto out;
75 odd = 1 & (unsigned long) buff;
76 if (odd) {
77 result = *buff << 8;
78 len--;
79 buff++;
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;
89 count >>= 1; /* nr of 32-bit words.. */
90 if (count) {
91 if (4 & (unsigned long) buff) {
92 result += *(unsigned int *) buff;
93 count--;
94 len -= 4;
95 buff += 4;
97 count >>= 1; /* nr of 64-bit words.. */
98 if (count) {
99 unsigned long carry = 0;
100 do {
101 unsigned long w = *(unsigned long *) buff;
102 count--;
103 buff += 8;
104 result += carry;
105 result += w;
106 carry = (w > result);
107 } while (count);
108 result += carry;
109 result = (result & 0xffffffff) + (result >> 32);
111 if (len & 4) {
112 result += *(unsigned int *) buff;
113 buff += 4;
116 if (len & 2) {
117 result += *(unsigned short *) buff;
118 buff += 2;
121 if (len & 1)
122 result += *buff;
123 result = from64to16(result);
124 if (odd)
125 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
126 out:
127 return result;
131 * This is a version of ip_compute_csum() optimized for IP headers,
132 * which always checksum on 4 octet boundaries.
134 unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
136 return ~do_csum(iph,ihl*4);
140 * computes the checksum of a memory block at buff, length len,
141 * and adds in "sum" (32-bit)
143 * returns a 32-bit number suitable for feeding into itself
144 * or csum_tcpudp_magic
146 * this function must be called with even lengths, except
147 * for the last fragment, which may be odd
149 * it's best to have buff aligned on a 32-bit boundary
151 unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
153 unsigned long result = do_csum(buff, len);
155 /* add in old sum, and carry.. */
156 result += sum;
157 /* 32+c bits -> 32 bits */
158 result = (result & 0xffffffff) + (result >> 32);
159 return result;
163 * this routine is used for miscellaneous IP-like checksums, mainly
164 * in icmp.c
166 unsigned short ip_compute_csum(unsigned char * buff, int len)
168 return ~from64to16(do_csum(buff,len));