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 )
{
return ( dsfield & INET_ECN_ECT_0 ) ;
}
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 ;
}
# define INET_ECN_xmit(sk) do { inet_sk(sk)->tos |= INET_ECN_ECT_0; } while (0)
# define INET_ECN_dontxmit(sk) \
do { inet_sk ( sk ) - > tos & = ~ INET_ECN_MASK ; } while ( 0 )
# 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 ) {
case __constant_htons ( 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 ;
case __constant_htons ( 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