Rev 422 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
422 | giacomo | 1 | #ifndef _I386_CHECKSUM_H |
2 | #define _I386_CHECKSUM_H |
||
3 | |||
4 | #include <linux/in6.h> |
||
5 | |||
6 | /* |
||
7 | * computes the checksum of a memory block at buff, length len, |
||
8 | * and adds in "sum" (32-bit) |
||
9 | * |
||
10 | * returns a 32-bit number suitable for feeding into itself |
||
11 | * or csum_tcpudp_magic |
||
12 | * |
||
13 | * this function must be called with even lengths, except |
||
14 | * for the last fragment, which may be odd |
||
15 | * |
||
16 | * it's best to have buff aligned on a 32-bit boundary |
||
17 | */ |
||
18 | asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); |
||
19 | |||
20 | /* |
||
21 | * the same as csum_partial, but copies from src while it |
||
22 | * checksums, and handles user-space pointer exceptions correctly, when needed. |
||
23 | * |
||
24 | * here even more important to align src and dst on a 32-bit (or even |
||
25 | * better 64-bit) boundary |
||
26 | */ |
||
27 | |||
28 | asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum, |
||
29 | int *src_err_ptr, int *dst_err_ptr); |
||
30 | |||
31 | /* |
||
32 | * Note: when you get a NULL pointer exception here this means someone |
||
33 | * passed in an incorrect kernel address to one of these functions. |
||
34 | * |
||
35 | * If you use these functions directly please don't forget the |
||
36 | * verify_area(). |
||
37 | */ |
||
38 | static __inline__ |
||
39 | unsigned int csum_partial_copy_nocheck ( const char *src, char *dst, |
||
40 | int len, int sum) |
||
41 | { |
||
42 | return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL); |
||
43 | } |
||
44 | |||
45 | static __inline__ |
||
46 | unsigned int csum_partial_copy_from_user ( const char *src, char *dst, |
||
47 | int len, int sum, int *err_ptr) |
||
48 | { |
||
49 | return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL); |
||
50 | } |
||
51 | |||
52 | /* |
||
53 | * This is a version of ip_compute_csum() optimized for IP headers, |
||
54 | * which always checksum on 4 octet boundaries. |
||
55 | * |
||
56 | * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by |
||
57 | * Arnt Gulbrandsen. |
||
58 | */ |
||
59 | static inline unsigned short ip_fast_csum(unsigned char * iph, |
||
60 | unsigned int ihl) |
||
61 | { |
||
62 | unsigned int sum; |
||
63 | |||
64 | __asm__ __volatile__( |
||
65 | "movl (%1), %0 ;\n" |
||
66 | "subl $4, %2 ;\n" |
||
67 | "jbe 2f ;\n" |
||
68 | "addl 4(%1), %0 ;\n" |
||
69 | "adcl 8(%1), %0 ;\n" |
||
70 | "adcl 12(%1), %0 ;\n" |
||
71 | "1: adcl 16(%1), %0 ;\n" |
||
72 | "lea 4(%1), %1 ;\n" |
||
73 | "decl %2 ;\n" |
||
74 | "jne 1b ;\n" |
||
75 | "adcl $0, %0 ;\n" |
||
76 | "movl %0, %2 ;\n" |
||
77 | "shrl $16, %0 ;\n" |
||
78 | "addw %w2, %w0 ;\n" |
||
79 | "adcl $0, %0 ;\n" |
||
80 | "notl %0 ;\n" |
||
81 | "2: ;\n" |
||
82 | /* Since the input registers which are loaded with iph and ipl |
||
83 | are modified, we must also specify them as outputs, or gcc |
||
84 | will assume they contain their original values. */ |
||
85 | : "=r" (sum), "=r" (iph), "=r" (ihl) |
||
86 | : "1" (iph), "2" (ihl) |
||
87 | : "memory"); |
||
88 | return(sum); |
||
89 | } |
||
90 | |||
91 | /* |
||
92 | * Fold a partial checksum |
||
93 | */ |
||
94 | |||
95 | static inline unsigned int csum_fold(unsigned int sum) |
||
96 | { |
||
97 | __asm__( |
||
98 | "addl %1, %0 ;\n" |
||
99 | "adcl $0xffff, %0 ;\n" |
||
100 | : "=r" (sum) |
||
101 | : "r" (sum << 16), "0" (sum & 0xffff0000) |
||
102 | ); |
||
103 | return (~sum) >> 16; |
||
104 | } |
||
105 | |||
106 | static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, |
||
107 | unsigned long daddr, |
||
108 | unsigned short len, |
||
109 | unsigned short proto, |
||
110 | unsigned int sum) |
||
111 | { |
||
112 | __asm__( |
||
113 | "addl %1, %0 ;\n" |
||
114 | "adcl %2, %0 ;\n" |
||
115 | "adcl %3, %0 ;\n" |
||
116 | "adcl $0, %0 ;\n" |
||
117 | : "=r" (sum) |
||
118 | : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum)); |
||
119 | return sum; |
||
120 | } |
||
121 | |||
122 | /* |
||
123 | * computes the checksum of the TCP/UDP pseudo-header |
||
124 | * returns a 16-bit checksum, already complemented |
||
125 | */ |
||
126 | static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, |
||
127 | unsigned long daddr, |
||
128 | unsigned short len, |
||
129 | unsigned short proto, |
||
130 | unsigned int sum) |
||
131 | { |
||
132 | return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); |
||
133 | } |
||
134 | |||
135 | /* |
||
136 | * this routine is used for miscellaneous IP-like checksums, mainly |
||
137 | * in icmp.c |
||
138 | */ |
||
139 | |||
140 | static inline unsigned short ip_compute_csum(unsigned char * buff, int len) |
||
141 | { |
||
142 | return csum_fold (csum_partial(buff, len, 0)); |
||
143 | } |
||
144 | |||
145 | #define _HAVE_ARCH_IPV6_CSUM |
||
146 | static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, |
||
147 | struct in6_addr *daddr, |
||
148 | __u32 len, |
||
149 | unsigned short proto, |
||
150 | unsigned int sum) |
||
151 | { |
||
152 | __asm__( |
||
153 | "addl 0(%1), %0 ;\n" |
||
154 | "adcl 4(%1), %0 ;\n" |
||
155 | "adcl 8(%1), %0 ;\n" |
||
156 | "adcl 12(%1), %0 ;\n" |
||
157 | "adcl 0(%2), %0 ;\n" |
||
158 | "adcl 4(%2), %0 ;\n" |
||
159 | "adcl 8(%2), %0 ;\n" |
||
160 | "adcl 12(%2), %0 ;\n" |
||
161 | "adcl %3, %0 ;\n" |
||
162 | "adcl %4, %0 ;\n" |
||
163 | "adcl $0, %0 ;\n" |
||
164 | : "=&r" (sum) |
||
165 | : "r" (saddr), "r" (daddr), |
||
166 | "r"(htonl(len)), "r"(htonl(proto)), "0"(sum)); |
||
167 | |||
168 | return csum_fold(sum); |
||
169 | } |
||
170 | |||
171 | /* |
||
172 | * Copy and checksum to user |
||
173 | */ |
||
174 | #define HAVE_CSUM_COPY_USER |
||
175 | static __inline__ unsigned int csum_and_copy_to_user(const char *src, char *dst, |
||
176 | int len, int sum, int *err_ptr) |
||
177 | { |
||
178 | if (access_ok(VERIFY_WRITE, dst, len)) |
||
179 | return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr); |
||
180 | |||
181 | if (len) |
||
182 | *err_ptr = -EFAULT; |
||
183 | |||
184 | return -1; /* invalid checksum */ |
||
185 | } |
||
186 | |||
187 | #endif |