2006-05-28 10:05:54 +04:00
/*
* xfrm4_mode_transport . c - Transport mode encapsulation for IPv4 .
*
* Copyright ( c ) 2004 - 2006 Herbert Xu < herbert @ gondor . apana . org . au >
*/
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/skbuff.h>
# include <linux/stringify.h>
# include <net/dst.h>
# include <net/ip.h>
# include <net/xfrm.h>
2017-04-14 11:06:01 +03:00
# include <net/protocol.h>
2006-05-28 10:05:54 +04:00
/* Add encapsulation header.
*
* The IP header will be moved forward to make space for the encapsulation
* header .
*/
2006-09-01 04:42:59 +04:00
static int xfrm4_transport_output ( struct xfrm_state * x , struct sk_buff * skb )
2006-05-28 10:05:54 +04:00
{
2007-04-21 09:47:35 +04:00
struct iphdr * iph = ip_hdr ( skb ) ;
int ihl = iph - > ihl * 4 ;
2006-05-28 10:05:54 +04:00
2017-04-14 11:07:39 +03:00
skb_set_inner_transport_header ( skb , skb_transport_offset ( skb ) ) ;
2007-10-11 02:44:06 +04:00
skb_set_network_header ( skb , - x - > props . header_len ) ;
2007-10-11 02:44:44 +04:00
skb - > mac_header = skb - > network_header +
offsetof ( struct iphdr , protocol ) ;
skb - > transport_header = skb - > network_header + ihl ;
2007-10-11 02:44:06 +04:00
__skb_pull ( skb , ihl ) ;
2007-04-11 07:50:43 +04:00
memmove ( skb_network_header ( skb ) , iph , ihl ) ;
2006-05-28 10:05:54 +04:00
return 0 ;
}
2006-05-28 10:06:13 +04:00
/* Remove encapsulation header.
*
* The IP header will be moved over the top of the encapsulation header .
*
* On entry , skb - > h shall point to where the IP header should be and skb - > nh
* shall be set to where the IP header currently is . skb - > data shall point
* to the start of the payload .
*/
2006-05-28 10:05:54 +04:00
static int xfrm4_transport_input ( struct xfrm_state * x , struct sk_buff * skb )
{
2007-04-26 05:04:18 +04:00
int ihl = skb - > data - skb_transport_header ( skb ) ;
2017-02-15 11:40:00 +03:00
struct xfrm_offload * xo = xfrm_offload ( skb ) ;
2006-05-28 10:06:13 +04:00
2007-04-11 08:21:55 +04:00
if ( skb - > transport_header ! = skb - > network_header ) {
2007-04-26 05:04:18 +04:00
memmove ( skb_transport_header ( skb ) ,
skb_network_header ( skb ) , ihl ) ;
2007-04-11 08:21:55 +04:00
skb - > network_header = skb - > transport_header ;
2007-03-11 01:59:16 +03:00
}
2007-04-21 09:47:35 +04:00
ip_hdr ( skb ) - > tot_len = htons ( skb - > len + ihl ) ;
2017-02-15 11:40:00 +03:00
if ( ! xo | | ! ( xo - > flags & XFRM_GRO ) )
skb_reset_transport_header ( skb ) ;
2006-05-28 10:05:54 +04:00
return 0 ;
}
2017-04-14 11:06:01 +03:00
static struct sk_buff * xfrm4_transport_gso_segment ( struct xfrm_state * x ,
struct sk_buff * skb ,
netdev_features_t features )
{
const struct net_offload * ops ;
struct sk_buff * segs = ERR_PTR ( - EINVAL ) ;
struct xfrm_offload * xo = xfrm_offload ( skb ) ;
skb - > transport_header + = x - > props . header_len ;
ops = rcu_dereference ( inet_offloads [ xo - > proto ] ) ;
if ( likely ( ops & & ops - > callbacks . gso_segment ) )
segs = ops - > callbacks . gso_segment ( skb , features ) ;
return segs ;
}
static void xfrm4_transport_xmit ( struct xfrm_state * x , struct sk_buff * skb )
{
struct xfrm_offload * xo = xfrm_offload ( skb ) ;
skb_reset_mac_len ( skb ) ;
pskb_pull ( skb , skb - > mac_len + sizeof ( struct iphdr ) + x - > props . header_len ) ;
if ( xo - > flags & XFRM_GSO_SEGMENT ) {
skb_reset_transport_header ( skb ) ;
skb - > transport_header - = x - > props . header_len ;
}
}
2006-05-28 10:05:54 +04:00
static struct xfrm_mode xfrm4_transport_mode = {
. input = xfrm4_transport_input ,
. output = xfrm4_transport_output ,
2017-04-14 11:06:01 +03:00
. gso_segment = xfrm4_transport_gso_segment ,
. xmit = xfrm4_transport_xmit ,
2006-05-28 10:05:54 +04:00
. owner = THIS_MODULE ,
. encap = XFRM_MODE_TRANSPORT ,
} ;
static int __init xfrm4_transport_init ( void )
{
return xfrm_register_mode ( & xfrm4_transport_mode , AF_INET ) ;
}
static void __exit xfrm4_transport_exit ( void )
{
int err ;
err = xfrm_unregister_mode ( & xfrm4_transport_mode , AF_INET ) ;
BUG_ON ( err ) ;
}
module_init ( xfrm4_transport_init ) ;
module_exit ( xfrm4_transport_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS_XFRM_MODE ( AF_INET , XFRM_MODE_TRANSPORT ) ;