[IPSEC] Add complete xfrm event notification

Heres the final patch.
What this patch provides

- netlink xfrm events
- ability to have events generated by netlink propagated to pfkey
  and vice versa.
- fixes the acquire lets-be-happy-with-one-success issue

Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Jamal Hadi Salim
2005-06-18 22:42:13 -07:00
committed by David S. Miller
parent 3aa3dfb372
commit 26b15dad9f
5 changed files with 616 additions and 118 deletions

View File

@@ -50,7 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_gc_lock);
static int xfrm_state_gc_flush_bundles;
static void __xfrm_state_delete(struct xfrm_state *x);
static 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);
@@ -215,8 +215,10 @@ void __xfrm_state_destroy(struct xfrm_state *x)
}
EXPORT_SYMBOL(__xfrm_state_destroy);
static void __xfrm_state_delete(struct xfrm_state *x)
static int __xfrm_state_delete(struct xfrm_state *x)
{
int err = -ESRCH;
if (x->km.state != XFRM_STATE_DEAD) {
x->km.state = XFRM_STATE_DEAD;
spin_lock(&xfrm_state_lock);
@@ -245,14 +247,21 @@ static void __xfrm_state_delete(struct xfrm_state *x)
* is what we are dropping here.
*/
atomic_dec(&x->refcnt);
err = 0;
}
return err;
}
void xfrm_state_delete(struct xfrm_state *x)
int xfrm_state_delete(struct xfrm_state *x)
{
int err;
spin_lock_bh(&x->lock);
__xfrm_state_delete(x);
err = __xfrm_state_delete(x);
spin_unlock_bh(&x->lock);
return err;
}
EXPORT_SYMBOL(xfrm_state_delete);
@@ -796,34 +805,60 @@ EXPORT_SYMBOL(xfrm_replay_advance);
static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
static DEFINE_RWLOCK(xfrm_km_lock);
static void km_state_expired(struct xfrm_state *x, int hard)
void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
{
struct xfrm_mgr *km;
read_lock(&xfrm_km_lock);
list_for_each_entry(km, &xfrm_km_list, list)
if (km->notify_policy)
km->notify_policy(xp, dir, c);
read_unlock(&xfrm_km_lock);
}
void km_state_notify(struct xfrm_state *x, struct km_event *c)
{
struct xfrm_mgr *km;
read_lock(&xfrm_km_lock);
list_for_each_entry(km, &xfrm_km_list, list)
if (km->notify)
km->notify(x, c);
read_unlock(&xfrm_km_lock);
}
EXPORT_SYMBOL(km_policy_notify);
EXPORT_SYMBOL(km_state_notify);
static void km_state_expired(struct xfrm_state *x, int hard)
{
struct km_event c;
if (hard)
x->km.state = XFRM_STATE_EXPIRED;
else
x->km.dying = 1;
read_lock(&xfrm_km_lock);
list_for_each_entry(km, &xfrm_km_list, list)
km->notify(x, hard);
read_unlock(&xfrm_km_lock);
c.data = hard;
c.event = XFRM_SAP_EXPIRED;
km_state_notify(x, &c);
if (hard)
wake_up(&km_waitq);
}
/*
* We send to all registered managers regardless of failure
* We are happy with one success
*/
static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
{
int err = -EINVAL;
int err = -EINVAL, acqret;
struct xfrm_mgr *km;
read_lock(&xfrm_km_lock);
list_for_each_entry(km, &xfrm_km_list, list) {
err = km->acquire(x, t, pol, XFRM_POLICY_OUT);
if (!err)
break;
acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
if (!acqret)
err = acqret;
}
read_unlock(&xfrm_km_lock);
return err;
@@ -848,13 +883,12 @@ EXPORT_SYMBOL(km_new_mapping);
void km_policy_expired(struct xfrm_policy *pol, int dir, int hard)
{
struct xfrm_mgr *km;
struct km_event c;
read_lock(&xfrm_km_lock);
list_for_each_entry(km, &xfrm_km_list, list)
if (km->notify_policy)
km->notify_policy(pol, dir, hard);
read_unlock(&xfrm_km_lock);
c.data = hard;
c.data = hard;
c.event = XFRM_SAP_EXPIRED;
km_policy_notify(pol, dir, &c);
if (hard)
wake_up(&km_waitq);