[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>
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index d11747c..918a94c 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -50,7 +50,7 @@
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 @@
}
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 @@
* 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 @@
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 @@
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);