* PATCH: IPSEC xfrm events
@ 2005-04-01 1:37 jamal
2005-04-01 4:21 ` Herbert Xu
2005-04-01 17:28 ` Masahide NAKAMURA
0 siblings, 2 replies; 48+ messages in thread
From: jamal @ 2005-04-01 1:37 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
[-- Attachment #1: Type: text/plain, Size: 826 bytes --]
Herbert et al,
Ok, heres the final patch with all the changes discussed.
include/linux/xfrm.h | 2
include/net/xfrm.h | 29 ++++++-
net/key/af_key.c | 24 +++++-
net/xfrm/xfrm_policy.c | 25 ++++--
net/xfrm/xfrm_state.c | 84 +++++++++++++++++++--
net/xfrm/xfrm_user.c | 188
++++++++++++++++++++++++++++++++++++++++++++++++-
6 files changed, 323 insertions(+), 29 deletions(-)
I have tested this with both setkey and iproute2 (about 10 scenarios or
so). Masahide-san is doing a lot more thorough testing with key servers
as well. He has not tested this patch yet (time difference) but it is
based on the last one he tested.
Let me know what you think. If no issues i would like to push to Dave.
There are comments in the patch that are intentional so they can be
commented on.
cheers,
jamal
[-- Attachment #2: ipsec-xfrm-ev-p --]
[-- Type: text/plain, Size: 15659 bytes --]
--- a/include/net/xfrm.h 2005-03-25 22:28:26.000000000 -0500
+++ b/include/net/xfrm.h 2005-03-31 19:26:24.000000000 -0500
@@ -157,6 +157,25 @@
XFRM_STATE_DEAD
};
+/* events that could be sent by kernel */
+enum {
+ XFRM_SAP_INVALID,
+ XFRM_SAP_EXPIRED,
+ XFRM_SAP_ADDED,
+ XFRM_SAP_UPDATED,
+ XFRM_SAP_DELETED,
+ XFRM_SAP_FLUSHED,
+ __XFRM_SAP_MAX
+};
+#define XFRM_SAP_MAX (__XFRM_SAP_MAX - 1)
+
+/* callback structure passed from either netlink or pfkey */
+struct km_cb
+{
+ u32 data; /* callee to caller */
+};
+
+
struct xfrm_type;
struct xfrm_dst;
struct xfrm_policy_afinfo {
@@ -178,6 +197,8 @@
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo);
+extern void km_policy_notify(struct xfrm_policy *xp, int dir, int event, struct km_cb *c);
+
#define XFRM_ACQ_EXPIRES 30
@@ -283,17 +304,17 @@
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
-#define XFRM_KM_TIMEOUT 30
+#define XFRM_KM_TIMEOUT 30
struct xfrm_mgr
{
struct list_head list;
char *id;
- int (*notify)(struct xfrm_state *x, int event);
+ int (*notify)(struct xfrm_state *x, int event, struct km_cb *c);
int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir);
int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
- int (*notify_policy)(struct xfrm_policy *x, int dir, int event);
+ int (*notify_policy)(struct xfrm_policy *x, int dir, int event, struct km_cb *c);
};
extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -860,7 +881,7 @@
extern wait_queue_head_t km_waitq;
extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
-extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard);
+extern void km_policy_expired(struct xfrm_policy *pol, int dir, int event);
extern void xfrm_input_init(void);
extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq);
--- a/include/linux/xfrm.h 2005-03-25 22:28:39.000000000 -0500
+++ b/include/linux/xfrm.h 2005-03-31 19:26:24.000000000 -0500
@@ -254,5 +254,7 @@
#define XFRMGRP_ACQUIRE 1
#define XFRMGRP_EXPIRE 2
+#define XFRMGRP_SA 4
+#define XFRMGRP_POLICY 8
#endif /* _LINUX_XFRM_H */
--- a/net/xfrm/xfrm_state.c 2005-03-25 22:28:25.000000000 -0500
+++ b/net/xfrm/xfrm_state.c 2005-03-31 19:26:24.000000000 -0500
@@ -239,10 +239,56 @@
}
}
+static DEFINE_RWLOCK(xfrm_km_lock);
+static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
+
+void km_policy_notify(struct xfrm_policy *xp, int dir, int event, struct km_cb *c)
+{
+ struct xfrm_mgr *km;
+
+ read_lock(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list)
+ if (km && km->notify_policy)
+ km->notify_policy(xp, dir, event, c);
+ read_unlock(&xfrm_km_lock);
+}
+EXPORT_SYMBOL(km_policy_notify);
+
+void km_state_notify(struct xfrm_state *x, struct km_cb *c, int event)
+{
+ struct xfrm_mgr *km;
+ read_lock(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list)
+ km->notify(x, event, c);
+ read_unlock(&xfrm_km_lock);
+}
+
+void xfrm_state_del_flush(struct xfrm_state *x)
+{
+ spin_lock_bh(&x->lock);
+ __xfrm_state_delete(x);
+ spin_unlock_bh(&x->lock);
+}
+
void xfrm_state_delete(struct xfrm_state *x)
{
+ int notif = 0;
spin_lock_bh(&x->lock);
+ /*
+ * its unfortunate we have to freeze gc for this
+ * one moment - the other alternative would involve
+ * memcopying the state and then announcing that.
+ * think SMP where theres an iota where this could mess
+ * up - JHS
+ */
+ spin_lock_bh(&xfrm_state_gc_lock);
+ if (x->km.state != XFRM_STATE_DEAD)
+ notif = 1;
__xfrm_state_delete(x);
+
+ if (notif)
+ km_state_notify(x, NULL, XFRM_SAP_DELETED);
+ spin_unlock_bh(&xfrm_state_gc_lock);
spin_unlock_bh(&x->lock);
}
EXPORT_SYMBOL(xfrm_state_delete);
@@ -251,6 +297,8 @@
{
int i;
struct xfrm_state *x;
+ struct km_cb c;
+ int count = 0;
spin_lock_bh(&xfrm_state_lock);
for (i = 0; i < XFRM_DST_HSIZE; i++) {
@@ -261,7 +309,8 @@
xfrm_state_hold(x);
spin_unlock_bh(&xfrm_state_lock);
- xfrm_state_delete(x);
+ xfrm_state_del_flush(x);
+ count++;
xfrm_state_put(x);
spin_lock_bh(&xfrm_state_lock);
@@ -270,6 +319,10 @@
}
}
spin_unlock_bh(&xfrm_state_lock);
+ if (count) {
+ c.data = proto;
+ km_state_notify(NULL, &c, XFRM_SAP_FLUSHED);
+ }
wake_up(&km_waitq);
}
EXPORT_SYMBOL(xfrm_state_flush);
@@ -402,6 +455,7 @@
static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
+
int xfrm_state_add(struct xfrm_state *x)
{
struct xfrm_state_afinfo *afinfo;
@@ -438,6 +492,7 @@
&x->id.daddr, &x->props.saddr, 0);
__xfrm_state_insert(x);
+ km_state_notify(x, NULL, XFRM_SAP_ADDED);
err = 0;
out:
@@ -478,6 +533,7 @@
if (x1->km.state == XFRM_STATE_ACQ) {
__xfrm_state_insert(x);
+ km_state_notify(x, NULL, XFRM_SAP_ADDED);
x = NULL;
}
err = 0;
@@ -509,6 +565,7 @@
xfrm_state_check_expire(x1);
err = 0;
+ km_state_notify(x, NULL, XFRM_SAP_UPDATED);
}
spin_unlock_bh(&x1->lock);
@@ -764,37 +821,41 @@
}
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)
{
struct xfrm_mgr *km;
+ struct km_cb c;
if (hard)
x->km.state = XFRM_STATE_EXPIRED;
else
x->km.dying = 1;
+ c.data = hard;
read_lock(&xfrm_km_lock);
list_for_each_entry(km, &xfrm_km_list, list)
- km->notify(x, hard);
+ km->notify(x, XFRM_SAP_EXPIRED, &c);
read_unlock(&xfrm_km_lock);
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;
@@ -820,11 +881,13 @@
void km_policy_expired(struct xfrm_policy *pol, int dir, int hard)
{
struct xfrm_mgr *km;
+ struct km_cb c;
read_lock(&xfrm_km_lock);
+ c.data = hard;
list_for_each_entry(km, &xfrm_km_list, list)
if (km->notify_policy)
- km->notify_policy(pol, dir, hard);
+ km->notify_policy(pol, dir, XFRM_SAP_EXPIRED, &c);
read_unlock(&xfrm_km_lock);
if (hard)
@@ -957,8 +1020,9 @@
if (x->tunnel) {
struct xfrm_state *t = x->tunnel;
+ /* XXX: Avoid announce?? */
if (atomic_read(&t->tunnel_users) == 2)
- xfrm_state_delete(t);
+ xfrm_state_del_flush(t);
atomic_dec(&t->tunnel_users);
xfrm_state_put(t);
x->tunnel = NULL;
--- a/net/xfrm/xfrm_policy.c 2005-03-25 22:28:21.000000000 -0500
+++ b/net/xfrm/xfrm_policy.c 2005-03-31 19:26:24.000000000 -0500
@@ -298,7 +298,7 @@
* entry dead. The rule must be unlinked from lists to the moment.
*/
-static void xfrm_policy_kill(struct xfrm_policy *policy)
+static void xfrm_policy_kill(struct xfrm_policy *policy, int dir, int notif)
{
write_lock_bh(&policy->lock);
if (policy->dead)
@@ -307,6 +307,9 @@
policy->dead = 1;
spin_lock(&xfrm_policy_gc_lock);
+ if (notif) {
+ km_policy_notify(policy, dir, XFRM_SAP_DELETED, NULL);
+ }
list_add(&policy->list, &xfrm_policy_gc_list);
spin_unlock(&xfrm_policy_gc_lock);
schedule_work(&xfrm_policy_gc_work);
@@ -375,10 +378,11 @@
policy->curlft.use_time = 0;
if (!mod_timer(&policy->timer, jiffies + HZ))
xfrm_pol_hold(policy);
+ km_policy_notify(policy, dir, XFRM_SAP_ADDED, NULL);
write_unlock_bh(&xfrm_policy_lock);
if (delpol) {
- xfrm_policy_kill(delpol);
+ xfrm_policy_kill(delpol, dir, 1);
}
return 0;
}
@@ -402,7 +406,7 @@
if (pol && delete) {
atomic_inc(&flow_cache_genid);
- xfrm_policy_kill(pol);
+ xfrm_policy_kill(pol, dir, 1);
}
return pol;
}
@@ -425,16 +429,16 @@
if (pol && delete) {
atomic_inc(&flow_cache_genid);
- xfrm_policy_kill(pol);
+ xfrm_policy_kill(pol, dir, 1);
}
return pol;
}
EXPORT_SYMBOL(xfrm_policy_byid);
-void xfrm_policy_flush(void)
+void xfrm_policy_flush()
{
struct xfrm_policy *xp;
- int dir;
+ int dir, count = 0;
write_lock_bh(&xfrm_policy_lock);
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
@@ -442,12 +446,15 @@
xfrm_policy_list[dir] = xp->next;
write_unlock_bh(&xfrm_policy_lock);
- xfrm_policy_kill(xp);
+ xfrm_policy_kill(xp, dir, 0);
+ count++;
write_lock_bh(&xfrm_policy_lock);
}
}
atomic_inc(&flow_cache_genid);
+ if (count)
+ km_policy_notify(NULL, 0, XFRM_SAP_FLUSHED, NULL);
write_unlock_bh(&xfrm_policy_lock);
}
EXPORT_SYMBOL(xfrm_policy_flush);
@@ -558,7 +565,7 @@
if (pol) {
if (dir < XFRM_POLICY_MAX)
atomic_inc(&flow_cache_genid);
- xfrm_policy_kill(pol);
+ xfrm_policy_kill(pol, dir, 1);
}
}
@@ -579,7 +586,7 @@
write_unlock_bh(&xfrm_policy_lock);
if (old_pol) {
- xfrm_policy_kill(old_pol);
+ xfrm_policy_kill(old_pol, dir, 1);
}
return 0;
}
--- a/net/xfrm/xfrm_user.c 2005-03-25 22:28:22.000000000 -0500
+++ b/net/xfrm/xfrm_user.c 2005-03-31 19:26:24.000000000 -0500
@@ -683,6 +683,10 @@
if (!xp)
return err;
+ /* shouldnt excl be based on nlh flags??
+ * Aha! this is anti-netlink really i.e more pfkey derived
+ * in netlink excl is a flag and you wouldnt need
+ * a type XFRM_MSG_UPDPOLICY - JHS */
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
err = xfrm_policy_insert(p->dir, xp, excl);
if (err) {
@@ -1053,10 +1057,10 @@
return -1;
}
-static int xfrm_send_state_notify(struct xfrm_state *x, int hard)
+static int xfrm_exp_state_notify(struct xfrm_state *x, u32 hard)
{
struct sk_buff *skb;
-
+ /* fix to do alloc using NLM macros */
skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
@@ -1069,6 +1073,98 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_sa_flush(struct km_cb *c)
+{
+ struct xfrm_usersa_flush *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ u32 ppid = 0;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, ppid, jiffies,
+ XFRM_MSG_FLUSHSA, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ if (!c) {
+ printk("xfrm_notify_sa_flush NULL km cb\n");
+ p->proto = 0;
+ } else {
+ p->proto = c->data;
+ }
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, ppid, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_sa( struct xfrm_state *x, int event, struct km_cb *c)
+{
+ struct xfrm_usersa_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt;
+ unsigned char *b;
+ u32 ppid = 0;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWSA;
+ else if (event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDSA;
+ else if (event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELSA;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, ppid, jiffies,
+ nlt, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ copy_to_user_state(x, p);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, ppid, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_state_notify(struct xfrm_state *x, int event, struct km_cb *c)
+{
+
+ if ((event == XFRM_SAP_ADDED) ||
+ (event == XFRM_SAP_UPDATED) ||
+ (event == XFRM_SAP_DELETED))
+ return xfrm_notify_sa(x, event, c);
+
+ if (event == XFRM_SAP_FLUSHED)
+ xfrm_notify_sa_flush(c);
+
+ if (event != XFRM_SAP_EXPIRED)
+ return 0;
+
+ return xfrm_exp_state_notify(x, c->data);
+}
+
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_tmpl *xt, struct xfrm_policy *xp,
int dir)
@@ -1202,7 +1298,8 @@
return -1;
}
-static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard)
+
+static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, int hard)
{
struct sk_buff *skb;
size_t len;
@@ -1221,6 +1318,91 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_policy( struct xfrm_policy *xp, int dir, int event, struct km_cb *c)
+{
+ struct xfrm_userpolicy_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt = 0 ;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
+ u32 ppid = 0;
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWPOLICY;
+ else if (event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDPOLICY;
+ else if (event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELPOLICY;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, ppid, jiffies, nlt, sizeof(*p));
+
+ p = NLMSG_DATA(nlh);
+
+ nlh->nlmsg_flags = 0;
+
+ copy_to_user_policy(xp, p, dir);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, ppid, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_policy_flush(struct km_cb *c)
+{
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ u32 ppid = 0;
+ int len = NLMSG_LENGTH(0);
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+
+ nlh = NLMSG_PUT(skb, 0, jiffies, XFRM_MSG_FLUSHPOLICY, 0);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, ppid, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int event, struct km_cb *c)
+{
+
+ if ((event == XFRM_SAP_ADDED) ||
+ (event == XFRM_SAP_UPDATED) ||
+ (event == XFRM_SAP_DELETED))
+ return xfrm_notify_policy(xp, dir, event, c);
+
+ if (event == XFRM_SAP_FLUSHED)
+ return xfrm_notify_policy_flush(c);
+
+ if (event != XFRM_SAP_EXPIRED) {
+ printk("Netlink Unknown Policy event %d\n",event);
+ return 0;
+ }
+
+ return xfrm_exp_policy_notify(xp, dir, c->data);
+}
+
static struct xfrm_mgr netlink_mgr = {
.id = "netlink",
.notify = xfrm_send_state_notify,
--- a/net/key/af_key.c 2005-03-25 22:28:39.000000000 -0500
+++ b/net/key/af_key.c 2005-03-31 19:26:24.000000000 -0500
@@ -1240,7 +1240,6 @@
return 0;
}
-
static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
struct sk_buff *out_skb;
@@ -2317,11 +2316,30 @@
}
}
-static int pfkey_send_notify(struct xfrm_state *x, int hard)
+static int pfkey_send_notify(struct xfrm_state *x, int event, struct km_cb *c)
{
struct sk_buff *out_skb;
struct sadb_msg *out_hdr;
- int hsc = (hard ? 2 : 1);
+ int hard;
+ int hsc;
+
+ /*
+ * migrate pf_key later - for now only support is for
+ * expire events
+ */
+ if (event != XFRM_SAP_EXPIRED)
+ return 0;
+
+ if (!c) {
+ printk("pfkey_send_notify: bad CB data!\n");
+ return 0;
+ }
+
+ hard = c->data;
+ if (hard)
+ hsc = 2;
+ else
+ hsc = 1;
out_skb = pfkey_xfrm_state2msg(x, 0, hsc);
if (IS_ERR(out_skb))
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 1:37 PATCH: IPSEC xfrm events jamal
@ 2005-04-01 4:21 ` Herbert Xu
2005-04-01 11:03 ` jamal
2005-04-01 17:28 ` Masahide NAKAMURA
1 sibling, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-01 4:21 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Thu, Mar 31, 2005 at 08:37:21PM -0500, jamal wrote:
>
> Ok, heres the final patch with all the changes discussed.
Thanks Jamal. The patch looks good overall. However, the
delete/flush code is new so I've got something to say again :)
> --- a/include/net/xfrm.h 2005-03-25 22:28:26.000000000 -0500
> +++ b/include/net/xfrm.h 2005-03-31 19:26:24.000000000 -0500
>
> +/* callback structure passed from either netlink or pfkey */
> +struct km_cb
This name is a bit non-specific.
> +{
> + u32 data; /* callee to caller */
> +};
Might as well put the event into it if we're going to keep this
structure. It'll help to shorten the function prototypes that
use it.
And then we can just call this structure km_event.
> -extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard);
> +extern void km_policy_expired(struct xfrm_policy *pol, int dir, int event);
Bogus prototype change.
> +void xfrm_state_del_flush(struct xfrm_state *x)
> +{
> + spin_lock_bh(&x->lock);
> + __xfrm_state_delete(x);
> + spin_unlock_bh(&x->lock);
> +}
Sorry, I've changed my mind on this. This demonstrates why the
km_notify_* calls should be made from af_key/xfrm_user directly
instead of here.
Some of these functions are called internally as you discovered.
Since the notifications should only be generated by user requests,
calls to km_notify_* should be made at the places where the user
requests are handled, which is in the KM itself.
Otherwise we'll have to add hacks like this to avoid the
notification for internal users.
> void xfrm_state_delete(struct xfrm_state *x)
> {
> + int notif = 0;
> spin_lock_bh(&x->lock);
> + /*
> + * its unfortunate we have to freeze gc for this
> + * one moment - the other alternative would involve
> + * memcopying the state and then announcing that.
> + * think SMP where theres an iota where this could mess
> + * up - JHS
> + */
> + spin_lock_bh(&xfrm_state_gc_lock);
> + if (x->km.state != XFRM_STATE_DEAD)
> + notif = 1;
> __xfrm_state_delete(x);
> +
> + if (notif)
> + km_state_notify(x, NULL, XFRM_SAP_DELETED);
You've caught a real bug for af_key here. It's currently possible to
receive two delete notifications for the same state.
However, may I suggest that we code this differently. Make
__xfrm_state_delete return 0 if the state was really deleted
and -ESRCH otherwise.
Then af_key/xfrm_user can simply call km_state_notify if the
return value was zero.
BTW there is no need to grab xfrm_state_gc_lock. You've got
a reference count on the state from your caller.
> @@ -270,6 +319,10 @@
> }
> }
> spin_unlock_bh(&xfrm_state_lock);
> + if (count) {
> + c.data = proto;
> + km_state_notify(NULL, &c, XFRM_SAP_FLUSHED);
> + }
The notification should occur in all cases, even if count == 0.
> @@ -957,8 +1020,9 @@
> if (x->tunnel) {
> struct xfrm_state *t = x->tunnel;
>
> + /* XXX: Avoid announce?? */
> if (atomic_read(&t->tunnel_users) == 2)
> - xfrm_state_delete(t);
> + xfrm_state_del_flush(t);
That's right. We don't want to announce internal states to the world.
> --- a/net/xfrm/xfrm_policy.c 2005-03-25 22:28:21.000000000 -0500
> +++ b/net/xfrm/xfrm_policy.c 2005-03-31 19:26:24.000000000 -0500
> @@ -298,7 +298,7 @@
> * entry dead. The rule must be unlinked from lists to the moment.
> */
>
> -static void xfrm_policy_kill(struct xfrm_policy *policy)
> +static void xfrm_policy_kill(struct xfrm_policy *policy, int dir, int notif)
Again, had you done the km_* calls from af_key/xfrm_user, then there'd
be no need to check notif here.
BTW, as it is you're announcing expired policies twice. Once as an
expire event and once as a delete event. This problem will also go
away if you move the km_* calls into af_key/xfrm_user.
> @@ -579,7 +586,7 @@
> write_unlock_bh(&xfrm_policy_lock);
>
> if (old_pol) {
> - xfrm_policy_kill(old_pol);
> + xfrm_policy_kill(old_pol, dir, 1);
> }
Please don't announce socket policies :)
> --- a/net/xfrm/xfrm_user.c 2005-03-25 22:28:22.000000000 -0500
> +++ b/net/xfrm/xfrm_user.c 2005-03-31 19:26:24.000000000 -0500
> @@ -683,6 +683,10 @@
> if (!xp)
> return err;
>
> + /* shouldnt excl be based on nlh flags??
> + * Aha! this is anti-netlink really i.e more pfkey derived
> + * in netlink excl is a flag and you wouldnt need
> + * a type XFRM_MSG_UPDPOLICY - JHS */
Good point. Care to provide a patch to treat NEW + NLM_F_REPLACE
as UPD?
> @@ -1053,10 +1057,10 @@
> return -1;
> }
>
> -static int xfrm_send_state_notify(struct xfrm_state *x, int hard)
> +static int xfrm_exp_state_notify(struct xfrm_state *x, u32 hard)
How about calling this xfrm_notify_sa_expired for consistency?
Ditto for the policy function.
> +static int xfrm_notify_sa_flush(struct km_cb *c)
> +{
> + struct xfrm_usersa_flush *p;
> + struct nlmsghdr *nlh;
> + struct sk_buff *skb;
> + unsigned char *b;
> + u32 ppid = 0;
> + int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
> +
> + skb = alloc_skb(len, GFP_ATOMIC);
> + if (skb == NULL)
> + return -ENOMEM;
> + b = skb->tail;
> +
> + nlh = NLMSG_PUT(skb, ppid, jiffies,
If we're serious about providing sequence numbers then please
set it up as an atomic integer and use it throughout this file.
Otherwise just pop zero in there.
> + p = NLMSG_DATA(nlh);
> + if (!c) {
> + printk("xfrm_notify_sa_flush NULL km cb\n");
> + p->proto = 0;
Is anyone expected to call this with a NULL pointer? If not then
just let it OOPS. Same comment applies to the cb checks later on.
> +static int xfrm_notify_sa( struct xfrm_state *x, int event, struct km_cb *c)
> + if (event == XFRM_SAP_ADDED)
> + nlt = XFRM_MSG_NEWSA;
> + else if (event == XFRM_SAP_UPDATED)
> + nlt = XFRM_MSG_UPDSA;
> + else if (event == XFRM_SAP_DELETED)
> + nlt = XFRM_MSG_DELSA;
> + else
> + goto nlmsg_failure;
Please use a switch.
> +static int xfrm_send_state_notify(struct xfrm_state *x, int event, struct km_cb *c)
> +{
> +
> + if ((event == XFRM_SAP_ADDED) ||
> + (event == XFRM_SAP_UPDATED) ||
> + (event == XFRM_SAP_DELETED))
> + return xfrm_notify_sa(x, event, c);
> +
> + if (event == XFRM_SAP_FLUSHED)
> + xfrm_notify_sa_flush(c);
> +
> + if (event != XFRM_SAP_EXPIRED)
> + return 0;
Again a switch would be perfect.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 4:21 ` Herbert Xu
@ 2005-04-01 11:03 ` jamal
2005-04-01 11:42 ` Herbert Xu
0 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-01 11:03 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Thu, 2005-03-31 at 23:21, Herbert Xu wrote:
> On Thu, Mar 31, 2005 at 08:37:21PM -0500, jamal wrote:
>
> > --- a/include/net/xfrm.h 2005-03-25 22:28:26.000000000 -0500
> > +++ b/include/net/xfrm.h 2005-03-31 19:26:24.000000000 -0500
> >
> > +/* callback structure passed from either netlink or pfkey */
> > +struct km_cb
>
> This name is a bit non-specific.
>
note: used by both SP/SA
> > +{
> > + u32 data; /* callee to caller */
> > +};
>
> Might as well put the event into it if we're going to keep this
> structure. It'll help to shorten the function prototypes that
> use it.
>
> And then we can just call this structure km_event.
>
sure.
> > -extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard);
> > +extern void km_policy_expired(struct xfrm_policy *pol, int dir, int event);
>
> Bogus prototype change.
>
agreed.
> > +void xfrm_state_del_flush(struct xfrm_state *x)
> > +{
> > + spin_lock_bh(&x->lock);
> > + __xfrm_state_delete(x);
> > + spin_unlock_bh(&x->lock);
> > +}
>
> Sorry, I've changed my mind on this. This demonstrates why the
> km_notify_* calls should be made from af_key/xfrm_user directly
> instead of here.
>
>
> Some of these functions are called internally as you discovered.
> Since the notifications should only be generated by user requests,
> calls to km_notify_* should be made at the places where the user
> requests are handled, which is in the KM itself.
>
You need to be able to generate events at every km not just the one that
generated the request. You also (most of the time) need to do it before
affected object dissapears. So I am missing your point on this one.
> Otherwise we'll have to add hacks like this to avoid the
> notification for internal users.
>
I may be paranoid but i do this because x could be garbage collected way
before i send the km user message - and i need it to use it to generate
the event. I could take a copy of it ...
> > void xfrm_state_delete(struct xfrm_state *x)
> > {
> > + int notif = 0;
> > spin_lock_bh(&x->lock);
> > + /*
> > + * its unfortunate we have to freeze gc for this
> > + * one moment - the other alternative would involve
> > + * memcopying the state and then announcing that.
> > + * think SMP where theres an iota where this could mess
> > + * up - JHS
> > + */
> > + spin_lock_bh(&xfrm_state_gc_lock);
> > + if (x->km.state != XFRM_STATE_DEAD)
> > + notif = 1;
> > __xfrm_state_delete(x);
> > +
> > + if (notif)
> > + km_state_notify(x, NULL, XFRM_SAP_DELETED);
>
> You've caught a real bug for af_key here. It's currently possible to
> receive two delete notifications for the same state.
Can you elaborate?
> However, may I suggest that we code this differently. Make
> __xfrm_state_delete return 0 if the state was really deleted
> and -ESRCH otherwise.
>
> Then af_key/xfrm_user can simply call km_state_notify if the
> return value was zero.
>
Again like i said: I need to tell every km user about the event, not
just the originator.
> BTW there is no need to grab xfrm_state_gc_lock. You've got
> a reference count on the state from your caller.
>
Aha! I missed that - I will remove it.
> > @@ -270,6 +319,10 @@
> > }
> > }
> > spin_unlock_bh(&xfrm_state_lock);
> > + if (count) {
> > + c.data = proto;
> > + km_state_notify(NULL, &c, XFRM_SAP_FLUSHED);
> > + }
>
> The notification should occur in all cases, even if count == 0.
>
Well, Masahide-San and I actually did discuss this and he was of the
same opinion as you. My opinion: We only generate events when something
happens, not just because someone issues a command. If flush was issued
and there was nothing to flush why generate an event? does the PFKEY RFC
say anything on this?
> > @@ -957,8 +1020,9 @@
> > if (x->tunnel) {
> > struct xfrm_state *t = x->tunnel;
> >
> > + /* XXX: Avoid announce?? */
> > if (atomic_read(&t->tunnel_users) == 2)
> > - xfrm_state_delete(t);
> > + xfrm_state_del_flush(t);
>
> That's right. We don't want to announce internal states to the world.
>
I will remove that comment. Thats achieved in the above code although
the called funtion may not have the appropriate name .
> > --- a/net/xfrm/xfrm_policy.c 2005-03-25 22:28:21.000000000 -0500
> > +++ b/net/xfrm/xfrm_policy.c 2005-03-31 19:26:24.000000000 -0500
> > @@ -298,7 +298,7 @@
> > * entry dead. The rule must be unlinked from lists to the moment.
> > */
> >
> > -static void xfrm_policy_kill(struct xfrm_policy *policy)
> > +static void xfrm_policy_kill(struct xfrm_policy *policy, int dir, int notif)
>
> Again, had you done the km_* calls from af_key/xfrm_user, then there'd
> be no need to check notif here.
>
Refer to my comments above on being able to tell multiple managers about
the events originated by one.
Actually, given that this function is being called in many places i
would say this is the exact central location you want to issue the
announce from.
> BTW, as it is you're announcing expired policies twice. Once as an
> expire event and once as a delete event. This problem will also go
> away if you move the km_* calls into af_key/xfrm_user.
>
Theres an announcement only when policy goes dead ;->
So only one not two. Same with the state as well.
And again cant do it from af_key/xfrm_user if you want to have events
generated by one km to be sent to another as well. Its pf_key that needs
fixing.
> > @@ -579,7 +586,7 @@
> > write_unlock_bh(&xfrm_policy_lock);
> >
> > if (old_pol) {
> > - xfrm_policy_kill(old_pol);
> > + xfrm_policy_kill(old_pol, dir, 1);
> > }
>
> Please don't announce socket policies :)
>
I missed this one - sorry.
> > --- a/net/xfrm/xfrm_user.c 2005-03-25 22:28:22.000000000 -0500
> > +++ b/net/xfrm/xfrm_user.c 2005-03-31 19:26:24.000000000 -0500
> > @@ -683,6 +683,10 @@
> > if (!xp)
> > return err;
> >
> > + /* shouldnt excl be based on nlh flags??
> > + * Aha! this is anti-netlink really i.e more pfkey derived
> > + * in netlink excl is a flag and you wouldnt need
> > + * a type XFRM_MSG_UPDPOLICY - JHS */
>
> Good point. Care to provide a patch to treat NEW + NLM_F_REPLACE
> as UPD?
>
> > @@ -1053,10 +1057,10 @@
> > return -1;
> > }
> >
> > -static int xfrm_send_state_notify(struct xfrm_state *x, int hard)
> > +static int xfrm_exp_state_notify(struct xfrm_state *x, u32 hard)
>
> How about calling this xfrm_notify_sa_expired for consistency?
> Ditto for the policy function.
sure.
>
> > +static int xfrm_notify_sa_flush(struct km_cb *c)
> > +{
> > + struct xfrm_usersa_flush *p;
> > + struct nlmsghdr *nlh;
> > + struct sk_buff *skb;
> > + unsigned char *b;
> > + u32 ppid = 0;
> > + int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
> > +
> > + skb = alloc_skb(len, GFP_ATOMIC);
> > + if (skb == NULL)
> > + return -ENOMEM;
> > + b = skb->tail;
> > +
> > + nlh = NLMSG_PUT(skb, ppid, jiffies,
>
> If we're serious about providing sequence numbers then please
> set it up as an atomic integer and use it throughout this file.
>
> Otherwise just pop zero in there.
>
I was just being lazy. I could send a 0 but whats wrong with using
jiffies?
> > + p = NLMSG_DATA(nlh);
> > + if (!c) {
> > + printk("xfrm_notify_sa_flush NULL km cb\n");
> > + p->proto = 0;
>
> Is anyone expected to call this with a NULL pointer? If not then
> just let it OOPS. Same comment applies to the cb checks later on.
>
Will fix this.
> > +static int xfrm_notify_sa( struct xfrm_state *x, int event, struct km_cb *c)
>
> > + if (event == XFRM_SAP_ADDED)
> > + nlt = XFRM_MSG_NEWSA;
> > + else if (event == XFRM_SAP_UPDATED)
> > + nlt = XFRM_MSG_UPDSA;
> > + else if (event == XFRM_SAP_DELETED)
> > + nlt = XFRM_MSG_DELSA;
> > + else
> > + goto nlmsg_failure;
>
> Please use a switch.
>
sure.
> > +static int xfrm_send_state_notify(struct xfrm_state *x, int event, struct km_cb *c)
> > +{
> > +
> > + if ((event == XFRM_SAP_ADDED) ||
> > + (event == XFRM_SAP_UPDATED) ||
> > + (event == XFRM_SAP_DELETED))
> > + return xfrm_notify_sa(x, event, c);
> > +
> > + if (event == XFRM_SAP_FLUSHED)
> > + xfrm_notify_sa_flush(c);
> > +
> > + if (event != XFRM_SAP_EXPIRED)
> > + return 0;
>
> Again a switch would be perfect.
>
Will fix this.
BTW, Herbert, thanks for taking the time; appreciated.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 11:03 ` jamal
@ 2005-04-01 11:42 ` Herbert Xu
2005-04-01 12:24 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-01 11:42 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Fri, Apr 01, 2005 at 06:03:18AM -0500, jamal wrote:
>
> > Some of these functions are called internally as you discovered.
> > Since the notifications should only be generated by user requests,
> > calls to km_notify_* should be made at the places where the user
> > requests are handled, which is in the KM itself.
>
> You need to be able to generate events at every km not just the one that
> generated the request. You also (most of the time) need to do it before
I understand. However, that's not determined by where you put the
km_notify call itself. Even when you call km_notify from af_key
or xfrm_user it will notify every km in the system.
It's the fact that we're calling km_notify instead of pfkey_broadcast
or netlink_broadcast that's important, not the location.
Having the km_notify call made in af_key/xfrm_user is convenient though
for the reason I outlined above.
> I may be paranoid but i do this because x could be garbage collected way
> before i send the km user message - and i need it to use it to generate
> the event. I could take a copy of it ...
That's what the ref counter is for.
> > You've caught a real bug for af_key here. It's currently possible to
> > receive two delete notifications for the same state.
>
> Can you elaborate?
Imagine you've got a KM that's trying to delete a state via af_key that's
about to expire. If pfkey_delete looks up the state successfully, and
then the timer triggers before the actual xfrm_state_delete, you will
get one event generated by the timer and another by pfkey_delete.
> Again like i said: I need to tell every km user about the event, not
> just the originator.
I'm suggesting that you add the km_notify calls to af_key and xfrm_user.
That will take care of notifying everyone.
> Well, Masahide-San and I actually did discuss this and he was of the
> same opinion as you. My opinion: We only generate events when something
> happens, not just because someone issues a command. If flush was issued
> and there was nothing to flush why generate an event? does the PFKEY RFC
> say anything on this?
RFC 2367 says that:
The messaging behavior for SADB_FLUSH is:
Send an SADB_FLUSH message from a user process to the kernel.
<base>
The kernel will return an SADB_FLUSH message to all listening
sockets.
<base>
As you can see, there is no exception for the case of an empty database.
So my interpretation would be that a broadcast is needed.
> Refer to my comments above on being able to tell multiple managers about
> the events originated by one.
May I also refer you to my comment above about this being achieved
by calling km_notify, even if you do it from within af_key or
xfrm_user :)
> Actually, given that this function is being called in many places i
> would say this is the exact central location you want to issue the
> announce from.
Try this as an exercise. List all the xfrm_policy_kills that need
notifications and all those that don't, you will find that the former
all originate from delete/flush commands in af_key/xfrm_user, while
the latter originate from other callers.
In other words, by placing the call in af_key/xfrm_user you simplify
the logic and make it more maintainable.
> > BTW, as it is you're announcing expired policies twice. Once as an
> > expire event and once as a delete event. This problem will also go
> > away if you move the km_* calls into af_key/xfrm_user.
>
> Theres an announcement only when policy goes dead ;->
> So only one not two. Same with the state as well.
Well when the policy expires you will get one expire notification from
the current timer code and a new one from your patch since the timer
calls xfrm_policy_delete.
See my point? By putting the call in xfrm_policy.c you have to be
really careful in dividing the internal users which shouldn't
generate notifications and the external users which should. By doing
it in af_key/xfrm_user you can avoid all this work.
> And again cant do it from af_key/xfrm_user if you want to have events
> generated by one km to be sent to another as well. Its pf_key that needs
> fixing.
Well I must repeat that if you were calling km_notify from
af_key/xfrm_user you will be sending these events to all km's
no matter what their affiliation is :)
> > If we're serious about providing sequence numbers then please
> > set it up as an atomic integer and use it throughout this file.
> >
> > Otherwise just pop zero in there.
>
> I was just being lazy. I could send a 0 but whats wrong with using
> jiffies?
Using jiffies means that you can have two successive messages that
share the same sequence number. It's not a big deal of course. But
if we're going to indicate ordering, we might as well go the full
length.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 11:42 ` Herbert Xu
@ 2005-04-01 12:24 ` jamal
2005-04-01 12:35 ` Herbert Xu
0 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-01 12:24 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Fri, 2005-04-01 at 06:42, Herbert Xu wrote:
> On Fri, Apr 01, 2005 at 06:03:18AM -0500, jamal wrote:
> >
> > > Some of these functions are called internally as you discovered.
> > > Since the notifications should only be generated by user requests,
> > > calls to km_notify_* should be made at the places where the user
> > > requests are handled, which is in the KM itself.
> >
> > You need to be able to generate events at every km not just the one that
> > generated the request. You also (most of the time) need to do it before
>
> I understand. However, that's not determined by where you put the
> km_notify call itself. Even when you call km_notify from af_key
> or xfrm_user it will notify every km in the system.
>
> It's the fact that we're calling km_notify instead of pfkey_broadcast
> or netlink_broadcast that's important, not the location.
>
> Having the km_notify call made in af_key/xfrm_user is convenient though
> for the reason I outlined above.
I think either scheme is fine really;-> I will definetely go back and
consider the approach you are suggesting and see if it results into
more maintanable code - then fair. Otherwise you realize its more work
for me ;->
> > > You've caught a real bug for af_key here. It's currently possible to
> > > receive two delete notifications for the same state.
> >
> > Can you elaborate?
>
> Imagine you've got a KM that's trying to delete a state via af_key that's
> about to expire. If pfkey_delete looks up the state successfully, and
> then the timer triggers before the actual xfrm_state_delete, you will
> get one event generated by the timer and another by pfkey_delete.
>
I havent checked the state machine closely, but the following seems to
make sense:
The first thing that happens to delete the state/policy should win if
the state/policy is transitioned to dead.
> RFC 2367 says that:
>
> The messaging behavior for SADB_FLUSH is:
>
> Send an SADB_FLUSH message from a user process to the kernel.
>
> <base>
>
> The kernel will return an SADB_FLUSH message to all listening
> sockets.
>
> <base>
>
> As you can see, there is no exception for the case of an empty database.
> So my interpretation would be that a broadcast is needed.
>
Does it really make sense, Herbert? ;->
What is it that you just flushed that results in the event?
The RFC is ambigous in my opinion. Look at what it says about deleting
(same ambiguity).
----
3.1.4 SADB_DELETE
The SADB_DELETE message causes the kernel to delete a Security
Association from the key table. The delete message consists of the
base header followed by the association, and the source and
destination sockaddrs in the address extension. The kernel deletes
the security association matching the type, spi, source address, and
destination address in the message.
The message behavior for SADB_DELETE is as follows:
Send an SADB_DELETE message from a user process to the kernel.
<base, SA(*), address(SD)>
The kernel returns the SADB_DELETE message to all listening
processes.
<base, SA(*), address(SD)>
------
So why would you generate an event in the case when you didnt delete anything?
> > Actually, given that this function is being called in many places i
> > would say this is the exact central location you want to issue the
> > announce from.
>
> Try this as an exercise. List all the xfrm_policy_kills that need
> notifications and all those that don't, you will find that the former
> all originate from delete/flush commands in af_key/xfrm_user, while
> the latter originate from other callers.
>
> In other words, by placing the call in af_key/xfrm_user you simplify
> the logic and make it more maintainable.
>
I will go over the code and review.
You may be absolutely right - thats the better approach to take.
> BTW, as it is you're announcing expired policies twice. Once as an
> > > expire event and once as a delete event. This problem will also go
> > > away if you move the km_* calls into af_key/xfrm_user.
> >
> > Theres an announcement only when policy goes dead ;->
> > So only one not two. Same with the state as well.
>
> Well when the policy expires you will get one expire notification from
> the current timer code and a new one from your patch since the timer
> calls xfrm_policy_delete.
>
> See my point? By putting the call in xfrm_policy.c you have to be
> really careful in dividing the internal users which shouldn't
> generate notifications and the external users which should. By doing
> it in af_key/xfrm_user you can avoid all this work.
>
Thats a bug really which is being exposed now. So it has nothing to do
with the approach taken ;->
No expire should be sent if the policy has transitioned to dead. The bug
is trivial to fix - and actually should be fixed regardless of this
patch.
> > I was just being lazy. I could send a 0 but whats wrong with using
> > jiffies?
>
> Using jiffies means that you can have two successive messages that
> share the same sequence number. It's not a big deal of course. But
> if we're going to indicate ordering, we might as well go the full
> length.
>
Good point. I will stay lazy and just set a 0 ;->
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 12:24 ` jamal
@ 2005-04-01 12:35 ` Herbert Xu
2005-04-01 12:59 ` jamal
2005-04-02 1:04 ` jamal
0 siblings, 2 replies; 48+ messages in thread
From: Herbert Xu @ 2005-04-01 12:35 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Fri, Apr 01, 2005 at 07:24:38AM -0500, jamal wrote:
>
> I think either scheme is fine really;-> I will definetely go back and
> consider the approach you are suggesting and see if it results into
> more maintanable code - then fair. Otherwise you realize its more work
> for me ;->
Well I'm happy to code that part if you want :)
> I havent checked the state machine closely, but the following seems to
> make sense:
> The first thing that happens to delete the state/policy should win if
> the state/policy is transitioned to dead.
Agreed. That's what we'll get if we make __xfrm_state_delete return
success/failure.
> So why would you generate an event in the case when you didnt delete anything?
You're right that the RFC isn't very clear.
Let's forget about the RFC and simply consider the usefulness of this.
I contend that it is useful to see a FLUSH notification even when
it flushed nothing.
The reason is that this is an indication to all listeners that the
database is completely empty.
> > Well when the policy expires you will get one expire notification from
> > the current timer code and a new one from your patch since the timer
> > calls xfrm_policy_delete.
> >
> > See my point? By putting the call in xfrm_policy.c you have to be
> > really careful in dividing the internal users which shouldn't
> > generate notifications and the external users which should. By doing
> > it in af_key/xfrm_user you can avoid all this work.
>
> Thats a bug really which is being exposed now. So it has nothing to do
> with the approach taken ;->
You're right that it is a bug. However, this bug would've never triggered
before because we simply didn't have delete policy notifications :)
> No expire should be sent if the policy has transitioned to dead. The bug
> is trivial to fix - and actually should be fixed regardless of this
> patch.
Yes the same fix to __xfrm_state_delete can be applied to
xfrm_policy_delete.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 12:35 ` Herbert Xu
@ 2005-04-01 12:59 ` jamal
2005-04-01 13:18 ` jamal
2005-04-01 14:19 ` Masahide NAKAMURA
2005-04-02 1:04 ` jamal
1 sibling, 2 replies; 48+ messages in thread
From: jamal @ 2005-04-01 12:59 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Fri, 2005-04-01 at 07:35, Herbert Xu wrote:
> On Fri, Apr 01, 2005 at 07:24:38AM -0500, jamal wrote:
> >
> > I think either scheme is fine really;-> I will definetely go back and
> > consider the approach you are suggesting and see if it results into
> > more maintanable code - then fair. Otherwise you realize its more work
> > for me ;->
>
> Well I'm happy to code that part if you want :)
>
Let me review first. If it is valuable (we may have to leave expire
alone). If i can get it done within next day or two fine - else if i get
busyed out elsewhere i will hand it to you. Actually if you have plenty
cycles and are very enthusiastic about this i can hand it to you right
now ;-> Masahide and myself have some momentum going right now but i
dont think this will be that disruptive.
> You're right that the RFC isn't very clear.
>
> Let's forget about the RFC and simply consider the usefulness of this.
> I contend that it is useful to see a FLUSH notification even when
> it flushed nothing.
>
> The reason is that this is an indication to all listeners that the
> database is completely empty.
>
Ok, let me hear from Masahide-san: If he still holds the same opinion as
you then i will make the change.
> > Thats a bug really which is being exposed now. So it has nothing to do
> > with the approach taken ;->
>
> You're right that it is a bug. However, this bug would've never triggered
> before because we simply didn't have delete policy notifications :)
>
indeed.
> > No expire should be sent if the policy has transitioned to dead. The bug
> > is trivial to fix - and actually should be fixed regardless of this
> > patch.
>
> Yes the same fix to __xfrm_state_delete can be applied to
> xfrm_policy_delete.
>
agreed.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 12:59 ` jamal
@ 2005-04-01 13:18 ` jamal
2005-04-01 14:19 ` Masahide NAKAMURA
1 sibling, 0 replies; 48+ messages in thread
From: jamal @ 2005-04-01 13:18 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Fri, 2005-04-01 at 07:59, jamal wrote:
> Let me review first. If it is valuable (we may have to leave expire
> alone).
Ok, from a first review I would agree with you the result of doing it in
km user will be more maintainable. It will result in a larger patch
but in the long run more maintainable.
> If i can get it done within next day or two fine - else if i get
> busyed out elsewhere i will hand it to you.
Let me code away at it - The offer still stands though ;->
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 12:59 ` jamal
2005-04-01 13:18 ` jamal
@ 2005-04-01 14:19 ` Masahide NAKAMURA
1 sibling, 0 replies; 48+ messages in thread
From: Masahide NAKAMURA @ 2005-04-01 14:19 UTC (permalink / raw)
To: hadi, Herbert Xu; +Cc: Patrick McHardy, David S. Miller, netdev
Hello Jamal and Herbert,
jamal wrote:
> Let me review first. If it is valuable (we may have to leave expire
> alone). If i can get it done within next day or two fine - else if i get
> busyed out elsewhere i will hand it to you. Actually if you have plenty
> cycles and are very enthusiastic about this i can hand it to you right
> now ;-> Masahide and myself have some momentum going right now but i
> dont think this will be that disruptive.
>
>
>>You're right that the RFC isn't very clear.
>>
>>Let's forget about the RFC and simply consider the usefulness of this.
>>I contend that it is useful to see a FLUSH notification even when
>>it flushed nothing.
>>
>>The reason is that this is an indication to all listeners that the
>>database is completely empty.
>>
>
>
> Ok, let me hear from Masahide-san: If he still holds the same opinion as
> you then i will make the change.
I think FLUSH should be sent in such case.
Because flushing empty SADB/SPD is not an error (at current code),
it is reasonable to broadcast it.
Regards,
--
Masahide NAKAMURA
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 1:37 PATCH: IPSEC xfrm events jamal
2005-04-01 4:21 ` Herbert Xu
@ 2005-04-01 17:28 ` Masahide NAKAMURA
1 sibling, 0 replies; 48+ messages in thread
From: Masahide NAKAMURA @ 2005-04-01 17:28 UTC (permalink / raw)
To: hadi, Herbert Xu; +Cc: Patrick McHardy, David S. Miller, netdev
Jamal and Herbert,
jamal wrote:
> Herbert et al,
>
> Ok, heres the final patch with all the changes discussed.
>
> include/linux/xfrm.h | 2
> include/net/xfrm.h | 29 ++++++-
> net/key/af_key.c | 24 +++++-
> net/xfrm/xfrm_policy.c | 25 ++++--
> net/xfrm/xfrm_state.c | 84 +++++++++++++++++++--
> net/xfrm/xfrm_user.c | 188
> ++++++++++++++++++++++++++++++++++++++++++++++++-
> 6 files changed, 323 insertions(+), 29 deletions(-)
>
> I have tested this with both setkey and iproute2 (about 10 scenarios or
> so). Masahide-san is doing a lot more thorough testing with key servers
> as well. He has not tested this patch yet (time difference) but it is
> based on the last one he tested.
Short report:
I've tested on this patched kernel and it works.
- add/del/flush for SA/SP and allocspi/acquire/upd for SA
through netlink socket
- racoon runs fine (pfkey works for normal operation)
both without and with opening netlink socket to listen
Since we have discussion which is still going on about the patch,
the code will be change and I'll need to test again anyway.
Thanks,
--
Masahide NAKAMURA
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-01 12:35 ` Herbert Xu
2005-04-01 12:59 ` jamal
@ 2005-04-02 1:04 ` jamal
2005-04-02 1:28 ` Herbert Xu
1 sibling, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-02 1:04 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
Herbert,
Staring at the code, obversation:
-> PFKEY is going to be interesting to have it actually generate events
as a result of some app using netlink such as ip x - the reverse is
actually easier to deal with. This problem doesnt exist with current
approach i am taking.
The issue is that pfkey echoes back a few things from the original
message - important ones being version, pid, seq, and msgtype (as a
sample take a look at pfkey_add()). So these need to be remembered...
Brings back the original behavior i had netlink doing which was similar
(but innacurate now that i stare at this). At the time i carried the
nlmsg header around in the cb. So we would have to do the same for
netlink[1].
The good news is all these fields happen to exist on netlink (except for
the version - to which, for netlink created events, we could pass a
hardcoded matching PFKEY2).
In other words the structure i called km_cb will now have to have these
fields i mentioned above.
Thoughts before i start ?
cheers,
jamal
[1]I actually would have no problems using a pid/seq etc generated by
pfkey on a netlink header and viceversa. It shouldnt be an issue.
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-02 1:04 ` jamal
@ 2005-04-02 1:28 ` Herbert Xu
2005-04-02 1:42 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-02 1:28 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
Hi Jamal:
On Fri, Apr 01, 2005 at 08:04:05PM -0500, jamal wrote:
>
> The issue is that pfkey echoes back a few things from the original
> message - important ones being version, pid, seq, and msgtype (as a
> sample take a look at pfkey_add()). So these need to be remembered...
You're right. The pid and seq should be stored in km_event by
af_key and xfrm_user before they call km_notify. In fact bring
back that the km_type field too and put it in km_event. That'll
become useful when we figure out a way to include it in the netlink
message so that the originator can be uniquely identified.
The version should always be set by the kernel though. This is because
the packet we're broadcasting has been regenerated by the kernel. If
we ever get PFKEY v3 then in order that all existing applications
understand these messages you'll have to reformat them as PFKEY v2
anyway.
msgtype should be derived from the event as you did in xfrm_user.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-02 1:28 ` Herbert Xu
@ 2005-04-02 1:42 ` jamal
2005-04-02 1:45 ` Herbert Xu
2005-04-02 1:46 ` Herbert Xu
0 siblings, 2 replies; 48+ messages in thread
From: jamal @ 2005-04-02 1:42 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
Herbert,
On Fri, 2005-04-01 at 20:28, Herbert Xu wrote:
> Hi Jamal:
>
> On Fri, Apr 01, 2005 at 08:04:05PM -0500, jamal wrote:
> >
> > The issue is that pfkey echoes back a few things from the original
> > message - important ones being version, pid, seq, and msgtype (as a
> > sample take a look at pfkey_add()). So these need to be remembered...
>
> You're right. The pid and seq should be stored in km_event by
> af_key and xfrm_user before they call km_notify. In fact bring
> back that the km_type field too and put it in km_event.
Do we need km_type? Given we have: the event, seq, pid (regardless of
where it was generated) we have sufficient info to create eitehr a
netlink or pfkey message.
> That'll
> become useful when we figure out a way to include it in the netlink
> message so that the originator can be uniquely identified.
>
The pid seems pretty accurate to describe what process generated the
initial message.
hold on: Ah, I think i may get what you are trying to get to: You want
iproute to display something along the lines of "this was created by a
pfkey app pid 1534". Did i read you correctly?
> The version should always be set by the kernel though. This is because
> the packet we're broadcasting has been regenerated by the kernel. If
> we ever get PFKEY v3 then in order that all existing applications
> understand these messages you'll have to reformat them as PFKEY v2
> anyway.
>
So always go v2?
> msgtype should be derived from the event as you did in xfrm_user.
>
indeed.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-02 1:42 ` jamal
@ 2005-04-02 1:45 ` Herbert Xu
2005-04-02 1:46 ` Herbert Xu
1 sibling, 0 replies; 48+ messages in thread
From: Herbert Xu @ 2005-04-02 1:45 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Fri, Apr 01, 2005 at 08:42:45PM -0500, jamal wrote:
>
> hold on: Ah, I think i may get what you are trying to get to: You want
> iproute to display something along the lines of "this was created by a
> pfkey app pid 1534". Did i read you correctly?
That's right. Someone with a pathological mind might do pfkey and
netlink from the same pid :)
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: PATCH: IPSEC xfrm events
2005-04-02 1:42 ` jamal
2005-04-02 1:45 ` Herbert Xu
@ 2005-04-02 1:46 ` Herbert Xu
2005-04-02 19:20 ` take 2 WAS(Re: " jamal
1 sibling, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-02 1:46 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Fri, Apr 01, 2005 at 08:42:45PM -0500, jamal wrote:
>
> So always go v2?
Yes since that's the only version that the kernel knows how to generate.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-02 1:46 ` Herbert Xu
@ 2005-04-02 19:20 ` jamal
2005-04-03 14:31 ` jamal
2005-04-04 1:01 ` take 2 " Herbert Xu
0 siblings, 2 replies; 48+ messages in thread
From: jamal @ 2005-04-02 19:20 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
[-- Attachment #1: Type: text/plain, Size: 1165 bytes --]
On Fri, 2005-04-01 at 20:46, Herbert Xu wrote:
> On Fri, Apr 01, 2005 at 08:42:45PM -0500, jamal wrote:
> >
> > So always go v2?
>
> Yes since that's the only version that the kernel knows how to generate.
Ok, heres a general patch first cut i think i got all that was discussed
in there. ive done some basic 5 minutes tests on.
Once we have agreement i will pass it on to Masahide-san to do more
thorough testing.
Look at the XXX comments in the patch.
A couple of interesting things:
1) Weve discussed this before Herbert and i think you misspoke that
pfkey delivers to all listerners.
pfkey Add/del/upd now really do tell all processes about what happened.
Before pfkey would skip the originating process. So far this doesnt seem
to be an issue in the basic testing.
2) I ended adding a policy_notify to the pfkey manager to make the code
generic. Interesting thing is i dont think pfkey knows what to do with
policy expiration or i am misreading the code.
I dont see any message type for policy expiration as i do for sa
expiration. Ive put some hooks and a little noise. I could remove the
printks - for now they are just place holders.
cheers,
jamal
[-- Attachment #2: ipsec-event-take2 --]
[-- Type: text/plain, Size: 29278 bytes --]
--- a/include/net/xfrm.h 2005-03-25 22:28:26.000000000 -0500
+++ b/include/net/xfrm.h 2005-04-02 11:59:17.000000000 -0500
@@ -157,6 +157,28 @@
XFRM_STATE_DEAD
};
+/* events that could be sent by kernel */
+enum {
+ XFRM_SAP_INVALID,
+ XFRM_SAP_EXPIRED,
+ XFRM_SAP_ADDED,
+ XFRM_SAP_UPDATED,
+ XFRM_SAP_DELETED,
+ XFRM_SAP_FLUSHED,
+ __XFRM_SAP_MAX
+};
+#define XFRM_SAP_MAX (__XFRM_SAP_MAX - 1)
+
+/* callback structure passed from either netlink or pfkey */
+struct km_event
+{
+ u32 data;
+ u32 seq;
+ u32 pid;
+ u32 event;
+};
+
+
struct xfrm_type;
struct xfrm_dst;
struct xfrm_policy_afinfo {
@@ -178,6 +200,9 @@
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo);
+extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c);
+extern void km_state_notify(struct xfrm_state *x, struct km_event *c);
+
#define XFRM_ACQ_EXPIRES 30
@@ -283,17 +308,17 @@
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
-#define XFRM_KM_TIMEOUT 30
+#define XFRM_KM_TIMEOUT 30
struct xfrm_mgr
{
struct list_head list;
char *id;
- int (*notify)(struct xfrm_state *x, int event);
+ int (*notify)(struct xfrm_state *x, struct km_event *c);
int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir);
int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
- int (*notify_policy)(struct xfrm_policy *x, int dir, int event);
+ int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
};
extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -802,7 +827,7 @@
extern int xfrm_state_update(struct xfrm_state *x);
extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family);
extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
-extern void xfrm_state_delete(struct xfrm_state *x);
+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);
--- a/include/linux/xfrm.h 2005-03-25 22:28:39.000000000 -0500
+++ b/include/linux/xfrm.h 2005-04-02 09:53:03.000000000 -0500
@@ -254,5 +254,7 @@
#define XFRMGRP_ACQUIRE 1
#define XFRMGRP_EXPIRE 2
+#define XFRMGRP_SA 4
+#define XFRMGRP_POLICY 8
#endif /* _LINUX_XFRM_H */
--- a/net/xfrm/xfrm_state.c 2005-03-25 22:28:25.000000000 -0500
+++ b/net/xfrm/xfrm_state.c 2005-04-02 12:15:37.000000000 -0500
@@ -48,7 +48,7 @@
static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
-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);
@@ -208,8 +208,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);
@@ -236,14 +238,47 @@
* is what we are dropping here.
*/
atomic_dec(&x->refcnt);
+ err = 0;
}
+
+ return err;
}
-void xfrm_state_delete(struct xfrm_state *x)
+static DEFINE_RWLOCK(xfrm_km_lock);
+static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
+
+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)
+ km->notify(x, c);
+ read_unlock(&xfrm_km_lock);
+}
+
+EXPORT_SYMBOL(km_policy_notify);
+EXPORT_SYMBOL(km_state_notify);
+
+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);
@@ -402,6 +437,7 @@
static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
+
int xfrm_state_add(struct xfrm_state *x)
{
struct xfrm_state_afinfo *afinfo;
@@ -764,37 +800,45 @@
}
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)
{
- struct xfrm_mgr *km;
+ 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);
+ /* XXX: Do we wanna do this right at the top??
+ * if the state is dead we dont want to announce
+ * the expire - a delete may already have announced
+ * it
+ */
+ if (x->km.state == XFRM_STATE_DEAD)
+ return;
+ 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;
@@ -819,13 +863,20 @@
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);
+ /* XXX: Do we still wanna wakeup km_waitq?
+ * if the policy is dead we dont want to announce
+ * the expire - a delete may already have announced
+ * it
+ */
+ if (pol->dead)
+ return;
+
+ c.data = hard;
+ c.data = hard;
+ c.event = XFRM_SAP_EXPIRED;
+ km_policy_notify(pol, dir, &c);
if (hard)
wake_up(&km_waitq);
--- a/net/xfrm/xfrm_policy.c 2005-03-25 22:28:21.000000000 -0500
+++ b/net/xfrm/xfrm_policy.c 2005-04-02 12:16:30.000000000 -0500
@@ -298,7 +298,7 @@
* entry dead. The rule must be unlinked from lists to the moment.
*/
-static void xfrm_policy_kill(struct xfrm_policy *policy)
+static void xfrm_policy_kill(struct xfrm_policy *policy, int dir)
{
write_lock_bh(&policy->lock);
if (policy->dead)
@@ -378,7 +378,7 @@
write_unlock_bh(&xfrm_policy_lock);
if (delpol) {
- xfrm_policy_kill(delpol);
+ xfrm_policy_kill(delpol, dir);
}
return 0;
}
@@ -402,7 +402,7 @@
if (pol && delete) {
atomic_inc(&flow_cache_genid);
- xfrm_policy_kill(pol);
+ xfrm_policy_kill(pol, dir);
}
return pol;
}
@@ -425,7 +425,7 @@
if (pol && delete) {
atomic_inc(&flow_cache_genid);
- xfrm_policy_kill(pol);
+ xfrm_policy_kill(pol, dir);
}
return pol;
}
@@ -442,7 +442,7 @@
xfrm_policy_list[dir] = xp->next;
write_unlock_bh(&xfrm_policy_lock);
- xfrm_policy_kill(xp);
+ xfrm_policy_kill(xp, dir);
write_lock_bh(&xfrm_policy_lock);
}
@@ -558,7 +558,7 @@
if (pol) {
if (dir < XFRM_POLICY_MAX)
atomic_inc(&flow_cache_genid);
- xfrm_policy_kill(pol);
+ xfrm_policy_kill(pol, dir);
}
}
@@ -579,7 +579,7 @@
write_unlock_bh(&xfrm_policy_lock);
if (old_pol) {
- xfrm_policy_kill(old_pol);
+ xfrm_policy_kill(old_pol, dir);
}
return 0;
}
--- a/net/xfrm/xfrm_user.c 2005-03-25 22:28:22.000000000 -0500
+++ b/net/xfrm/xfrm_user.c 2005-04-02 12:21:32.000000000 -0500
@@ -268,6 +268,7 @@
struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
struct xfrm_state *x;
int err;
+ struct km_event c;
err = verify_newsa_info(p, (struct rtattr **) xfrma);
if (err)
@@ -285,14 +286,26 @@
if (err < 0) {
x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x);
+ return err;
}
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+
+ km_state_notify(x, &c);
+
return err;
}
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_state *x;
+ int err;
+ struct km_event c;
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
@@ -304,10 +317,20 @@
return -EPERM;
}
- xfrm_state_delete(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ x->km.state = XFRM_STATE_DEAD;
+ xfrm_state_put(x);
+ return err;
+ }
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
xfrm_state_put(x);
- return 0;
+ return err;
}
static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
@@ -672,6 +695,7 @@
{
struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);
struct xfrm_policy *xp;
+ struct km_event c;
int err;
int excl;
@@ -683,6 +707,10 @@
if (!xp)
return err;
+ /* shouldnt excl be based on nlh flags??
+ * Aha! this is anti-netlink really i.e more pfkey derived
+ * in netlink excl is a flag and you wouldnt need
+ * a type XFRM_MSG_UPDPOLICY - JHS */
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
err = xfrm_policy_insert(p->dir, xp, excl);
if (err) {
@@ -690,6 +718,16 @@
return err;
}
+
+ if (!excl)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
+
xfrm_pol_put(xp);
return 0;
@@ -807,8 +845,10 @@
struct xfrm_policy *xp;
struct xfrm_userpolicy_id *p;
int err;
+ struct km_event c;
int delete;
+
p = NLMSG_DATA(nlh);
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
@@ -834,6 +874,11 @@
NETLINK_CB(skb).pid,
MSG_DONTWAIT);
}
+ } else {
+ c.event = XFRM_SAP_DELETED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
}
xfrm_pol_put(xp);
@@ -843,15 +888,28 @@
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
xfrm_state_flush(p->proto);
+ c.data = p->proto;
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_state_notify(NULL, &c);
+
return 0;
}
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
+
xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -1053,10 +1111,11 @@
return -1;
}
-static int xfrm_send_state_notify(struct xfrm_state *x, int hard)
+static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *skb;
-
+ int hard = c ->data;
+ /* fix to do alloc using NLM macros */
skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
@@ -1069,6 +1128,94 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_sa_flush(struct km_event *c)
+{
+ struct xfrm_usersa_flush *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq,
+ XFRM_MSG_FLUSHSA, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ p->proto = c->data;
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_sa( struct xfrm_state *x, struct km_event *c)
+{
+ struct xfrm_usersa_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWSA;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDSA;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELSA;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ copy_to_user_state(x, p);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_state_notify(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_ADDED:
+ return xfrm_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_sa_flush(c);
+ default:
+ printk("pfkey: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+
+}
+
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_tmpl *xt, struct xfrm_policy *xp,
int dir)
@@ -1202,7 +1349,8 @@
return -1;
}
-static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard)
+
+static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
{
struct sk_buff *skb;
size_t len;
@@ -1213,7 +1361,7 @@
if (skb == NULL)
return -ENOMEM;
- if (build_polexpire(skb, xp, dir, hard) < 0)
+ if (build_polexpire(skb, xp, dir, c->data) < 0)
BUG();
NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
@@ -1221,6 +1369,90 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct xfrm_userpolicy_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt = 0 ;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWPOLICY;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDPOLICY;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELPOLICY;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+
+ p = NLMSG_DATA(nlh);
+
+ nlh->nlmsg_flags = 0;
+
+ copy_to_user_policy(xp, p, dir);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_policy_flush(struct km_event *c)
+{
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(0);
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_DELETED:
+ return xfrm_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_policy_flush(c);
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_policy_notify(xp, dir, c);
+ default:
+ printk("Netlink Unknown Policy event %d\n",c->event);
+ }
+
+ return 0;
+
+}
+
static struct xfrm_mgr netlink_mgr = {
.id = "netlink",
.notify = xfrm_send_state_notify,
--- a/net/key/af_key.c 2005-03-25 22:28:39.000000000 -0500
+++ b/net/key/af_key.c 2005-04-02 12:25:49.000000000 -0500
@@ -1240,13 +1240,85 @@
return 0;
}
+static inline int event2poltype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_X_SPDDELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_X_SPDADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_X_SPDUPDATE;
+ case XFRM_SAP_EXPIRED:
+ // return SADB_X_SPDEXPIRE;
+ default:
+ printk("pfkey: Unknown policy event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int event2keytype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_DELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_ADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_UPDATE;
+ case XFRM_SAP_EXPIRED:
+ return SADB_EXPIRE;
+ default:
+ printk("pfkey: Unknown SA event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+/* ADD/UPD/DEL */
+static int key_notify_sa(struct xfrm_state *x, struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+ int hsc = 3;
+
+ if (c->event == XFRM_SAP_DELETED)
+ hsc = 0;
+
+ if (c->event == XFRM_SAP_EXPIRED) {
+ if (c->data)
+ hsc = 2;
+ else
+ hsc = 1;
+ }
+
+ skb = pfkey_xfrm_state2msg(x, 0, hsc);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ hdr = (struct sadb_msg *) skb->data;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_type = event2keytype(c->event);
+ hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+ hdr->sadb_msg_errno = 0;
+ hdr->sadb_msg_reserved = 0;
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_state *x;
int err;
+ struct km_event c;
xfrm_probe_algs();
@@ -1256,7 +1328,7 @@
if (hdr->sadb_msg_type == SADB_ADD)
err = xfrm_state_add(x);
- else
+ else
err = xfrm_state_update(x);
if (err < 0) {
@@ -1265,27 +1337,22 @@
return err;
}
- out_skb = pfkey_xfrm_state2msg(x, 0, 3);
- if (IS_ERR(out_skb))
- return PTR_ERR(out_skb); /* XXX Should we return 0 here ? */
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_reserved = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
-
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ if (hdr->sadb_msg_type == SADB_ADD)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ km_state_notify(x, &c);
- return 0;
+ return err;
}
static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
struct xfrm_state *x;
+ struct km_event c;
+ int err;
if (!ext_hdrs[SADB_EXT_SA-1] ||
!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
@@ -1301,13 +1368,20 @@
return -EPERM;
}
- xfrm_state_delete(x);
- xfrm_state_put(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ x->km.state = XFRM_STATE_DEAD;
+ xfrm_state_put(x);
+ return err;
+ }
- pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
- BROADCAST_ALL, sk);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
- return 0;
+ return err;
}
static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -1445,28 +1519,42 @@
return 0;
}
+static int key_notify_sa_flush(struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+
+ skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
+ if (!skb)
+ return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+ // XXX:do we have to pass proto as well?
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+
+ pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ALL, NULL);
+
+ return 0;
+}
+
static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
unsigned proto;
- struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
+ struct km_event c;
proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0)
return -EINVAL;
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
- if (!skb_out)
- return -ENOBUFS;
-
xfrm_state_flush(proto);
-
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
-
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+ c.data = proto;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_FLUSHED;
+ km_state_notify(NULL, &c);
return 0;
}
@@ -1859,6 +1947,31 @@
hdr->sadb_msg_reserved = atomic_read(&xp->refcnt);
}
+static int key_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct sk_buff *out_skb;
+ struct sadb_msg *out_hdr;
+ int err;
+
+ out_skb = pfkey_xfrm_policy2msg_prep(xp);
+ if (IS_ERR(out_skb)) {
+ err = PTR_ERR(out_skb);
+ goto out;
+ }
+ pfkey_xfrm_policy2msg(out_skb, xp, dir);
+
+ out_hdr = (struct sadb_msg *) out_skb->data;
+ out_hdr->sadb_msg_version = PF_KEY_V2;
+ out_hdr->sadb_msg_type = event2poltype(c->event);
+ out_hdr->sadb_msg_errno = 0;
+ out_hdr->sadb_msg_seq = c->seq;
+ out_hdr->sadb_msg_pid = c->pid;
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+out:
+ return 0;
+
+}
+
static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
int err;
@@ -1866,8 +1979,7 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -1935,31 +2047,25 @@
(err = parse_ipsecrequests(xp, pol)) < 0)
goto out;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
- }
err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp,
hdr->sadb_msg_type != SADB_X_SPDUPDATE);
+
if (err) {
- kfree_skb(out_skb);
- goto out;
+ kfree(xp);
+ return err;
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
+ if (hdr->sadb_msg_type == SADB_X_SPDUPDATE)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
- xfrm_pol_put(xp);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+ xfrm_pol_put(xp);
return 0;
out:
@@ -1973,9 +2079,8 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_selector sel;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -2010,24 +2115,11 @@
err = 0;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
- }
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = SADB_X_SPDDELETE;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
- err = 0;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
-out:
xfrm_pol_put(xp);
return err;
}
@@ -2037,8 +2129,7 @@
int err;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL)
return -EINVAL;
@@ -2050,24 +2141,19 @@
err = 0;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
+ /*
+ * XXX: previous get was doing a broadcast-all _always_
+ * which didnt seem right for non-deletion case - JHS
+ * This is like the way netlink behaves ..
+ * Shall i restore original behavior?
+ */
+ if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) {
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
- err = 0;
-out:
xfrm_pol_put(xp);
return err;
}
@@ -2102,22 +2188,33 @@
return xfrm_policy_walk(dump_sp, &data);
}
-static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+static int key_notify_policy_flush(struct km_event *c)
{
struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
-
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
+ struct sadb_msg *hdr;
+ skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
if (!skb_out)
return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+ pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+ return 0;
- xfrm_policy_flush();
+}
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+ struct km_event c;
+
+ xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.pid = hdr->sadb_msg_pid;
+ c.seq = hdr->sadb_msg_seq;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -2317,11 +2414,25 @@
}
}
-static int pfkey_send_notify(struct xfrm_state *x, int hard)
+/* XXX: Noisy for now */
+static int key_notify_policy_expire(struct xfrm_policy *xp, struct km_event *c)
+{
+ printk("pfkey doesnt deal with expired policies ..\n");
+ return 0;
+}
+
+static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *out_skb;
struct sadb_msg *out_hdr;
- int hsc = (hard ? 2 : 1);
+ int hard;
+ int hsc;
+
+ hard = c->data;
+ if (hard)
+ hsc = 2;
+ else
+ hsc = 1;
out_skb = pfkey_xfrm_state2msg(x, 0, hsc);
if (IS_ERR(out_skb))
@@ -2340,6 +2451,43 @@
return 0;
}
+static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_sa_expire(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_sa_flush(c);
+ default:
+ printk("pfkey: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
+
+static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_policy_expire(xp, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_policy_flush(c);
+ default:
+ printk("pfkey: Unknown policy event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
static u32 get_acqseq(void)
{
u32 res;
@@ -2856,6 +3004,7 @@
.acquire = pfkey_send_acquire,
.compile_policy = pfkey_compile_policy,
.new_mapping = pfkey_send_new_mapping,
+ .notify_policy = pfkey_send_policy_notify,
};
static void __exit ipsec_pfkey_exit(void)
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-02 19:20 ` take 2 WAS(Re: " jamal
@ 2005-04-03 14:31 ` jamal
2005-04-03 15:47 ` Patrick McHardy
2005-04-04 0:58 ` Herbert Xu
2005-04-04 1:01 ` take 2 " Herbert Xu
1 sibling, 2 replies; 48+ messages in thread
From: jamal @ 2005-04-03 14:31 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
[-- Attachment #1: Type: text/plain, Size: 1211 bytes --]
Small change after some testing.
Herbert havent heard back from you - this looks very palatable in my
opinion with comments below still in effect.
cheers,
jamal
On Sat, 2005-04-02 at 14:20, jamal wrote:
> Ok, heres a general patch first cut i think i got all that was discussed
> in there. ive done some basic 5 minutes tests on.
> Once we have agreement i will pass it on to Masahide-san to do more
> thorough testing.
> Look at the XXX comments in the patch.
>
> A couple of interesting things:
>
> 1) Weve discussed this before Herbert and i think you misspoke that
> pfkey delivers to all listerners.
>
> pfkey Add/del/upd now really do tell all processes about what happened.
> Before pfkey would skip the originating process. So far this doesnt seem
> to be an issue in the basic testing.
>
> 2) I ended adding a policy_notify to the pfkey manager to make the code
> generic. Interesting thing is i dont think pfkey knows what to do with
> policy expiration or i am misreading the code.
> I dont see any message type for policy expiration as i do for sa
> expiration. Ive put some hooks and a little noise. I could remove the
> printks - for now they are just place holders.
>
> cheers,
> jamal
[-- Attachment #2: ipsec-event-take2-1 --]
[-- Type: text/plain, Size: 29278 bytes --]
--- a/include/net/xfrm.h 2005-03-25 22:28:26.000000000 -0500
+++ b/include/net/xfrm.h 2005-04-02 11:59:17.000000000 -0500
@@ -157,6 +157,28 @@
XFRM_STATE_DEAD
};
+/* events that could be sent by kernel */
+enum {
+ XFRM_SAP_INVALID,
+ XFRM_SAP_EXPIRED,
+ XFRM_SAP_ADDED,
+ XFRM_SAP_UPDATED,
+ XFRM_SAP_DELETED,
+ XFRM_SAP_FLUSHED,
+ __XFRM_SAP_MAX
+};
+#define XFRM_SAP_MAX (__XFRM_SAP_MAX - 1)
+
+/* callback structure passed from either netlink or pfkey */
+struct km_event
+{
+ u32 data;
+ u32 seq;
+ u32 pid;
+ u32 event;
+};
+
+
struct xfrm_type;
struct xfrm_dst;
struct xfrm_policy_afinfo {
@@ -178,6 +200,9 @@
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo);
+extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c);
+extern void km_state_notify(struct xfrm_state *x, struct km_event *c);
+
#define XFRM_ACQ_EXPIRES 30
@@ -283,17 +308,17 @@
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
-#define XFRM_KM_TIMEOUT 30
+#define XFRM_KM_TIMEOUT 30
struct xfrm_mgr
{
struct list_head list;
char *id;
- int (*notify)(struct xfrm_state *x, int event);
+ int (*notify)(struct xfrm_state *x, struct km_event *c);
int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir);
int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
- int (*notify_policy)(struct xfrm_policy *x, int dir, int event);
+ int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
};
extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -802,7 +827,7 @@
extern int xfrm_state_update(struct xfrm_state *x);
extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family);
extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
-extern void xfrm_state_delete(struct xfrm_state *x);
+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);
--- a/include/linux/xfrm.h 2005-03-25 22:28:39.000000000 -0500
+++ b/include/linux/xfrm.h 2005-04-02 09:53:03.000000000 -0500
@@ -254,5 +254,7 @@
#define XFRMGRP_ACQUIRE 1
#define XFRMGRP_EXPIRE 2
+#define XFRMGRP_SA 4
+#define XFRMGRP_POLICY 8
#endif /* _LINUX_XFRM_H */
--- a/net/xfrm/xfrm_state.c 2005-03-25 22:28:25.000000000 -0500
+++ b/net/xfrm/xfrm_state.c 2005-04-02 12:15:37.000000000 -0500
@@ -48,7 +48,7 @@
static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
-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);
@@ -208,8 +208,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);
@@ -236,14 +238,47 @@
* is what we are dropping here.
*/
atomic_dec(&x->refcnt);
+ err = 0;
}
+
+ return err;
}
-void xfrm_state_delete(struct xfrm_state *x)
+static DEFINE_RWLOCK(xfrm_km_lock);
+static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
+
+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)
+ km->notify(x, c);
+ read_unlock(&xfrm_km_lock);
+}
+
+EXPORT_SYMBOL(km_policy_notify);
+EXPORT_SYMBOL(km_state_notify);
+
+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);
@@ -402,6 +437,7 @@
static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
+
int xfrm_state_add(struct xfrm_state *x)
{
struct xfrm_state_afinfo *afinfo;
@@ -764,37 +800,45 @@
}
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)
{
- struct xfrm_mgr *km;
+ 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);
+ /* XXX: Do we wanna do this right at the top??
+ * if the state is dead we dont want to announce
+ * the expire - a delete may already have announced
+ * it
+ */
+ if (x->km.state == XFRM_STATE_DEAD)
+ return;
+ 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;
@@ -819,13 +863,20 @@
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);
+ /* XXX: Do we still wanna wakeup km_waitq?
+ * if the policy is dead we dont want to announce
+ * the expire - a delete may already have announced
+ * it
+ */
+ if (pol->dead)
+ return;
+
+ c.data = hard;
+ c.data = hard;
+ c.event = XFRM_SAP_EXPIRED;
+ km_policy_notify(pol, dir, &c);
if (hard)
wake_up(&km_waitq);
--- a/net/xfrm/xfrm_policy.c 2005-03-25 22:28:21.000000000 -0500
+++ b/net/xfrm/xfrm_policy.c 2005-04-02 12:16:30.000000000 -0500
@@ -298,7 +298,7 @@
* entry dead. The rule must be unlinked from lists to the moment.
*/
-static void xfrm_policy_kill(struct xfrm_policy *policy)
+static void xfrm_policy_kill(struct xfrm_policy *policy, int dir)
{
write_lock_bh(&policy->lock);
if (policy->dead)
@@ -378,7 +378,7 @@
write_unlock_bh(&xfrm_policy_lock);
if (delpol) {
- xfrm_policy_kill(delpol);
+ xfrm_policy_kill(delpol, dir);
}
return 0;
}
@@ -402,7 +402,7 @@
if (pol && delete) {
atomic_inc(&flow_cache_genid);
- xfrm_policy_kill(pol);
+ xfrm_policy_kill(pol, dir);
}
return pol;
}
@@ -425,7 +425,7 @@
if (pol && delete) {
atomic_inc(&flow_cache_genid);
- xfrm_policy_kill(pol);
+ xfrm_policy_kill(pol, dir);
}
return pol;
}
@@ -442,7 +442,7 @@
xfrm_policy_list[dir] = xp->next;
write_unlock_bh(&xfrm_policy_lock);
- xfrm_policy_kill(xp);
+ xfrm_policy_kill(xp, dir);
write_lock_bh(&xfrm_policy_lock);
}
@@ -558,7 +558,7 @@
if (pol) {
if (dir < XFRM_POLICY_MAX)
atomic_inc(&flow_cache_genid);
- xfrm_policy_kill(pol);
+ xfrm_policy_kill(pol, dir);
}
}
@@ -579,7 +579,7 @@
write_unlock_bh(&xfrm_policy_lock);
if (old_pol) {
- xfrm_policy_kill(old_pol);
+ xfrm_policy_kill(old_pol, dir);
}
return 0;
}
--- a/net/xfrm/xfrm_user.c 2005-03-25 22:28:22.000000000 -0500
+++ b/net/xfrm/xfrm_user.c 2005-04-02 12:21:32.000000000 -0500
@@ -268,6 +268,7 @@
struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
struct xfrm_state *x;
int err;
+ struct km_event c;
err = verify_newsa_info(p, (struct rtattr **) xfrma);
if (err)
@@ -285,14 +286,26 @@
if (err < 0) {
x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x);
+ return err;
}
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+
+ km_state_notify(x, &c);
+
return err;
}
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_state *x;
+ int err;
+ struct km_event c;
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
@@ -304,10 +317,20 @@
return -EPERM;
}
- xfrm_state_delete(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ x->km.state = XFRM_STATE_DEAD;
+ xfrm_state_put(x);
+ return err;
+ }
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
xfrm_state_put(x);
- return 0;
+ return err;
}
static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
@@ -672,6 +695,7 @@
{
struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);
struct xfrm_policy *xp;
+ struct km_event c;
int err;
int excl;
@@ -683,6 +707,10 @@
if (!xp)
return err;
+ /* shouldnt excl be based on nlh flags??
+ * Aha! this is anti-netlink really i.e more pfkey derived
+ * in netlink excl is a flag and you wouldnt need
+ * a type XFRM_MSG_UPDPOLICY - JHS */
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
err = xfrm_policy_insert(p->dir, xp, excl);
if (err) {
@@ -690,6 +718,16 @@
return err;
}
+
+ if (!excl)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
+
xfrm_pol_put(xp);
return 0;
@@ -807,8 +845,10 @@
struct xfrm_policy *xp;
struct xfrm_userpolicy_id *p;
int err;
+ struct km_event c;
int delete;
+
p = NLMSG_DATA(nlh);
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
@@ -834,6 +874,11 @@
NETLINK_CB(skb).pid,
MSG_DONTWAIT);
}
+ } else {
+ c.event = XFRM_SAP_DELETED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
}
xfrm_pol_put(xp);
@@ -843,15 +888,28 @@
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
xfrm_state_flush(p->proto);
+ c.data = p->proto;
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_state_notify(NULL, &c);
+
return 0;
}
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
+
xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -1053,10 +1111,11 @@
return -1;
}
-static int xfrm_send_state_notify(struct xfrm_state *x, int hard)
+static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *skb;
-
+ int hard = c ->data;
+ /* fix to do alloc using NLM macros */
skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
@@ -1069,6 +1128,94 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_sa_flush(struct km_event *c)
+{
+ struct xfrm_usersa_flush *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq,
+ XFRM_MSG_FLUSHSA, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ p->proto = c->data;
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_sa( struct xfrm_state *x, struct km_event *c)
+{
+ struct xfrm_usersa_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWSA;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDSA;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELSA;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ copy_to_user_state(x, p);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_state_notify(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_ADDED:
+ return xfrm_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_sa_flush(c);
+ default:
+ printk("pfkey: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+
+}
+
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_tmpl *xt, struct xfrm_policy *xp,
int dir)
@@ -1202,7 +1349,8 @@
return -1;
}
-static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard)
+
+static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
{
struct sk_buff *skb;
size_t len;
@@ -1213,7 +1361,7 @@
if (skb == NULL)
return -ENOMEM;
- if (build_polexpire(skb, xp, dir, hard) < 0)
+ if (build_polexpire(skb, xp, dir, c->data) < 0)
BUG();
NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
@@ -1221,6 +1369,90 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct xfrm_userpolicy_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt = 0 ;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWPOLICY;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDPOLICY;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELPOLICY;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+
+ p = NLMSG_DATA(nlh);
+
+ nlh->nlmsg_flags = 0;
+
+ copy_to_user_policy(xp, p, dir);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_policy_flush(struct km_event *c)
+{
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(0);
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_DELETED:
+ return xfrm_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_policy_flush(c);
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_policy_notify(xp, dir, c);
+ default:
+ printk("Netlink Unknown Policy event %d\n",c->event);
+ }
+
+ return 0;
+
+}
+
static struct xfrm_mgr netlink_mgr = {
.id = "netlink",
.notify = xfrm_send_state_notify,
--- a/net/key/af_key.c 2005-03-25 22:28:39.000000000 -0500
+++ b/net/key/af_key.c 2005-04-02 18:05:24.000000000 -0500
@@ -1240,13 +1240,85 @@
return 0;
}
+static inline int event2poltype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_X_SPDDELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_X_SPDADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_X_SPDUPDATE;
+ case XFRM_SAP_EXPIRED:
+ // return SADB_X_SPDEXPIRE;
+ default:
+ printk("pfkey: Unknown policy event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int event2keytype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_DELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_ADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_UPDATE;
+ case XFRM_SAP_EXPIRED:
+ return SADB_EXPIRE;
+ default:
+ printk("pfkey: Unknown SA event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+/* ADD/UPD/DEL */
+static int key_notify_sa(struct xfrm_state *x, struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+ int hsc = 3;
+
+ if (c->event == XFRM_SAP_DELETED)
+ hsc = 0;
+
+ if (c->event == XFRM_SAP_EXPIRED) {
+ if (c->data)
+ hsc = 2;
+ else
+ hsc = 1;
+ }
+
+ skb = pfkey_xfrm_state2msg(x, 0, hsc);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ hdr = (struct sadb_msg *) skb->data;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_type = event2keytype(c->event);
+ hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+ hdr->sadb_msg_errno = 0;
+ hdr->sadb_msg_reserved = 0;
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_state *x;
int err;
+ struct km_event c;
xfrm_probe_algs();
@@ -1256,7 +1328,7 @@
if (hdr->sadb_msg_type == SADB_ADD)
err = xfrm_state_add(x);
- else
+ else
err = xfrm_state_update(x);
if (err < 0) {
@@ -1265,27 +1337,22 @@
return err;
}
- out_skb = pfkey_xfrm_state2msg(x, 0, 3);
- if (IS_ERR(out_skb))
- return PTR_ERR(out_skb); /* XXX Should we return 0 here ? */
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_reserved = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
-
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ if (hdr->sadb_msg_type == SADB_ADD)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ km_state_notify(x, &c);
- return 0;
+ return err;
}
static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
struct xfrm_state *x;
+ struct km_event c;
+ int err;
if (!ext_hdrs[SADB_EXT_SA-1] ||
!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
@@ -1301,13 +1368,20 @@
return -EPERM;
}
- xfrm_state_delete(x);
- xfrm_state_put(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ x->km.state = XFRM_STATE_DEAD;
+ xfrm_state_put(x);
+ return err;
+ }
- pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
- BROADCAST_ALL, sk);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
- return 0;
+ return err;
}
static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -1445,28 +1519,42 @@
return 0;
}
+static int key_notify_sa_flush(struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+
+ skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
+ if (!skb)
+ return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+ // XXX:do we have to pass proto as well?
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
+
static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
unsigned proto;
- struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
+ struct km_event c;
proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0)
return -EINVAL;
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
- if (!skb_out)
- return -ENOBUFS;
-
xfrm_state_flush(proto);
-
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
-
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+ c.data = proto;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_FLUSHED;
+ km_state_notify(NULL, &c);
return 0;
}
@@ -1859,6 +1947,31 @@
hdr->sadb_msg_reserved = atomic_read(&xp->refcnt);
}
+static int key_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct sk_buff *out_skb;
+ struct sadb_msg *out_hdr;
+ int err;
+
+ out_skb = pfkey_xfrm_policy2msg_prep(xp);
+ if (IS_ERR(out_skb)) {
+ err = PTR_ERR(out_skb);
+ goto out;
+ }
+ pfkey_xfrm_policy2msg(out_skb, xp, dir);
+
+ out_hdr = (struct sadb_msg *) out_skb->data;
+ out_hdr->sadb_msg_version = PF_KEY_V2;
+ out_hdr->sadb_msg_type = event2poltype(c->event);
+ out_hdr->sadb_msg_errno = 0;
+ out_hdr->sadb_msg_seq = c->seq;
+ out_hdr->sadb_msg_pid = c->pid;
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+out:
+ return 0;
+
+}
+
static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
int err;
@@ -1866,8 +1979,7 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -1935,31 +2047,25 @@
(err = parse_ipsecrequests(xp, pol)) < 0)
goto out;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
- }
err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp,
hdr->sadb_msg_type != SADB_X_SPDUPDATE);
+
if (err) {
- kfree_skb(out_skb);
- goto out;
+ kfree(xp);
+ return err;
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
+ if (hdr->sadb_msg_type == SADB_X_SPDUPDATE)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
- xfrm_pol_put(xp);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+ xfrm_pol_put(xp);
return 0;
out:
@@ -1973,9 +2079,8 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_selector sel;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -2010,24 +2115,11 @@
err = 0;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
- }
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = SADB_X_SPDDELETE;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
- err = 0;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
-out:
xfrm_pol_put(xp);
return err;
}
@@ -2037,8 +2129,7 @@
int err;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL)
return -EINVAL;
@@ -2050,24 +2141,19 @@
err = 0;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
+ /*
+ * XXX: previous get was doing a broadcast-all _always_
+ * which didnt seem right for non-deletion case - JHS
+ * This is like the way netlink behaves ..
+ * Shall i restore original behavior?
+ */
+ if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) {
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
- err = 0;
-out:
xfrm_pol_put(xp);
return err;
}
@@ -2102,22 +2188,33 @@
return xfrm_policy_walk(dump_sp, &data);
}
-static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+static int key_notify_policy_flush(struct km_event *c)
{
struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
-
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
+ struct sadb_msg *hdr;
+ skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
if (!skb_out)
return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+ pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL);
+ return 0;
- xfrm_policy_flush();
+}
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+ struct km_event c;
+
+ xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.pid = hdr->sadb_msg_pid;
+ c.seq = hdr->sadb_msg_seq;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -2317,11 +2414,25 @@
}
}
-static int pfkey_send_notify(struct xfrm_state *x, int hard)
+/* XXX: Noisy for now */
+static int key_notify_policy_expire(struct xfrm_policy *xp, struct km_event *c)
+{
+ printk("pfkey doesnt deal with expired policies ..\n");
+ return 0;
+}
+
+static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *out_skb;
struct sadb_msg *out_hdr;
- int hsc = (hard ? 2 : 1);
+ int hard;
+ int hsc;
+
+ hard = c->data;
+ if (hard)
+ hsc = 2;
+ else
+ hsc = 1;
out_skb = pfkey_xfrm_state2msg(x, 0, hsc);
if (IS_ERR(out_skb))
@@ -2340,6 +2451,43 @@
return 0;
}
+static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_sa_expire(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_sa_flush(c);
+ default:
+ printk("pfkey: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
+
+static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_policy_expire(xp, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_policy_flush(c);
+ default:
+ printk("pfkey: Unknown policy event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
static u32 get_acqseq(void)
{
u32 res;
@@ -2856,6 +3004,7 @@
.acquire = pfkey_send_acquire,
.compile_policy = pfkey_compile_policy,
.new_mapping = pfkey_send_new_mapping,
+ .notify_policy = pfkey_send_policy_notify,
};
static void __exit ipsec_pfkey_exit(void)
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-03 14:31 ` jamal
@ 2005-04-03 15:47 ` Patrick McHardy
2005-04-03 16:29 ` jamal
2005-04-03 16:36 ` jamal
2005-04-04 0:58 ` Herbert Xu
1 sibling, 2 replies; 48+ messages in thread
From: Patrick McHardy @ 2005-04-03 15:47 UTC (permalink / raw)
To: hadi; +Cc: Herbert Xu, Masahide NAKAMURA, David S. Miller, netdev
jamal wrote:
>>+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)
>>+ km->notify(x, c);
>>+ read_unlock(&xfrm_km_lock);
>>+}
You call these functions from both softirq- and user-context, so you
need to protect against BHs.
Regards
Patrick
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-03 15:47 ` Patrick McHardy
@ 2005-04-03 16:29 ` jamal
2005-04-03 16:36 ` jamal
1 sibling, 0 replies; 48+ messages in thread
From: jamal @ 2005-04-03 16:29 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Herbert Xu, Masahide NAKAMURA, David S. Miller, netdev
On Sun, 2005-04-03 at 11:47, Patrick McHardy wrote:
> >>+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)
> >>+ km->notify(x, c);
> >>+ read_unlock(&xfrm_km_lock);
> >>+}
>
> You call these functions from both softirq- and user-context, so you
> need to protect against BHs.
>
You are absolutely correct. Thanks for catching this.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-03 15:47 ` Patrick McHardy
2005-04-03 16:29 ` jamal
@ 2005-04-03 16:36 ` jamal
1 sibling, 0 replies; 48+ messages in thread
From: jamal @ 2005-04-03 16:36 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Herbert Xu, Masahide NAKAMURA, David S. Miller, netdev
[-- Attachment #1: Type: text/plain, Size: 358 bytes --]
Masahide,
Attached is incremental patch on top of the one posted earlier.
Looks ok from my basic testing. Please run it against your tests
and see if it stands.
cheers,
jamal
On Sun, 2005-04-03 at 11:47, Patrick McHardy wrote:
> You call these functions from both softirq- and user-context, so you
> need to protect against BHs.
>
> Regards
> Patrick
>
[-- Attachment #2: ipsec-event-take2-1-1 --]
[-- Type: text/plain, Size: 704 bytes --]
--- a/net/xfrm/xfrm_state.c 2005/04/03 16:30:31 1.2
+++ b/net/xfrm/xfrm_state.c 2005/04/03 16:31:27
@@ -251,20 +251,20 @@
{
struct xfrm_mgr *km;
- read_lock(&xfrm_km_lock);
+ read_lock_bh(&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);
+ read_unlock_bh(&xfrm_km_lock);
}
void km_state_notify(struct xfrm_state *x, struct km_event *c)
{
struct xfrm_mgr *km;
- read_lock(&xfrm_km_lock);
+ read_lock_bh(&xfrm_km_lock);
list_for_each_entry(km, &xfrm_km_list, list)
km->notify(x, c);
- read_unlock(&xfrm_km_lock);
+ read_unlock_bh(&xfrm_km_lock);
}
EXPORT_SYMBOL(km_policy_notify);
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-03 14:31 ` jamal
2005-04-03 15:47 ` Patrick McHardy
@ 2005-04-04 0:58 ` Herbert Xu
2005-04-04 1:56 ` jamal
` (2 more replies)
1 sibling, 3 replies; 48+ messages in thread
From: Herbert Xu @ 2005-04-04 0:58 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
Hi Jamal:
On Sun, Apr 03, 2005 at 10:31:58AM -0400, jamal wrote:
>
> Small change after some testing.
> Herbert havent heard back from you - this looks very palatable in my
> opinion with comments below still in effect.
It's definitely looking better all the time.
> -void xfrm_state_delete(struct xfrm_state *x)
> +static DEFINE_RWLOCK(xfrm_km_lock);
> +static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
> +
> +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)
> + km->notify(x, c);
> + read_unlock(&xfrm_km_lock);
> +}
> +
> +EXPORT_SYMBOL(km_policy_notify);
> +EXPORT_SYMBOL(km_state_notify);
Can we perhaps move these lines next to the other km functions
further down? They look rather lonely here.
> + /* XXX: Do we wanna do this right at the top??
> + * if the state is dead we dont want to announce
> + * the expire - a delete may already have announced
> + * it
> + */
Please code this check differently so that it isn't racy.
One way to do it is to change xfrm_timer_handler to do:
if (__xfrm_state_delete(x) && x->id.spi)
km_state_expired(x, 1);
> + /* XXX: Do we still wanna wakeup km_waitq?
> + * if the policy is dead we dont want to announce
> + * the expire - a delete may already have announced
> + * it
> + */
Ditto.
> --- a/net/xfrm/xfrm_policy.c 2005-03-25 22:28:21.000000000 -0500
> +++ b/net/xfrm/xfrm_policy.c 2005-04-02 12:16:30.000000000 -0500
> @@ -298,7 +298,7 @@
> * entry dead. The rule must be unlinked from lists to the moment.
> */
>
> -static void xfrm_policy_kill(struct xfrm_policy *policy)
> +static void xfrm_policy_kill(struct xfrm_policy *policy, int dir)
What's this for?
> + c.seq = nlh->nlmsg_seq;
> + c.pid = nlh->nlmsg_pid;
> + if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
> + c.event = XFRM_SAP_ADDED;
> + else
> + c.event = XFRM_SAP_UPDATED;
> +
> + km_state_notify(x, &c);
You need to hold onto x here. So do a hold before you call xfrm_state_*
and then drop the reference after km_state_notify.
> static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
> - xfrm_state_delete(x);
> + err = xfrm_state_delete(x);
> + if (err < 0) {
> + x->km.state = XFRM_STATE_DEAD;
> + xfrm_state_put(x);
> + return err;
If the xfrm_state_delete fails then it's already dead. So kill
the line that modifies its state.
> +static int xfrm_notify_sa( struct xfrm_state *x, struct km_event *c)
Extra space after the paren.
> + int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
Please add the additional payloads for NAT-T and the keys.
> +static int xfrm_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
> +{
> + struct xfrm_userpolicy_info *p;
> + struct nlmsghdr *nlh;
> + struct sk_buff *skb;
> + u32 nlt = 0 ;
> + unsigned char *b;
> + int len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
Please attach the templates.
> @@ -1256,7 +1328,7 @@
>
> if (hdr->sadb_msg_type == SADB_ADD)
> err = xfrm_state_add(x);
> - else
> + else
A better editor that doesn't leave trailing spaces is needed here :)
> - xfrm_state_delete(x);
> - xfrm_state_put(x);
> + err = xfrm_state_delete(x);
> + if (err < 0) {
> + x->km.state = XFRM_STATE_DEAD;
Please remove this line as it's already dead if the delete fails.
> +static int key_notify_sa_flush(struct km_event *c)
> +{
> + struct sk_buff *skb;
> + struct sadb_msg *hdr;
> +
> + skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
> + if (!skb)
> + return -ENOBUFS;
> + hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
> + // XXX:do we have to pass proto as well?
I think so. A flush of all IPCOMP states is certainly quite different
from a flush of all states. It's just a matter of calling satype2proto.
> + /*
> + * XXX: previous get was doing a broadcast-all _always_
> + * which didnt seem right for non-deletion case - JHS
> + * This is like the way netlink behaves ..
> + * Shall i restore original behavior?
> + */
You're right. The original behaviour was broken.
> - pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
> -
> - out_hdr = (struct sadb_msg *) out_skb->data;
> - out_hdr->sadb_msg_version = hdr->sadb_msg_version;
> - out_hdr->sadb_msg_type = hdr->sadb_msg_type;
> - out_hdr->sadb_msg_satype = 0;
> - out_hdr->sadb_msg_errno = 0;
> - out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
> - out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
> - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
> - err = 0;
However, you do need to keep this code for the real GET case.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-02 19:20 ` take 2 WAS(Re: " jamal
2005-04-03 14:31 ` jamal
@ 2005-04-04 1:01 ` Herbert Xu
2005-04-04 1:58 ` jamal
1 sibling, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-04 1:01 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sat, Apr 02, 2005 at 02:20:01PM -0500, jamal wrote:
>
> 1) Weve discussed this before Herbert and i think you misspoke that
> pfkey delivers to all listerners.
>
> pfkey Add/del/upd now really do tell all processes about what happened.
> Before pfkey would skip the originating process. So far this doesnt seem
> to be an issue in the basic testing.
Are you sure? Previously they did BROADCAST_ALL which goes to everyone
including the sender.
> 2) I ended adding a policy_notify to the pfkey manager to make the code
> generic. Interesting thing is i dont think pfkey knows what to do with
> policy expiration or i am misreading the code.
That's right, pfkey never had policy expire messages. In general,
anything to do with policies cannot be done portably in pfkey since
the RFC only specified the SA operations.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 0:58 ` Herbert Xu
@ 2005-04-04 1:56 ` jamal
2005-04-04 2:26 ` Herbert Xu
2005-04-04 2:34 ` jamal
2005-04-04 11:38 ` take 2-2 " jamal
2 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-04 1:56 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
Herbert,
Now that you are picking on whitespaces i think we are almost there ;->
Comments below
On Sun, 2005-04-03 at 20:58, Herbert Xu wrote:
> On Sun, Apr 03, 2005 at 10:31:58AM -0400, jamal wrote:
[.. ..]
> > +
> > +EXPORT_SYMBOL(km_policy_notify);
> > +EXPORT_SYMBOL(km_state_notify);
>
> Can we perhaps move these lines next to the other km functions
> further down? They look rather lonely here.
>
Sure.
> > + /* XXX: Do we wanna do this right at the top??
> > + * if the state is dead we dont want to announce
> > + * the expire - a delete may already have announced
> > + * it
> > + */
>
> Please code this check differently so that it isn't racy.
>
> One way to do it is to change xfrm_timer_handler to do:
>
> if (__xfrm_state_delete(x) && x->id.spi)
> km_state_expired(x, 1);
>
> > + /* XXX: Do we still wanna wakeup km_waitq?
> > + * if the policy is dead we dont want to announce
> > + * the expire - a delete may already have announced
> > + * it
> > + */
>
> Ditto.
>
I think i am gonna take out any attempts to address this race above.
It's a bug thats there already - a separate patch after this will be
better.
> > --- a/net/xfrm/xfrm_policy.c 2005-03-25 22:28:21.000000000 -0500
> > +++ b/net/xfrm/xfrm_policy.c 2005-04-02 12:16:30.000000000 -0500
> > @@ -298,7 +298,7 @@
> > * entry dead. The rule must be unlinked from lists to the moment.
> > */
> >
> > -static void xfrm_policy_kill(struct xfrm_policy *policy)
> > +static void xfrm_policy_kill(struct xfrm_policy *policy, int dir)
>
> What's this for?
>
Good catch - gunk from previous patch.
> > + c.seq = nlh->nlmsg_seq;
> > + c.pid = nlh->nlmsg_pid;
> > + if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
> > + c.event = XFRM_SAP_ADDED;
> > + else
> > + c.event = XFRM_SAP_UPDATED;
> > +
> > + km_state_notify(x, &c);
>
> You need to hold onto x here. So do a hold before you call xfrm_state_*
> and then drop the reference after km_state_notify.
Good point.
>
> > static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
>
> > - xfrm_state_delete(x);
> > + err = xfrm_state_delete(x);
> > + if (err < 0) {
> > + x->km.state = XFRM_STATE_DEAD;
> > + xfrm_state_put(x);
> > + return err;
>
> If the xfrm_state_delete fails then it's already dead. So kill
> the line that modifies its state.
>
Good point.
> > +static int xfrm_notify_sa( struct xfrm_state *x, struct km_event *c)
>
> Extra space after the paren.
>
> > + int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
>
> Please add the additional payloads for NAT-T and the keys.
>
I dont think we should broadcast out keys.
NAT-T - where do i look at to see what to send?
> > +static int xfrm_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
> > +{
> > + struct xfrm_userpolicy_info *p;
> > + struct nlmsghdr *nlh;
> > + struct sk_buff *skb;
> > + u32 nlt = 0 ;
> > + unsigned char *b;
> > + int len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
>
> Please attach the templates.
>
What is not being attached right now?
> > @@ -1256,7 +1328,7 @@
> >
> > if (hdr->sadb_msg_type == SADB_ADD)
> > err = xfrm_state_add(x);
> > - else
> > + else
>
> A better editor that doesn't leave trailing spaces is needed here :)
you insulting vi? ;->
>
> > - xfrm_state_delete(x);
> > - xfrm_state_put(x);
> > + err = xfrm_state_delete(x);
> > + if (err < 0) {
> > + x->km.state = XFRM_STATE_DEAD;
>
> Please remove this line as it's already dead if the delete fails.
>
> > +static int key_notify_sa_flush(struct km_event *c)
> > +{
> > + struct sk_buff *skb;
> > + struct sadb_msg *hdr;
> > +
> > + skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
> > + if (!skb)
> > + return -ENOBUFS;
> > + hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
> > + // XXX:do we have to pass proto as well?
>
> I think so. A flush of all IPCOMP states is certainly quite different
> from a flush of all states. It's just a matter of calling satype2proto.
>
Looks doable.
> > - pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
> > -
> > - out_hdr = (struct sadb_msg *) out_skb->data;
> > - out_hdr->sadb_msg_version = hdr->sadb_msg_version;
> > - out_hdr->sadb_msg_type = hdr->sadb_msg_type;
> > - out_hdr->sadb_msg_satype = 0;
> > - out_hdr->sadb_msg_errno = 0;
> > - out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
> > - out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
> > - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
> > - err = 0;
>
> However, you do need to keep this code for the real GET case.
>
Get seems to a separate entry point - pfkey_get() which i didnt touch.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 1:01 ` take 2 " Herbert Xu
@ 2005-04-04 1:58 ` jamal
2005-04-04 2:27 ` Herbert Xu
0 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-04 1:58 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sun, 2005-04-03 at 21:01, Herbert Xu wrote:
> On Sat, Apr 02, 2005 at 02:20:01PM -0500, jamal wrote:
> >
> > 1) Weve discussed this before Herbert and i think you misspoke that
> > pfkey delivers to all listerners.
> >
> > pfkey Add/del/upd now really do tell all processes about what happened.
> > Before pfkey would skip the originating process. So far this doesnt seem
> > to be an issue in the basic testing.
>
> Are you sure? Previously they did BROADCAST_ALL which goes to everyone
> including the sender.
>
Yes, he key is in the sk parameter to the broadcast. if a NULL is passed
then all listeners are told. Else the passed sk is excluded.
> > 2) I ended adding a policy_notify to the pfkey manager to make the code
> > generic. Interesting thing is i dont think pfkey knows what to do with
> > policy expiration or i am misreading the code.
>
> That's right, pfkey never had policy expire messages. In general,
> anything to do with policies cannot be done portably in pfkey since
> the RFC only specified the SA operations.
>
Well, hopefully whoever defined that pfkey carries policies as well will
have to worry about this in the future. I will just leave teh hook but
remove the printk.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 1:56 ` jamal
@ 2005-04-04 2:26 ` Herbert Xu
2005-04-04 2:39 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-04 2:26 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sun, Apr 03, 2005 at 09:56:01PM -0400, jamal wrote:
> Now that you are picking on whitespaces i think we are almost there ;->
Yes I think we're getting really close now :)
> I think i am gonna take out any attempts to address this race above.
> It's a bug thats there already - a separate patch after this will be
> better.
OK.
> > > +static int xfrm_notify_sa( struct xfrm_state *x, struct km_event *c)
> >
> > Extra space after the paren.
> >
> > > + int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
> >
> > Please add the additional payloads for NAT-T and the keys.
>
> I dont think we should broadcast out keys.
I think that decision should be made by the KM. So you wouldn't do it
for PFKEY, but netlink should definitely do it.
For netlink we require root privileges to listen for these events.
> NAT-T - where do i look at to see what to send?
Check out dump_one_state.
> What is not being attached right now?
copy_to_user_tmpl
> you insulting vi? ;->
Yes unless you're using elvis :)
> > > - pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
> > > -
> > > - out_hdr = (struct sadb_msg *) out_skb->data;
> > > - out_hdr->sadb_msg_version = hdr->sadb_msg_version;
> > > - out_hdr->sadb_msg_type = hdr->sadb_msg_type;
> > > - out_hdr->sadb_msg_satype = 0;
> > > - out_hdr->sadb_msg_errno = 0;
> > > - out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
> > > - out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
> > > - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
> > > - err = 0;
> >
> > However, you do need to keep this code for the real GET case.
>
> Get seems to a separate entry point - pfkey_get() which i didnt touch.
pfkey_get() only does states. The code above is in pfkey_spdget().
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 1:58 ` jamal
@ 2005-04-04 2:27 ` Herbert Xu
0 siblings, 0 replies; 48+ messages in thread
From: Herbert Xu @ 2005-04-04 2:27 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sun, Apr 03, 2005 at 09:58:31PM -0400, jamal wrote:
>
> > Are you sure? Previously they did BROADCAST_ALL which goes to everyone
> > including the sender.
>
> Yes, he key is in the sk parameter to the broadcast. if a NULL is passed
> then all listeners are told. Else the passed sk is excluded.
Actually pfkey_broadcast is playing tricks on you :) It always does
one_sk at the end of the function.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 0:58 ` Herbert Xu
2005-04-04 1:56 ` jamal
@ 2005-04-04 2:34 ` jamal
2005-04-04 2:52 ` Herbert Xu
2005-04-04 11:38 ` take 2-2 " jamal
2 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-04 2:34 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sun, 2005-04-03 at 20:58, Herbert Xu wrote:
> ;
> > + // XXX:do we have to pass proto as well?
>
> I think so. A flush of all IPCOMP states is certainly quite different
> from a flush of all states. It's just a matter of calling satype2proto.
I think you meant pfkey_proto2satype(). i.e
hdr->sadb_msg_satype = pfkey_proto2satype(c->data);
BTW, slightly different from the way netlink does bussiness.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 2:26 ` Herbert Xu
@ 2005-04-04 2:39 ` jamal
2005-04-04 2:46 ` Herbert Xu
0 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-04 2:39 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sun, 2005-04-03 at 22:26, Herbert Xu wrote:
> On Sun, Apr 03, 2005 at 09:56:01PM -0400, jamal wrote:
> > I dont think we should broadcast out keys.
>
> I think that decision should be made by the KM. So you wouldn't do it
> for PFKEY, but netlink should definitely do it.
>
Is it possible to have non-root privileged pfkey sockets. If yes,
then it makes sense.
> Yes unless you're using elvis :)
Elvis left the building a while back ;->
But sightings of him in some doughnought shops in a small town not far
from here are rampant ;->
> The code above is in pfkey_spdget().
>
How did i miss that? ;->
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 2:39 ` jamal
@ 2005-04-04 2:46 ` Herbert Xu
2005-04-04 3:05 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-04 2:46 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sun, Apr 03, 2005 at 10:39:56PM -0400, jamal wrote:
> On Sun, 2005-04-03 at 22:26, Herbert Xu wrote:
>
> > I think that decision should be made by the KM. So you wouldn't do it
> > for PFKEY, but netlink should definitely do it.
>
> Is it possible to have non-root privileged pfkey sockets. If yes,
> then it makes sense.
Currently Linux requires CAP_NET_ADMIN for PFKEY. However, this
may not be the case on other systems. That's the reason why the
RFC requires that the keys not be sent via PFKEY.
However for netlink there is no such issue.
Even if we do eventually open up netlink for non-root listeners
(this will actually require structural changes to netlink itself),
we can create a new multicast group for non-privileged users that
don't get the keys.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 2:34 ` jamal
@ 2005-04-04 2:52 ` Herbert Xu
2005-04-04 3:07 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-04 2:52 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sun, Apr 03, 2005 at 10:34:04PM -0400, jamal wrote:
>
> I think you meant pfkey_proto2satype(). i.e
> hdr->sadb_msg_satype = pfkey_proto2satype(c->data);
Yes I was being dyslexic :)
> BTW, slightly different from the way netlink does bussiness.
You mean how netlink just passes the proto through verbatim?
Yes netlink uses the natural representation wherever possible.
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 2:46 ` Herbert Xu
@ 2005-04-04 3:05 ` jamal
0 siblings, 0 replies; 48+ messages in thread
From: jamal @ 2005-04-04 3:05 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sun, 2005-04-03 at 22:46, Herbert Xu wrote:
> Even if we do eventually open up netlink for non-root listeners
> (this will actually require structural changes to netlink itself),
> we can create a new multicast group for non-privileged users that
> don't get the keys.
>
Ok, I will add the keys in the case of the netlink announce.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 2:52 ` Herbert Xu
@ 2005-04-04 3:07 ` jamal
0 siblings, 0 replies; 48+ messages in thread
From: jamal @ 2005-04-04 3:07 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Sun, 2005-04-03 at 22:52, Herbert Xu wrote:
> You mean how netlink just passes the proto through verbatim?
> Yes netlink uses the natural representation wherever possible.
>
The one thing that needs discussing at some point is how to break down
the policy and state structural entities into TLVs in netlink. Not
now, future topic ;->
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 0:58 ` Herbert Xu
2005-04-04 1:56 ` jamal
2005-04-04 2:34 ` jamal
@ 2005-04-04 11:38 ` jamal
2005-04-04 12:16 ` Herbert Xu
2 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-04 11:38 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
[-- Attachment #1: Type: text/plain, Size: 46 bytes --]
Herbert!
Ok, heres an update.
cheers,
jamal
[-- Attachment #2: ipsec-event-take2-2 --]
[-- Type: text/plain, Size: 28796 bytes --]
--- a/include/net/xfrm.h 2005-03-25 22:28:26.000000000 -0500
+++ b/include/net/xfrm.h 2005-04-02 11:59:17.000000000 -0500
@@ -157,6 +157,28 @@
XFRM_STATE_DEAD
};
+/* events that could be sent by kernel */
+enum {
+ XFRM_SAP_INVALID,
+ XFRM_SAP_EXPIRED,
+ XFRM_SAP_ADDED,
+ XFRM_SAP_UPDATED,
+ XFRM_SAP_DELETED,
+ XFRM_SAP_FLUSHED,
+ __XFRM_SAP_MAX
+};
+#define XFRM_SAP_MAX (__XFRM_SAP_MAX - 1)
+
+/* callback structure passed from either netlink or pfkey */
+struct km_event
+{
+ u32 data;
+ u32 seq;
+ u32 pid;
+ u32 event;
+};
+
+
struct xfrm_type;
struct xfrm_dst;
struct xfrm_policy_afinfo {
@@ -178,6 +200,9 @@
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo);
+extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c);
+extern void km_state_notify(struct xfrm_state *x, struct km_event *c);
+
#define XFRM_ACQ_EXPIRES 30
@@ -283,17 +308,17 @@
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
-#define XFRM_KM_TIMEOUT 30
+#define XFRM_KM_TIMEOUT 30
struct xfrm_mgr
{
struct list_head list;
char *id;
- int (*notify)(struct xfrm_state *x, int event);
+ int (*notify)(struct xfrm_state *x, struct km_event *c);
int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir);
int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
- int (*notify_policy)(struct xfrm_policy *x, int dir, int event);
+ int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
};
extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -802,7 +827,7 @@
extern int xfrm_state_update(struct xfrm_state *x);
extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family);
extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
-extern void xfrm_state_delete(struct xfrm_state *x);
+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);
--- a/include/linux/xfrm.h 2005-03-25 22:28:39.000000000 -0500
+++ b/include/linux/xfrm.h 2005-04-02 09:53:03.000000000 -0500
@@ -254,5 +254,7 @@
#define XFRMGRP_ACQUIRE 1
#define XFRMGRP_EXPIRE 2
+#define XFRMGRP_SA 4
+#define XFRMGRP_POLICY 8
#endif /* _LINUX_XFRM_H */
--- a/net/xfrm/xfrm_state.c 2005-03-25 22:28:25.000000000 -0500
+++ b/net/xfrm/xfrm_state.c 2005-04-04 07:35:03.000000000 -0400
@@ -40,6 +40,8 @@
DECLARE_WAIT_QUEUE_HEAD(km_waitq);
EXPORT_SYMBOL(km_waitq);
+static DEFINE_RWLOCK(xfrm_km_lock);
+static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
static DEFINE_RWLOCK(xfrm_state_afinfo_lock);
static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO];
@@ -48,13 +50,15 @@
static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
-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);
static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
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);
+void km_state_notify(struct xfrm_state *x, struct km_event *c);
static void xfrm_state_gc_destroy(struct xfrm_state *x)
{
@@ -208,8 +212,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);
@@ -236,14 +242,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);
@@ -402,6 +415,7 @@
static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
+
int xfrm_state_add(struct xfrm_state *x)
{
struct xfrm_state_afinfo *afinfo;
@@ -764,37 +778,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_bh(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list)
+ if (km->notify_policy)
+ km->notify_policy(xp, dir, c);
+ read_unlock_bh(&xfrm_km_lock);
+}
+
+void km_state_notify(struct xfrm_state *x, struct km_event *c)
{
struct xfrm_mgr *km;
+ read_lock_bh(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list)
+ km->notify(x, c);
+ read_unlock_bh(&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;
@@ -819,13 +856,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);
--- a/net/xfrm/xfrm_user.c 2005-03-25 22:28:22.000000000 -0500
+++ b/net/xfrm/xfrm_user.c 2005-04-04 07:23:31.000000000 -0400
@@ -268,6 +268,7 @@
struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
struct xfrm_state *x;
int err;
+ struct km_event c;
err = verify_newsa_info(p, (struct rtattr **) xfrma);
if (err)
@@ -285,14 +286,28 @@
if (err < 0) {
x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x);
+ return err;
}
+ xfrm_state_hold(x);
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
+
return err;
}
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_state *x;
+ int err;
+ struct km_event c;
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
@@ -304,10 +319,19 @@
return -EPERM;
}
- xfrm_state_delete(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ xfrm_state_put(x);
+ return err;
+ }
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
xfrm_state_put(x);
- return 0;
+ return err;
}
static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
@@ -672,6 +696,7 @@
{
struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);
struct xfrm_policy *xp;
+ struct km_event c;
int err;
int excl;
@@ -683,6 +708,10 @@
if (!xp)
return err;
+ /* shouldnt excl be based on nlh flags??
+ * Aha! this is anti-netlink really i.e more pfkey derived
+ * in netlink excl is a flag and you wouldnt need
+ * a type XFRM_MSG_UPDPOLICY - JHS */
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
err = xfrm_policy_insert(p->dir, xp, excl);
if (err) {
@@ -690,6 +719,16 @@
return err;
}
+
+ if (!excl)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
+
xfrm_pol_put(xp);
return 0;
@@ -807,8 +846,10 @@
struct xfrm_policy *xp;
struct xfrm_userpolicy_id *p;
int err;
+ struct km_event c;
int delete;
+
p = NLMSG_DATA(nlh);
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
@@ -834,6 +875,11 @@
NETLINK_CB(skb).pid,
MSG_DONTWAIT);
}
+ } else {
+ c.event = XFRM_SAP_DELETED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
}
xfrm_pol_put(xp);
@@ -843,15 +889,28 @@
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
xfrm_state_flush(p->proto);
+ c.data = p->proto;
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_state_notify(NULL, &c);
+
return 0;
}
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
+
xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -1053,10 +1112,11 @@
return -1;
}
-static int xfrm_send_state_notify(struct xfrm_state *x, int hard)
+static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *skb;
-
+ int hard = c ->data;
+ /* fix to do alloc using NLM macros */
skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
@@ -1069,6 +1129,107 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_sa_flush(struct km_event *c)
+{
+ struct xfrm_usersa_flush *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq,
+ XFRM_MSG_FLUSHSA, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ p->proto = c->data;
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
+{
+ struct xfrm_usersa_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWSA;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDSA;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELSA;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ copy_to_user_state(x, p);
+
+ if (x->aalg)
+ RTA_PUT(skb, XFRMA_ALG_AUTH,
+ sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg);
+ if (x->ealg)
+ RTA_PUT(skb, XFRMA_ALG_CRYPT,
+ sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg);
+ if (x->calg)
+ RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
+
+ if (x->encap)
+ RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+rtattr_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_state_notify(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_ADDED:
+ return xfrm_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_sa_flush(c);
+ default:
+ printk("pfkey: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+
+}
+
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_tmpl *xt, struct xfrm_policy *xp,
int dir)
@@ -1202,7 +1363,8 @@
return -1;
}
-static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard)
+
+static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
{
struct sk_buff *skb;
size_t len;
@@ -1213,7 +1375,7 @@
if (skb == NULL)
return -ENOMEM;
- if (build_polexpire(skb, xp, dir, hard) < 0)
+ if (build_polexpire(skb, xp, dir, c->data) < 0)
BUG();
NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
@@ -1221,6 +1383,92 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct xfrm_userpolicy_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt = 0 ;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWPOLICY;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDPOLICY;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELPOLICY;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+
+ p = NLMSG_DATA(nlh);
+
+ nlh->nlmsg_flags = 0;
+
+ copy_to_user_policy(xp, p, dir);
+ if (copy_to_user_tmpl(xp, skb) < 0)
+ goto nlmsg_failure;
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_policy_flush(struct km_event *c)
+{
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(0);
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_DELETED:
+ return xfrm_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_policy_flush(c);
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_policy_notify(xp, dir, c);
+ default:
+ printk("Netlink Unknown Policy event %d\n",c->event);
+ }
+
+ return 0;
+
+}
+
static struct xfrm_mgr netlink_mgr = {
.id = "netlink",
.notify = xfrm_send_state_notify,
--- a/net/key/af_key.c 2005-03-25 22:28:39.000000000 -0500
+++ b/net/key/af_key.c 2005-04-04 07:20:12.000000000 -0400
@@ -1240,13 +1240,85 @@
return 0;
}
+static inline int event2poltype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_X_SPDDELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_X_SPDADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_X_SPDUPDATE;
+ case XFRM_SAP_EXPIRED:
+ // return SADB_X_SPDEXPIRE;
+ default:
+ printk("pfkey: Unknown policy event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int event2keytype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_DELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_ADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_UPDATE;
+ case XFRM_SAP_EXPIRED:
+ return SADB_EXPIRE;
+ default:
+ printk("pfkey: Unknown SA event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+/* ADD/UPD/DEL */
+static int key_notify_sa(struct xfrm_state *x, struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+ int hsc = 3;
+
+ if (c->event == XFRM_SAP_DELETED)
+ hsc = 0;
+
+ if (c->event == XFRM_SAP_EXPIRED) {
+ if (c->data)
+ hsc = 2;
+ else
+ hsc = 1;
+ }
+
+ skb = pfkey_xfrm_state2msg(x, 0, hsc);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ hdr = (struct sadb_msg *) skb->data;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_type = event2keytype(c->event);
+ hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+ hdr->sadb_msg_errno = 0;
+ hdr->sadb_msg_reserved = 0;
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_state *x;
int err;
+ struct km_event c;
xfrm_probe_algs();
@@ -1265,27 +1337,24 @@
return err;
}
- out_skb = pfkey_xfrm_state2msg(x, 0, 3);
- if (IS_ERR(out_skb))
- return PTR_ERR(out_skb); /* XXX Should we return 0 here ? */
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_reserved = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
-
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ xfrm_state_hold(x);
+ if (hdr->sadb_msg_type == SADB_ADD)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
- return 0;
+ return err;
}
static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
struct xfrm_state *x;
+ struct km_event c;
+ int err;
if (!ext_hdrs[SADB_EXT_SA-1] ||
!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
@@ -1301,13 +1370,19 @@
return -EPERM;
}
- xfrm_state_delete(x);
- xfrm_state_put(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ xfrm_state_put(x);
+ return err;
+ }
- pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
- BROADCAST_ALL, sk);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
- return 0;
+ return err;
}
static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -1445,28 +1520,42 @@
return 0;
}
+static int key_notify_sa_flush(struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+
+ skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
+ if (!skb)
+ return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+ hdr->sadb_msg_satype = pfkey_proto2satype(c->data);
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
+
static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
unsigned proto;
- struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
+ struct km_event c;
proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0)
return -EINVAL;
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
- if (!skb_out)
- return -ENOBUFS;
-
xfrm_state_flush(proto);
-
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
-
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+ c.data = proto;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_FLUSHED;
+ km_state_notify(NULL, &c);
return 0;
}
@@ -1859,6 +1948,35 @@
hdr->sadb_msg_reserved = atomic_read(&xp->refcnt);
}
+static int key_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct sk_buff *out_skb;
+ struct sadb_msg *out_hdr;
+ int err;
+
+ out_skb = pfkey_xfrm_policy2msg_prep(xp);
+ if (IS_ERR(out_skb)) {
+ err = PTR_ERR(out_skb);
+ goto out;
+ }
+ pfkey_xfrm_policy2msg(out_skb, xp, dir);
+
+ out_hdr = (struct sadb_msg *) out_skb->data;
+ out_hdr->sadb_msg_version = PF_KEY_V2;
+
+ if (c->data && c->event == XFRM_SAP_DELETED)
+ out_hdr->sadb_msg_type = SADB_X_SPDDELETE2;
+ else
+ out_hdr->sadb_msg_type = event2poltype(c->event);
+ out_hdr->sadb_msg_errno = 0;
+ out_hdr->sadb_msg_seq = c->seq;
+ out_hdr->sadb_msg_pid = c->pid;
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+out:
+ return 0;
+
+}
+
static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
int err;
@@ -1866,8 +1984,7 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -1935,31 +2052,25 @@
(err = parse_ipsecrequests(xp, pol)) < 0)
goto out;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
- }
err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp,
hdr->sadb_msg_type != SADB_X_SPDUPDATE);
+
if (err) {
- kfree_skb(out_skb);
- goto out;
+ kfree(xp);
+ return err;
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
+ if (hdr->sadb_msg_type == SADB_X_SPDUPDATE)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
- xfrm_pol_put(xp);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+ xfrm_pol_put(xp);
return 0;
out:
@@ -1973,9 +2084,8 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_selector sel;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -2010,25 +2120,41 @@
err = 0;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+
+ xfrm_pol_put(xp);
+ return err;
+}
+
+
+static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, struct sadb_msg *hdr, int dir)
+{
+ int err;
+ struct sk_buff *out_skb;
+ struct sadb_msg *out_hdr;
+ err = 0;
+
out_skb = pfkey_xfrm_policy2msg_prep(xp);
if (IS_ERR(out_skb)) {
err = PTR_ERR(out_skb);
goto out;
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
+ pfkey_xfrm_policy2msg(out_skb, xp, dir);
out_hdr = (struct sadb_msg *) out_skb->data;
out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = SADB_X_SPDDELETE;
+ out_hdr->sadb_msg_type = hdr->sadb_msg_type;
out_hdr->sadb_msg_satype = 0;
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk);
err = 0;
out:
- xfrm_pol_put(xp);
return err;
}
@@ -2037,8 +2163,7 @@
int err;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL)
return -EINVAL;
@@ -2050,24 +2175,16 @@
err = 0;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) {
+ c.data = 1; // to signal pfkey of SADB_X_SPDDELETE2
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+ } else {
+ err = key_pol_get_resp(sk, xp, hdr, pol->sadb_x_policy_dir-1);
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
- err = 0;
-out:
xfrm_pol_put(xp);
return err;
}
@@ -2102,22 +2219,33 @@
return xfrm_policy_walk(dump_sp, &data);
}
-static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+static int key_notify_policy_flush(struct km_event *c)
{
struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
-
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
+ struct sadb_msg *hdr;
+ skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
if (!skb_out)
return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+ pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL);
+ return 0;
- xfrm_policy_flush();
+}
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+ struct km_event c;
+
+ xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.pid = hdr->sadb_msg_pid;
+ c.seq = hdr->sadb_msg_seq;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -2317,11 +2445,25 @@
}
}
-static int pfkey_send_notify(struct xfrm_state *x, int hard)
+/* XXX: Noisy for now */
+static int key_notify_policy_expire(struct xfrm_policy *xp, struct km_event *c)
+{
+ printk("pfkey doesnt deal with expired policies ..\n");
+ return 0;
+}
+
+static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *out_skb;
struct sadb_msg *out_hdr;
- int hsc = (hard ? 2 : 1);
+ int hard;
+ int hsc;
+
+ hard = c->data;
+ if (hard)
+ hsc = 2;
+ else
+ hsc = 1;
out_skb = pfkey_xfrm_state2msg(x, 0, hsc);
if (IS_ERR(out_skb))
@@ -2340,6 +2482,43 @@
return 0;
}
+static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_sa_expire(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_sa_flush(c);
+ default:
+ printk("pfkey: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
+
+static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_policy_expire(xp, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_policy_flush(c);
+ default:
+ printk("pfkey: Unknown policy event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
static u32 get_acqseq(void)
{
u32 res;
@@ -2856,6 +3035,7 @@
.acquire = pfkey_send_acquire,
.compile_policy = pfkey_compile_policy,
.new_mapping = pfkey_send_new_mapping,
+ .notify_policy = pfkey_send_policy_notify,
};
static void __exit ipsec_pfkey_exit(void)
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 11:38 ` take 2-2 " jamal
@ 2005-04-04 12:16 ` Herbert Xu
2005-04-04 12:51 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-04 12:16 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
Hi Jamal:
On Mon, Apr 04, 2005 at 07:38:26AM -0400, jamal wrote:
> Ok, heres an update.
Great! White space comments only this time, almost :)
> @@ -48,13 +50,15 @@
> static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
> static DEFINE_SPINLOCK(xfrm_state_gc_lock);
>
> -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);
>
> static int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol);
> 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);
> +void km_state_notify(struct xfrm_state *x, struct km_event *c);
No need for these prototypes since they're already in xfrm.h.
> @@ -764,37 +778,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);
How about letting these guys stay where they are? The move was
necessary before because the km_*_notify functions had to be called
in this file but that's no longer the case.
> --- a/net/xfrm/xfrm_user.c 2005-03-25 22:28:22.000000000 -0500
> +++ b/net/xfrm/xfrm_user.c 2005-04-04 07:23:31.000000000 -0400
> @@ -268,6 +268,7 @@
> struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
> struct xfrm_state *x;
> int err;
> + struct km_event c;
>
> err = verify_newsa_info(p, (struct rtattr **) xfrma);
> if (err)
> @@ -285,14 +286,28 @@
> if (err < 0) {
> x->km.state = XFRM_STATE_DEAD;
> xfrm_state_put(x);
> + return err;
> }
>
> + xfrm_state_hold(x);
Sorry, you need to hold x before the call to
xfrm_state_add/xfrm_state_update as otherwise
they can cause x to be freed.
In general hold/put is only useful if
1) When you call hold you already have a reference to the object.
2) In between the hold/put you may free the object.
> static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
> {
> - struct sk_buff *out_skb;
> - struct sadb_msg *out_hdr;
> struct xfrm_state *x;
> int err;
> + struct km_event c;
>
> xfrm_probe_algs();
...
> - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
> + xfrm_state_hold(x);
Same problem as xfrm_user. We need the hold to occur before the
add/update for it to be effective. In fact the original code was
buggy too since it didn't hold a reference at all.
Of course this is very unlikely to crash since it requires a
small life time and some bad luck in getting preempted.
Thanks,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 12:16 ` Herbert Xu
@ 2005-04-04 12:51 ` jamal
2005-04-04 13:02 ` Herbert Xu
0 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-04 12:51 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
[-- Attachment #1: Type: text/plain, Size: 1711 bytes --]
Herbert,
On Mon, 2005-04-04 at 08:16, Herbert Xu wrote:
> Hi Jamal:
>
> On Mon, Apr 04, 2005 at 07:38:26AM -0400, jamal wrote:
> > Ok, heres an update.
> > +void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c);
> > +void km_state_notify(struct xfrm_state *x, struct km_event *c);
>
> No need for these prototypes since they're already in xfrm.h.
Good catch.
>
> > @@ -764,37 +778,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);
>
> How about letting these guys stay where they are? The move was
> necessary before because the km_*_notify functions had to be called
> in this file but that's no longer the case.
>
Changed
- dont see what the harm was as they were in that patch though.
[..]
> Sorry, you need to hold x before the call to
> xfrm_state_add/xfrm_state_update as otherwise
> they can cause x to be freed.
>
> In general hold/put is only useful if
>
> 1) When you call hold you already have a reference to the object.
> 2) In between the hold/put you may free the object.
>
[..]
> Same problem as xfrm_user. We need the hold to occur before the
> add/update for it to be effective. In fact the original code was
> buggy too since it didn't hold a reference at all.
>
> Of course this is very unlikely to crash since it requires a
> small life time and some bad luck in getting preempted.
>
;-> Yes, indeed. I think its time for you to throw in the towel ;->
There was really not even a need for that hold given the likelihood of
anything like this happening. Anyways ive made this fix and heres the
updated patch.
cheers,
jamal
[-- Attachment #2: ipsec-event-take2-3 --]
[-- Type: text/plain, Size: 28543 bytes --]
--- a/include/net/xfrm.h 2005-03-25 22:28:26.000000000 -0500
+++ b/include/net/xfrm.h 2005-04-02 11:59:17.000000000 -0500
@@ -157,6 +157,28 @@
XFRM_STATE_DEAD
};
+/* events that could be sent by kernel */
+enum {
+ XFRM_SAP_INVALID,
+ XFRM_SAP_EXPIRED,
+ XFRM_SAP_ADDED,
+ XFRM_SAP_UPDATED,
+ XFRM_SAP_DELETED,
+ XFRM_SAP_FLUSHED,
+ __XFRM_SAP_MAX
+};
+#define XFRM_SAP_MAX (__XFRM_SAP_MAX - 1)
+
+/* callback structure passed from either netlink or pfkey */
+struct km_event
+{
+ u32 data;
+ u32 seq;
+ u32 pid;
+ u32 event;
+};
+
+
struct xfrm_type;
struct xfrm_dst;
struct xfrm_policy_afinfo {
@@ -178,6 +200,9 @@
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo);
+extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c);
+extern void km_state_notify(struct xfrm_state *x, struct km_event *c);
+
#define XFRM_ACQ_EXPIRES 30
@@ -283,17 +308,17 @@
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
-#define XFRM_KM_TIMEOUT 30
+#define XFRM_KM_TIMEOUT 30
struct xfrm_mgr
{
struct list_head list;
char *id;
- int (*notify)(struct xfrm_state *x, int event);
+ int (*notify)(struct xfrm_state *x, struct km_event *c);
int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir);
int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
- int (*notify_policy)(struct xfrm_policy *x, int dir, int event);
+ int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
};
extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -802,7 +827,7 @@
extern int xfrm_state_update(struct xfrm_state *x);
extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family);
extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
-extern void xfrm_state_delete(struct xfrm_state *x);
+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);
--- a/include/linux/xfrm.h 2005-03-25 22:28:39.000000000 -0500
+++ b/include/linux/xfrm.h 2005-04-02 09:53:03.000000000 -0500
@@ -254,5 +254,7 @@
#define XFRMGRP_ACQUIRE 1
#define XFRMGRP_EXPIRE 2
+#define XFRMGRP_SA 4
+#define XFRMGRP_POLICY 8
#endif /* _LINUX_XFRM_H */
--- a/net/xfrm/xfrm_state.c 2005-03-25 22:28:25.000000000 -0500
+++ b/net/xfrm/xfrm_state.c 2005-04-04 08:41:52.000000000 -0400
@@ -48,7 +48,7 @@
static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
-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);
@@ -208,8 +208,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);
@@ -236,14 +238,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);
@@ -402,6 +411,7 @@
static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
+
int xfrm_state_add(struct xfrm_state *x)
{
struct xfrm_state_afinfo *afinfo;
@@ -762,39 +772,64 @@
x->replay.bitmap |= (1U << diff);
}
}
+static DEFINE_RWLOCK(xfrm_km_lock);
+static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
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_bh(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list)
+ if (km->notify_policy)
+ km->notify_policy(xp, dir, c);
+ read_unlock_bh(&xfrm_km_lock);
+}
+
+void km_state_notify(struct xfrm_state *x, struct km_event *c)
+{
+ struct xfrm_mgr *km;
+ read_lock_bh(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list)
+ km->notify(x, c);
+ read_unlock_bh(&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;
@@ -819,13 +854,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);
--- a/net/xfrm/xfrm_user.c 2005-03-25 22:28:22.000000000 -0500
+++ b/net/xfrm/xfrm_user.c 2005-04-04 08:44:31.000000000 -0400
@@ -268,6 +268,7 @@
struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
struct xfrm_state *x;
int err;
+ struct km_event c;
err = verify_newsa_info(p, (struct rtattr **) xfrma);
if (err)
@@ -277,6 +278,7 @@
if (!x)
return err;
+ xfrm_state_hold(x);
if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
err = xfrm_state_add(x);
else
@@ -285,14 +287,27 @@
if (err < 0) {
x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x);
+ return err;
}
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
+
return err;
}
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_state *x;
+ int err;
+ struct km_event c;
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
@@ -304,10 +319,19 @@
return -EPERM;
}
- xfrm_state_delete(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ xfrm_state_put(x);
+ return err;
+ }
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
xfrm_state_put(x);
- return 0;
+ return err;
}
static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
@@ -672,6 +696,7 @@
{
struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);
struct xfrm_policy *xp;
+ struct km_event c;
int err;
int excl;
@@ -683,6 +708,10 @@
if (!xp)
return err;
+ /* shouldnt excl be based on nlh flags??
+ * Aha! this is anti-netlink really i.e more pfkey derived
+ * in netlink excl is a flag and you wouldnt need
+ * a type XFRM_MSG_UPDPOLICY - JHS */
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
err = xfrm_policy_insert(p->dir, xp, excl);
if (err) {
@@ -690,6 +719,16 @@
return err;
}
+
+ if (!excl)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
+
xfrm_pol_put(xp);
return 0;
@@ -807,8 +846,10 @@
struct xfrm_policy *xp;
struct xfrm_userpolicy_id *p;
int err;
+ struct km_event c;
int delete;
+
p = NLMSG_DATA(nlh);
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
@@ -834,6 +875,11 @@
NETLINK_CB(skb).pid,
MSG_DONTWAIT);
}
+ } else {
+ c.event = XFRM_SAP_DELETED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
}
xfrm_pol_put(xp);
@@ -843,15 +889,28 @@
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
xfrm_state_flush(p->proto);
+ c.data = p->proto;
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_state_notify(NULL, &c);
+
return 0;
}
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
+
xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -1053,10 +1112,11 @@
return -1;
}
-static int xfrm_send_state_notify(struct xfrm_state *x, int hard)
+static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *skb;
-
+ int hard = c ->data;
+ /* fix to do alloc using NLM macros */
skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
@@ -1069,6 +1129,107 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_sa_flush(struct km_event *c)
+{
+ struct xfrm_usersa_flush *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq,
+ XFRM_MSG_FLUSHSA, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ p->proto = c->data;
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
+{
+ struct xfrm_usersa_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWSA;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDSA;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELSA;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ copy_to_user_state(x, p);
+
+ if (x->aalg)
+ RTA_PUT(skb, XFRMA_ALG_AUTH,
+ sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg);
+ if (x->ealg)
+ RTA_PUT(skb, XFRMA_ALG_CRYPT,
+ sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg);
+ if (x->calg)
+ RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
+
+ if (x->encap)
+ RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+rtattr_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_state_notify(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_ADDED:
+ return xfrm_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_sa_flush(c);
+ default:
+ printk("pfkey: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+
+}
+
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_tmpl *xt, struct xfrm_policy *xp,
int dir)
@@ -1202,7 +1363,8 @@
return -1;
}
-static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard)
+
+static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
{
struct sk_buff *skb;
size_t len;
@@ -1213,7 +1375,7 @@
if (skb == NULL)
return -ENOMEM;
- if (build_polexpire(skb, xp, dir, hard) < 0)
+ if (build_polexpire(skb, xp, dir, c->data) < 0)
BUG();
NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
@@ -1221,6 +1383,92 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct xfrm_userpolicy_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt = 0 ;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWPOLICY;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDPOLICY;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELPOLICY;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+
+ p = NLMSG_DATA(nlh);
+
+ nlh->nlmsg_flags = 0;
+
+ copy_to_user_policy(xp, p, dir);
+ if (copy_to_user_tmpl(xp, skb) < 0)
+ goto nlmsg_failure;
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_policy_flush(struct km_event *c)
+{
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(0);
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_DELETED:
+ return xfrm_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_policy_flush(c);
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_policy_notify(xp, dir, c);
+ default:
+ printk("Netlink Unknown Policy event %d\n",c->event);
+ }
+
+ return 0;
+
+}
+
static struct xfrm_mgr netlink_mgr = {
.id = "netlink",
.notify = xfrm_send_state_notify,
--- a/net/key/af_key.c 2005-03-25 22:28:39.000000000 -0500
+++ b/net/key/af_key.c 2005-04-04 08:44:50.000000000 -0400
@@ -1240,13 +1240,85 @@
return 0;
}
+static inline int event2poltype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_X_SPDDELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_X_SPDADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_X_SPDUPDATE;
+ case XFRM_SAP_EXPIRED:
+ // return SADB_X_SPDEXPIRE;
+ default:
+ printk("pfkey: Unknown policy event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int event2keytype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_DELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_ADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_UPDATE;
+ case XFRM_SAP_EXPIRED:
+ return SADB_EXPIRE;
+ default:
+ printk("pfkey: Unknown SA event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+/* ADD/UPD/DEL */
+static int key_notify_sa(struct xfrm_state *x, struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+ int hsc = 3;
+
+ if (c->event == XFRM_SAP_DELETED)
+ hsc = 0;
+
+ if (c->event == XFRM_SAP_EXPIRED) {
+ if (c->data)
+ hsc = 2;
+ else
+ hsc = 1;
+ }
+
+ skb = pfkey_xfrm_state2msg(x, 0, hsc);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ hdr = (struct sadb_msg *) skb->data;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_type = event2keytype(c->event);
+ hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+ hdr->sadb_msg_errno = 0;
+ hdr->sadb_msg_reserved = 0;
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_state *x;
int err;
+ struct km_event c;
xfrm_probe_algs();
@@ -1254,6 +1326,7 @@
if (IS_ERR(x))
return PTR_ERR(x);
+ xfrm_state_hold(x);
if (hdr->sadb_msg_type == SADB_ADD)
err = xfrm_state_add(x);
else
@@ -1265,27 +1338,23 @@
return err;
}
- out_skb = pfkey_xfrm_state2msg(x, 0, 3);
- if (IS_ERR(out_skb))
- return PTR_ERR(out_skb); /* XXX Should we return 0 here ? */
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_reserved = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
-
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ if (hdr->sadb_msg_type == SADB_ADD)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
- return 0;
+ return err;
}
static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
struct xfrm_state *x;
+ struct km_event c;
+ int err;
if (!ext_hdrs[SADB_EXT_SA-1] ||
!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
@@ -1301,13 +1370,19 @@
return -EPERM;
}
- xfrm_state_delete(x);
- xfrm_state_put(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ xfrm_state_put(x);
+ return err;
+ }
- pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
- BROADCAST_ALL, sk);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
- return 0;
+ return err;
}
static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -1445,28 +1520,42 @@
return 0;
}
+static int key_notify_sa_flush(struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+
+ skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
+ if (!skb)
+ return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+ hdr->sadb_msg_satype = pfkey_proto2satype(c->data);
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
+
static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
unsigned proto;
- struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
+ struct km_event c;
proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0)
return -EINVAL;
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
- if (!skb_out)
- return -ENOBUFS;
-
xfrm_state_flush(proto);
-
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
-
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+ c.data = proto;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_FLUSHED;
+ km_state_notify(NULL, &c);
return 0;
}
@@ -1859,6 +1948,35 @@
hdr->sadb_msg_reserved = atomic_read(&xp->refcnt);
}
+static int key_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct sk_buff *out_skb;
+ struct sadb_msg *out_hdr;
+ int err;
+
+ out_skb = pfkey_xfrm_policy2msg_prep(xp);
+ if (IS_ERR(out_skb)) {
+ err = PTR_ERR(out_skb);
+ goto out;
+ }
+ pfkey_xfrm_policy2msg(out_skb, xp, dir);
+
+ out_hdr = (struct sadb_msg *) out_skb->data;
+ out_hdr->sadb_msg_version = PF_KEY_V2;
+
+ if (c->data && c->event == XFRM_SAP_DELETED)
+ out_hdr->sadb_msg_type = SADB_X_SPDDELETE2;
+ else
+ out_hdr->sadb_msg_type = event2poltype(c->event);
+ out_hdr->sadb_msg_errno = 0;
+ out_hdr->sadb_msg_seq = c->seq;
+ out_hdr->sadb_msg_pid = c->pid;
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+out:
+ return 0;
+
+}
+
static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
int err;
@@ -1866,8 +1984,7 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -1935,31 +2052,25 @@
(err = parse_ipsecrequests(xp, pol)) < 0)
goto out;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
- }
err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp,
hdr->sadb_msg_type != SADB_X_SPDUPDATE);
+
if (err) {
- kfree_skb(out_skb);
- goto out;
+ kfree(xp);
+ return err;
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
+ if (hdr->sadb_msg_type == SADB_X_SPDUPDATE)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
- xfrm_pol_put(xp);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+ xfrm_pol_put(xp);
return 0;
out:
@@ -1973,9 +2084,8 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_selector sel;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -2010,25 +2120,41 @@
err = 0;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+
+ xfrm_pol_put(xp);
+ return err;
+}
+
+
+static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, struct sadb_msg *hdr, int dir)
+{
+ int err;
+ struct sk_buff *out_skb;
+ struct sadb_msg *out_hdr;
+ err = 0;
+
out_skb = pfkey_xfrm_policy2msg_prep(xp);
if (IS_ERR(out_skb)) {
err = PTR_ERR(out_skb);
goto out;
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
+ pfkey_xfrm_policy2msg(out_skb, xp, dir);
out_hdr = (struct sadb_msg *) out_skb->data;
out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = SADB_X_SPDDELETE;
+ out_hdr->sadb_msg_type = hdr->sadb_msg_type;
out_hdr->sadb_msg_satype = 0;
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk);
err = 0;
out:
- xfrm_pol_put(xp);
return err;
}
@@ -2037,8 +2163,7 @@
int err;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL)
return -EINVAL;
@@ -2050,24 +2175,16 @@
err = 0;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) {
+ c.data = 1; // to signal pfkey of SADB_X_SPDDELETE2
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+ } else {
+ err = key_pol_get_resp(sk, xp, hdr, pol->sadb_x_policy_dir-1);
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
- err = 0;
-out:
xfrm_pol_put(xp);
return err;
}
@@ -2102,22 +2219,33 @@
return xfrm_policy_walk(dump_sp, &data);
}
-static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+static int key_notify_policy_flush(struct km_event *c)
{
struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
-
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
+ struct sadb_msg *hdr;
+ skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
if (!skb_out)
return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+ pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL);
+ return 0;
- xfrm_policy_flush();
+}
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+ struct km_event c;
+
+ xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.pid = hdr->sadb_msg_pid;
+ c.seq = hdr->sadb_msg_seq;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -2317,11 +2445,25 @@
}
}
-static int pfkey_send_notify(struct xfrm_state *x, int hard)
+/* XXX: Noisy for now */
+static int key_notify_policy_expire(struct xfrm_policy *xp, struct km_event *c)
+{
+ printk("pfkey doesnt deal with expired policies ..\n");
+ return 0;
+}
+
+static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *out_skb;
struct sadb_msg *out_hdr;
- int hsc = (hard ? 2 : 1);
+ int hard;
+ int hsc;
+
+ hard = c->data;
+ if (hard)
+ hsc = 2;
+ else
+ hsc = 1;
out_skb = pfkey_xfrm_state2msg(x, 0, hsc);
if (IS_ERR(out_skb))
@@ -2340,6 +2482,43 @@
return 0;
}
+static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_sa_expire(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_sa_flush(c);
+ default:
+ printk("pfkey: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
+
+static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_policy_expire(xp, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_policy_flush(c);
+ default:
+ printk("pfkey: Unknown policy event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
static u32 get_acqseq(void)
{
u32 res;
@@ -2856,6 +3035,7 @@
.acquire = pfkey_send_acquire,
.compile_policy = pfkey_compile_policy,
.new_mapping = pfkey_send_new_mapping,
+ .notify_policy = pfkey_send_policy_notify,
};
static void __exit ipsec_pfkey_exit(void)
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 12:51 ` jamal
@ 2005-04-04 13:02 ` Herbert Xu
2005-04-04 13:16 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-04 13:02 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Mon, Apr 04, 2005 at 08:51:37AM -0400, jamal wrote:
>
> > > -static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
> > > -static DEFINE_RWLOCK(xfrm_km_lock);
> >
> > How about letting these guys stay where they are? The move was
> > necessary before because the km_*_notify functions had to be called
> > in this file but that's no longer the case.
>
> Changed
> - dont see what the harm was as they were in that patch though.
Please see below.
> +static DEFINE_RWLOCK(xfrm_km_lock);
> +static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
> EXPORT_SYMBOL(xfrm_replay_advance);
>
> -static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
> -static DEFINE_RWLOCK(xfrm_km_lock);
All I wanted was to leave these lines as is so that they didn't
appear in the patch at all (except as conext) :)
When reviewing patches the most annoying thing is to see things
moved around or rearranged because that distracts the reviewer
from the substantiative changes.
> ;-> Yes, indeed. I think its time for you to throw in the towel ;->
Alright I give in :)
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 13:02 ` Herbert Xu
@ 2005-04-04 13:16 ` jamal
2005-04-04 21:31 ` Herbert Xu
0 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-04 13:16 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Mon, 2005-04-04 at 09:02, Herbert Xu wrote:
> > -static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
> > -static DEFINE_RWLOCK(xfrm_km_lock);
>
> All I wanted was to leave these lines as is so that they didn't
> appear in the patch at all (except as conext) :)
>
> When reviewing patches the most annoying thing is to see things
> moved around or rearranged because that distracts the reviewer
> from the substantiative changes.
Ok, fair enough. It annoys me too when i review patches ;->
So i will fix this before final.
>
> > ;-> Yes, indeed. I think its time for you to throw in the towel ;->
>
> Alright I give in :)
Goody - now we can have Masahide run his full test.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 13:16 ` jamal
@ 2005-04-04 21:31 ` Herbert Xu
2005-04-04 22:20 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: Herbert Xu @ 2005-04-04 21:31 UTC (permalink / raw)
To: jamal; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Mon, Apr 04, 2005 at 09:16:55AM -0400, jamal wrote:
>
> Ok, fair enough. It annoys me too when i review patches ;->
> So i will fix this before final.
Just one more thing, can you please remove the _bh's that you
added to the read_lock for xfrm_km_list? It turns out that they're
not necessary since the write_lock()'s are only held in process
context.
Thanks,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 21:31 ` Herbert Xu
@ 2005-04-04 22:20 ` jamal
2005-04-04 22:25 ` David S. Miller
0 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-04 22:20 UTC (permalink / raw)
To: Herbert Xu; +Cc: Patrick McHardy, Masahide NAKAMURA, David S. Miller, netdev
On Mon, 2005-04-04 at 17:31, Herbert Xu wrote:
> On Mon, Apr 04, 2005 at 09:16:55AM -0400, jamal wrote:
> >
> > Ok, fair enough. It annoys me too when i review patches ;->
> > So i will fix this before final.
>
> Just one more thing, can you please remove the _bh's that you
> added to the read_lock for xfrm_km_list? It turns out that they're
> not necessary since the write_lock()'s are only held in process
> context.
Doesnt the policy notification one need it at least ? I thought it is
entered at interupt context on packet path, no?
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 22:20 ` jamal
@ 2005-04-04 22:25 ` David S. Miller
2005-04-04 22:42 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: David S. Miller @ 2005-04-04 22:25 UTC (permalink / raw)
To: hadi; +Cc: herbert, kaber, nakam, netdev
On 04 Apr 2005 18:20:17 -0400
jamal <hadi@cyberus.ca> wrote:
> On Mon, 2005-04-04 at 17:31, Herbert Xu wrote:
> > On Mon, Apr 04, 2005 at 09:16:55AM -0400, jamal wrote:
> > >
> > > Ok, fair enough. It annoys me too when i review patches ;->
> > > So i will fix this before final.
> >
> > Just one more thing, can you please remove the _bh's that you
> > added to the read_lock for xfrm_km_list? It turns out that they're
> > not necessary since the write_lock()'s are only held in process
> > context.
>
> Doesnt the policy notification one need it at least ? I thought it is
> entered at interupt context on packet path, no?
If you only take write_lock() from process context, only the write_lock()'s
need BH disabling. read_lock() takers can then nest arbitrarily, BH or not.
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 22:25 ` David S. Miller
@ 2005-04-04 22:42 ` jamal
2005-04-05 7:35 ` Masahide NAKAMURA
0 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-04 22:42 UTC (permalink / raw)
To: David S. Miller; +Cc: herbert, kaber, nakam, netdev
On Mon, 2005-04-04 at 18:25, David S. Miller wrote:
> If you only take write_lock() from process context, only the write_lock()'s
> need BH disabling. read_lock() takers can then nest arbitrarily, BH or not.
Ok, never mind - Ive made the change.
As soon as Masahide tests i will post the final patch.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-04 22:42 ` jamal
@ 2005-04-05 7:35 ` Masahide NAKAMURA
2005-04-05 10:18 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: Masahide NAKAMURA @ 2005-04-05 7:35 UTC (permalink / raw)
To: hadi; +Cc: David S. Miller, herbert, kaber, netdev
Hello Jamal,
jamal wrote:
> On Mon, 2005-04-04 at 18:25, David S. Miller wrote:
>
>
>>If you only take write_lock() from process context, only the write_lock()'s
>>need BH disabling. read_lock() takers can then nest arbitrarily, BH or not.
>
>
> Ok, never mind - Ive made the change.
> As soon as Masahide tests i will post the final patch.
I've tested normal cases below with the latest patch and it works fine.
I think you can go ahead.
tested cases:
o netlink (using iproute2 "ip xfrm monitor" to confirm it)
- add/del/flush/expire for SA/SP
- acquire,allocspi,update for SA
- update for SP
o pfkey
- running racoon
o both sockets
- running racoon with using "ip xfrm monitor".
Regards,
--
Masahide NAKAMURA
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-05 7:35 ` Masahide NAKAMURA
@ 2005-04-05 10:18 ` jamal
2005-04-05 10:22 ` Herbert Xu
0 siblings, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-05 10:18 UTC (permalink / raw)
To: Masahide NAKAMURA; +Cc: David S. Miller, herbert, kaber, netdev
[-- Attachment #1: Type: text/plain, Size: 576 bytes --]
On Tue, 2005-04-05 at 03:35, Masahide NAKAMURA wrote:
> Hello Jamal,
[..]
> I've tested normal cases below with the latest patch and it works fine.
> I think you can go ahead.
>
> tested cases:
> o netlink (using iproute2 "ip xfrm monitor" to confirm it)
> - add/del/flush/expire for SA/SP
> - acquire,allocspi,update for SA
> - update for SP
> o pfkey
> - running racoon
> o both sockets
> - running racoon with using "ip xfrm monitor".
>
Thanks a lot Masahide!
Ok, heres the patch i will shoot to Dave if no further comments.
cheers,
jamal
[-- Attachment #2: ipsec-event-take2-5 --]
[-- Type: text/plain, Size: 28858 bytes --]
--- a/include/net/xfrm.h 2005-03-25 22:28:26.000000000 -0500
+++ b/include/net/xfrm.h 2005-04-02 11:59:17.000000000 -0500
@@ -157,6 +157,28 @@
XFRM_STATE_DEAD
};
+/* events that could be sent by kernel */
+enum {
+ XFRM_SAP_INVALID,
+ XFRM_SAP_EXPIRED,
+ XFRM_SAP_ADDED,
+ XFRM_SAP_UPDATED,
+ XFRM_SAP_DELETED,
+ XFRM_SAP_FLUSHED,
+ __XFRM_SAP_MAX
+};
+#define XFRM_SAP_MAX (__XFRM_SAP_MAX - 1)
+
+/* callback structure passed from either netlink or pfkey */
+struct km_event
+{
+ u32 data;
+ u32 seq;
+ u32 pid;
+ u32 event;
+};
+
+
struct xfrm_type;
struct xfrm_dst;
struct xfrm_policy_afinfo {
@@ -178,6 +200,9 @@
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo);
+extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c);
+extern void km_state_notify(struct xfrm_state *x, struct km_event *c);
+
#define XFRM_ACQ_EXPIRES 30
@@ -283,17 +308,17 @@
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
-#define XFRM_KM_TIMEOUT 30
+#define XFRM_KM_TIMEOUT 30
struct xfrm_mgr
{
struct list_head list;
char *id;
- int (*notify)(struct xfrm_state *x, int event);
+ int (*notify)(struct xfrm_state *x, struct km_event *c);
int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir);
int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport);
- int (*notify_policy)(struct xfrm_policy *x, int dir, int event);
+ int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c);
};
extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -802,7 +827,7 @@
extern int xfrm_state_update(struct xfrm_state *x);
extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family);
extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
-extern void xfrm_state_delete(struct xfrm_state *x);
+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);
--- a/include/linux/xfrm.h 2005-03-25 22:28:39.000000000 -0500
+++ b/include/linux/xfrm.h 2005-04-02 09:53:03.000000000 -0500
@@ -254,5 +254,7 @@
#define XFRMGRP_ACQUIRE 1
#define XFRMGRP_EXPIRE 2
+#define XFRMGRP_SA 4
+#define XFRMGRP_POLICY 8
#endif /* _LINUX_XFRM_H */
--- a/net/xfrm/xfrm_state.c 2005-03-25 22:28:25.000000000 -0500
+++ b/net/xfrm/xfrm_state.c 2005-04-04 18:22:32.000000000 -0400
@@ -48,7 +48,7 @@
static struct list_head xfrm_state_gc_list = LIST_HEAD_INIT(xfrm_state_gc_list);
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
-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);
@@ -208,8 +208,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);
@@ -236,14 +238,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);
@@ -402,6 +411,7 @@
static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
+
int xfrm_state_add(struct xfrm_state *x)
{
struct xfrm_state_afinfo *afinfo;
@@ -767,34 +777,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;
- 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)
+ 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)
- km->notify(x, hard);
+ 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;
+ 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;
@@ -819,13 +855,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);
--- a/net/xfrm/xfrm_user.c 2005-03-25 22:28:22.000000000 -0500
+++ b/net/xfrm/xfrm_user.c 2005-04-04 18:36:44.000000000 -0400
@@ -268,6 +268,7 @@
struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
struct xfrm_state *x;
int err;
+ struct km_event c;
err = verify_newsa_info(p, (struct rtattr **) xfrma);
if (err)
@@ -277,6 +278,7 @@
if (!x)
return err;
+ xfrm_state_hold(x);
if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
err = xfrm_state_add(x);
else
@@ -285,14 +287,27 @@
if (err < 0) {
x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x);
+ return err;
}
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ if (nlh->nlmsg_type == XFRM_MSG_NEWSA)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
+
return err;
}
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_state *x;
+ int err;
+ struct km_event c;
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family);
@@ -304,10 +319,19 @@
return -EPERM;
}
- xfrm_state_delete(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ xfrm_state_put(x);
+ return err;
+ }
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
xfrm_state_put(x);
- return 0;
+ return err;
}
static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
@@ -335,6 +359,7 @@
int this_idx;
};
+
static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
{
struct xfrm_dump_info *sp = ptr;
@@ -672,6 +697,7 @@
{
struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);
struct xfrm_policy *xp;
+ struct km_event c;
int err;
int excl;
@@ -683,6 +709,10 @@
if (!xp)
return err;
+ /* shouldnt excl be based on nlh flags??
+ * Aha! this is anti-netlink really i.e more pfkey derived
+ * in netlink excl is a flag and you wouldnt need
+ * a type XFRM_MSG_UPDPOLICY - JHS */
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
err = xfrm_policy_insert(p->dir, xp, excl);
if (err) {
@@ -690,6 +720,16 @@
return err;
}
+
+ if (!excl)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
+
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
+
xfrm_pol_put(xp);
return 0;
@@ -807,8 +847,10 @@
struct xfrm_policy *xp;
struct xfrm_userpolicy_id *p;
int err;
+ struct km_event c;
int delete;
+
p = NLMSG_DATA(nlh);
delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY;
@@ -834,6 +876,11 @@
NETLINK_CB(skb).pid,
MSG_DONTWAIT);
}
+ } else {
+ c.event = XFRM_SAP_DELETED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(xp, p->dir, &c);
}
xfrm_pol_put(xp);
@@ -843,15 +890,28 @@
static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
struct xfrm_usersa_flush *p = NLMSG_DATA(nlh);
xfrm_state_flush(p->proto);
+ c.data = p->proto;
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_state_notify(NULL, &c);
+
return 0;
}
static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
+ struct km_event c;
+
xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.seq = nlh->nlmsg_seq;
+ c.pid = nlh->nlmsg_pid;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -1053,10 +1113,11 @@
return -1;
}
-static int xfrm_send_state_notify(struct xfrm_state *x, int hard)
+static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *skb;
-
+ int hard = c ->data;
+ /* fix to do alloc using NLM macros */
skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
@@ -1069,6 +1130,122 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_sa_flush(struct km_event *c)
+{
+ struct xfrm_usersa_flush *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq,
+ XFRM_MSG_FLUSHSA, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ p->proto = c->data;
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int inline xfrm_sa_len(struct xfrm_state *x)
+{
+ int l = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+ if (x->aalg)
+ l+= RTA_SPACE(sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8);
+ if (x->ealg)
+ l+= RTA_SPACE(sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8);
+ if (x->calg)
+ l+= RTA_SPACE(sizeof(*(x->calg)));
+ if (x->encap)
+ l+= RTA_SPACE(sizeof(*x->encap));
+
+ return l;
+}
+
+static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c)
+{
+ struct xfrm_usersa_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt;
+ unsigned char *b;
+ int len = xfrm_sa_len(x);
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWSA;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDSA;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELSA;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+ nlh->nlmsg_flags = 0;
+
+ p = NLMSG_DATA(nlh);
+ copy_to_user_state(x, p);
+
+ if (x->aalg)
+ RTA_PUT(skb, XFRMA_ALG_AUTH,
+ sizeof(*(x->aalg))+(x->aalg->alg_key_len+7)/8, x->aalg);
+ if (x->ealg)
+ RTA_PUT(skb, XFRMA_ALG_CRYPT,
+ sizeof(*(x->ealg))+(x->ealg->alg_key_len+7)/8, x->ealg);
+ if (x->calg)
+ RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
+
+ if (x->encap)
+ RTA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_SA, GFP_ATOMIC);
+
+nlmsg_failure:
+rtattr_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_state_notify(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_ADDED:
+ return xfrm_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_sa_flush(c);
+ default:
+ printk("netlink: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+
+}
+
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_tmpl *xt, struct xfrm_policy *xp,
int dir)
@@ -1202,7 +1379,8 @@
return -1;
}
-static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, int hard)
+
+static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
{
struct sk_buff *skb;
size_t len;
@@ -1213,7 +1391,7 @@
if (skb == NULL)
return -ENOMEM;
- if (build_polexpire(skb, xp, dir, hard) < 0)
+ if (build_polexpire(skb, xp, dir, c->data) < 0)
BUG();
NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
@@ -1221,6 +1399,93 @@
return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
}
+static int xfrm_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct xfrm_userpolicy_info *p;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ u32 nlt = 0 ;
+ unsigned char *b;
+ int len = RTA_SPACE(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr);
+ len += NLMSG_SPACE(sizeof(struct xfrm_userpolicy_info));
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+ if (c->event == XFRM_SAP_ADDED)
+ nlt = XFRM_MSG_NEWPOLICY;
+ else if (c->event == XFRM_SAP_UPDATED)
+ nlt = XFRM_MSG_UPDPOLICY;
+ else if (c->event == XFRM_SAP_DELETED)
+ nlt = XFRM_MSG_DELPOLICY;
+ else
+ goto nlmsg_failure;
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, nlt, sizeof(*p));
+
+ p = NLMSG_DATA(nlh);
+
+ nlh->nlmsg_flags = 0;
+
+ copy_to_user_policy(xp, p, dir);
+ if (copy_to_user_tmpl(xp, skb) < 0)
+ goto nlmsg_failure;
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_notify_policy_flush(struct km_event *c)
+{
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ unsigned char *b;
+ int len = NLMSG_LENGTH(0);
+
+ skb = alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return -ENOMEM;
+ b = skb->tail;
+
+
+ nlh = NLMSG_PUT(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0);
+
+ nlh->nlmsg_len = skb->tail - b;
+
+ return netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_POLICY, GFP_ATOMIC);
+
+nlmsg_failure:
+ kfree_skb(skb);
+ return -1;
+}
+
+static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+
+ switch (c->event) {
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ case XFRM_SAP_DELETED:
+ return xfrm_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return xfrm_notify_policy_flush(c);
+ case XFRM_SAP_EXPIRED:
+ return xfrm_exp_policy_notify(xp, dir, c);
+ default:
+ printk("Netlink Unknown Policy event %d\n",c->event);
+ }
+
+ return 0;
+
+}
+
static struct xfrm_mgr netlink_mgr = {
.id = "netlink",
.notify = xfrm_send_state_notify,
--- a/net/key/af_key.c 2005-03-25 22:28:39.000000000 -0500
+++ b/net/key/af_key.c 2005-04-04 18:45:48.000000000 -0400
@@ -1240,13 +1240,85 @@
return 0;
}
+static inline int event2poltype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_X_SPDDELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_X_SPDADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_X_SPDUPDATE;
+ case XFRM_SAP_EXPIRED:
+ // return SADB_X_SPDEXPIRE;
+ default:
+ printk("pfkey: Unknown policy event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+static inline int event2keytype (int event)
+{
+ switch (event) {
+ case XFRM_SAP_DELETED:
+ return SADB_DELETE;
+ case XFRM_SAP_ADDED:
+ return SADB_ADD;
+ case XFRM_SAP_UPDATED:
+ return SADB_UPDATE;
+ case XFRM_SAP_EXPIRED:
+ return SADB_EXPIRE;
+ default:
+ printk("pfkey: Unknown SA event %d\n",event);
+ break;
+ }
+
+ return 0;
+}
+
+/* ADD/UPD/DEL */
+static int key_notify_sa(struct xfrm_state *x, struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+ int hsc = 3;
+
+ if (c->event == XFRM_SAP_DELETED)
+ hsc = 0;
+
+ if (c->event == XFRM_SAP_EXPIRED) {
+ if (c->data)
+ hsc = 2;
+ else
+ hsc = 1;
+ }
+
+ skb = pfkey_xfrm_state2msg(x, 0, hsc);
+
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ hdr = (struct sadb_msg *) skb->data;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_type = event2keytype(c->event);
+ hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+ hdr->sadb_msg_errno = 0;
+ hdr->sadb_msg_reserved = 0;
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_state *x;
int err;
+ struct km_event c;
xfrm_probe_algs();
@@ -1254,6 +1326,7 @@
if (IS_ERR(x))
return PTR_ERR(x);
+ xfrm_state_hold(x);
if (hdr->sadb_msg_type == SADB_ADD)
err = xfrm_state_add(x);
else
@@ -1265,27 +1338,23 @@
return err;
}
- out_skb = pfkey_xfrm_state2msg(x, 0, 3);
- if (IS_ERR(out_skb))
- return PTR_ERR(out_skb); /* XXX Should we return 0 here ? */
-
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_reserved = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
-
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ if (hdr->sadb_msg_type == SADB_ADD)
+ c.event = XFRM_SAP_ADDED;
+ else
+ c.event = XFRM_SAP_UPDATED;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
- return 0;
+ return err;
}
static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
struct xfrm_state *x;
+ struct km_event c;
+ int err;
if (!ext_hdrs[SADB_EXT_SA-1] ||
!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
@@ -1301,13 +1370,19 @@
return -EPERM;
}
- xfrm_state_delete(x);
- xfrm_state_put(x);
+ err = xfrm_state_delete(x);
+ if (err < 0) {
+ xfrm_state_put(x);
+ return err;
+ }
- pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
- BROADCAST_ALL, sk);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_state_notify(x, &c);
+ xfrm_state_put(x);
- return 0;
+ return err;
}
static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -1445,28 +1520,42 @@
return 0;
}
+static int key_notify_sa_flush(struct km_event *c)
+{
+ struct sk_buff *skb;
+ struct sadb_msg *hdr;
+
+ skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
+ if (!skb)
+ return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+ hdr->sadb_msg_satype = pfkey_proto2satype(c->data);
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+
+ pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+
+ return 0;
+}
+
static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
unsigned proto;
- struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
+ struct km_event c;
proto = pfkey_satype2proto(hdr->sadb_msg_satype);
if (proto == 0)
return -EINVAL;
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
- if (!skb_out)
- return -ENOBUFS;
-
xfrm_state_flush(proto);
-
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
-
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+ c.data = proto;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_FLUSHED;
+ km_state_notify(NULL, &c);
return 0;
}
@@ -1859,6 +1948,35 @@
hdr->sadb_msg_reserved = atomic_read(&xp->refcnt);
}
+static int key_notify_policy( struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ struct sk_buff *out_skb;
+ struct sadb_msg *out_hdr;
+ int err;
+
+ out_skb = pfkey_xfrm_policy2msg_prep(xp);
+ if (IS_ERR(out_skb)) {
+ err = PTR_ERR(out_skb);
+ goto out;
+ }
+ pfkey_xfrm_policy2msg(out_skb, xp, dir);
+
+ out_hdr = (struct sadb_msg *) out_skb->data;
+ out_hdr->sadb_msg_version = PF_KEY_V2;
+
+ if (c->data && c->event == XFRM_SAP_DELETED)
+ out_hdr->sadb_msg_type = SADB_X_SPDDELETE2;
+ else
+ out_hdr->sadb_msg_type = event2poltype(c->event);
+ out_hdr->sadb_msg_errno = 0;
+ out_hdr->sadb_msg_seq = c->seq;
+ out_hdr->sadb_msg_pid = c->pid;
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL);
+out:
+ return 0;
+
+}
+
static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
int err;
@@ -1866,8 +1984,7 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -1935,31 +2052,25 @@
(err = parse_ipsecrequests(xp, pol)) < 0)
goto out;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
- }
err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp,
hdr->sadb_msg_type != SADB_X_SPDUPDATE);
+
if (err) {
- kfree_skb(out_skb);
- goto out;
+ kfree(xp);
+ return err;
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
+ if (hdr->sadb_msg_type == SADB_X_SPDUPDATE)
+ c.event = XFRM_SAP_UPDATED;
+ else
+ c.event = XFRM_SAP_ADDED;
- xfrm_pol_put(xp);
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+ xfrm_pol_put(xp);
return 0;
out:
@@ -1973,9 +2084,8 @@
struct sadb_address *sa;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
struct xfrm_selector sel;
+ struct km_event c;
if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
@@ -2010,25 +2120,41 @@
err = 0;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+
+ xfrm_pol_put(xp);
+ return err;
+}
+
+
+static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, struct sadb_msg *hdr, int dir)
+{
+ int err;
+ struct sk_buff *out_skb;
+ struct sadb_msg *out_hdr;
+ err = 0;
+
out_skb = pfkey_xfrm_policy2msg_prep(xp);
if (IS_ERR(out_skb)) {
err = PTR_ERR(out_skb);
goto out;
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
+ pfkey_xfrm_policy2msg(out_skb, xp, dir);
out_hdr = (struct sadb_msg *) out_skb->data;
out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = SADB_X_SPDDELETE;
+ out_hdr->sadb_msg_type = hdr->sadb_msg_type;
out_hdr->sadb_msg_satype = 0;
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+ pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk);
err = 0;
out:
- xfrm_pol_put(xp);
return err;
}
@@ -2037,8 +2163,7 @@
int err;
struct sadb_x_policy *pol;
struct xfrm_policy *xp;
- struct sk_buff *out_skb;
- struct sadb_msg *out_hdr;
+ struct km_event c;
if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL)
return -EINVAL;
@@ -2050,24 +2175,16 @@
err = 0;
- out_skb = pfkey_xfrm_policy2msg_prep(xp);
- if (IS_ERR(out_skb)) {
- err = PTR_ERR(out_skb);
- goto out;
+ c.seq = hdr->sadb_msg_seq;
+ c.pid = hdr->sadb_msg_pid;
+ if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) {
+ c.data = 1; // to signal pfkey of SADB_X_SPDDELETE2
+ c.event = XFRM_SAP_DELETED;
+ km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c);
+ } else {
+ err = key_pol_get_resp(sk, xp, hdr, pol->sadb_x_policy_dir-1);
}
- pfkey_xfrm_policy2msg(out_skb, xp, pol->sadb_x_policy_dir-1);
- out_hdr = (struct sadb_msg *) out_skb->data;
- out_hdr->sadb_msg_version = hdr->sadb_msg_version;
- out_hdr->sadb_msg_type = hdr->sadb_msg_type;
- out_hdr->sadb_msg_satype = 0;
- out_hdr->sadb_msg_errno = 0;
- out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
- out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
- pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
- err = 0;
-
-out:
xfrm_pol_put(xp);
return err;
}
@@ -2102,22 +2219,33 @@
return xfrm_policy_walk(dump_sp, &data);
}
-static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+static int key_notify_policy_flush(struct km_event *c)
{
struct sk_buff *skb_out;
- struct sadb_msg *hdr_out;
-
- skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
+ struct sadb_msg *hdr;
+ skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC);
if (!skb_out)
return -ENOBUFS;
+ hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
+ hdr->sadb_msg_seq = c->seq;
+ hdr->sadb_msg_pid = c->pid;
+ hdr->sadb_msg_version = PF_KEY_V2;
+ hdr->sadb_msg_errno = (uint8_t) 0;
+ hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+ pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL);
+ return 0;
- xfrm_policy_flush();
+}
- hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
- pfkey_hdr_dup(hdr_out, hdr);
- hdr_out->sadb_msg_errno = (uint8_t) 0;
- hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
- pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+ struct km_event c;
+
+ xfrm_policy_flush();
+ c.event = XFRM_SAP_FLUSHED;
+ c.pid = hdr->sadb_msg_pid;
+ c.seq = hdr->sadb_msg_seq;
+ km_policy_notify(NULL, 0, &c);
return 0;
}
@@ -2317,11 +2445,24 @@
}
}
-static int pfkey_send_notify(struct xfrm_state *x, int hard)
+/* XXX: Noisy for now */
+static int key_notify_policy_expire(struct xfrm_policy *xp, struct km_event *c)
+{
+ return 0;
+}
+
+static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c)
{
struct sk_buff *out_skb;
struct sadb_msg *out_hdr;
- int hsc = (hard ? 2 : 1);
+ int hard;
+ int hsc;
+
+ hard = c->data;
+ if (hard)
+ hsc = 2;
+ else
+ hsc = 1;
out_skb = pfkey_xfrm_state2msg(x, 0, hsc);
if (IS_ERR(out_skb))
@@ -2340,6 +2481,43 @@
return 0;
}
+static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_sa_expire(x, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_sa(x, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_sa_flush(c);
+ default:
+ printk("pfkey: Unknown SA event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
+
+static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c)
+{
+ switch (c->event) {
+ case XFRM_SAP_EXPIRED:
+ return key_notify_policy_expire(xp, c);
+ case XFRM_SAP_DELETED:
+ case XFRM_SAP_ADDED:
+ case XFRM_SAP_UPDATED:
+ return key_notify_policy(xp, dir, c);
+ case XFRM_SAP_FLUSHED:
+ return key_notify_policy_flush(c);
+ default:
+ printk("pfkey: Unknown policy event %d\n",c->event);
+ break;
+ }
+
+ return 0;
+}
static u32 get_acqseq(void)
{
u32 res;
@@ -2856,6 +3034,7 @@
.acquire = pfkey_send_acquire,
.compile_policy = pfkey_compile_policy,
.new_mapping = pfkey_send_new_mapping,
+ .notify_policy = pfkey_send_policy_notify,
};
static void __exit ipsec_pfkey_exit(void)
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-05 10:18 ` jamal
@ 2005-04-05 10:22 ` Herbert Xu
2005-04-05 10:35 ` jamal
2005-04-05 11:58 ` jamal
0 siblings, 2 replies; 48+ messages in thread
From: Herbert Xu @ 2005-04-05 10:22 UTC (permalink / raw)
To: jamal; +Cc: Masahide NAKAMURA, David S. Miller, kaber, netdev
On Tue, Apr 05, 2005 at 06:18:22AM -0400, jamal wrote:
>
> Ok, heres the patch i will shoot to Dave if no further comments.
Thanks for your great work Jamal.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-05 10:22 ` Herbert Xu
@ 2005-04-05 10:35 ` jamal
2005-04-05 11:58 ` jamal
1 sibling, 0 replies; 48+ messages in thread
From: jamal @ 2005-04-05 10:35 UTC (permalink / raw)
To: Herbert Xu; +Cc: Masahide NAKAMURA, David S. Miller, kaber, netdev
On Tue, 2005-04-05 at 06:22, Herbert Xu wrote:
>
> Thanks for your great work Jamal.
>
Well, thanks to you for the shepherding and to Masahide-san for the
testing and bugs found.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-05 10:22 ` Herbert Xu
2005-04-05 10:35 ` jamal
@ 2005-04-05 11:58 ` jamal
2005-04-05 17:46 ` David S. Miller
1 sibling, 1 reply; 48+ messages in thread
From: jamal @ 2005-04-05 11:58 UTC (permalink / raw)
To: Herbert Xu; +Cc: Masahide NAKAMURA, David S. Miller, kaber, netdev
On Tue, 2005-04-05 at 06:22, Herbert Xu wrote:
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
I have a feeling that Dave is not following this thread. All along we
have been testing against 2.6.11.6; I just tested against -rc2 and
found the patch applies with some fuzz. I fixed that as well as a couple
of error messages Masahide didnt like.
So please signoff instead the next patch i post in a new thread.
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-05 11:58 ` jamal
@ 2005-04-05 17:46 ` David S. Miller
2005-04-05 18:05 ` jamal
0 siblings, 1 reply; 48+ messages in thread
From: David S. Miller @ 2005-04-05 17:46 UTC (permalink / raw)
To: hadi; +Cc: herbert, nakam, kaber, netdev
On 05 Apr 2005 07:58:23 -0400
jamal <hadi@cyberus.ca> wrote:
> On Tue, 2005-04-05 at 06:22, Herbert Xu wrote:
>
> > Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
>
> I have a feeling that Dave is not following this thread.
Believe it or not I have been :-)
^ permalink raw reply [flat|nested] 48+ messages in thread
* Re: take 2-2 WAS(Re: PATCH: IPSEC xfrm events
2005-04-05 17:46 ` David S. Miller
@ 2005-04-05 18:05 ` jamal
0 siblings, 0 replies; 48+ messages in thread
From: jamal @ 2005-04-05 18:05 UTC (permalink / raw)
To: David S. Miller; +Cc: herbert, nakam, kaber, netdev
On Tue, 2005-04-05 at 13:46, David S. Miller wrote:
> On 05 Apr 2005 07:58:23 -0400
> jamal <hadi@cyberus.ca> wrote:
>
> > On Tue, 2005-04-05 at 06:22, Herbert Xu wrote:
> >
> > > Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
> >
> > I have a feeling that Dave is not following this thread.
>
> Believe it or not I have been :-)
Impressive ;->
After the 10th email it seemed to me only Herbert and myself would still
be reading this ;-> Did you see the bit about Elvis? ;->
cheers,
jamal
^ permalink raw reply [flat|nested] 48+ messages in thread
end of thread, other threads:[~2005-04-05 18:05 UTC | newest]
Thread overview: 48+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-04-01 1:37 PATCH: IPSEC xfrm events jamal
2005-04-01 4:21 ` Herbert Xu
2005-04-01 11:03 ` jamal
2005-04-01 11:42 ` Herbert Xu
2005-04-01 12:24 ` jamal
2005-04-01 12:35 ` Herbert Xu
2005-04-01 12:59 ` jamal
2005-04-01 13:18 ` jamal
2005-04-01 14:19 ` Masahide NAKAMURA
2005-04-02 1:04 ` jamal
2005-04-02 1:28 ` Herbert Xu
2005-04-02 1:42 ` jamal
2005-04-02 1:45 ` Herbert Xu
2005-04-02 1:46 ` Herbert Xu
2005-04-02 19:20 ` take 2 WAS(Re: " jamal
2005-04-03 14:31 ` jamal
2005-04-03 15:47 ` Patrick McHardy
2005-04-03 16:29 ` jamal
2005-04-03 16:36 ` jamal
2005-04-04 0:58 ` Herbert Xu
2005-04-04 1:56 ` jamal
2005-04-04 2:26 ` Herbert Xu
2005-04-04 2:39 ` jamal
2005-04-04 2:46 ` Herbert Xu
2005-04-04 3:05 ` jamal
2005-04-04 2:34 ` jamal
2005-04-04 2:52 ` Herbert Xu
2005-04-04 3:07 ` jamal
2005-04-04 11:38 ` take 2-2 " jamal
2005-04-04 12:16 ` Herbert Xu
2005-04-04 12:51 ` jamal
2005-04-04 13:02 ` Herbert Xu
2005-04-04 13:16 ` jamal
2005-04-04 21:31 ` Herbert Xu
2005-04-04 22:20 ` jamal
2005-04-04 22:25 ` David S. Miller
2005-04-04 22:42 ` jamal
2005-04-05 7:35 ` Masahide NAKAMURA
2005-04-05 10:18 ` jamal
2005-04-05 10:22 ` Herbert Xu
2005-04-05 10:35 ` jamal
2005-04-05 11:58 ` jamal
2005-04-05 17:46 ` David S. Miller
2005-04-05 18:05 ` jamal
2005-04-04 1:01 ` take 2 " Herbert Xu
2005-04-04 1:58 ` jamal
2005-04-04 2:27 ` Herbert Xu
2005-04-01 17:28 ` Masahide NAKAMURA
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).