2005-04-17 02:20:36 +04:00
/*
* xfrm4_state . c
*
* Changes :
* YOSHIFUJI Hideaki @ USAGI
* Split up af - specific portion
*
*/
2005-06-21 00:21:43 +04:00
# include <net/ip.h>
2005-04-17 02:20:36 +04:00
# include <net/xfrm.h>
# include <linux/pfkeyv2.h>
# include <linux/ipsec.h>
static struct xfrm_state_afinfo xfrm4_state_afinfo ;
2005-06-21 00:21:43 +04:00
static int xfrm4_init_flags ( struct xfrm_state * x )
{
if ( ipv4_config . no_pmtu_disc )
x - > props . flags | = XFRM_STATE_NOPMTUDISC ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
static void
__xfrm4_init_tempsel ( struct xfrm_state * x , struct flowi * fl ,
struct xfrm_tmpl * tmpl ,
xfrm_address_t * daddr , xfrm_address_t * saddr )
{
x - > sel . daddr . a4 = fl - > fl4_dst ;
x - > sel . saddr . a4 = fl - > fl4_src ;
x - > sel . dport = xfrm_flowi_dport ( fl ) ;
x - > sel . dport_mask = ~ 0 ;
x - > sel . sport = xfrm_flowi_sport ( fl ) ;
x - > sel . sport_mask = ~ 0 ;
x - > sel . prefixlen_d = 32 ;
x - > sel . prefixlen_s = 32 ;
x - > sel . proto = fl - > proto ;
x - > sel . ifindex = fl - > oif ;
x - > id = tmpl - > id ;
if ( x - > id . daddr . a4 = = 0 )
x - > id . daddr . a4 = daddr - > a4 ;
x - > props . saddr = tmpl - > saddr ;
if ( x - > props . saddr . a4 = = 0 )
x - > props . saddr . a4 = saddr - > a4 ;
2006-01-14 01:34:36 +03:00
if ( tmpl - > mode & & x - > props . saddr . a4 = = 0 ) {
struct rtable * rt ;
struct flowi fl_tunnel = {
. nl_u = {
. ip4_u = {
. daddr = x - > id . daddr . a4 ,
}
}
} ;
if ( ! xfrm_dst_lookup ( ( struct xfrm_dst * * ) & rt ,
& fl_tunnel , AF_INET ) ) {
x - > props . saddr . a4 = rt - > rt_src ;
dst_release ( & rt - > u . dst ) ;
}
}
2005-04-17 02:20:36 +04:00
x - > props . mode = tmpl - > mode ;
x - > props . reqid = tmpl - > reqid ;
x - > props . family = AF_INET ;
}
static struct xfrm_state *
__xfrm4_state_lookup ( xfrm_address_t * daddr , u32 spi , u8 proto )
{
unsigned h = __xfrm4_spi_hash ( daddr , spi , proto ) ;
struct xfrm_state * x ;
list_for_each_entry ( x , xfrm4_state_afinfo . state_byspi + h , byspi ) {
if ( x - > props . family = = AF_INET & &
spi = = x - > id . spi & &
daddr - > a4 = = x - > id . daddr . a4 & &
proto = = x - > id . proto ) {
xfrm_state_hold ( x ) ;
return x ;
}
}
return NULL ;
}
static struct xfrm_state *
__xfrm4_find_acq ( u8 mode , u32 reqid , u8 proto ,
xfrm_address_t * daddr , xfrm_address_t * saddr ,
int create )
{
struct xfrm_state * x , * x0 ;
unsigned h = __xfrm4_dst_hash ( daddr ) ;
x0 = NULL ;
list_for_each_entry ( x , xfrm4_state_afinfo . state_bydst + h , bydst ) {
if ( x - > props . family = = AF_INET & &
daddr - > a4 = = x - > id . daddr . a4 & &
mode = = x - > props . mode & &
proto = = x - > id . proto & &
saddr - > a4 = = x - > props . saddr . a4 & &
reqid = = x - > props . reqid & &
x - > km . state = = XFRM_STATE_ACQ & &
! x - > id . spi ) {
x0 = x ;
break ;
}
}
if ( ! x0 & & create & & ( x0 = xfrm_state_alloc ( ) ) ! = NULL ) {
x0 - > sel . daddr . a4 = daddr - > a4 ;
x0 - > sel . saddr . a4 = saddr - > a4 ;
x0 - > sel . prefixlen_d = 32 ;
x0 - > sel . prefixlen_s = 32 ;
x0 - > props . saddr . a4 = saddr - > a4 ;
x0 - > km . state = XFRM_STATE_ACQ ;
x0 - > id . daddr . a4 = daddr - > a4 ;
x0 - > id . proto = proto ;
x0 - > props . family = AF_INET ;
x0 - > props . mode = mode ;
x0 - > props . reqid = reqid ;
x0 - > props . family = AF_INET ;
x0 - > lft . hard_add_expires_seconds = XFRM_ACQ_EXPIRES ;
xfrm_state_hold ( x0 ) ;
x0 - > timer . expires = jiffies + XFRM_ACQ_EXPIRES * HZ ;
add_timer ( & x0 - > timer ) ;
xfrm_state_hold ( x0 ) ;
list_add_tail ( & x0 - > bydst , xfrm4_state_afinfo . state_bydst + h ) ;
wake_up ( & km_waitq ) ;
}
if ( x0 )
xfrm_state_hold ( x0 ) ;
return x0 ;
}
static struct xfrm_state_afinfo xfrm4_state_afinfo = {
. family = AF_INET ,
. lock = RW_LOCK_UNLOCKED ,
2005-06-21 00:21:43 +04:00
. init_flags = xfrm4_init_flags ,
2005-04-17 02:20:36 +04:00
. init_tempsel = __xfrm4_init_tempsel ,
. state_lookup = __xfrm4_state_lookup ,
. find_acq = __xfrm4_find_acq ,
} ;
void __init xfrm4_state_init ( void )
{
xfrm_state_register_afinfo ( & xfrm4_state_afinfo ) ;
}
2005-08-10 06:35:47 +04:00
#if 0
2005-04-17 02:20:36 +04:00
void __exit xfrm4_state_fini ( void )
{
xfrm_state_unregister_afinfo ( & xfrm4_state_afinfo ) ;
}
2005-08-10 06:35:47 +04:00
# endif /* 0 */
2005-04-17 02:20:36 +04:00