2005-04-17 02:20:36 +04:00
/*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 1995 , 96 , 97 , 98 , 99 , 2001 by Ralf Baechle
* Copyright ( C ) 1999 Silicon Graphics , Inc .
* Copyright ( C ) 2001 Thiemo Seufer .
* Copyright ( C ) 2002 Maciej W . Rozycki
2013-12-12 20:21:00 +04:00
* Copyright ( C ) 2014 Imagination Technologies Ltd .
2005-04-17 02:20:36 +04:00
*/
# ifndef _ASM_CHECKSUM_H
# define _ASM_CHECKSUM_H
2014-11-13 14:25:27 +03:00
# ifdef CONFIG_GENERIC_CSUM
# include <asm-generic/checksum.h>
# else
2005-04-17 02:20:36 +04:00
# include <linux/in6.h>
# include <asm/uaccess.h>
/*
* computes the checksum of a memory block at buff , length len ,
* and adds in " sum " ( 32 - bit )
*
* returns a 32 - bit number suitable for feeding into itself
* or csum_tcpudp_magic
*
* this function must be called with even lengths , except
* for the last fragment , which may be odd
*
* it ' s best to have buff aligned on a 32 - bit boundary
*/
2006-11-15 08:18:18 +03:00
__wsum csum_partial ( const void * buff , int len , __wsum sum ) ;
2005-04-17 02:20:36 +04:00
2013-12-12 20:21:00 +04:00
__wsum __csum_partial_copy_kernel ( const void * src , void * dst ,
int len , __wsum sum , int * err_ptr ) ;
__wsum __csum_partial_copy_from_user ( const void * src , void * dst ,
int len , __wsum sum , int * err_ptr ) ;
__wsum __csum_partial_copy_to_user ( const void * src , void * dst ,
int len , __wsum sum , int * err_ptr ) ;
2005-04-17 02:20:36 +04:00
/*
* this is a new version of the above that records errors it finds in * errp ,
* but continues and zeros the rest of the buffer .
*/
2006-12-12 19:22:06 +03:00
static inline
__wsum csum_partial_copy_from_user ( const void __user * src , void * dst , int len ,
__wsum sum , int * err_ptr )
{
2009-04-28 16:17:54 +04:00
might_fault ( ) ;
2013-12-19 21:09:17 +04:00
if ( segment_eq ( get_fs ( ) , get_ds ( ) ) )
return __csum_partial_copy_kernel ( ( __force void * ) src , dst ,
len , sum , err_ptr ) ;
else
return __csum_partial_copy_from_user ( ( __force void * ) src , dst ,
len , sum , err_ptr ) ;
2006-12-12 19:22:06 +03:00
}
2005-04-17 02:20:36 +04:00
2013-12-17 13:30:13 +04:00
# define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
static inline
__wsum csum_and_copy_from_user ( const void __user * src , void * dst ,
int len , __wsum sum , int * err_ptr )
{
if ( access_ok ( VERIFY_READ , src , len ) )
return csum_partial_copy_from_user ( src , dst , len , sum ,
err_ptr ) ;
if ( len )
* err_ptr = - EFAULT ;
return sum ;
}
2005-04-17 02:20:36 +04:00
/*
* Copy and checksum to user
*/
# define HAVE_CSUM_COPY_USER
2006-12-12 19:22:06 +03:00
static inline
__wsum csum_and_copy_to_user ( const void * src , void __user * dst , int len ,
__wsum sum , int * err_ptr )
2005-04-17 02:20:36 +04:00
{
2009-04-28 16:17:54 +04:00
might_fault ( ) ;
2013-12-19 21:09:17 +04:00
if ( access_ok ( VERIFY_WRITE , dst , len ) ) {
if ( segment_eq ( get_fs ( ) , get_ds ( ) ) )
return __csum_partial_copy_kernel ( src ,
( __force void * ) dst ,
len , sum , err_ptr ) ;
else
return __csum_partial_copy_to_user ( src ,
( __force void * ) dst ,
len , sum , err_ptr ) ;
}
2006-12-12 19:22:06 +03:00
if ( len )
2005-04-17 02:20:36 +04:00
* err_ptr = - EFAULT ;
2006-12-12 19:22:06 +03:00
return ( __force __wsum ) - 1 ; /* invalid checksum */
2005-04-17 02:20:36 +04:00
}
/*
* the same as csum_partial , but copies from user space ( but on MIPS
* we have just one address space , so this is identical to the above )
*/
2006-11-15 08:18:18 +03:00
__wsum csum_partial_copy_nocheck ( const void * src , void * dst ,
int len , __wsum sum ) ;
2014-12-18 01:03:46 +03:00
# define csum_partial_copy_nocheck csum_partial_copy_nocheck
2005-04-17 02:20:36 +04:00
/*
* Fold a partial checksum without adding pseudo headers
*/
2014-12-17 16:06:00 +03:00
static inline __sum16 csum_fold ( __wsum csum )
2005-04-17 02:20:36 +04:00
{
2014-12-17 16:06:00 +03:00
u32 sum = ( __force u32 ) csum ; ;
2005-04-17 02:20:36 +04:00
2014-12-17 16:06:00 +03:00
sum + = ( sum < < 16 ) ;
csum = ( sum < csum ) ;
sum > > = 16 ;
sum + = csum ;
return ( __force __sum16 ) ~ sum ;
2005-04-17 02:20:36 +04:00
}
2014-12-18 01:03:46 +03:00
# define csum_fold csum_fold
2005-04-17 02:20:36 +04:00
/*
* This is a version of ip_compute_csum ( ) optimized for IP headers ,
* which always checksum on 4 octet boundaries .
*
* By Jorge Cwik < jorge @ laser . satlink . net > , adapted for linux by
* Arnt Gulbrandsen .
*/
2006-11-15 08:18:18 +03:00
static inline __sum16 ip_fast_csum ( const void * iph , unsigned int ihl )
2005-04-17 02:20:36 +04:00
{
2006-11-15 08:18:18 +03:00
const unsigned int * word = iph ;
const unsigned int * stop = word + ihl ;
2005-04-17 02:20:36 +04:00
unsigned int csum ;
int carry ;
csum = word [ 0 ] ;
csum + = word [ 1 ] ;
carry = ( csum < word [ 1 ] ) ;
csum + = carry ;
csum + = word [ 2 ] ;
carry = ( csum < word [ 2 ] ) ;
csum + = carry ;
csum + = word [ 3 ] ;
carry = ( csum < word [ 3 ] ) ;
csum + = carry ;
word + = 4 ;
do {
csum + = * word ;
carry = ( csum < * word ) ;
csum + = carry ;
word + + ;
} while ( word ! = stop ) ;
return csum_fold ( csum ) ;
}
2014-12-18 01:03:46 +03:00
# define ip_fast_csum ip_fast_csum
2005-04-17 02:20:36 +04:00
2006-11-15 08:18:18 +03:00
static inline __wsum csum_tcpudp_nofold ( __be32 saddr ,
__be32 daddr , unsigned short len , unsigned short proto ,
__wsum sum )
2005-04-17 02:20:36 +04:00
{
__asm__ (
2005-07-08 13:17:05 +04:00
" .set push # csum_tcpudp_nofold \n "
" .set noat \n "
2005-09-04 02:56:16 +04:00
# ifdef CONFIG_32BIT
2005-07-08 13:17:05 +04:00
" addu %0, %2 \n "
" sltu $1, %0, %2 \n "
" addu %0, $1 \n "
2005-04-17 02:20:36 +04:00
2005-07-08 13:17:05 +04:00
" addu %0, %3 \n "
" sltu $1, %0, %3 \n "
" addu %0, $1 \n "
2005-04-17 02:20:36 +04:00
2005-07-08 13:17:05 +04:00
" addu %0, %4 \n "
" sltu $1, %0, %4 \n "
" addu %0, $1 \n "
2005-04-17 02:20:36 +04:00
# endif
2005-09-04 02:56:16 +04:00
# ifdef CONFIG_64BIT
2005-07-08 13:17:05 +04:00
" daddu %0, %2 \n "
" daddu %0, %3 \n "
" daddu %0, %4 \n "
" dsll32 $1, %0, 0 \n "
" daddu %0, $1 \n "
2005-09-20 14:56:26 +04:00
" dsra32 %0, %0, 0 \n "
2005-04-17 02:20:36 +04:00
# endif
2005-07-08 13:17:05 +04:00
" .set pop "
2005-04-17 02:20:36 +04:00
: " =r " ( sum )
2007-01-24 09:43:34 +03:00
: " 0 " ( ( __force unsigned long ) daddr ) ,
" r " ( ( __force unsigned long ) saddr ) ,
2005-04-17 02:20:36 +04:00
# ifdef __MIPSEL__
2006-11-15 08:18:18 +03:00
" r " ( ( proto + len ) < < 8 ) ,
2005-04-17 02:20:36 +04:00
# else
2006-11-15 08:18:18 +03:00
" r " ( proto + len ) ,
2005-04-17 02:20:36 +04:00
# endif
2007-04-18 18:39:41 +04:00
" r " ( ( __force unsigned long ) sum ) ) ;
2005-04-17 02:20:36 +04:00
return sum ;
}
2014-12-18 01:03:46 +03:00
# define csum_tcpudp_nofold csum_tcpudp_nofold
2005-04-17 02:20:36 +04:00
/*
* this routine is used for miscellaneous IP - like checksums , mainly
* in icmp . c
*/
2006-11-15 08:18:18 +03:00
static inline __sum16 ip_compute_csum ( const void * buff , int len )
2005-04-17 02:20:36 +04:00
{
return csum_fold ( csum_partial ( buff , len , 0 ) ) ;
}
# define _HAVE_ARCH_IPV6_CSUM
2006-11-15 08:18:18 +03:00
static __inline__ __sum16 csum_ipv6_magic ( const struct in6_addr * saddr ,
2013-01-22 15:59:30 +04:00
const struct in6_addr * daddr ,
2006-11-15 08:18:18 +03:00
__u32 len , unsigned short proto ,
__wsum sum )
2005-04-17 02:20:36 +04:00
{
2015-02-24 18:25:10 +03:00
__wsum tmp ;
2005-04-17 02:20:36 +04:00
__asm__ (
2005-07-08 13:17:05 +04:00
" .set push # csum_ipv6_magic \n "
" .set noreorder \n "
" .set noat \n "
" addu %0, %5 # proto (long in network byte order) \n "
" sltu $1, %0, %5 \n "
" addu %0, $1 \n "
" addu %0, %6 # csum \n "
" sltu $1, %0, %6 \n "
" lw %1, 0(%2) # four words source address \n "
" addu %0, $1 \n "
" addu %0, %1 \n "
" sltu $1, %0, %1 \n "
" lw %1, 4(%2) \n "
" addu %0, $1 \n "
" addu %0, %1 \n "
" sltu $1, %0, %1 \n "
" lw %1, 8(%2) \n "
" addu %0, $1 \n "
" addu %0, %1 \n "
" sltu $1, %0, %1 \n "
" lw %1, 12(%2) \n "
" addu %0, $1 \n "
" addu %0, %1 \n "
" sltu $1, %0, %1 \n "
" lw %1, 0(%3) \n "
" addu %0, $1 \n "
" addu %0, %1 \n "
" sltu $1, %0, %1 \n "
" lw %1, 4(%3) \n "
" addu %0, $1 \n "
" addu %0, %1 \n "
" sltu $1, %0, %1 \n "
" lw %1, 8(%3) \n "
" addu %0, $1 \n "
" addu %0, %1 \n "
" sltu $1, %0, %1 \n "
" lw %1, 12(%3) \n "
" addu %0, $1 \n "
" addu %0, %1 \n "
" sltu $1, %0, %1 \n "
" addu %0, $1 # Add final carry \n "
" .set pop "
2015-02-24 18:25:10 +03:00
: " =&r " ( sum ) , " =&r " ( tmp )
2005-04-17 02:20:36 +04:00
: " r " ( saddr ) , " r " ( daddr ) ,
2015-02-24 18:25:10 +03:00
" 0 " ( htonl ( len ) ) , " r " ( htonl ( proto ) ) , " r " ( sum ) ) ;
2005-04-17 02:20:36 +04:00
return csum_fold ( sum ) ;
}
2014-12-18 01:03:46 +03:00
# include <asm-generic/checksum.h>
2014-11-13 14:25:27 +03:00
# endif /* CONFIG_GENERIC_CSUM */
2014-12-18 01:03:46 +03:00
2005-04-17 02:20:36 +04:00
# endif /* _ASM_CHECKSUM_H */