2005-04-17 02:20:36 +04:00
/*
* xfrm6_input . c : based on net / ipv4 / xfrm4_input . c
*
* Authors :
* Mitsuru KANDA @ USAGI
2014-08-25 00:53:10 +04:00
* Kazunori MIYAZAWA @ USAGI
* Kunihiro Ishiguro < kunihiro @ ipinfusion . com >
2005-04-17 02:20:36 +04:00
* YOSHIFUJI Hideaki @ USAGI
* IPv6 support
*/
# include <linux/module.h>
# include <linux/string.h>
2006-01-07 10:03:34 +03:00
# include <linux/netfilter.h>
# include <linux/netfilter_ipv6.h>
2005-04-17 02:20:36 +04:00
# include <net/ipv6.h>
# include <net/xfrm.h>
2007-11-14 08:41:28 +03:00
int xfrm6_extract_input ( struct xfrm_state * x , struct sk_buff * skb )
{
return xfrm6_extract_header ( skb ) ;
}
2016-09-19 17:17:57 +03:00
int xfrm6_rcv_spi ( struct sk_buff * skb , int nexthdr , __be32 spi ,
struct ip6_tnl * t )
2005-04-17 02:20:36 +04:00
{
2016-09-19 17:17:57 +03:00
XFRM_TUNNEL_SKB_CB ( skb ) - > tunnel . ip6 = t ;
2007-12-04 09:54:12 +03:00
XFRM_SPI_SKB_CB ( skb ) - > family = AF_INET6 ;
2007-11-14 08:44:23 +03:00
XFRM_SPI_SKB_CB ( skb ) - > daddroff = offsetof ( struct ipv6hdr , daddr ) ;
return xfrm_input ( skb , nexthdr , spi , 0 ) ;
}
EXPORT_SYMBOL ( xfrm6_rcv_spi ) ;
2006-01-07 10:03:34 +03:00
2007-11-14 08:44:23 +03:00
int xfrm6_transport_finish ( struct sk_buff * skb , int async )
{
2017-02-15 11:40:00 +03:00
struct xfrm_offload * xo = xfrm_offload ( skb ) ;
2017-08-01 12:49:06 +03:00
int nhlen = skb - > data - skb_network_header ( skb ) ;
2017-02-15 11:40:00 +03:00
2007-11-20 05:47:58 +03:00
skb_network_header ( skb ) [ IP6CB ( skb ) - > nhoff ] =
XFRM_MODE_SKB_CB ( skb ) - > protocol ;
2007-12-31 08:10:14 +03:00
# ifndef CONFIG_NETFILTER
if ( ! async )
return 1 ;
# endif
2017-08-01 12:49:06 +03:00
__skb_push ( skb , nhlen ) ;
2017-06-22 11:37:10 +03:00
ipv6_hdr ( skb ) - > payload_len = htons ( skb - > len - sizeof ( struct ipv6hdr ) ) ;
2017-08-01 12:49:06 +03:00
skb_postpush_rcsum ( skb , skb_network_header ( skb ) , nhlen ) ;
2006-01-07 10:03:34 +03:00
2017-02-15 11:40:00 +03:00
if ( xo & & ( xo - > flags & XFRM_GRO ) ) {
skb_mac_header_rebuild ( skb ) ;
return - 1 ;
}
2015-09-16 04:04:16 +03:00
NF_HOOK ( NFPROTO_IPV6 , NF_INET_PRE_ROUTING ,
dev_net ( skb - > dev ) , NULL , skb , skb - > dev , NULL ,
2007-11-14 08:44:23 +03:00
ip6_rcv_finish ) ;
return - 1 ;
2005-04-17 02:20:36 +04:00
}
2016-09-19 17:17:57 +03:00
int xfrm6_rcv_tnl ( struct sk_buff * skb , struct ip6_tnl * t )
2005-04-17 02:20:36 +04:00
{
2007-10-18 08:29:25 +04:00
return xfrm6_rcv_spi ( skb , skb_network_header ( skb ) [ IP6CB ( skb ) - > nhoff ] ,
2016-09-19 17:17:57 +03:00
0 , t ) ;
2005-04-17 02:20:36 +04:00
}
2016-09-19 17:17:57 +03:00
EXPORT_SYMBOL ( xfrm6_rcv_tnl ) ;
2007-02-22 16:05:40 +03:00
2016-09-19 17:17:57 +03:00
int xfrm6_rcv ( struct sk_buff * skb )
{
return xfrm6_rcv_tnl ( skb , NULL ) ;
}
EXPORT_SYMBOL ( xfrm6_rcv ) ;
2006-08-24 05:08:21 +04:00
int xfrm6_input_addr ( struct sk_buff * skb , xfrm_address_t * daddr ,
xfrm_address_t * saddr , u8 proto )
{
2008-11-26 04:59:52 +03:00
struct net * net = dev_net ( skb - > dev ) ;
2007-02-09 17:24:49 +03:00
struct xfrm_state * x = NULL ;
2006-08-24 05:08:21 +04:00
int i = 0 ;
2017-02-15 11:39:24 +03:00
if ( secpath_set ( skb ) ) {
XFRM_INC_STATS ( net , LINUX_MIB_XFRMINERROR ) ;
goto drop ;
2007-12-21 07:41:57 +03:00
}
if ( 1 + skb - > sp - > len = = XFRM_MAX_DEPTH ) {
2008-11-26 04:59:52 +03:00
XFRM_INC_STATS ( net , LINUX_MIB_XFRMINBUFFERERROR ) ;
2007-12-21 07:41:57 +03:00
goto drop ;
}
2006-08-24 05:08:21 +04:00
for ( i = 0 ; i < 3 ; i + + ) {
xfrm_address_t * dst , * src ;
2008-02-19 11:24:33 +03:00
2006-08-24 05:08:21 +04:00
switch ( i ) {
case 0 :
dst = daddr ;
src = saddr ;
break ;
case 1 :
/* lookup state with wild-card source address */
dst = daddr ;
2008-02-19 11:24:33 +03:00
src = ( xfrm_address_t * ) & in6addr_any ;
2006-08-24 05:08:21 +04:00
break ;
default :
2007-02-09 17:24:49 +03:00
/* lookup state with wild-card addresses */
2008-02-19 11:24:33 +03:00
dst = ( xfrm_address_t * ) & in6addr_any ;
src = ( xfrm_address_t * ) & in6addr_any ;
2006-08-24 05:08:21 +04:00
break ;
2007-02-09 17:24:49 +03:00
}
2006-08-24 05:08:21 +04:00
2010-02-23 03:20:22 +03:00
x = xfrm_state_lookup_byaddr ( net , skb - > mark , dst , src , proto , AF_INET6 ) ;
2006-08-24 05:08:21 +04:00
if ( ! x )
continue ;
spin_lock ( & x - > lock ) ;
2008-02-19 11:24:33 +03:00
if ( ( ! i | | ( x - > props . flags & XFRM_STATE_WILDRECV ) ) & &
likely ( x - > km . state = = XFRM_STATE_VALID ) & &
! xfrm_state_check_expire ( x ) ) {
2006-08-24 05:08:21 +04:00
spin_unlock ( & x - > lock ) ;
2008-02-19 11:24:33 +03:00
if ( x - > type - > input ( x , skb ) > 0 ) {
/* found a valid state */
break ;
}
} else
2006-08-24 05:08:21 +04:00
spin_unlock ( & x - > lock ) ;
2008-02-19 11:24:33 +03:00
xfrm_state_put ( x ) ;
x = NULL ;
2006-08-24 05:08:21 +04:00
}
2007-12-21 07:41:57 +03:00
if ( ! x ) {
2008-11-26 04:59:52 +03:00
XFRM_INC_STATS ( net , LINUX_MIB_XFRMINNOSTATES ) ;
2007-12-22 01:58:11 +03:00
xfrm_audit_state_notfound_simple ( skb , AF_INET6 ) ;
2006-08-24 05:08:21 +04:00
goto drop ;
}
2007-12-21 07:41:57 +03:00
skb - > sp - > xvec [ skb - > sp - > len + + ] = x ;
spin_lock ( & x - > lock ) ;
2006-08-24 05:08:21 +04:00
2007-12-21 07:41:57 +03:00
x - > curlft . bytes + = skb - > len ;
x - > curlft . packets + + ;
spin_unlock ( & x - > lock ) ;
2006-08-24 05:08:21 +04:00
return 1 ;
2007-12-21 07:41:57 +03:00
2006-08-24 05:08:21 +04:00
drop :
return - 1 ;
}
2007-02-22 16:05:40 +03:00
EXPORT_SYMBOL ( xfrm6_input_addr ) ;