/*
* xfrm_state.c
*
* Changes:
* Mitsuru KANDA @USAGI
* Kazunori MIYAZAWA @USAGI
* Kunihiro Ishiguro <kunihiro@ipinfusion.com>
* IPv6 support
* YOSHIFUJI Hideaki @USAGI
* Split up af-specific functions
* Derek Atkins <derek@ihtfp.com>
* Add UDP Encapsulation
*
*/
#include <linux/workqueue.h>
#include <net/xfrm.h>
#include <linux/pfkeyv2.h>
#include <linux/ipsec.h>
#include <linux/module.h>
#include <asm/uaccess.h>
struct sock *xfrm_nl;
EXPORT_SYMBOL(xfrm_nl);
u32 sysctl_xfrm_aevent_etime = XFRM_AE_ETIME;
EXPORT_SYMBOL(sysctl_xfrm_aevent_etime);
u32 sysctl_xfrm_aevent_rseqth = XFRM_AE_SEQT_SIZE;
EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth);
/* Each xfrm_state may be linked to two tables:
1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
2. Hash table by daddr to find what SAs exist for given
destination/tunnel endpoint. (output)
*/
static DEFINE_SPINLOCK(xfrm_state_lock);
/* Hash table to find appropriate SA towards given target (endpoint
* of tunnel or destination of transport mode) allowed by selector.
*
* Main use is finding SA after policy selected tunnel or transport mode.
* Also, it can be used by ah/esp icmp error handler to find offending SA.
*/
static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE];
static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE];
DECLARE_WAIT_QUEUE_HEAD(km_waitq);
EXPORT_SYMBOL(km_waitq);
static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
static struct work_struct xfrm_state_gc_work;
static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
static int xfrm_state_gc_flush_bundles;
int __xfrm_state_delete(struct xfrm_state *x);
static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
void km_state_expired(struct xfrm_state *x, int hard, u32 pid);
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);
kfree(x->encap);
if (x->mode)
xfrm_put_mode(x->mode);
if (x->type) {
x->type->destructor(x);
xfrm_put_type(x->type);
}
security_xfrm_state_free(x);
kfree(x);
}
static void xfrm_state_gc_task(void *data)
{
struct xfrm_state *x;
struct list_head *entry, *tmp;
struct list_head gc_list = LIST_HEAD_INIT(gc_list);
if (xfrm_state_gc_flush_bundles) {
xfrm_state_gc_flush_bundles = 0;
xfrm_flush_bundles();
}
spin_lock_bh(&xfrm_state_gc_lock);
list_splice_init(&xfrm_state_gc_list, &gc_list);
spin_unlock_bh(&xfrm_state_gc_lock);
list_for_each_safe(entry, tmp, &gc_list) {
x = list_entry(entry, struct xfrm_state, bydst);
xfrm_state_gc_destroy(x);
}
wake_up(&km_waitq);
}
static inline unsigned long make_jiffies(long secs)
{