2013-01-08 00:52:40 +04:00
# include <net/ip.h>
# include <net/udp.h>
# include <net/udplite.h>
# include <asm/checksum.h>
# ifndef _HAVE_ARCH_IPV6_CSUM
__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 csum )
2013-01-08 00:52:40 +04:00
{
int carry ;
__u32 ulen ;
__u32 uproto ;
__u32 sum = ( __force u32 ) csum ;
sum + = ( __force u32 ) saddr - > s6_addr32 [ 0 ] ;
carry = ( sum < ( __force u32 ) saddr - > s6_addr32 [ 0 ] ) ;
sum + = carry ;
sum + = ( __force u32 ) saddr - > s6_addr32 [ 1 ] ;
carry = ( sum < ( __force u32 ) saddr - > s6_addr32 [ 1 ] ) ;
sum + = carry ;
sum + = ( __force u32 ) saddr - > s6_addr32 [ 2 ] ;
carry = ( sum < ( __force u32 ) saddr - > s6_addr32 [ 2 ] ) ;
sum + = carry ;
sum + = ( __force u32 ) saddr - > s6_addr32 [ 3 ] ;
carry = ( sum < ( __force u32 ) saddr - > s6_addr32 [ 3 ] ) ;
sum + = carry ;
sum + = ( __force u32 ) daddr - > s6_addr32 [ 0 ] ;
carry = ( sum < ( __force u32 ) daddr - > s6_addr32 [ 0 ] ) ;
sum + = carry ;
sum + = ( __force u32 ) daddr - > s6_addr32 [ 1 ] ;
carry = ( sum < ( __force u32 ) daddr - > s6_addr32 [ 1 ] ) ;
sum + = carry ;
sum + = ( __force u32 ) daddr - > s6_addr32 [ 2 ] ;
carry = ( sum < ( __force u32 ) daddr - > s6_addr32 [ 2 ] ) ;
sum + = carry ;
sum + = ( __force u32 ) daddr - > s6_addr32 [ 3 ] ;
carry = ( sum < ( __force u32 ) daddr - > s6_addr32 [ 3 ] ) ;
sum + = carry ;
ulen = ( __force u32 ) htonl ( ( __u32 ) len ) ;
sum + = ulen ;
carry = ( sum < ulen ) ;
sum + = carry ;
uproto = ( __force u32 ) htonl ( proto ) ;
sum + = uproto ;
carry = ( sum < uproto ) ;
sum + = carry ;
return csum_fold ( ( __force __wsum ) sum ) ;
}
EXPORT_SYMBOL ( csum_ipv6_magic ) ;
# endif
int udp6_csum_init ( struct sk_buff * skb , struct udphdr * uh , int proto )
{
int err ;
UDP_SKB_CB ( skb ) - > partial_cov = 0 ;
UDP_SKB_CB ( skb ) - > cscov = skb - > len ;
if ( proto = = IPPROTO_UDPLITE ) {
err = udplite_checksum_init ( skb , uh ) ;
if ( err )
return err ;
}
2014-05-03 03:29:58 +04:00
/* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels)
* we accept a checksum of zero here . When we find the socket
* for the UDP packet we ' ll check if that socket allows zero checksum
* for IPv6 ( set by socket option ) .
2016-06-11 22:15:37 +03:00
*
* Note , we are only interested in ! = 0 or = = 0 , thus the
* force to int .
2014-05-03 03:29:58 +04:00
*/
2016-06-11 22:15:37 +03:00
return ( __force int ) skb_checksum_init_zero_check ( skb , proto , uh - > check ,
ip6_compute_pseudo ) ;
2013-01-08 00:52:40 +04:00
}
EXPORT_SYMBOL ( udp6_csum_init ) ;
2014-06-05 04:19:48 +04:00
/* Function to set UDP checksum for an IPv6 UDP packet. This is intended
* for the simple case like when setting the checksum for a UDP tunnel .
*/
void udp6_set_csum ( bool nocheck , struct sk_buff * skb ,
const struct in6_addr * saddr ,
const struct in6_addr * daddr , int len )
{
struct udphdr * uh = udp_hdr ( skb ) ;
if ( nocheck )
uh - > check = 0 ;
else if ( skb_is_gso ( skb ) )
uh - > check = ~ udp_v6_check ( len , saddr , daddr , 0 ) ;
2016-02-11 23:48:04 +03:00
else if ( skb - > ip_summed = = CHECKSUM_PARTIAL ) {
uh - > check = 0 ;
uh - > check = udp_v6_check ( len , saddr , daddr , lco_csum ( skb ) ) ;
if ( uh - > check = = 0 )
uh - > check = CSUM_MANGLED_0 ;
2016-02-11 23:49:40 +03:00
} else {
2014-06-05 04:19:48 +04:00
skb - > ip_summed = CHECKSUM_PARTIAL ;
skb - > csum_start = skb_transport_header ( skb ) - skb - > head ;
skb - > csum_offset = offsetof ( struct udphdr , check ) ;
uh - > check = ~ udp_v6_check ( len , saddr , daddr , 0 ) ;
}
}
EXPORT_SYMBOL ( udp6_set_csum ) ;