Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Licensed under the GPL | |
3 | */ | |
4 | ||
5 | #ifndef __UM_SYSDEP_CHECKSUM_H | |
6 | #define __UM_SYSDEP_CHECKSUM_H | |
7 | ||
8 | #include "linux/string.h" | |
9 | #include "linux/in6.h" | |
10 | #include "asm/uaccess.h" | |
11 | ||
abf419b8 | 12 | extern __wsum csum_partial(const void *buff, int len, __wsum sum); |
1da177e4 LT |
13 | |
14 | /* | |
15 | * Note: when you get a NULL pointer exception here this means someone | |
16 | * passed in an incorrect kernel address to one of these functions. | |
17 | * | |
18 | * If you use these functions directly please don't forget the | |
19 | * access_ok(). | |
20 | */ | |
21 | ||
22 | static __inline__ | |
abf419b8 AV |
23 | __wsum csum_partial_copy_nocheck(const void *src, void *dst, |
24 | int len, __wsum sum) | |
1da177e4 LT |
25 | { |
26 | memcpy(dst, src, len); | |
27 | return(csum_partial(dst, len, sum)); | |
28 | } | |
29 | ||
30 | static __inline__ | |
abf419b8 AV |
31 | __wsum csum_partial_copy_from_user(const void __user *src, |
32 | void *dst, int len, __wsum sum, | |
ba9950c8 | 33 | int *err_ptr) |
1da177e4 | 34 | { |
abf419b8 | 35 | if (copy_from_user(dst, src, len)) { |
ba9950c8 | 36 | *err_ptr = -EFAULT; |
abf419b8 | 37 | return (__force __wsum)-1; |
ba9950c8 JD |
38 | } |
39 | return csum_partial(dst, len, sum); | |
1da177e4 LT |
40 | } |
41 | ||
42 | /** | |
43 | * csum_fold - Fold and invert a 32bit checksum. | |
44 | * sum: 32bit unfolded sum | |
45 | * | |
46 | * Fold a 32bit running checksum to 16bit and invert it. This is usually | |
47 | * the last step before putting a checksum into a packet. | |
48 | * Make sure not to mix with 64bit checksums. | |
49 | */ | |
abf419b8 | 50 | static inline __sum16 csum_fold(__wsum sum) |
1da177e4 LT |
51 | { |
52 | __asm__( | |
53 | " addl %1,%0\n" | |
54 | " adcl $0xffff,%0" | |
55 | : "=r" (sum) | |
abf419b8 AV |
56 | : "r" ((__force u32)sum << 16), |
57 | "0" ((__force u32)sum & 0xffff0000) | |
1da177e4 | 58 | ); |
abf419b8 | 59 | return (__force __sum16)(~(__force u32)sum >> 16); |
1da177e4 LT |
60 | } |
61 | ||
62 | /** | |
63 | * csum_tcpup_nofold - Compute an IPv4 pseudo header checksum. | |
64 | * @saddr: source address | |
65 | * @daddr: destination address | |
66 | * @len: length of packet | |
67 | * @proto: ip protocol of packet | |
68 | * @sum: initial sum to be added in (32bit unfolded) | |
69 | * | |
70 | * Returns the pseudo header checksum the input data. Result is | |
71 | * 32bit unfolded. | |
72 | */ | |
abf419b8 AV |
73 | static inline __wsum |
74 | csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, | |
75 | unsigned short proto, __wsum sum) | |
1da177e4 LT |
76 | { |
77 | asm(" addl %1, %0\n" | |
78 | " adcl %2, %0\n" | |
79 | " adcl %3, %0\n" | |
80 | " adcl $0, %0\n" | |
81 | : "=r" (sum) | |
abf419b8 AV |
82 | : "g" (daddr), "g" (saddr), "g" ((len + proto) << 8), "0" (sum)); |
83 | return sum; | |
1da177e4 LT |
84 | } |
85 | ||
86 | /* | |
87 | * computes the checksum of the TCP/UDP pseudo-header | |
88 | * returns a 16-bit checksum, already complemented | |
89 | */ | |
abf419b8 AV |
90 | static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, |
91 | unsigned short len, | |
92 | unsigned short proto, | |
93 | __wsum sum) | |
1da177e4 LT |
94 | { |
95 | return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); | |
96 | } | |
97 | ||
98 | /** | |
99 | * ip_fast_csum - Compute the IPv4 header checksum efficiently. | |
100 | * iph: ipv4 header | |
101 | * ihl: length of header / 4 | |
102 | */ | |
abf419b8 | 103 | static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) |
1da177e4 LT |
104 | { |
105 | unsigned int sum; | |
106 | ||
107 | asm( " movl (%1), %0\n" | |
108 | " subl $4, %2\n" | |
109 | " jbe 2f\n" | |
110 | " addl 4(%1), %0\n" | |
111 | " adcl 8(%1), %0\n" | |
112 | " adcl 12(%1), %0\n" | |
113 | "1: adcl 16(%1), %0\n" | |
114 | " lea 4(%1), %1\n" | |
115 | " decl %2\n" | |
116 | " jne 1b\n" | |
117 | " adcl $0, %0\n" | |
118 | " movl %0, %2\n" | |
119 | " shrl $16, %0\n" | |
120 | " addw %w2, %w0\n" | |
121 | " adcl $0, %0\n" | |
122 | " notl %0\n" | |
123 | "2:" | |
124 | /* Since the input registers which are loaded with iph and ipl | |
125 | are modified, we must also specify them as outputs, or gcc | |
126 | will assume they contain their original values. */ | |
127 | : "=r" (sum), "=r" (iph), "=r" (ihl) | |
128 | : "1" (iph), "2" (ihl) | |
129 | : "memory"); | |
abf419b8 | 130 | return (__force __sum16)sum; |
1da177e4 LT |
131 | } |
132 | ||
133 | static inline unsigned add32_with_carry(unsigned a, unsigned b) | |
134 | { | |
135 | asm("addl %2,%0\n\t" | |
136 | "adcl $0,%0" | |
137 | : "=r" (a) | |
138 | : "0" (a), "r" (b)); | |
139 | return a; | |
140 | } | |
141 | ||
abf419b8 | 142 | extern __sum16 ip_compute_csum(const void *buff, int len); |
1da177e4 | 143 | |
ba9950c8 | 144 | #endif |