2006-10-04 10:47:05 +04:00
/*
* xfrm6_mode_beet . c - BEET mode encapsulation for IPv6 .
*
* Copyright ( c ) 2006 Diego Beltrami < diego . beltrami @ gmail . com >
* Miika Komu < miika @ iki . fi >
* Herbert Xu < herbert @ gondor . apana . org . au >
* Abhinav Pathak < abhinav . pathak @ hiit . fi >
* Jeff Ahrenholz < ahrenholz @ gmail . com >
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/skbuff.h>
# include <linux/stringify.h>
# include <net/dsfield.h>
# include <net/dst.h>
# include <net/inet_ecn.h>
# include <net/ipv6.h>
# include <net/xfrm.h>
2007-11-14 08:41:28 +03:00
static void xfrm6_beet_make_header ( struct sk_buff * skb )
{
struct ipv6hdr * iph = ipv6_hdr ( skb ) ;
iph - > version = 6 ;
memcpy ( iph - > flow_lbl , XFRM_MODE_SKB_CB ( skb ) - > flow_lbl ,
sizeof ( iph - > flow_lbl ) ) ;
iph - > nexthdr = XFRM_MODE_SKB_CB ( skb ) - > protocol ;
ipv6_change_dsfield ( iph , 0 , XFRM_MODE_SKB_CB ( skb ) - > tos ) ;
iph - > hop_limit = XFRM_MODE_SKB_CB ( skb ) - > ttl ;
}
2006-10-04 10:47:05 +04:00
/* Add encapsulation header.
*
* The top IP header will be constructed per draft - nikander - esp - beet - mode - 06. txt .
*/
static int xfrm6_beet_output ( struct xfrm_state * x , struct sk_buff * skb )
{
2007-11-14 08:40:52 +03:00
struct ipv6hdr * top_iph ;
2008-08-06 13:40:25 +04:00
struct ip_beet_phdr * ph ;
int optlen , hdr_len ;
2006-10-04 10:47:05 +04:00
2008-08-06 13:40:25 +04:00
hdr_len = 0 ;
optlen = XFRM_MODE_SKB_CB ( skb ) - > optlen ;
if ( unlikely ( optlen ) )
hdr_len + = IPV4_BEET_PHMAXLEN - ( optlen & 4 ) ;
skb_set_network_header ( skb , - x - > props . header_len - hdr_len ) ;
if ( x - > sel . family ! = AF_INET6 )
skb - > network_header + = IPV4_BEET_PHMAXLEN ;
2007-11-14 08:40:52 +03:00
skb - > mac_header = skb - > network_header +
offsetof ( struct ipv6hdr , nexthdr ) ;
skb - > transport_header = skb - > network_header + sizeof ( * top_iph ) ;
2008-08-06 13:40:25 +04:00
ph = ( struct ip_beet_phdr * ) __skb_pull ( skb , XFRM_MODE_SKB_CB ( skb ) - > ihl - hdr_len ) ;
2006-10-04 10:47:05 +04:00
2007-11-14 08:41:28 +03:00
xfrm6_beet_make_header ( skb ) ;
2007-11-14 08:40:52 +03:00
2007-11-14 08:41:28 +03:00
top_iph = ipv6_hdr ( skb ) ;
2008-08-06 13:40:25 +04:00
if ( unlikely ( optlen ) ) {
BUG_ON ( optlen < 0 ) ;
ph - > padlen = 4 - ( optlen & 4 ) ;
ph - > hdrlen = optlen / 8 ;
ph - > nexthdr = top_iph - > nexthdr ;
if ( ph - > padlen )
memset ( ph + 1 , IPOPT_NOP , ph - > padlen ) ;
top_iph - > nexthdr = IPPROTO_BEETPH ;
}
2007-11-14 08:40:52 +03:00
2011-11-21 07:39:03 +04:00
top_iph - > saddr = * ( struct in6_addr * ) & x - > props . saddr ;
top_iph - > daddr = * ( struct in6_addr * ) & x - > id . daddr ;
2006-10-04 10:47:05 +04:00
return 0 ;
}
static int xfrm6_beet_input ( struct xfrm_state * x , struct sk_buff * skb )
{
struct ipv6hdr * ip6h ;
int size = sizeof ( struct ipv6hdr ) ;
2007-11-14 08:41:28 +03:00
int err ;
2006-10-04 10:47:05 +04:00
2007-11-14 08:41:28 +03:00
err = skb_cow_head ( skb , size + skb - > mac_len ) ;
if ( err )
2006-10-04 10:47:05 +04:00
goto out ;
2007-11-14 08:41:28 +03:00
__skb_push ( skb , size ) ;
2007-04-11 07:45:18 +04:00
skb_reset_network_header ( skb ) ;
2012-02-23 14:55:02 +04:00
skb_mac_header_rebuild ( skb ) ;
2006-10-04 10:47:05 +04:00
2007-11-14 08:41:28 +03:00
xfrm6_beet_make_header ( skb ) ;
2007-04-26 04:54:47 +04:00
ip6h = ipv6_hdr ( skb ) ;
2006-10-04 10:47:05 +04:00
ip6h - > payload_len = htons ( skb - > len - size ) ;
2011-11-21 07:39:03 +04:00
ip6h - > daddr = * ( struct in6_addr * ) & x - > sel . daddr . a6 ;
ip6h - > saddr = * ( struct in6_addr * ) & x - > sel . saddr . a6 ;
2006-10-04 10:47:05 +04:00
err = 0 ;
out :
return err ;
}
static struct xfrm_mode xfrm6_beet_mode = {
2007-11-14 08:41:28 +03:00
. input2 = xfrm6_beet_input ,
. input = xfrm_prepare_input ,
2007-11-14 08:40:52 +03:00
. output2 = xfrm6_beet_output ,
. output = xfrm6_prepare_output ,
2006-10-04 10:47:05 +04:00
. owner = THIS_MODULE ,
. encap = XFRM_MODE_BEET ,
2007-10-18 08:31:50 +04:00
. flags = XFRM_MODE_FLAG_TUNNEL ,
2006-10-04 10:47:05 +04:00
} ;
static int __init xfrm6_beet_init ( void )
{
return xfrm_register_mode ( & xfrm6_beet_mode , AF_INET6 ) ;
}
static void __exit xfrm6_beet_exit ( void )
{
int err ;
err = xfrm_unregister_mode ( & xfrm6_beet_mode , AF_INET6 ) ;
BUG_ON ( err ) ;
}
module_init ( xfrm6_beet_init ) ;
module_exit ( xfrm6_beet_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS_XFRM_MODE ( AF_INET6 , XFRM_MODE_BEET ) ;