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: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 struct xfrm_state_afinfo xfrm6_state_afinfo ;
static void
__xfrm6_init_tempsel ( struct xfrm_state * x , struct flowi * fl ,
struct xfrm_tmpl * tmpl ,
xfrm_address_t * daddr , xfrm_address_t * saddr )
{
/* Initialize temporary selector matching only
* to current session . */
ipv6_addr_copy ( ( struct in6_addr * ) & x - > sel . daddr , & fl - > fl6_dst ) ;
ipv6_addr_copy ( ( struct in6_addr * ) & x - > sel . saddr , & fl - > fl6_src ) ;
x - > sel . dport = xfrm_flowi_dport ( fl ) ;
2006-09-28 05:46:11 +04:00
x - > sel . dport_mask = htons ( 0xffff ) ;
2005-04-17 02:20:36 +04:00
x - > sel . sport = xfrm_flowi_sport ( fl ) ;
2006-09-28 05:46:11 +04:00
x - > sel . sport_mask = htons ( 0xffff ) ;
2005-04-17 02:20:36 +04:00
x - > sel . prefixlen_d = 128 ;
x - > sel . prefixlen_s = 128 ;
x - > sel . proto = fl - > proto ;
x - > sel . ifindex = fl - > oif ;
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 ;
}
2006-08-24 09:51:02 +04:00
static int
__xfrm6_state_sort ( struct xfrm_state * * dst , struct xfrm_state * * src , int n )
{
int i ;
int j = 0 ;
/* Rule 1: select IPsec transport except AH */
for ( i = 0 ; i < n ; i + + ) {
if ( src [ i ] - > props . mode = = XFRM_MODE_TRANSPORT & &
src [ i ] - > id . proto ! = IPPROTO_AH ) {
dst [ j + + ] = src [ i ] ;
src [ i ] = NULL ;
}
}
if ( j = = n )
goto end ;
2006-08-24 09:54:07 +04:00
/* Rule 2: select MIPv6 RO or inbound trigger */
2007-06-27 10:56:32 +04:00
# if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
2006-08-24 09:54:07 +04:00
for ( i = 0 ; i < n ; i + + ) {
if ( src [ i ] & &
( src [ i ] - > props . mode = = XFRM_MODE_ROUTEOPTIMIZATION | |
src [ i ] - > props . mode = = XFRM_MODE_IN_TRIGGER ) ) {
dst [ j + + ] = src [ i ] ;
src [ i ] = NULL ;
}
}
if ( j = = n )
goto end ;
# endif
2006-08-24 09:51:02 +04:00
/* Rule 3: select IPsec transport AH */
for ( i = 0 ; i < n ; i + + ) {
if ( src [ i ] & &
src [ i ] - > props . mode = = XFRM_MODE_TRANSPORT & &
src [ i ] - > id . proto = = IPPROTO_AH ) {
dst [ j + + ] = src [ i ] ;
src [ i ] = NULL ;
}
}
if ( j = = n )
goto end ;
/* Rule 4: select IPsec tunnel */
for ( i = 0 ; i < n ; i + + ) {
if ( src [ i ] & &
2007-10-18 08:31:50 +04:00
( src [ i ] - > props . mode = = XFRM_MODE_TUNNEL | |
src [ i ] - > props . mode = = XFRM_MODE_BEET ) ) {
2006-08-24 09:51:02 +04:00
dst [ j + + ] = src [ i ] ;
src [ i ] = NULL ;
}
}
if ( likely ( j = = n ) )
goto end ;
/* Final rule */
for ( i = 0 ; i < n ; i + + ) {
if ( src [ i ] ) {
dst [ j + + ] = src [ i ] ;
src [ i ] = NULL ;
}
}
end :
return 0 ;
}
static int
__xfrm6_tmpl_sort ( struct xfrm_tmpl * * dst , struct xfrm_tmpl * * src , int n )
{
int i ;
int j = 0 ;
/* Rule 1: select IPsec transport */
for ( i = 0 ; i < n ; i + + ) {
if ( src [ i ] - > mode = = XFRM_MODE_TRANSPORT ) {
dst [ j + + ] = src [ i ] ;
src [ i ] = NULL ;
}
}
if ( j = = n )
goto end ;
2006-08-24 09:54:07 +04:00
/* Rule 2: select MIPv6 RO or inbound trigger */
2007-06-27 10:56:32 +04:00
# if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
2006-08-24 09:54:07 +04:00
for ( i = 0 ; i < n ; i + + ) {
if ( src [ i ] & &
( src [ i ] - > mode = = XFRM_MODE_ROUTEOPTIMIZATION | |
src [ i ] - > mode = = XFRM_MODE_IN_TRIGGER ) ) {
dst [ j + + ] = src [ i ] ;
src [ i ] = NULL ;
}
}
if ( j = = n )
goto end ;
# endif
2006-08-24 09:51:02 +04:00
/* Rule 3: select IPsec tunnel */
for ( i = 0 ; i < n ; i + + ) {
if ( src [ i ] & &
2007-10-18 08:31:50 +04:00
( src [ i ] - > mode = = XFRM_MODE_TUNNEL | |
src [ i ] - > mode = = XFRM_MODE_BEET ) ) {
2006-08-24 09:51:02 +04:00
dst [ j + + ] = src [ i ] ;
src [ i ] = NULL ;
}
}
if ( likely ( j = = n ) )
goto end ;
/* Final rule */
for ( i = 0 ; i < n ; i + + ) {
if ( src [ i ] ) {
dst [ j + + ] = src [ i ] ;
src [ i ] = NULL ;
}
}
end :
return 0 ;
}
2007-11-14 08:40:52 +03:00
int xfrm6_extract_header ( struct sk_buff * skb )
{
struct ipv6hdr * iph = ipv6_hdr ( skb ) ;
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 ;
2007-11-14 08:41:28 +03:00
XFRM_MODE_SKB_CB ( skb ) - > protocol =
skb_network_header ( skb ) [ IP6CB ( skb ) - > nhoff ] ;
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 ,
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 ,
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 ,
2005-04-17 02:20:36 +04:00
} ;
void __init xfrm6_state_init ( void )
{
xfrm_state_register_afinfo ( & xfrm6_state_afinfo ) ;
}
void xfrm6_state_fini ( void )
{
xfrm_state_unregister_afinfo ( & xfrm6_state_afinfo ) ;
}