2006-11-27 22:10:57 +03:00
/*
* Definitions for the UDP - Lite ( RFC 3828 ) code .
*/
# ifndef _UDPLITE_H
# define _UDPLITE_H
2006-11-15 12:09:32 +03:00
# include <net/ip6_checksum.h>
2006-11-27 22:10:57 +03:00
/* UDP-Lite socket options */
# define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */
# define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */
extern struct proto udplite_prot ;
2008-10-29 11:41:45 +03:00
extern struct udp_table udplite_table ;
2006-11-27 22:10:57 +03:00
/*
* Checksum computation is all in software , hence simpler getfrag .
*/
static __inline__ int udplite_getfrag ( void * from , char * to , int offset ,
int len , int odd , struct sk_buff * skb )
{
2014-11-24 21:23:40 +03:00
struct msghdr * msg = from ;
2016-11-04 01:17:31 +03:00
return copy_from_iter_full ( to , len , & msg - > msg_iter ) ? 0 : - EFAULT ;
2006-11-27 22:10:57 +03:00
}
/* Designate sk as UDP-Lite socket */
static inline int udplite_sk_init ( struct sock * sk )
{
2017-05-16 12:20:14 +03:00
udp_init_sock ( sk ) ;
2006-11-27 22:10:57 +03:00
udp_sk ( sk ) - > pcflag = UDPLITE_BIT ;
return 0 ;
}
/*
* Checksumming routines
*/
static inline int udplite_checksum_init ( struct sk_buff * skb , struct udphdr * uh )
{
u16 cscov ;
/* In UDPv4 a zero checksum means that the transmitter generated no
* checksum . UDP - Lite ( like IPv6 ) mandates checksums , hence packets
* with a zero checksum field are illegal . */
if ( uh - > check = = 0 ) {
2014-11-11 21:59:17 +03:00
net_dbg_ratelimited ( " UDPLite: zeroed checksum field \n " ) ;
2006-11-27 22:10:57 +03:00
return 1 ;
}
cscov = ntohs ( uh - > len ) ;
if ( cscov = = 0 ) /* Indicates that full coverage is required. */
2007-03-26 07:10:56 +04:00
;
2006-11-27 22:10:57 +03:00
else if ( cscov < 8 | | cscov > skb - > len ) {
/*
* Coverage length violates RFC 3828 : log and discard silently .
*/
2014-11-11 21:59:17 +03:00
net_dbg_ratelimited ( " UDPLite: bad csum coverage %d/%d \n " ,
cscov , skb - > len ) ;
2006-11-27 22:10:57 +03:00
return 1 ;
2007-03-26 07:10:56 +04:00
} else if ( cscov < skb - > len ) {
2006-11-27 22:10:57 +03:00
UDP_SKB_CB ( skb ) - > partial_cov = 1 ;
2007-03-26 07:10:56 +04:00
UDP_SKB_CB ( skb ) - > cscov = cscov ;
if ( skb - > ip_summed = = CHECKSUM_COMPLETE )
skb - > ip_summed = CHECKSUM_NONE ;
}
2006-11-27 22:10:57 +03:00
return 0 ;
}
2011-10-18 03:07:30 +04:00
/* Slow-path computation of checksum. Socket is locked. */
static inline __wsum udplite_csum_outgoing ( struct sock * sk , struct sk_buff * skb )
2006-11-27 22:10:57 +03:00
{
2011-10-18 03:07:30 +04:00
const struct udp_sock * up = udp_sk ( skb - > sk ) ;
2006-11-27 22:10:57 +03:00
int cscov = up - > len ;
2011-10-18 03:07:30 +04:00
__wsum csum = 0 ;
2006-11-27 22:10:57 +03:00
2011-10-18 03:07:30 +04:00
if ( up - > pcflag & UDPLITE_SEND_CC ) {
/*
* Sender has set ` partial coverage ' option on UDP - Lite socket .
* The special case " up->pcslen == 0 " signifies full coverage .
*/
2006-11-27 22:10:57 +03:00
if ( up - > pcslen < up - > len ) {
2011-10-18 03:07:30 +04:00
if ( 0 < up - > pcslen )
cscov = up - > pcslen ;
udp_hdr ( skb ) - > len = htons ( up - > pcslen ) ;
2006-11-27 22:10:57 +03:00
}
2011-10-18 03:07:30 +04:00
/*
* NOTE : Causes for the error case ` up - > pcslen > up - > len ' :
* ( i ) Application error ( will not be penalized ) .
* ( ii ) Payload too big for send buffer : data is split
* into several packets , each with its own header .
* In this case ( e . g . last segment ) , coverage may
* exceed packet length .
* Since packets with coverage length > packet length are
* illegal , we fall back to the defaults here .
*/
2006-11-27 22:10:57 +03:00
}
skb - > ip_summed = CHECKSUM_NONE ; /* no HW support for checksumming */
skb_queue_walk ( & sk - > sk_write_queue , skb ) {
2007-04-26 04:55:53 +04:00
const int off = skb_transport_offset ( skb ) ;
const int len = skb - > len - off ;
2006-11-27 22:10:57 +03:00
csum = skb_checksum ( skb , off , ( cscov > len ) ? len : cscov , csum ) ;
if ( ( cscov - = len ) < = 0 )
break ;
}
return csum ;
}
2011-10-18 03:07:30 +04:00
/* Fast-path computation of checksum. Socket may not be locked. */
2011-03-01 05:36:48 +03:00
static inline __wsum udplite_csum ( struct sk_buff * skb )
{
2011-10-18 03:07:30 +04:00
const struct udp_sock * up = udp_sk ( skb - > sk ) ;
2011-03-01 05:36:48 +03:00
const int off = skb_transport_offset ( skb ) ;
2011-10-18 03:07:30 +04:00
int len = skb - > len - off ;
2011-03-01 05:36:48 +03:00
2011-10-18 03:07:30 +04:00
if ( ( up - > pcflag & UDPLITE_SEND_CC ) & & up - > pcslen < len ) {
if ( 0 < up - > pcslen )
len = up - > pcslen ;
udp_hdr ( skb ) - > len = htons ( up - > pcslen ) ;
}
2011-03-01 05:36:48 +03:00
skb - > ip_summed = CHECKSUM_NONE ; /* no HW support for checksumming */
2011-10-18 03:07:30 +04:00
return skb_checksum ( skb , off , len , 0 ) ;
2011-03-01 05:36:48 +03:00
}
2013-09-23 22:33:39 +04:00
void udplite4_register ( void ) ;
int udplite_get_port ( struct sock * sk , unsigned short snum ,
int ( * scmp ) ( const struct sock * , const struct sock * ) ) ;
2006-11-27 22:10:57 +03:00
# endif /* _UDPLITE_H */