2019-05-28 20:10:25 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-02-17 18:48:25 +03:00
/*
* Copyright 2002 , 2003 Andi Kleen , SuSE Labs .
2008-02-17 16:56:50 +03:00
*
2005-04-17 02:20:36 +04:00
* Wrappers of assembly checksum functions for x86 - 64.
*/
# include <asm/checksum.h>
2016-07-14 03:18:57 +03:00
# include <linux/export.h>
2016-07-14 23:22:57 +03:00
# include <linux/uaccess.h>
2013-08-31 02:43:03 +04:00
# include <asm/smap.h>
2005-04-17 02:20:36 +04:00
2008-02-17 16:56:50 +03:00
/**
2020-02-17 00:50:00 +03:00
* csum_and_copy_from_user - Copy and checksum from user space .
2008-02-17 16:56:50 +03:00
* @ src : source address ( user space )
2005-04-17 02:20:36 +04:00
* @ dst : destination address
* @ len : number of bytes to be copied .
2008-02-17 16:56:50 +03:00
*
2005-04-17 02:20:36 +04:00
* Returns an 32 bit unfolded checksum of the buffer .
2008-02-17 16:56:50 +03:00
* src and dst are best aligned to 64 bits .
*/
2006-11-15 08:20:08 +03:00
__wsum
2020-07-20 04:56:07 +03:00
csum_and_copy_from_user ( const void __user * src , void * dst , int len )
2008-02-17 16:56:50 +03:00
{
2020-07-20 04:56:07 +03:00
__wsum sum ;
2020-07-11 07:27:49 +03:00
2005-04-17 02:20:36 +04:00
might_sleep ( ) ;
2020-02-16 22:56:36 +03:00
if ( ! user_access_begin ( src , len ) )
2020-07-11 07:27:49 +03:00
return 0 ;
2020-07-20 04:56:07 +03:00
sum = csum_partial_copy_generic ( ( __force const void * ) src , dst , len ) ;
2020-02-16 22:56:36 +03:00
user_access_end ( ) ;
2020-07-20 04:56:07 +03:00
return sum ;
2008-02-17 16:56:50 +03:00
}
2005-04-17 02:20:36 +04:00
2008-02-17 16:56:50 +03:00
/**
2020-03-19 20:19:34 +03:00
* csum_and_copy_to_user - Copy and checksum to user space .
2005-04-17 02:20:36 +04:00
* @ src : source address
* @ dst : destination address ( user space )
* @ len : number of bytes to be copied .
2008-02-17 16:56:50 +03:00
*
2005-04-17 02:20:36 +04:00
* Returns an 32 bit unfolded checksum of the buffer .
* src and dst are best aligned to 64 bits .
2008-02-17 16:56:50 +03:00
*/
2006-11-15 08:20:08 +03:00
__wsum
2020-07-20 04:56:07 +03:00
csum_and_copy_to_user ( const void * src , void __user * dst , int len )
2008-02-17 16:56:50 +03:00
{
2020-07-20 04:56:07 +03:00
__wsum sum ;
2013-08-31 02:43:03 +04:00
2005-04-17 02:20:36 +04:00
might_sleep ( ) ;
2020-07-11 07:27:49 +03:00
if ( ! user_access_begin ( dst , len ) )
2008-02-17 16:56:50 +03:00
return 0 ;
2020-07-20 04:56:07 +03:00
sum = csum_partial_copy_generic ( src , ( void __force * ) dst , len ) ;
2020-02-16 22:56:36 +03:00
user_access_end ( ) ;
2020-07-20 04:56:07 +03:00
return sum ;
2008-02-17 16:56:50 +03:00
}
2005-04-17 02:20:36 +04:00
2008-02-17 16:56:50 +03:00
/**
2005-04-17 02:20:36 +04:00
* csum_partial_copy_nocheck - Copy and checksum .
* @ src : source address
* @ dst : destination address
* @ len : number of bytes to be copied .
2008-02-17 16:56:50 +03:00
*
2005-04-17 02:20:36 +04:00
* Returns an 32 bit unfolded checksum of the buffer .
2008-02-17 16:56:50 +03:00
*/
2006-11-15 08:20:08 +03:00
__wsum
2020-07-11 07:12:07 +03:00
csum_partial_copy_nocheck ( const void * src , void * dst , int len )
2008-02-17 16:56:50 +03:00
{
2020-07-20 04:56:07 +03:00
return csum_partial_copy_generic ( src , dst , len ) ;
2008-02-17 16:56:50 +03:00
}
2006-06-26 15:59:44 +04:00
EXPORT_SYMBOL ( csum_partial_copy_nocheck ) ;
2005-04-17 02:20:36 +04:00
2006-11-15 08:20:08 +03:00
__sum16 csum_ipv6_magic ( const struct in6_addr * saddr ,
const struct in6_addr * daddr ,
2016-03-12 01:05:41 +03:00
__u32 len , __u8 proto , __wsum sum )
2005-04-17 02:20:36 +04:00
{
__u64 rest , sum64 ;
2008-02-17 16:56:50 +03:00
2006-11-15 08:20:08 +03:00
rest = ( __force __u64 ) htonl ( len ) + ( __force __u64 ) htons ( proto ) +
( __force __u64 ) sum ;
2008-02-17 18:48:25 +03:00
asm ( " addq (%[saddr]),%[sum] \n "
" adcq 8(%[saddr]),%[sum] \n "
" adcq (%[daddr]),%[sum] \n "
" adcq 8(%[daddr]),%[sum] \n "
" adcq $0,%[sum] \n "
2008-02-17 16:56:50 +03:00
: [ sum ] " =r " ( sum64 )
: " [sum] " ( rest ) , [ saddr ] " r " ( saddr ) , [ daddr ] " r " ( daddr ) ) ;
2005-04-17 02:20:36 +04:00
2008-02-17 18:48:25 +03:00
return csum_fold (
( __force __wsum ) add32_with_carry ( sum64 & 0xffffffff , sum64 > > 32 ) ) ;
}
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( csum_ipv6_magic ) ;