Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2002, 2003 Andi Kleen, SuSE Labs.
0004  *
0005  * Wrappers of assembly checksum functions for x86-64.
0006  */
0007 #include <asm/checksum.h>
0008 #include <linux/export.h>
0009 #include <linux/uaccess.h>
0010 #include <asm/smap.h>
0011 
0012 /**
0013  * csum_and_copy_from_user - Copy and checksum from user space.
0014  * @src: source address (user space)
0015  * @dst: destination address
0016  * @len: number of bytes to be copied.
0017  * @isum: initial sum that is added into the result (32bit unfolded)
0018  * @errp: set to -EFAULT for an bad source address.
0019  *
0020  * Returns an 32bit unfolded checksum of the buffer.
0021  * src and dst are best aligned to 64bits.
0022  */
0023 __wsum
0024 csum_and_copy_from_user(const void __user *src, void *dst, int len)
0025 {
0026     __wsum sum;
0027 
0028     might_sleep();
0029     if (!user_access_begin(src, len))
0030         return 0;
0031     sum = csum_partial_copy_generic((__force const void *)src, dst, len);
0032     user_access_end();
0033     return sum;
0034 }
0035 
0036 /**
0037  * csum_and_copy_to_user - Copy and checksum to user space.
0038  * @src: source address
0039  * @dst: destination address (user space)
0040  * @len: number of bytes to be copied.
0041  * @isum: initial sum that is added into the result (32bit unfolded)
0042  * @errp: set to -EFAULT for an bad destination address.
0043  *
0044  * Returns an 32bit unfolded checksum of the buffer.
0045  * src and dst are best aligned to 64bits.
0046  */
0047 __wsum
0048 csum_and_copy_to_user(const void *src, void __user *dst, int len)
0049 {
0050     __wsum sum;
0051 
0052     might_sleep();
0053     if (!user_access_begin(dst, len))
0054         return 0;
0055     sum = csum_partial_copy_generic(src, (void __force *)dst, len);
0056     user_access_end();
0057     return sum;
0058 }
0059 
0060 /**
0061  * csum_partial_copy_nocheck - Copy and checksum.
0062  * @src: source address
0063  * @dst: destination address
0064  * @len: number of bytes to be copied.
0065  * @sum: initial sum that is added into the result (32bit unfolded)
0066  *
0067  * Returns an 32bit unfolded checksum of the buffer.
0068  */
0069 __wsum
0070 csum_partial_copy_nocheck(const void *src, void *dst, int len)
0071 {
0072     return csum_partial_copy_generic(src, dst, len);
0073 }
0074 EXPORT_SYMBOL(csum_partial_copy_nocheck);
0075 
0076 __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
0077             const struct in6_addr *daddr,
0078             __u32 len, __u8 proto, __wsum sum)
0079 {
0080     __u64 rest, sum64;
0081 
0082     rest = (__force __u64)htonl(len) + (__force __u64)htons(proto) +
0083         (__force __u64)sum;
0084 
0085     asm("   addq (%[saddr]),%[sum]\n"
0086         "   adcq 8(%[saddr]),%[sum]\n"
0087         "   adcq (%[daddr]),%[sum]\n"
0088         "   adcq 8(%[daddr]),%[sum]\n"
0089         "   adcq $0,%[sum]\n"
0090 
0091         : [sum] "=r" (sum64)
0092         : "[sum]" (rest), [saddr] "r" (saddr), [daddr] "r" (daddr));
0093 
0094     return csum_fold(
0095            (__force __wsum)add32_with_carry(sum64 & 0xffffffff, sum64>>32));
0096 }
0097 EXPORT_SYMBOL(csum_ipv6_magic);