2005-04-17 02:20:36 +04:00
/*
* xfrm6_state . c : based on xfrm4_state . c
*
* Authors :
* Mitsuru KANDA @ USAGI
* Kazunori MIYAZAWA @ USAGI
* Kunihiro Ishiguro < kunihiro @ ipinfusion . com >
* IPv6 support
* YOSHIFUJI Hideaki @ USAGI
* Split up af - specific portion
2007-02-09 17:24:49 +03:00
*
2005-04-17 02:20:36 +04:00
*/
# include <net/xfrm.h>
# include <linux/pfkeyv2.h>
# include <linux/ipsec.h>
2007-11-14 08:43:11 +03:00
# include <linux/netfilter_ipv6.h>
2011-07-15 19:47:34 +04:00
# include <linux/export.h>
2007-11-14 08:40:52 +03:00
# include <net/dsfield.h>
2005-04-17 02:20:36 +04:00
# include <net/ipv6.h>
2006-01-14 01:34:36 +03:00
# include <net/addrconf.h>
2005-04-17 02:20:36 +04:00
static void
2011-02-23 04:51:44 +03:00
__xfrm6_init_tempsel ( struct xfrm_selector * sel , const struct flowi * fl )
2005-04-17 02:20:36 +04:00
{
2011-03-12 10:42:11 +03:00
const struct flowi6 * fl6 = & fl - > u . ip6 ;
2005-04-17 02:20:36 +04:00
/* Initialize temporary selector matching only
* to current session . */
2011-11-21 07:39:03 +04:00
* ( struct in6_addr * ) & sel - > daddr = fl6 - > daddr ;
* ( struct in6_addr * ) & sel - > saddr = fl6 - > saddr ;
2011-03-12 10:42:11 +03:00
sel - > dport = xfrm_flowi_dport ( fl , & fl6 - > uli ) ;
2010-09-20 22:11:38 +04:00
sel - > dport_mask = htons ( 0xffff ) ;
2011-03-12 10:42:11 +03:00
sel - > sport = xfrm_flowi_sport ( fl , & fl6 - > uli ) ;
2010-09-20 22:11:38 +04:00
sel - > sport_mask = htons ( 0xffff ) ;
sel - > family = AF_INET6 ;
sel - > prefixlen_d = 128 ;
sel - > prefixlen_s = 128 ;
2011-03-12 10:42:11 +03:00
sel - > proto = fl6 - > flowi6_proto ;
sel - > ifindex = fl6 - > flowi6_oif ;
2010-09-20 22:11:38 +04:00
}
static void
2011-02-24 08:07:20 +03:00
xfrm6_init_temprop ( struct xfrm_state * x , const struct xfrm_tmpl * tmpl ,
const xfrm_address_t * daddr , const xfrm_address_t * saddr )
2010-09-20 22:11:38 +04:00
{
2005-04-17 02:20:36 +04:00
x - > id = tmpl - > id ;
if ( ipv6_addr_any ( ( struct in6_addr * ) & x - > id . daddr ) )
memcpy ( & x - > id . daddr , daddr , sizeof ( x - > sel . daddr ) ) ;
memcpy ( & x - > props . saddr , & tmpl - > saddr , sizeof ( x - > props . saddr ) ) ;
if ( ipv6_addr_any ( ( struct in6_addr * ) & x - > props . saddr ) )
memcpy ( & x - > props . saddr , saddr , sizeof ( x - > props . saddr ) ) ;
x - > props . mode = tmpl - > mode ;
x - > props . reqid = tmpl - > reqid ;
x - > props . family = AF_INET6 ;
}
2008-02-19 04:15:27 +03:00
/* distribution counting sort function for xfrm_state and xfrm_tmpl */
2006-08-24 09:51:02 +04:00
static int
2008-02-19 04:15:27 +03:00
__xfrm6_sort ( void * * dst , void * * src , int n , int ( * cmp ) ( void * p ) , int maxclass )
2006-08-24 09:51:02 +04:00
{
int i ;
2008-02-19 04:15:27 +03:00
int class [ XFRM_MAX_DEPTH ] ;
int count [ maxclass ] ;
2006-08-24 09:51:02 +04:00
2008-02-19 04:15:27 +03:00
memset ( count , 0 , sizeof ( count ) ) ;
2006-08-24 09:51:02 +04:00
2006-08-24 09:54:07 +04:00
for ( i = 0 ; i < n ; i + + ) {
2008-02-19 04:15:27 +03:00
int c ;
class [ i ] = c = cmp ( src [ i ] ) ;
count [ c ] + + ;
2006-08-24 09:54:07 +04:00
}
2006-08-24 09:51:02 +04:00
2008-02-19 04:15:27 +03:00
for ( i = 2 ; i < maxclass ; i + + )
count [ i ] + = count [ i - 1 ] ;
2006-08-24 09:51:02 +04:00
for ( i = 0 ; i < n ; i + + ) {
2008-02-19 04:15:27 +03:00
dst [ count [ class [ i ] - 1 ] + + ] = src [ i ] ;
2009-02-22 10:37:10 +03:00
src [ i ] = NULL ;
2006-08-24 09:51:02 +04:00
}
return 0 ;
}
2008-02-19 04:15:27 +03:00
/*
* Rule for xfrm_state :
*
* rule 1 : select IPsec transport except AH
* rule 2 : select MIPv6 RO or inbound trigger
* rule 3 : select IPsec transport AH
* rule 4 : select IPsec tunnel
* rule 5 : others
*/
static int __xfrm6_state_sort_cmp ( void * p )
2006-08-24 09:51:02 +04:00
{
2008-02-19 04:15:27 +03:00
struct xfrm_state * v = p ;
switch ( v - > props . mode ) {
case XFRM_MODE_TRANSPORT :
if ( v - > id . proto ! = IPPROTO_AH )
return 1 ;
else
return 3 ;
2012-10-29 20:23:10 +04:00
# if IS_ENABLED(CONFIG_IPV6_MIP6)
2008-02-19 04:15:27 +03:00
case XFRM_MODE_ROUTEOPTIMIZATION :
case XFRM_MODE_IN_TRIGGER :
return 2 ;
2006-08-24 09:54:07 +04:00
# endif
2008-02-19 04:15:27 +03:00
case XFRM_MODE_TUNNEL :
case XFRM_MODE_BEET :
return 4 ;
2006-08-24 09:51:02 +04:00
}
2008-02-19 04:15:27 +03:00
return 5 ;
}
2006-08-24 09:51:02 +04:00
2008-02-19 04:15:27 +03:00
static int
__xfrm6_state_sort ( struct xfrm_state * * dst , struct xfrm_state * * src , int n )
{
return __xfrm6_sort ( ( void * * ) dst , ( void * * ) src , n ,
__xfrm6_state_sort_cmp , 6 ) ;
}
/*
* Rule for xfrm_tmpl :
*
* rule 1 : select IPsec transport
* rule 2 : select MIPv6 RO or inbound trigger
* rule 3 : select IPsec tunnel
* rule 4 : others
*/
static int __xfrm6_tmpl_sort_cmp ( void * p )
{
struct xfrm_tmpl * v = p ;
switch ( v - > mode ) {
case XFRM_MODE_TRANSPORT :
return 1 ;
2012-10-29 20:23:10 +04:00
# if IS_ENABLED(CONFIG_IPV6_MIP6)
2008-02-19 04:15:27 +03:00
case XFRM_MODE_ROUTEOPTIMIZATION :
case XFRM_MODE_IN_TRIGGER :
return 2 ;
# endif
case XFRM_MODE_TUNNEL :
case XFRM_MODE_BEET :
return 3 ;
2006-08-24 09:51:02 +04:00
}
2008-02-19 04:15:27 +03:00
return 4 ;
}
2006-08-24 09:51:02 +04:00
2008-02-19 04:15:27 +03:00
static int
__xfrm6_tmpl_sort ( struct xfrm_tmpl * * dst , struct xfrm_tmpl * * src , int n )
{
return __xfrm6_sort ( ( void * * ) dst , ( void * * ) src , n ,
__xfrm6_tmpl_sort_cmp , 5 ) ;
2006-08-24 09:51:02 +04:00
}
2007-11-14 08:40:52 +03:00
int xfrm6_extract_header ( struct sk_buff * skb )
{
struct ipv6hdr * iph = ipv6_hdr ( skb ) ;
2008-03-27 02:51:09 +03:00
XFRM_MODE_SKB_CB ( skb ) - > ihl = sizeof ( * iph ) ;
2007-11-14 08:40:52 +03:00
XFRM_MODE_SKB_CB ( skb ) - > id = 0 ;
XFRM_MODE_SKB_CB ( skb ) - > frag_off = htons ( IP_DF ) ;
XFRM_MODE_SKB_CB ( skb ) - > tos = ipv6_get_dsfield ( iph ) ;
XFRM_MODE_SKB_CB ( skb ) - > ttl = iph - > hop_limit ;
2008-03-27 02:51:09 +03:00
XFRM_MODE_SKB_CB ( skb ) - > optlen = 0 ;
2007-11-14 08:40:52 +03:00
memcpy ( XFRM_MODE_SKB_CB ( skb ) - > flow_lbl , iph - > flow_lbl ,
sizeof ( XFRM_MODE_SKB_CB ( skb ) - > flow_lbl ) ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
static struct xfrm_state_afinfo xfrm6_state_afinfo = {
. family = AF_INET6 ,
2007-11-14 08:40:52 +03:00
. proto = IPPROTO_IPV6 ,
2007-11-14 08:41:28 +03:00
. eth_proto = htons ( ETH_P_IPV6 ) ,
2007-10-18 08:33:12 +04:00
. owner = THIS_MODULE ,
2005-04-17 02:20:36 +04:00
. init_tempsel = __xfrm6_init_tempsel ,
2010-09-20 22:11:38 +04:00
. init_temprop = xfrm6_init_temprop ,
2006-08-24 09:51:02 +04:00
. tmpl_sort = __xfrm6_tmpl_sort ,
. state_sort = __xfrm6_state_sort ,
2007-02-07 01:24:56 +03:00
. output = xfrm6_output ,
2011-05-09 23:36:38 +04:00
. output_finish = xfrm6_output_finish ,
2007-11-14 08:41:28 +03:00
. extract_input = xfrm6_extract_input ,
2007-11-14 08:40:52 +03:00
. extract_output = xfrm6_extract_output ,
2007-11-14 08:44:23 +03:00
. transport_finish = xfrm6_transport_finish ,
2013-08-14 15:05:23 +04:00
. local_error = xfrm6_local_error ,
2005-04-17 02:20:36 +04:00
} ;
2007-12-07 11:42:11 +03:00
int __init xfrm6_state_init ( void )
2005-04-17 02:20:36 +04:00
{
2007-12-07 11:42:11 +03:00
return xfrm_state_register_afinfo ( & xfrm6_state_afinfo ) ;
2005-04-17 02:20:36 +04:00
}
void xfrm6_state_fini ( void )
{
xfrm_state_unregister_afinfo ( & xfrm6_state_afinfo ) ;
}