From 26b15dad9f1c19d6d4f7b999b07eaa6d98e4b375 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Sat, 18 Jun 2005 22:42:13 -0700 Subject: [IPSEC] Add complete xfrm event notification Heres the final patch. What this patch provides - netlink xfrm events - ability to have events generated by netlink propagated to pfkey and vice versa. - fixes the acquire lets-be-happy-with-one-success issue Signed-off-by: Jamal Hadi Salim Signed-off-by: Herbert Xu --- net/key/af_key.c | 357 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 267 insertions(+), 90 deletions(-) (limited to 'net/key') diff --git a/net/key/af_key.c b/net/key/af_key.c index ce980aa94e..d086c117f5 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1240,13 +1240,85 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg * 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 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, 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 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, 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 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h 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 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, struct sadb_msg 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 @@ static void pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, i 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 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h 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,23 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h (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 +2082,8 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg 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 +2118,40 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg 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 +2160,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h 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 +2172,16 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h 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 +2216,34 @@ static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg * 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; + struct sadb_msg *hdr; - skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL); + 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(); +} + +static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) +{ + struct km_event c; - 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); + 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 +2443,23 @@ static void dump_esp_combs(struct sk_buff *skb, struct xfrm_tmpl *t) } } -static int pfkey_send_notify(struct xfrm_state *x, int hard) +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 +2478,44 @@ static int pfkey_send_notify(struct xfrm_state *x, int hard) 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 +3032,7 @@ static struct xfrm_mgr pfkeyv2_mgr = .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) -- cgit v1.2.2 From 4f09f0bbc1cb3c74e8f2047ad4be201a059829ee Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 18 Jun 2005 22:43:43 -0700 Subject: [IPSEC] Fix xfrm to pfkey SA state conversion This patch adjusts the SA state conversion in af_key such that XFRM_STATE_ERROR/XFRM_STATE_DEAD will be converted to SADB_STATE_DEAD instead of SADB_STATE_DYING. According to RFC 2367, SADB_STATE_DYING SAs can be turned into mature ones through updating their lifetime settings. Since SAs which are in the states XFRM_STATE_ERROR/XFRM_STATE_DEAD cannot be resurrected, this value is unsuitable. Signed-off-by: Herbert Xu --- net/key/af_key.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'net/key') diff --git a/net/key/af_key.c b/net/key/af_key.c index d086c117f5..560c93c108 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -656,13 +656,18 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, sa->sadb_sa_exttype = SADB_EXT_SA; sa->sadb_sa_spi = x->id.spi; sa->sadb_sa_replay = x->props.replay_window; - sa->sadb_sa_state = SADB_SASTATE_DYING; - if (x->km.state == XFRM_STATE_VALID && !x->km.dying) - sa->sadb_sa_state = SADB_SASTATE_MATURE; - else if (x->km.state == XFRM_STATE_ACQ) + switch (x->km.state) { + case XFRM_STATE_VALID: + sa->sadb_sa_state = x->km.dying ? + SADB_SASTATE_DYING : SADB_SASTATE_MATURE; + break; + case XFRM_STATE_ACQ: sa->sadb_sa_state = SADB_SASTATE_LARVAL; - else if (x->km.state == XFRM_STATE_EXPIRED) + break; + default: sa->sadb_sa_state = SADB_SASTATE_DEAD; + break; + } sa->sadb_sa_auth = 0; if (x->aalg) { struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name, 0); -- cgit v1.2.2 From bf08867f91a43aa3ba2e4598c06c4769a6cdddf6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 18 Jun 2005 22:44:00 -0700 Subject: [IPSEC] Turn km_event.data into a union This patch turns km_event.data into a union. This makes code that uses it clearer. Signed-off-by: Herbert Xu --- net/key/af_key.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'net/key') diff --git a/net/key/af_key.c b/net/key/af_key.c index 560c93c108..3fae5c4b48 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1293,13 +1293,6 @@ static int key_notify_sa(struct xfrm_state *x, struct km_event *c) 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)) @@ -1534,7 +1527,7 @@ static int key_notify_sa_flush(struct km_event *c) 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_satype = pfkey_proto2satype(c->data.proto); hdr->sadb_msg_seq = c->seq; hdr->sadb_msg_pid = c->pid; hdr->sadb_msg_version = PF_KEY_V2; @@ -1556,7 +1549,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd return -EINVAL; xfrm_state_flush(proto); - c.data = proto; + c.data.proto = proto; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; c.event = XFRM_SAP_FLUSHED; @@ -1969,7 +1962,7 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c out_hdr = (struct sadb_msg *) out_skb->data; out_hdr->sadb_msg_version = PF_KEY_V2; - if (c->data && c->event == XFRM_SAP_DELETED) + if (c->data.byid && c->event == XFRM_SAP_DELETED) out_hdr->sadb_msg_type = SADB_X_SPDDELETE2; else out_hdr->sadb_msg_type = event2poltype(c->event); @@ -2180,7 +2173,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h 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.data.byid = 1; c.event = XFRM_SAP_DELETED; km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); } else { @@ -2460,7 +2453,7 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) int hard; int hsc; - hard = c->data; + hard = c->data.hard; if (hard) hsc = 2; else -- cgit v1.2.2 From f60f6b8f70c756fc786d68f02ec17a1e84db645f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 18 Jun 2005 22:44:37 -0700 Subject: [IPSEC] Use XFRM_MSG_* instead of XFRM_SAP_* This patch removes XFRM_SAP_* and converts them over to XFRM_MSG_*. The netlink interface is meant to map directly onto the underlying xfrm subsystem. Therefore rather than using a new independent representation for the events we can simply use the existing ones from xfrm_user. Signed-off-by: Herbert Xu --- net/key/af_key.c | 60 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'net/key') diff --git a/net/key/af_key.c b/net/key/af_key.c index 3fae5c4b48..577f0bb5bb 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1248,13 +1248,13 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg * static inline int event2poltype(int event) { switch (event) { - case XFRM_SAP_DELETED: + case XFRM_MSG_DELPOLICY: return SADB_X_SPDDELETE; - case XFRM_SAP_ADDED: + case XFRM_MSG_NEWPOLICY: return SADB_X_SPDADD; - case XFRM_SAP_UPDATED: + case XFRM_MSG_UPDPOLICY: return SADB_X_SPDUPDATE; - case XFRM_SAP_EXPIRED: + case XFRM_MSG_POLEXPIRE: // return SADB_X_SPDEXPIRE; default: printk("pfkey: Unknown policy event %d\n", event); @@ -1267,13 +1267,13 @@ static inline int event2poltype(int event) static inline int event2keytype(int event) { switch (event) { - case XFRM_SAP_DELETED: + case XFRM_MSG_DELSA: return SADB_DELETE; - case XFRM_SAP_ADDED: + case XFRM_MSG_NEWSA: return SADB_ADD; - case XFRM_SAP_UPDATED: + case XFRM_MSG_UPDSA: return SADB_UPDATE; - case XFRM_SAP_EXPIRED: + case XFRM_MSG_EXPIRE: return SADB_EXPIRE; default: printk("pfkey: Unknown SA event %d\n", event); @@ -1290,7 +1290,7 @@ static int key_notify_sa(struct xfrm_state *x, struct km_event *c) struct sadb_msg *hdr; int hsc = 3; - if (c->event == XFRM_SAP_DELETED) + if (c->event == XFRM_MSG_DELSA) hsc = 0; skb = pfkey_xfrm_state2msg(x, 0, hsc); @@ -1337,9 +1337,9 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, } if (hdr->sadb_msg_type == SADB_ADD) - c.event = XFRM_SAP_ADDED; + c.event = XFRM_MSG_NEWSA; else - c.event = XFRM_SAP_UPDATED; + c.event = XFRM_MSG_UPDSA; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; km_state_notify(x, &c); @@ -1376,7 +1376,7 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; - c.event = XFRM_SAP_DELETED; + c.event = XFRM_MSG_DELSA; km_state_notify(x, &c); xfrm_state_put(x); @@ -1552,7 +1552,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd c.data.proto = proto; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; - c.event = XFRM_SAP_FLUSHED; + c.event = XFRM_MSG_FLUSHSA; km_state_notify(NULL, &c); return 0; @@ -1962,7 +1962,7 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c out_hdr = (struct sadb_msg *) out_skb->data; out_hdr->sadb_msg_version = PF_KEY_V2; - if (c->data.byid && c->event == XFRM_SAP_DELETED) + if (c->data.byid && c->event == XFRM_MSG_DELPOLICY) out_hdr->sadb_msg_type = SADB_X_SPDDELETE2; else out_hdr->sadb_msg_type = event2poltype(c->event); @@ -2058,9 +2058,9 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h } if (hdr->sadb_msg_type == SADB_X_SPDUPDATE) - c.event = XFRM_SAP_UPDATED; - else - c.event = XFRM_SAP_ADDED; + c.event = XFRM_MSG_UPDPOLICY; + else + c.event = XFRM_MSG_NEWPOLICY; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; @@ -2118,7 +2118,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; - c.event = XFRM_SAP_DELETED; + c.event = XFRM_MSG_DELPOLICY; km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); xfrm_pol_put(xp); @@ -2174,7 +2174,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h c.pid = hdr->sadb_msg_pid; if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) { c.data.byid = 1; - c.event = XFRM_SAP_DELETED; + c.event = XFRM_MSG_DELPOLICY; 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); @@ -2238,7 +2238,7 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg struct km_event c; xfrm_policy_flush(); - c.event = XFRM_SAP_FLUSHED; + c.event = XFRM_MSG_FLUSHPOLICY; c.pid = hdr->sadb_msg_pid; c.seq = hdr->sadb_msg_seq; km_policy_notify(NULL, 0, &c); @@ -2479,13 +2479,13 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) { switch (c->event) { - case XFRM_SAP_EXPIRED: + case XFRM_MSG_EXPIRE: return key_notify_sa_expire(x, c); - case XFRM_SAP_DELETED: - case XFRM_SAP_ADDED: - case XFRM_SAP_UPDATED: + case XFRM_MSG_DELSA: + case XFRM_MSG_NEWSA: + case XFRM_MSG_UPDSA: return key_notify_sa(x, c); - case XFRM_SAP_FLUSHED: + case XFRM_MSG_FLUSHSA: return key_notify_sa_flush(c); default: printk("pfkey: Unknown SA event %d\n", c->event); @@ -2498,13 +2498,13 @@ static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) { switch (c->event) { - case XFRM_SAP_EXPIRED: + case XFRM_MSG_POLEXPIRE: return key_notify_policy_expire(xp, c); - case XFRM_SAP_DELETED: - case XFRM_SAP_ADDED: - case XFRM_SAP_UPDATED: + case XFRM_MSG_DELPOLICY: + case XFRM_MSG_NEWPOLICY: + case XFRM_MSG_UPDPOLICY: return key_notify_policy(xp, dir, c); - case XFRM_SAP_FLUSHED: + case XFRM_MSG_FLUSHPOLICY: return key_notify_policy_flush(c); default: printk("pfkey: Unknown policy event %d\n", c->event); -- cgit v1.2.2 From 7d6dfe1f5bc4c56e0c31173014a099ec3fa35907 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Sat, 18 Jun 2005 22:45:31 -0700 Subject: [IPSEC] Fix xfrm_state leaks in error path Herbert Xu wrote: > @@ -1254,6 +1326,7 @@ static int pfkey_add(struct sock *sk, st > if (IS_ERR(x)) > return PTR_ERR(x); > > + xfrm_state_hold(x); This introduces a leak when xfrm_state_add()/xfrm_state_update() fail. We hold two references (one from xfrm_state_alloc(), one from xfrm_state_hold()), but only drop one. We need to take the reference because the reference from xfrm_state_alloc() can be dropped by __xfrm_state_delete(), so the fix is to drop both references on error. Same problem in xfrm_user.c. Signed-off-by: Patrick McHardy Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/key/af_key.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/key') diff --git a/net/key/af_key.c b/net/key/af_key.c index 577f0bb5bb..98b72f2024 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1333,7 +1333,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, if (err < 0) { x->km.state = XFRM_STATE_DEAD; xfrm_state_put(x); - return err; + goto out; } if (hdr->sadb_msg_type == SADB_ADD) @@ -1343,8 +1343,8 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; km_state_notify(x, &c); +out: xfrm_state_put(x); - return err; } -- cgit v1.2.2 From 72cb6962a91f2af9eef69a06198e1949c10259ae Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 20 Jun 2005 13:18:08 -0700 Subject: [IPSEC]: Add xfrm_init_state This patch adds xfrm_init_state which is simply a wrapper that calls xfrm_get_type and subsequently x->type->init_state. It also gets rid of the unused args argument. Abstracting it out allows us to add common initialisation code, e.g., to set family-specific flags. The add_time setting in xfrm_user.c was deleted because it's already set by xfrm_state_alloc. Signed-off-by: Herbert Xu Acked-by: James Morris Signed-off-by: David S. Miller --- net/key/af_key.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'net/key') diff --git a/net/key/af_key.c b/net/key/af_key.c index 98b72f2024..652dd09ccd 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1096,17 +1096,11 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, } } - x->type = xfrm_get_type(proto, x->props.family); - if (x->type == NULL) { - err = -ENOPROTOOPT; - goto out; - } - if (x->type->init_state(x, NULL)) { - err = -EINVAL; + err = xfrm_init_state(x); + if (err) goto out; - } + x->km.seq = hdr->sadb_msg_seq; - x->km.state = XFRM_STATE_VALID; return x; out: -- cgit v1.2.2 From dd87147eed934eaff92869f3d158697c7239d1d2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 20 Jun 2005 13:21:43 -0700 Subject: [IPSEC]: Add XFRM_STATE_NOPMTUDISC flag This patch adds the flag XFRM_STATE_NOPMTUDISC for xfrm states. It is similar to the nopmtudisc on IPIP/GRE tunnels. It only has an effect on IPv4 tunnel mode states. For these states, it will ensure that the DF flag is always cleared. This is primarily useful to work around ICMP blackholes. In future this flag could also allow a larger MTU to be set within the tunnel just like IPIP/GRE tunnels. This could be useful for short haul tunnels where temporary fragmentation outside the tunnel is desired over smaller fragments inside the tunnel. Signed-off-by: Herbert Xu Acked-by: James Morris Signed-off-by: David S. Miller --- net/key/af_key.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/key') diff --git a/net/key/af_key.c b/net/key/af_key.c index 652dd09ccd..4879743b94 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -690,6 +690,8 @@ static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN; if (x->props.flags & XFRM_STATE_DECAP_DSCP) sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP; + if (x->props.flags & XFRM_STATE_NOPMTUDISC) + sa->sadb_sa_flags |= SADB_SAFLAGS_NOPMTUDISC; /* hard time */ if (hsc & 2) { @@ -974,6 +976,8 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, x->props.flags |= XFRM_STATE_NOECN; if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP) x->props.flags |= XFRM_STATE_DECAP_DSCP; + if (sa->sadb_sa_flags & SADB_SAFLAGS_NOPMTUDISC) + x->props.flags |= XFRM_STATE_NOPMTUDISC; lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1]; if (lifetime != NULL) { -- cgit v1.2.2