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
2014-05-03 03:28:03 +04:00
# ifndef HAVE_ARCH_CSUM_ADD
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
}
2014-05-03 03:28:03 +04:00
# endif
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 ) ;
}
2014-03-24 06:51:36 +04:00
static inline __sum16 csum16_add ( __sum16 csum , __be16 addend )
{
u16 res = ( __force u16 ) csum ;
res + = ( __force u16 ) addend ;
return ( __force __sum16 ) ( res + ( res < ( __force u16 ) addend ) ) ;
}
static inline __sum16 csum16_sub ( __sum16 csum , __be16 addend )
{
return csum16_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
}
2013-10-30 14:50:51 +04:00
static inline __wsum
csum_block_add_ext ( __wsum csum , __wsum csum2 , int offset , int len )
{
return csum_block_add ( csum , csum2 , offset ) ;
}
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
}
2013-11-04 20:10:25 +04:00
static inline __wsum csum_partial_ext ( const void * buff , int len , __wsum sum )
{
return csum_partial ( buff , len , sum ) ;
}
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 )
{
2014-09-23 12:54:32 +04:00
* sum = csum_fold ( csum_add ( csum_sub ( ~ csum_unfold ( * sum ) , from ) , to ) ) ;
2007-11-29 17:14:30 +03:00
}
2014-03-24 06:51:36 +04:00
/* Implements RFC 1624 (Incremental Internet Checksum)
* 3. Discussion states :
* HC ' = ~ ( ~ HC + ~ m + m ' )
* m : old value of a 16 bit field
* m ' : new value of a 16 bit field
*/
static inline void csum_replace2 ( __sum16 * sum , __be16 old , __be16 new )
2007-11-29 17:14:30 +03:00
{
2014-03-24 06:51:36 +04:00
* sum = ~ csum16_add ( csum16_sub ( ~ ( * sum ) , old ) , new ) ;
2007-11-29 17:14:30 +03:00
}
struct sk_buff ;
2013-08-01 04:31:38 +04:00
void inet_proto_csum_replace4 ( __sum16 * sum , struct sk_buff * skb ,
__be32 from , __be32 to , int pseudohdr ) ;
void inet_proto_csum_replace16 ( __sum16 * sum , struct sk_buff * skb ,
const __be32 * from , const __be32 * to ,
int pseudohdr ) ;
2007-11-29 17:14:30 +03:00
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 ) ;
}
2014-11-25 22:21:19 +03:00
static inline __wsum remcsum_adjust ( void * ptr , __wsum csum ,
int start , int offset )
{
__sum16 * psum = ( __sum16 * ) ( ptr + offset ) ;
__wsum delta ;
/* Subtract out checksum up to start */
csum = csum_sub ( csum , csum_partial ( ptr , start , 0 ) ) ;
/* Set derived checksum in packet */
delta = csum_sub ( csum_fold ( csum ) , * psum ) ;
* psum = csum_fold ( csum ) ;
return delta ;
}
2005-04-17 02:20:36 +04:00
# endif