diff options
| -rw-r--r-- | include/linux/sysctl.h | 2 | ||||
| -rw-r--r-- | include/linux/xfrm.h | 30 | ||||
| -rw-r--r-- | include/net/xfrm.h | 44 | ||||
| -rw-r--r-- | net/core/sysctl_net_core.c | 23 | ||||
| -rw-r--r-- | net/xfrm/xfrm_state.c | 76 | ||||
| -rw-r--r-- | net/xfrm/xfrm_user.c | 4 | 
6 files changed, 176 insertions, 3 deletions
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 6e8880ea49e..b686548f32e 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -261,6 +261,8 @@ enum  	NET_CORE_DEV_WEIGHT=17,  	NET_CORE_SOMAXCONN=18,  	NET_CORE_BUDGET=19, +	NET_CORE_AEVENT_ETIME=20, +	NET_CORE_AEVENT_RSEQTH=21,  };  /* /proc/sys/net/ethernet */ diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 82fbb758e28..b54a12940ef 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -156,6 +156,10 @@ enum {  	XFRM_MSG_FLUSHPOLICY,  #define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY +	XFRM_MSG_NEWAE, +#define XFRM_MSG_NEWAE XFRM_MSG_NEWAE +	XFRM_MSG_GETAE, +#define XFRM_MSG_GETAE XFRM_MSG_GETAE  	__XFRM_MSG_MAX  };  #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) @@ -194,6 +198,21 @@ struct xfrm_encap_tmpl {  	xfrm_address_t	encap_oa;  }; +/* AEVENT flags  */ +enum xfrm_ae_ftype_t { +	XFRM_AE_UNSPEC, +	XFRM_AE_RTHR=1,	/* replay threshold*/ +	XFRM_AE_RVAL=2, /* replay value */ +	XFRM_AE_LVAL=4, /* lifetime value */ +	XFRM_AE_ETHR=8, /* expiry timer threshold */ +	XFRM_AE_CR=16, /* Event cause is replay update */ +	XFRM_AE_CE=32, /* Event cause is timer expiry */ +	XFRM_AE_CU=64, /* Event cause is policy update */ +	__XFRM_AE_MAX + +#define XFRM_AE_MAX (__XFRM_AE_MAX - 1) +}; +  /* Netlink message attributes.  */  enum xfrm_attr_type_t {  	XFRMA_UNSPEC, @@ -205,6 +224,10 @@ enum xfrm_attr_type_t {  	XFRMA_SA,  	XFRMA_POLICY,  	XFRMA_SEC_CTX,		/* struct xfrm_sec_ctx */ +	XFRMA_LTIME_VAL, +	XFRMA_REPLAY_VAL, +	XFRMA_REPLAY_THRESH, +	XFRMA_ETIMER_THRESH,  	__XFRMA_MAX  #define XFRMA_MAX (__XFRMA_MAX - 1) @@ -235,6 +258,11 @@ struct xfrm_usersa_id {  	__u8				proto;  }; +struct xfrm_aevent_id { +	__u32				flags; +	struct xfrm_usersa_id		sa_id; +}; +  struct xfrm_userspi_info {  	struct xfrm_usersa_info		info;  	__u32				min; @@ -306,6 +334,8 @@ enum xfrm_nlgroups {  #define XFRMNLGRP_SA		XFRMNLGRP_SA  	XFRMNLGRP_POLICY,  #define XFRMNLGRP_POLICY	XFRMNLGRP_POLICY +	XFRMNLGRP_AEVENTS, +#define XFRMNLGRP_AEVENTS	XFRMNLGRP_AEVENTS  	__XFRMNLGRP_MAX  };  #define XFRMNLGRP_MAX	(__XFRMNLGRP_MAX - 1) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 8d362c49b8a..bc005e62e43 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -20,6 +20,10 @@  #define XFRM_ALIGN8(len)	(((len) + 7) & ~7) +extern struct sock *xfrm_nl; +extern u32 sysctl_xfrm_aevent_etime; +extern u32 sysctl_xfrm_aevent_rseqth; +  extern struct semaphore xfrm_cfg_sem;  /* Organization of SPD aka "XFRM rules" @@ -135,6 +139,16 @@ struct xfrm_state  	/* State for replay detection */  	struct xfrm_replay_state replay; +	/* Replay detection state at the time we sent the last notification */ +	struct xfrm_replay_state preplay; + +	/* Replay detection notification settings */ +	u32			replay_maxage; +	u32			replay_maxdiff; + +	/* Replay detection notification timer */ +	struct timer_list	rtimer; +  	/* Statistics */  	struct xfrm_stats	stats; @@ -169,6 +183,7 @@ struct km_event  		u32 hard;  		u32 proto;  		u32 byid; +		u32 aevent;  	} data;  	u32	seq; @@ -305,7 +320,21 @@ struct xfrm_policy  	struct xfrm_tmpl       	xfrm_vec[XFRM_MAX_DEPTH];  }; -#define XFRM_KM_TIMEOUT		30 +#define XFRM_KM_TIMEOUT                30 +/* which seqno */ +#define XFRM_REPLAY_SEQ		1 +#define XFRM_REPLAY_OSEQ	2 +#define XFRM_REPLAY_SEQ_MASK	3 +/* what happened */ +#define XFRM_REPLAY_UPDATE	XFRM_AE_CR +#define XFRM_REPLAY_TIMEOUT	XFRM_AE_CE + +/* default aevent timeout in units of 100ms */ +#define XFRM_AE_ETIME			10 +/* Async Event timer multiplier */ +#define XFRM_AE_ETH_M			10 +/* default seq threshold size */ +#define XFRM_AE_SEQT_SIZE		2  struct xfrm_mgr  { @@ -865,6 +894,7 @@ extern int xfrm_state_delete(struct xfrm_state *x);  extern void xfrm_state_flush(u8 proto);  extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);  extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq); +extern void xfrm_replay_notify(struct xfrm_state *x, int event);  extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb);  extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);  extern int xfrm_init_state(struct xfrm_state *x); @@ -965,4 +995,16 @@ static inline int xfrm_policy_id2dir(u32 index)  	return index & 7;  } +static inline int xfrm_aevent_is_on(void) +{ +	return netlink_has_listeners(xfrm_nl,XFRMNLGRP_AEVENTS); +} + +static inline void xfrm_aevent_doreplay(struct xfrm_state *x) +{ +	if (xfrm_aevent_is_on()) +		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); +} + +  #endif	/* _NET_XFRM_H */ diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 2f278c8e474..71045365672 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -26,6 +26,11 @@ extern int sysctl_core_destroy_delay;  extern char sysctl_divert_version[];  #endif /* CONFIG_NET_DIVERT */ +#ifdef CONFIG_XFRM +extern u32 sysctl_xfrm_aevent_etime; +extern u32 sysctl_xfrm_aevent_rseqth; +#endif +  ctl_table core_table[] = {  #ifdef CONFIG_NET  	{ @@ -111,6 +116,24 @@ ctl_table core_table[] = {  		.proc_handler	= &proc_dostring  	},  #endif /* CONFIG_NET_DIVERT */ +#ifdef CONFIG_XFRM +	{ +		.ctl_name	= NET_CORE_AEVENT_ETIME, +		.procname	= "xfrm_aevent_etime", +		.data		= &sysctl_xfrm_aevent_etime, +		.maxlen		= sizeof(u32), +		.mode		= 0644, +		.proc_handler	= &proc_dointvec +	}, +	{ +		.ctl_name	= NET_CORE_AEVENT_RSEQTH, +		.procname	= "xfrm_aevent_rseqth", +		.data		= &sysctl_xfrm_aevent_rseqth, +		.maxlen		= sizeof(u32), +		.mode		= 0644, +		.proc_handler	= &proc_dointvec +	}, +#endif /* CONFIG_XFRM */  #endif /* CONFIG_NET */  	{  		.ctl_name	= NET_CORE_SOMAXCONN, diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index c656cbaf35e..8eaee499cad 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -20,6 +20,8 @@  #include <linux/module.h>  #include <asm/uaccess.h> +u32 sysctl_xfrm_aevent_etime = XFRM_AE_ETIME; +u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE;  /* Each xfrm_state may be linked to two tables:     1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) @@ -62,6 +64,8 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)  {  	if (del_timer(&x->timer))  		BUG(); +	if (del_timer(&x->rtimer)) +		BUG();  	kfree(x->aalg);  	kfree(x->ealg);  	kfree(x->calg); @@ -190,11 +194,16 @@ struct xfrm_state *xfrm_state_alloc(void)  		init_timer(&x->timer);  		x->timer.function = xfrm_timer_handler;  		x->timer.data	  = (unsigned long)x; +		init_timer(&x->rtimer); +		x->rtimer.function = xfrm_replay_timer_handler; +		x->rtimer.data     = (unsigned long)x;  		x->curlft.add_time = (unsigned long)xtime.tv_sec;  		x->lft.soft_byte_limit = XFRM_INF;  		x->lft.soft_packet_limit = XFRM_INF;  		x->lft.hard_byte_limit = XFRM_INF;  		x->lft.hard_packet_limit = XFRM_INF; +		x->replay_maxage = 0; +		x->replay_maxdiff = 0;  		spin_lock_init(&x->lock);  	}  	return x; @@ -228,6 +237,8 @@ static int __xfrm_state_delete(struct xfrm_state *x)  		spin_unlock(&xfrm_state_lock);  		if (del_timer(&x->timer))  			__xfrm_state_put(x); +		if (del_timer(&x->rtimer)) +			__xfrm_state_put(x);  		/* The number two in this test is the reference  		 * mentioned in the comment below plus the reference @@ -426,6 +437,10 @@ static void __xfrm_state_insert(struct xfrm_state *x)  	if (!mod_timer(&x->timer, jiffies + HZ))  		xfrm_state_hold(x); +	if (x->replay_maxage && +	    !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) +		xfrm_state_hold(x); +  	wake_up(&km_waitq);  } @@ -762,6 +777,62 @@ out:  }  EXPORT_SYMBOL(xfrm_state_walk); + +void xfrm_replay_notify(struct xfrm_state *x, int event) +{ +	struct km_event c; +	/* we send notify messages in case +	 *  1. we updated on of the sequence numbers, and the seqno difference +	 *     is at least x->replay_maxdiff, in this case we also update the +	 *     timeout of our timer function +	 *  2. if x->replay_maxage has elapsed since last update, +	 *     and there were changes +	 * +	 *  The state structure must be locked! +	 */ + +	switch (event) { +	case XFRM_REPLAY_UPDATE: +		if (x->replay_maxdiff && +		    (x->replay.seq - x->preplay.seq < x->replay_maxdiff) && +		    (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) +			return; + +		break; + +	case XFRM_REPLAY_TIMEOUT: +		if ((x->replay.seq == x->preplay.seq) && +		    (x->replay.bitmap == x->preplay.bitmap) && +		    (x->replay.oseq == x->preplay.oseq)) +			return; + +		break; +	} + +	memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); +	c.event = XFRM_MSG_NEWAE; +	c.data.aevent = event; +	km_state_notify(x, &c); + +resched: +	if (x->replay_maxage && +	    !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) +		xfrm_state_hold(x); + +} + +static void xfrm_replay_timer_handler(unsigned long data) +{ +	struct xfrm_state *x = (struct xfrm_state*)data; + +	spin_lock(&x->lock); + +	if (xfrm_aevent_is_on() && x->km.state == XFRM_STATE_VALID) +		xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); + +	spin_unlock(&x->lock); +} +  int xfrm_replay_check(struct xfrm_state *x, u32 seq)  {  	u32 diff; @@ -805,6 +876,9 @@ void xfrm_replay_advance(struct xfrm_state *x, u32 seq)  		diff = x->replay.seq - seq;  		x->replay.bitmap |= (1U << diff);  	} + +	if (xfrm_aevent_is_on()) +		xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);  }  EXPORT_SYMBOL(xfrm_replay_advance); @@ -835,7 +909,7 @@ void km_state_notify(struct xfrm_state *x, struct km_event *c)  EXPORT_SYMBOL(km_policy_notify);  EXPORT_SYMBOL(km_state_notify); -static void km_state_expired(struct xfrm_state *x, int hard) +void km_state_expired(struct xfrm_state *x, int hard)  {  	struct km_event c; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 7de17559249..6f643e58e04 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -28,7 +28,7 @@  #include <net/netlink.h>  #include <asm/uaccess.h> -static struct sock *xfrm_nl; +struct sock *xfrm_nl;  static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type)  { @@ -1618,3 +1618,5 @@ module_init(xfrm_user_init);  module_exit(xfrm_user_exit);  MODULE_LICENSE("GPL");  MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); +EXPORT_SYMBOL(xfrm_nl); +  |