1 /* $Id: checksum.h,v 1.10 1995/11/25 02:31:23 davem Exp $ */
2 #ifndef __SPARC_CHECKSUM_H
3 #define __SPARC_CHECKSUM_H
4
5 /* checksum.h: IP/UDP/TCP checksum routines on the Sparc.
6 *
7 * Copyright(C) 1995 Linus Torvalds
8 * Copyright(C) 1995 Miguel de Icaza
9 */
10
11
12 /* 32 bits version of the checksum routines written for the Alpha by Linus */
13 extern inline unsigned short from32to16(unsigned long x)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
14 {
15 /* add up 16-bit and 17-bit words for 17+c bits */
16 x = (x & 0xffff) + (x >> 16);
17 /* add up 16-bit and 2-bit for 16+c bit */
18 x = (x & 0xffff) + (x >> 16);
19 /* add up carry.. */
20 x = (x & 0xffff) + (x >> 16);
21 return x;
22 }
23
24 extern inline unsigned long
25 do_csum(unsigned char * buff, int len)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
26 {
27 int odd, count;
28 unsigned long result = 0;
29
30 if (len <= 0)
31 goto out;
32 odd = 1 & (unsigned long) buff;
33 if (odd) {
34 result = *buff << 8;
35 len--;
36 buff++;
37 }
38 count = len >> 1; /* nr of 16-bit words.. */
39 if (count) {
40 if (2 & (unsigned long) buff) {
41 result += *(unsigned short *) buff;
42 count--;
43 len -= 2;
44 buff += 2;
45 }
46 count >>= 1; /* nr of 32-bit words.. */
47 if (count) {
48 unsigned long carry = 0;
49 do {
50 unsigned long w = *(unsigned long *) buff;
51 count--;
52 buff += 4;
53 len -= 4;
54 result += carry;
55 result += w;
56 carry = (w > result);
57 } while (count);
58 result += carry;
59 result = (result & 0xffff) + (result >> 16);
60 }
61 if (len & 2) {
62 result += *(unsigned short *) buff;
63 buff += 2;
64 }
65 }
66 if (len & 1)
67 result += (*buff) << 8;
68 result = from32to16(result);
69 if (odd)
70 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
71 out:
72 return result;
73 }
74
75 extern inline unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
76 {
77 return ~do_csum(iph,ihl*4);
78 }
79
80 /*
81 * computes the checksum of a memory block at buff, length len,
82 * and adds in "sum" (32-bit)
83 *
84 * returns a 32-bit number suitable for feeding into itself
85 * or csum_tcpudp_magic
86 *
87 * this function must be called with even lengths, except
88 * for the last fragment, which may be odd
89 *
90 * it's best to have buff aligned on a 32-bit boundary
91 */
92 extern inline unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
93 {
94 unsigned long result = do_csum(buff, len);
95
96 /* add in old sum, and carry.. */
97 result += sum;
98 /* 32+c bits -> 32 bits */
99 result = (result & 0xffff) + (result >> 16);
100 return result;
101 }
102
103 /*
104 * the same as csum_partial, but copies from fs:src while it
105 * checksums
106 *
107 * here even more important to align src and dst on a 32-bit (or even
108 * better 64-bit) boundary
109 */
110 extern inline unsigned int csum_partial_copy(char *src, char *dst, int len, int sum)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
111 {
112 /*
113 * The whole idea is to do the copy and the checksum at
114 * the same time, but we do it the easy way now.
115 *
116 * At least csum on the source, not destination, for cache
117 * reasons..
118 */
119 sum = csum_partial(src, len, sum);
120 memcpy(dst, src, len);
121 return sum;
122 }
123
124 /*
125 * this routine is used for miscellaneous IP-like checksums, mainly
126 * in icmp.c
127 */
128 extern inline unsigned short ip_compute_csum(unsigned char * buff, int len)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
129 {
130 return ~from32to16(do_csum(buff,len));
131 }
132
133 #define csum_partial_copy_fromuser(s, d, l, w) \
134 csum_partial_copy((char *) (s), (d), (l), (w))
135
136 /*
137 * Fold a partial checksum without adding pseudo headers
138 */
139
140 static inline unsigned short csum_fold(unsigned int sum)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
141 {
142 sum = (sum & 0xffff) + (sum >> 16);
143 sum = (sum & 0xffff) + (sum >> 16);
144 return ~sum;
145 }
146
147 /*
148 * computes the checksum of the TCP/UDP pseudo-header
149 * returns a 16-bit checksum, already complemented
150 */
151 extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
152 unsigned long daddr,
153 unsigned short len,
154 unsigned short proto,
155 unsigned int sum)
156 {
157 return ~from32to16 (((saddr >> 16) + (saddr & 0xffff) + (daddr >> 16)
158 + (daddr & 0xffff) + (sum >> 16) +
159 (sum & 0xffff) + proto + len));
160 }
161
162 #endif /* !(__SPARC_CHECKSUM_H) */