Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This file is subject to the terms and conditions of the GNU General Public
0003  * License.  See the file "COPYING" in the main directory of this archive
0004  * for more details.
0005  *
0006  * Copyright (C) 1995, 96, 97, 98, 99, 2001 by Ralf Baechle
0007  * Copyright (C) 1999 Silicon Graphics, Inc.
0008  * Copyright (C) 2001 Thiemo Seufer.
0009  * Copyright (C) 2002 Maciej W. Rozycki
0010  * Copyright (C) 2014 Imagination Technologies Ltd.
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  * computes the checksum of a memory block at buff, length len,
0025  * and adds in "sum" (32-bit)
0026  *
0027  * returns a 32-bit number suitable for feeding into itself
0028  * or csum_tcpudp_magic
0029  *
0030  * this function must be called with even lengths, except
0031  * for the last fragment, which may be odd
0032  *
0033  * it's best to have buff aligned on a 32-bit boundary
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  * Copy and checksum to user
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  * the same as csum_partial, but copies from user space (but on MIPS
0065  * we have just one address space, so this is identical to the above)
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  *  Fold a partial checksum without adding pseudo headers
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  *  This is a version of ip_compute_csum() optimized for IP headers,
0092  *  which always checksum on 4 octet boundaries.
0093  *
0094  *  By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
0095  *  Arnt Gulbrandsen.
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      * We know PROTO + LEN has the sign bit clear, so cast to a signed
0146      * type to avoid an extraneous zero-extension where TMP is 64-bit.
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  * this routine is used for miscellaneous IP-like checksums, mainly
0175  * in icmp.c
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 /* CONFIG_GENERIC_CSUM */
0251 
0252 #endif /* _ASM_CHECKSUM_H */