0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef _ASM_CHECKSUM_H
0013 #define _ASM_CHECKSUM_H
0014
0015 #ifdef CONFIG_GENERIC_CSUM
0016 #include <asm-generic/checksum.h>
0017 #else
0018
0019 #include <linux/in6.h>
0020
0021 #include <linux/uaccess.h>
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 __wsum csum_partial(const void *buff, int len, __wsum sum);
0036
0037 __wsum __csum_partial_copy_from_user(const void __user *src, void *dst, int len);
0038 __wsum __csum_partial_copy_to_user(const void *src, void __user *dst, int len);
0039
0040 #define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
0041 static inline
0042 __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len)
0043 {
0044 might_fault();
0045 if (!access_ok(src, len))
0046 return 0;
0047 return __csum_partial_copy_from_user(src, dst, len);
0048 }
0049
0050
0051
0052
0053 #define HAVE_CSUM_COPY_USER
0054 static inline
0055 __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len)
0056 {
0057 might_fault();
0058 if (!access_ok(dst, len))
0059 return 0;
0060 return __csum_partial_copy_to_user(src, dst, len);
0061 }
0062
0063
0064
0065
0066
0067 #define _HAVE_ARCH_CSUM_AND_COPY
0068 __wsum __csum_partial_copy_nocheck(const void *src, void *dst, int len);
0069 static inline __wsum csum_partial_copy_nocheck(const void *src, void *dst, int len)
0070 {
0071 return __csum_partial_copy_nocheck(src, dst, len);
0072 }
0073
0074
0075
0076
0077 static inline __sum16 csum_fold(__wsum csum)
0078 {
0079 u32 sum = (__force u32)csum;
0080
0081 sum += (sum << 16);
0082 csum = (__force __wsum)(sum < (__force u32)csum);
0083 sum >>= 16;
0084 sum += (__force u32)csum;
0085
0086 return (__force __sum16)~sum;
0087 }
0088 #define csum_fold csum_fold
0089
0090
0091
0092
0093
0094
0095
0096
0097 static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
0098 {
0099 const unsigned int *word = iph;
0100 const unsigned int *stop = word + ihl;
0101 unsigned int csum;
0102 int carry;
0103
0104 csum = word[0];
0105 csum += word[1];
0106 carry = (csum < word[1]);
0107 csum += carry;
0108
0109 csum += word[2];
0110 carry = (csum < word[2]);
0111 csum += carry;
0112
0113 csum += word[3];
0114 carry = (csum < word[3]);
0115 csum += carry;
0116
0117 word += 4;
0118 do {
0119 csum += *word;
0120 carry = (csum < *word);
0121 csum += carry;
0122 word++;
0123 } while (word != stop);
0124
0125 return csum_fold(csum);
0126 }
0127 #define ip_fast_csum ip_fast_csum
0128
0129 static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
0130 __u32 len, __u8 proto,
0131 __wsum isum)
0132 {
0133 const unsigned int sh32 = IS_ENABLED(CONFIG_64BIT) ? 32 : 0;
0134 unsigned long sum = (__force unsigned long)daddr;
0135 unsigned long tmp;
0136 __u32 osum;
0137
0138 tmp = (__force unsigned long)saddr;
0139 sum += tmp;
0140
0141 if (IS_ENABLED(CONFIG_32BIT))
0142 sum += sum < tmp;
0143
0144
0145
0146
0147
0148 tmp = (__s32)(proto + len);
0149 tmp <<= IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN) ? 8 : 0;
0150 sum += tmp;
0151 if (IS_ENABLED(CONFIG_32BIT))
0152 sum += sum < tmp;
0153
0154 tmp = (__force unsigned long)isum;
0155 sum += tmp;
0156
0157 if (IS_ENABLED(CONFIG_32BIT)) {
0158 sum += sum < tmp;
0159 osum = sum;
0160 } else if (IS_ENABLED(CONFIG_64BIT)) {
0161 tmp = sum << sh32;
0162 sum += tmp;
0163 osum = sum < tmp;
0164 osum += sum >> sh32;
0165 } else {
0166 BUILD_BUG();
0167 }
0168
0169 return (__force __wsum)osum;
0170 }
0171 #define csum_tcpudp_nofold csum_tcpudp_nofold
0172
0173
0174
0175
0176
0177 static inline __sum16 ip_compute_csum(const void *buff, int len)
0178 {
0179 return csum_fold(csum_partial(buff, len, 0));
0180 }
0181
0182 #define _HAVE_ARCH_IPV6_CSUM
0183 static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
0184 const struct in6_addr *daddr,
0185 __u32 len, __u8 proto,
0186 __wsum sum)
0187 {
0188 __wsum tmp;
0189
0190 __asm__(
0191 " .set push # csum_ipv6_magic\n"
0192 " .set noreorder \n"
0193 " .set noat \n"
0194 " addu %0, %5 # proto (long in network byte order)\n"
0195 " sltu $1, %0, %5 \n"
0196 " addu %0, $1 \n"
0197
0198 " addu %0, %6 # csum\n"
0199 " sltu $1, %0, %6 \n"
0200 " lw %1, 0(%2) # four words source address\n"
0201 " addu %0, $1 \n"
0202 " addu %0, %1 \n"
0203 " sltu $1, %0, %1 \n"
0204
0205 " lw %1, 4(%2) \n"
0206 " addu %0, $1 \n"
0207 " addu %0, %1 \n"
0208 " sltu $1, %0, %1 \n"
0209
0210 " lw %1, 8(%2) \n"
0211 " addu %0, $1 \n"
0212 " addu %0, %1 \n"
0213 " sltu $1, %0, %1 \n"
0214
0215 " lw %1, 12(%2) \n"
0216 " addu %0, $1 \n"
0217 " addu %0, %1 \n"
0218 " sltu $1, %0, %1 \n"
0219
0220 " lw %1, 0(%3) \n"
0221 " addu %0, $1 \n"
0222 " addu %0, %1 \n"
0223 " sltu $1, %0, %1 \n"
0224
0225 " lw %1, 4(%3) \n"
0226 " addu %0, $1 \n"
0227 " addu %0, %1 \n"
0228 " sltu $1, %0, %1 \n"
0229
0230 " lw %1, 8(%3) \n"
0231 " addu %0, $1 \n"
0232 " addu %0, %1 \n"
0233 " sltu $1, %0, %1 \n"
0234
0235 " lw %1, 12(%3) \n"
0236 " addu %0, $1 \n"
0237 " addu %0, %1 \n"
0238 " sltu $1, %0, %1 \n"
0239
0240 " addu %0, $1 # Add final carry\n"
0241 " .set pop"
0242 : "=&r" (sum), "=&r" (tmp)
0243 : "r" (saddr), "r" (daddr),
0244 "0" (htonl(len)), "r" (htonl(proto)), "r" (sum));
0245
0246 return csum_fold(sum);
0247 }
0248
0249 #include <asm-generic/checksum.h>
0250 #endif
0251
0252 #endif