2005-04-17 02:20:36 +04:00
# ifndef _INET_ECN_H_
# define _INET_ECN_H_
# include <linux/ip.h>
2005-11-05 23:14:04 +03:00
# include <linux/skbuff.h>
2005-12-27 07:43:12 +03:00
# include <net/inet_sock.h>
2005-04-17 02:20:36 +04:00
# include <net/dsfield.h>
enum {
INET_ECN_NOT_ECT = 0 ,
INET_ECN_ECT_1 = 1 ,
INET_ECN_ECT_0 = 2 ,
INET_ECN_CE = 3 ,
INET_ECN_MASK = 3 ,
} ;
static inline int INET_ECN_is_ce ( __u8 dsfield )
{
return ( dsfield & INET_ECN_MASK ) = = INET_ECN_CE ;
}
static inline int INET_ECN_is_not_ect ( __u8 dsfield )
{
return ( dsfield & INET_ECN_MASK ) = = INET_ECN_NOT_ECT ;
}
static inline int INET_ECN_is_capable ( __u8 dsfield )
{
2010-09-23 00:43:57 +04:00
return dsfield & INET_ECN_ECT_0 ;
2005-04-17 02:20:36 +04:00
}
2011-10-22 09:25:23 +04:00
/*
* RFC 3168 9.1 .1
* The full - functionality option for ECN encapsulation is to copy the
* ECN codepoint of the inside header to the outside header on
* encapsulation if the inside header is not - ECT or ECT , and to set the
* ECN codepoint of the outside header to ECT ( 0 ) if the ECN codepoint of
* the inside header is CE .
*/
2005-04-17 02:20:36 +04:00
static inline __u8 INET_ECN_encapsulate ( __u8 outer , __u8 inner )
{
outer & = ~ INET_ECN_MASK ;
outer | = ! INET_ECN_is_ce ( inner ) ? ( inner & INET_ECN_MASK ) :
INET_ECN_ECT_0 ;
return outer ;
}
2011-05-07 03:44:46 +04:00
static inline void INET_ECN_xmit ( struct sock * sk )
{
inet_sk ( sk ) - > tos | = INET_ECN_ECT_0 ;
if ( inet6_sk ( sk ) ! = NULL )
inet6_sk ( sk ) - > tclass | = INET_ECN_ECT_0 ;
}
static inline void INET_ECN_dontxmit ( struct sock * sk )
{
inet_sk ( sk ) - > tos & = ~ INET_ECN_MASK ;
if ( inet6_sk ( sk ) ! = NULL )
inet6_sk ( sk ) - > tclass & = ~ INET_ECN_MASK ;
}
2005-04-17 02:20:36 +04:00
# define IP6_ECN_flow_init(label) do { \
( label ) & = ~ htonl ( INET_ECN_MASK < < 20 ) ; \
} while ( 0 )
# define IP6_ECN_flow_xmit(sk, label) do { \
2008-04-14 10:40:51 +04:00
if ( INET_ECN_is_capable ( inet6_sk ( sk ) - > tclass ) ) \
2006-11-03 11:55:35 +03:00
( label ) | = htonl ( INET_ECN_ECT_0 < < 20 ) ; \
2005-04-17 02:20:36 +04:00
} while ( 0 )
2005-11-05 23:14:04 +03:00
static inline int IP_ECN_set_ce ( struct iphdr * iph )
2005-04-17 02:20:36 +04:00
{
2006-11-15 08:42:26 +03:00
u32 check = ( __force u32 ) iph - > check ;
2005-04-17 02:20:36 +04:00
u32 ecn = ( iph - > tos + 1 ) & INET_ECN_MASK ;
/*
* After the last operation we have ( in binary ) :
* INET_ECN_NOT_ECT = > 01
* INET_ECN_ECT_1 = > 10
* INET_ECN_ECT_0 = > 11
* INET_ECN_CE = > 00
*/
if ( ! ( ecn & 2 ) )
2005-11-05 23:14:04 +03:00
return ! ecn ;
2005-04-17 02:20:36 +04:00
/*
* The following gives us :
* INET_ECN_ECT_1 = > check + = htons ( 0xFFFD )
* INET_ECN_ECT_0 = > check + = htons ( 0xFFFE )
*/
2006-11-15 08:42:26 +03:00
check + = ( __force u16 ) htons ( 0xFFFB ) + ( __force u16 ) htons ( ecn ) ;
2005-04-17 02:20:36 +04:00
2006-11-15 08:42:26 +03:00
iph - > check = ( __force __sum16 ) ( check + ( check > = 0xFFFF ) ) ;
2005-04-17 02:20:36 +04:00
iph - > tos | = INET_ECN_CE ;
2005-11-05 23:14:04 +03:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
static inline void IP_ECN_clear ( struct iphdr * iph )
{
iph - > tos & = ~ INET_ECN_MASK ;
}
2007-11-14 08:40:13 +03:00
static inline void ipv4_copy_dscp ( unsigned int dscp , struct iphdr * inner )
2005-04-17 02:20:36 +04:00
{
2007-11-14 08:40:13 +03:00
dscp & = ~ INET_ECN_MASK ;
2005-04-17 02:20:36 +04:00
ipv4_change_dsfield ( inner , INET_ECN_MASK , dscp ) ;
}
struct ipv6hdr ;
2005-11-05 23:14:04 +03:00
static inline int IP6_ECN_set_ce ( struct ipv6hdr * iph )
2005-04-17 02:20:36 +04:00
{
if ( INET_ECN_is_not_ect ( ipv6_get_dsfield ( iph ) ) )
2005-11-05 23:14:04 +03:00
return 0 ;
2006-11-08 11:24:47 +03:00
* ( __be32 * ) iph | = htonl ( INET_ECN_CE < < 20 ) ;
2005-11-05 23:14:04 +03:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
static inline void IP6_ECN_clear ( struct ipv6hdr * iph )
{
2006-11-08 11:24:47 +03:00
* ( __be32 * ) iph & = ~ htonl ( INET_ECN_MASK < < 20 ) ;
2005-04-17 02:20:36 +04:00
}
2007-11-14 08:40:13 +03:00
static inline void ipv6_copy_dscp ( unsigned int dscp , struct ipv6hdr * inner )
2005-04-17 02:20:36 +04:00
{
2007-11-14 08:40:13 +03:00
dscp & = ~ INET_ECN_MASK ;
2005-04-17 02:20:36 +04:00
ipv6_change_dsfield ( inner , INET_ECN_MASK , dscp ) ;
}
2005-11-05 23:14:04 +03:00
static inline int INET_ECN_set_ce ( struct sk_buff * skb )
{
switch ( skb - > protocol ) {
2009-02-15 09:58:35 +03:00
case cpu_to_be16 ( ETH_P_IP ) :
2007-04-20 07:29:13 +04:00
if ( skb - > network_header + sizeof ( struct iphdr ) < = skb - > tail )
2007-04-21 09:47:35 +04:00
return IP_ECN_set_ce ( ip_hdr ( skb ) ) ;
2005-11-05 23:14:04 +03:00
break ;
2009-02-15 09:58:35 +03:00
case cpu_to_be16 ( ETH_P_IPV6 ) :
2007-04-20 07:29:13 +04:00
if ( skb - > network_header + sizeof ( struct ipv6hdr ) < = skb - > tail )
2007-04-26 04:54:47 +04:00
return IP6_ECN_set_ce ( ipv6_hdr ( skb ) ) ;
2005-11-05 23:14:04 +03:00
break ;
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
# endif