2005-04-17 02:20:36 +04:00
/*
* INET An implementation of the TCP / IP protocol suite for the LINUX
* operating system . INET is implemented using the BSD Socket
* interface as the means of communication with the user level .
*
* Checksumming functions for IP , TCP , UDP and so on
*
* Authors : Jorge Cwik , < jorge @ laser . satlink . net >
* Arnt Gulbrandsen , < agulbra @ nvg . unit . no >
* Borrows very liberally from tcp . c and ip . c , see those
* files for more names .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# ifndef _CHECKSUM_H
# define _CHECKSUM_H
# include <linux/errno.h>
# include <asm/types.h>
# include <asm/byteorder.h>
# include <asm/uaccess.h>
# include <asm/checksum.h>
# ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
static inline
2006-11-15 08:23:59 +03:00
__wsum csum_and_copy_from_user ( const void __user * src , void * dst ,
int len , __wsum sum , int * err_ptr )
2005-04-17 02:20:36 +04:00
{
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 ;
}
# endif
# ifndef HAVE_CSUM_COPY_USER
2006-11-15 08:23:59 +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
{
sum = csum_partial ( src , len , sum ) ;
if ( access_ok ( VERIFY_WRITE , dst , len ) ) {
if ( copy_to_user ( dst , src , len ) = = 0 )
return sum ;
}
if ( len )
* err_ptr = - EFAULT ;
2006-11-15 08:23:59 +03:00
return ( __force __wsum ) - 1 ; /* invalid checksum */
2005-04-17 02:20:36 +04:00
}
# endif
2006-11-15 08:23:59 +03:00
static inline __wsum csum_add ( __wsum csum , __wsum addend )
2005-04-17 02:20:36 +04:00
{
2006-11-15 08:23:59 +03:00
u32 res = ( __force u32 ) csum ;
res + = ( __force u32 ) addend ;
return ( __force __wsum ) ( res + ( res < ( __force u32 ) addend ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-15 08:23:59 +03:00
static inline __wsum csum_sub ( __wsum csum , __wsum addend )
2005-04-17 02:20:36 +04:00
{
return csum_add ( csum , ~ addend ) ;
}
2006-11-15 08:23:59 +03:00
static inline __wsum
csum_block_add ( __wsum csum , __wsum csum2 , int offset )
2005-04-17 02:20:36 +04:00
{
2006-11-15 08:23:59 +03:00
u32 sum = ( __force u32 ) csum2 ;
2005-04-17 02:20:36 +04:00
if ( offset & 1 )
2006-11-15 08:23:59 +03:00
sum = ( ( sum & 0xFF00FF ) < < 8 ) + ( ( sum > > 8 ) & 0xFF00FF ) ;
return csum_add ( csum , ( __force __wsum ) sum ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-15 08:23:59 +03:00
static inline __wsum
csum_block_sub ( __wsum csum , __wsum csum2 , int offset )
2005-04-17 02:20:36 +04:00
{
2006-11-15 08:23:59 +03:00
u32 sum = ( __force u32 ) csum2 ;
2005-04-17 02:20:36 +04:00
if ( offset & 1 )
2006-11-15 08:23:59 +03:00
sum = ( ( sum & 0xFF00FF ) < < 8 ) + ( ( sum > > 8 ) & 0xFF00FF ) ;
return csum_sub ( csum , ( __force __wsum ) sum ) ;
}
static inline __wsum csum_unfold ( __sum16 n )
{
return ( __force __wsum ) n ;
2005-04-17 02:20:36 +04:00
}
2006-11-16 13:36:50 +03:00
# define CSUM_MANGLED_0 ((__force __sum16)0xffff)
2007-11-29 17:14:30 +03:00
static inline void csum_replace4 ( __sum16 * sum , __be32 from , __be32 to )
{
__be32 diff [ ] = { ~ from , to } ;
2008-11-20 02:44:53 +03:00
* sum = csum_fold ( csum_partial ( diff , sizeof ( diff ) , ~ csum_unfold ( * sum ) ) ) ;
2007-11-29 17:14:30 +03:00
}
static inline void csum_replace2 ( __sum16 * sum , __be16 from , __be16 to )
{
csum_replace4 ( sum , ( __force __be32 ) from , ( __force __be32 ) to ) ;
}
struct sk_buff ;
extern void inet_proto_csum_replace4 ( __sum16 * sum , struct sk_buff * skb ,
__be32 from , __be32 to , int pseudohdr ) ;
static inline void inet_proto_csum_replace2 ( __sum16 * sum , struct sk_buff * skb ,
__be16 from , __be16 to ,
int pseudohdr )
{
inet_proto_csum_replace4 ( sum , skb , ( __force __be32 ) from ,
( __force __be32 ) to , pseudohdr ) ;
}
2005-04-17 02:20:36 +04:00
# endif