Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8cd5488 authored by Jamal Hadi Salim's avatar Jamal Hadi Salim Committed by David S. Miller
Browse files

[IPSEC]: Sync series - core changes



This patch provides the core functionality needed for sync events
for ipsec. Derived work of Krisztian KOVACS <hidden@balabit.hu>

Signed-off-by: default avatarJamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f5539eb8
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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 */
+30 −0
Original line number Diff line number Diff line
@@ -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)
+43 −1
Original line number Diff line number Diff line
@@ -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;
@@ -306,6 +321,20 @@ struct xfrm_policy
};

#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 */
+23 −0
Original line number Diff line number Diff line
@@ -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,
+75 −1
Original line number Diff line number Diff line
@@ -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 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
}
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;

Loading