2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-16 15:20:36 -07:00
/*
* xfrm4_output . c - Common IPsec encapsulation code for IPv4 .
* Copyright ( c ) 2004 Herbert Xu < herbert @ gondor . apana . org . au >
*/
2006-06-22 03:08:03 -07:00
# include <linux/if_ether.h>
# include <linux/kernel.h>
2007-11-13 21:40:52 -08:00
# include <linux/module.h>
2005-04-16 15:20:36 -07:00
# include <linux/skbuff.h>
2006-01-06 23:01:48 -08:00
# include <linux/netfilter_ipv4.h>
2007-11-13 21:40:52 -08:00
# include <net/dst.h>
2005-04-16 15:20:36 -07:00
# include <net/ip.h>
# include <net/xfrm.h>
# include <net/icmp.h>
static int xfrm4_tunnel_check_size ( struct sk_buff * skb )
{
int mtu , ret = 0 ;
if ( IPCB ( skb ) - > flags & IPSKB_XFRM_TUNNEL_SIZE )
goto out ;
2014-05-04 16:39:18 -07:00
if ( ! ( ip_hdr ( skb ) - > frag_off & htons ( IP_DF ) ) | | skb - > ignore_df )
2005-04-16 15:20:36 -07:00
goto out ;
2013-08-26 12:31:19 +02:00
mtu = dst_mtu ( skb_dst ( skb ) ) ;
2017-04-14 10:06:10 +02:00
if ( ( ! skb_is_gso ( skb ) & & skb - > len > mtu ) | |
2018-03-01 17:13:39 +11:00
( skb_is_gso ( skb ) & &
! skb_gso_validate_network_len ( skb , ip_skb_dst_mtu ( skb - > sk , skb ) ) ) ) {
2015-10-19 10:30:05 +02:00
skb - > protocol = htons ( ETH_P_IP ) ;
2011-06-29 23:20:41 +00:00
if ( skb - > sk )
2013-08-14 13:05:23 +02:00
xfrm_local_error ( skb , mtu ) ;
2011-06-29 23:20:41 +00:00
else
icmp_send ( skb , ICMP_DEST_UNREACH ,
ICMP_FRAG_NEEDED , htonl ( mtu ) ) ;
2005-04-16 15:20:36 -07:00
ret = - EMSGSIZE ;
}
out :
return ret ;
}
2007-11-13 21:40:52 -08:00
int xfrm4_extract_output ( struct xfrm_state * x , struct sk_buff * skb )
{
int err ;
err = xfrm4_tunnel_check_size ( skb ) ;
if ( err )
return err ;
2007-11-19 18:47:58 -08:00
XFRM_MODE_SKB_CB ( skb ) - > protocol = ip_hdr ( skb ) - > protocol ;
2007-11-13 21:40:52 -08:00
return xfrm4_extract_header ( skb ) ;
}
2015-04-05 22:19:04 -04:00
int xfrm4_output_finish ( struct sock * sk , struct sk_buff * skb )
2006-06-22 03:08:03 -07:00
{
2014-04-07 08:08:52 +02:00
memset ( IPCB ( skb ) , 0 , sizeof ( * IPCB ( skb ) ) ) ;
IPCB ( skb ) - > flags | = IPSKB_XFRM_TRANSFORMED ;
2015-04-05 22:19:04 -04:00
return xfrm_output ( sk , skb ) ;
2014-04-07 08:08:52 +02:00
}
2015-09-15 20:04:18 -05:00
static int __xfrm4_output ( struct net * net , struct sock * sk , struct sk_buff * skb )
2014-04-07 08:08:52 +02:00
{
struct xfrm_state * x = skb_dst ( skb ) - > xfrm ;
2019-03-29 21:16:30 +01:00
const struct xfrm_state_afinfo * afinfo ;
int ret = - EAFNOSUPPORT ;
2014-04-07 08:08:52 +02:00
2006-06-22 03:08:03 -07:00
# ifdef CONFIG_NETFILTER
2014-04-07 08:08:52 +02:00
if ( ! x ) {
2006-06-22 03:08:03 -07:00
IPCB ( skb ) - > flags | = IPSKB_REROUTED ;
2015-10-07 16:48:35 -05:00
return dst_output ( net , sk , skb ) ;
2006-06-22 03:08:03 -07:00
}
2007-11-13 21:43:11 -08:00
# endif
2006-06-22 03:08:03 -07:00
2019-03-29 21:16:30 +01:00
rcu_read_lock ( ) ;
2019-03-29 21:16:32 +01:00
afinfo = xfrm_state_afinfo_get_rcu ( x - > outer_mode . family ) ;
2019-03-29 21:16:30 +01:00
if ( likely ( afinfo ) )
ret = afinfo - > output_finish ( sk , skb ) ;
else
kfree_skb ( skb ) ;
rcu_read_unlock ( ) ;
return ret ;
2006-06-22 03:08:03 -07:00
}
2015-10-07 16:48:47 -05:00
int xfrm4_output ( struct net * net , struct sock * sk , struct sk_buff * skb )
2006-01-06 23:01:48 -08:00
{
2015-09-15 20:04:16 -05:00
return NF_HOOK_COND ( NFPROTO_IPV4 , NF_INET_POST_ROUTING ,
2019-11-12 17:14:37 +01:00
net , sk , skb , skb - > dev , skb_dst ( skb ) - > dev ,
2015-09-15 20:04:16 -05:00
__xfrm4_output ,
2006-02-15 15:10:22 -08:00
! ( IPCB ( skb ) - > flags & IPSKB_REROUTED ) ) ;
2006-01-06 23:01:48 -08:00
}
2013-08-14 13:05:23 +02:00
void xfrm4_local_error ( struct sk_buff * skb , u32 mtu )
{
struct iphdr * hdr ;
hdr = skb - > encapsulation ? inner_ip_hdr ( skb ) : ip_hdr ( skb ) ;
ip_local_error ( skb - > sk , EMSGSIZE , hdr - > daddr ,
inet_sk ( skb - > sk ) - > inet_dport , mtu ) ;
}