0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <linux/export.h>
0032 #include <net/checksum.h>
0033
0034 #include <asm/byteorder.h>
0035
0036 #ifndef do_csum
0037 static inline unsigned short from32to16(unsigned int x)
0038 {
0039
0040 x = (x & 0xffff) + (x >> 16);
0041
0042 x = (x & 0xffff) + (x >> 16);
0043 return x;
0044 }
0045
0046 static unsigned int do_csum(const unsigned char *buff, int len)
0047 {
0048 int odd;
0049 unsigned int result = 0;
0050
0051 if (len <= 0)
0052 goto out;
0053 odd = 1 & (unsigned long) buff;
0054 if (odd) {
0055 #ifdef __LITTLE_ENDIAN
0056 result += (*buff << 8);
0057 #else
0058 result = *buff;
0059 #endif
0060 len--;
0061 buff++;
0062 }
0063 if (len >= 2) {
0064 if (2 & (unsigned long) buff) {
0065 result += *(unsigned short *) buff;
0066 len -= 2;
0067 buff += 2;
0068 }
0069 if (len >= 4) {
0070 const unsigned char *end = buff + ((unsigned)len & ~3);
0071 unsigned int carry = 0;
0072 do {
0073 unsigned int w = *(unsigned int *) buff;
0074 buff += 4;
0075 result += carry;
0076 result += w;
0077 carry = (w > result);
0078 } while (buff < end);
0079 result += carry;
0080 result = (result & 0xffff) + (result >> 16);
0081 }
0082 if (len & 2) {
0083 result += *(unsigned short *) buff;
0084 buff += 2;
0085 }
0086 }
0087 if (len & 1)
0088 #ifdef __LITTLE_ENDIAN
0089 result += *buff;
0090 #else
0091 result += (*buff << 8);
0092 #endif
0093 result = from32to16(result);
0094 if (odd)
0095 result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
0096 out:
0097 return result;
0098 }
0099 #endif
0100
0101 #ifndef ip_fast_csum
0102
0103
0104
0105
0106 __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
0107 {
0108 return (__force __sum16)~do_csum(iph, ihl*4);
0109 }
0110 EXPORT_SYMBOL(ip_fast_csum);
0111 #endif
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125 __wsum csum_partial(const void *buff, int len, __wsum wsum)
0126 {
0127 unsigned int sum = (__force unsigned int)wsum;
0128 unsigned int result = do_csum(buff, len);
0129
0130
0131 result += sum;
0132 if (sum > result)
0133 result += 1;
0134 return (__force __wsum)result;
0135 }
0136 EXPORT_SYMBOL(csum_partial);
0137
0138
0139
0140
0141
0142 __sum16 ip_compute_csum(const void *buff, int len)
0143 {
0144 return (__force __sum16)~do_csum(buff, len);
0145 }
0146 EXPORT_SYMBOL(ip_compute_csum);
0147
0148 #ifndef csum_tcpudp_nofold
0149 static inline u32 from64to32(u64 x)
0150 {
0151
0152 x = (x & 0xffffffff) + (x >> 32);
0153
0154 x = (x & 0xffffffff) + (x >> 32);
0155 return (u32)x;
0156 }
0157
0158 __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
0159 __u32 len, __u8 proto, __wsum sum)
0160 {
0161 unsigned long long s = (__force u32)sum;
0162
0163 s += (__force u32)saddr;
0164 s += (__force u32)daddr;
0165 #ifdef __BIG_ENDIAN
0166 s += proto + len;
0167 #else
0168 s += (proto + len) << 8;
0169 #endif
0170 return (__force __wsum)from64to32(s);
0171 }
0172 EXPORT_SYMBOL(csum_tcpudp_nofold);
0173 #endif