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