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

[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
...@@ -261,6 +261,8 @@ enum ...@@ -261,6 +261,8 @@ enum
NET_CORE_DEV_WEIGHT=17, NET_CORE_DEV_WEIGHT=17,
NET_CORE_SOMAXCONN=18, NET_CORE_SOMAXCONN=18,
NET_CORE_BUDGET=19, NET_CORE_BUDGET=19,
NET_CORE_AEVENT_ETIME=20,
NET_CORE_AEVENT_RSEQTH=21,
}; };
/* /proc/sys/net/ethernet */ /* /proc/sys/net/ethernet */
......
...@@ -156,6 +156,10 @@ enum { ...@@ -156,6 +156,10 @@ enum {
XFRM_MSG_FLUSHPOLICY, XFRM_MSG_FLUSHPOLICY,
#define XFRM_MSG_FLUSHPOLICY 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 __XFRM_MSG_MAX
}; };
#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
...@@ -194,6 +198,21 @@ struct xfrm_encap_tmpl { ...@@ -194,6 +198,21 @@ struct xfrm_encap_tmpl {
xfrm_address_t encap_oa; 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. */ /* Netlink message attributes. */
enum xfrm_attr_type_t { enum xfrm_attr_type_t {
XFRMA_UNSPEC, XFRMA_UNSPEC,
...@@ -205,6 +224,10 @@ enum xfrm_attr_type_t { ...@@ -205,6 +224,10 @@ enum xfrm_attr_type_t {
XFRMA_SA, XFRMA_SA,
XFRMA_POLICY, XFRMA_POLICY,
XFRMA_SEC_CTX, /* struct xfrm_sec_ctx */ XFRMA_SEC_CTX, /* struct xfrm_sec_ctx */
XFRMA_LTIME_VAL,
XFRMA_REPLAY_VAL,
XFRMA_REPLAY_THRESH,
XFRMA_ETIMER_THRESH,
__XFRMA_MAX __XFRMA_MAX
#define XFRMA_MAX (__XFRMA_MAX - 1) #define XFRMA_MAX (__XFRMA_MAX - 1)
...@@ -235,6 +258,11 @@ struct xfrm_usersa_id { ...@@ -235,6 +258,11 @@ struct xfrm_usersa_id {
__u8 proto; __u8 proto;
}; };
struct xfrm_aevent_id {
__u32 flags;
struct xfrm_usersa_id sa_id;
};
struct xfrm_userspi_info { struct xfrm_userspi_info {
struct xfrm_usersa_info info; struct xfrm_usersa_info info;
__u32 min; __u32 min;
...@@ -306,6 +334,8 @@ enum xfrm_nlgroups { ...@@ -306,6 +334,8 @@ enum xfrm_nlgroups {
#define XFRMNLGRP_SA XFRMNLGRP_SA #define XFRMNLGRP_SA XFRMNLGRP_SA
XFRMNLGRP_POLICY, XFRMNLGRP_POLICY,
#define XFRMNLGRP_POLICY XFRMNLGRP_POLICY #define XFRMNLGRP_POLICY XFRMNLGRP_POLICY
XFRMNLGRP_AEVENTS,
#define XFRMNLGRP_AEVENTS XFRMNLGRP_AEVENTS
__XFRMNLGRP_MAX __XFRMNLGRP_MAX
}; };
#define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1) #define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1)
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#define XFRM_ALIGN8(len) (((len) + 7) & ~7) #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; extern struct semaphore xfrm_cfg_sem;
/* Organization of SPD aka "XFRM rules" /* Organization of SPD aka "XFRM rules"
...@@ -135,6 +139,16 @@ struct xfrm_state ...@@ -135,6 +139,16 @@ struct xfrm_state
/* State for replay detection */ /* State for replay detection */
struct xfrm_replay_state replay; 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 */ /* Statistics */
struct xfrm_stats stats; struct xfrm_stats stats;
...@@ -169,6 +183,7 @@ struct km_event ...@@ -169,6 +183,7 @@ struct km_event
u32 hard; u32 hard;
u32 proto; u32 proto;
u32 byid; u32 byid;
u32 aevent;
} data; } data;
u32 seq; u32 seq;
...@@ -306,6 +321,20 @@ struct xfrm_policy ...@@ -306,6 +321,20 @@ struct xfrm_policy
}; };
#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 struct xfrm_mgr
{ {
...@@ -865,6 +894,7 @@ extern int xfrm_state_delete(struct xfrm_state *x); ...@@ -865,6 +894,7 @@ extern int xfrm_state_delete(struct xfrm_state *x);
extern void xfrm_state_flush(u8 proto); extern void xfrm_state_flush(u8 proto);
extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); 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_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_check(struct xfrm_state *x, struct sk_buff *skb);
extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
extern int xfrm_init_state(struct xfrm_state *x); extern int xfrm_init_state(struct xfrm_state *x);
...@@ -965,4 +995,16 @@ static inline int xfrm_policy_id2dir(u32 index) ...@@ -965,4 +995,16 @@ static inline int xfrm_policy_id2dir(u32 index)
return index & 7; 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 */ #endif /* _NET_XFRM_H */
...@@ -26,6 +26,11 @@ extern int sysctl_core_destroy_delay; ...@@ -26,6 +26,11 @@ extern int sysctl_core_destroy_delay;
extern char sysctl_divert_version[]; extern char sysctl_divert_version[];
#endif /* CONFIG_NET_DIVERT */ #endif /* CONFIG_NET_DIVERT */
#ifdef CONFIG_XFRM
extern u32 sysctl_xfrm_aevent_etime;
extern u32 sysctl_xfrm_aevent_rseqth;
#endif
ctl_table core_table[] = { ctl_table core_table[] = {
#ifdef CONFIG_NET #ifdef CONFIG_NET
{ {
...@@ -111,6 +116,24 @@ ctl_table core_table[] = { ...@@ -111,6 +116,24 @@ ctl_table core_table[] = {
.proc_handler = &proc_dostring .proc_handler = &proc_dostring
}, },
#endif /* CONFIG_NET_DIVERT */ #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 */ #endif /* CONFIG_NET */
{ {
.ctl_name = NET_CORE_SOMAXCONN, .ctl_name = NET_CORE_SOMAXCONN,
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <asm/uaccess.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: /* Each xfrm_state may be linked to two tables:
1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) 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) ...@@ -62,6 +64,8 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
{ {
if (del_timer(&x->timer)) if (del_timer(&x->timer))
BUG(); BUG();
if (del_timer(&x->rtimer))
BUG();
kfree(x->aalg); kfree(x->aalg);
kfree(x->ealg); kfree(x->ealg);
kfree(x->calg); kfree(x->calg);
...@@ -190,11 +194,16 @@ struct xfrm_state *xfrm_state_alloc(void) ...@@ -190,11 +194,16 @@ struct xfrm_state *xfrm_state_alloc(void)
init_timer(&x->timer); init_timer(&x->timer);
x->timer.function = xfrm_timer_handler; x->timer.function = xfrm_timer_handler;
x->timer.data = (unsigned long)x; 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->curlft.add_time = (unsigned long)xtime.tv_sec;
x->lft.soft_byte_limit = XFRM_INF; x->lft.soft_byte_limit = XFRM_INF;
x->lft.soft_packet_limit = XFRM_INF; x->lft.soft_packet_limit = XFRM_INF;
x->lft.hard_byte_limit = XFRM_INF; x->lft.hard_byte_limit = XFRM_INF;
x->lft.hard_packet_limit = XFRM_INF; x->lft.hard_packet_limit = XFRM_INF;
x->replay_maxage = 0;
x->replay_maxdiff = 0;
spin_lock_init(&x->lock); spin_lock_init(&x->lock);
} }
return x; return x;
...@@ -228,6 +237,8 @@ static int __xfrm_state_delete(struct xfrm_state *x) ...@@ -228,6 +237,8 @@ static int __xfrm_state_delete(struct xfrm_state *x)
spin_unlock(&xfrm_state_lock); spin_unlock(&xfrm_state_lock);
if (del_timer(&x->timer)) if (del_timer(&x->timer))
__xfrm_state_put(x); __xfrm_state_put(x);
if (del_timer(&x->rtimer))
__xfrm_state_put(x);
/* The number two in this test is the reference /* The number two in this test is the reference
* mentioned in the comment below plus the reference * mentioned in the comment below plus the reference
...@@ -426,6 +437,10 @@ static void __xfrm_state_insert(struct xfrm_state *x) ...@@ -426,6 +437,10 @@ static void __xfrm_state_insert(struct xfrm_state *x)
if (!mod_timer(&x->timer, jiffies + HZ)) if (!mod_timer(&x->timer, jiffies + HZ))
xfrm_state_hold(x); xfrm_state_hold(x);
if (x->replay_maxage &&
!mod_timer(&x->rtimer, jiffies + x->replay_maxage))
xfrm_state_hold(x);
wake_up(&km_waitq); wake_up(&km_waitq);
} }
...@@ -762,6 +777,62 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), ...@@ -762,6 +777,62 @@ int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
} }
EXPORT_SYMBOL(xfrm_state_walk); 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) int xfrm_replay_check(struct xfrm_state *x, u32 seq)
{ {
u32 diff; u32 diff;
...@@ -805,6 +876,9 @@ void xfrm_replay_advance(struct xfrm_state *x, u32 seq) ...@@ -805,6 +876,9 @@ void xfrm_replay_advance(struct xfrm_state *x, u32 seq)
diff = x->replay.seq - seq; diff = x->replay.seq - seq;
x->replay.bitmap |= (1U << diff); x->replay.bitmap |= (1U << diff);
} }
if (xfrm_aevent_is_on())
xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);
} }
EXPORT_SYMBOL(xfrm_replay_advance); EXPORT_SYMBOL(xfrm_replay_advance);
...@@ -835,7 +909,7 @@ void km_state_notify(struct xfrm_state *x, struct km_event *c) ...@@ -835,7 +909,7 @@ void km_state_notify(struct xfrm_state *x, struct km_event *c)
EXPORT_SYMBOL(km_policy_notify); EXPORT_SYMBOL(km_policy_notify);
EXPORT_SYMBOL(km_state_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; struct km_event c;
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <net/netlink.h> #include <net/netlink.h>
#include <asm/uaccess.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) static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type)
{ {
...@@ -1618,3 +1618,5 @@ module_init(xfrm_user_init); ...@@ -1618,3 +1618,5 @@ module_init(xfrm_user_init);
module_exit(xfrm_user_exit); module_exit(xfrm_user_exit);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM);
EXPORT_SYMBOL(xfrm_nl);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment