diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /net/xfrm | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_algo.c | 129 | ||||
-rw-r--r-- | net/xfrm/xfrm_input.c | 2 | ||||
-rw-r--r-- | net/xfrm/xfrm_ipcomp.c | 18 | ||||
-rw-r--r-- | net/xfrm/xfrm_output.c | 1 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 127 | ||||
-rw-r--r-- | net/xfrm/xfrm_proc.c | 6 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 139 | ||||
-rw-r--r-- | net/xfrm/xfrm_sysctl.c | 9 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 272 |
9 files changed, 482 insertions, 221 deletions
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c index faf54c6bf96b..8b4d6e3246e5 100644 --- a/net/xfrm/xfrm_algo.c +++ b/net/xfrm/xfrm_algo.c | |||
@@ -125,6 +125,22 @@ static struct xfrm_algo_desc aead_list[] = { | |||
125 | .sadb_alg_maxbits = 256 | 125 | .sadb_alg_maxbits = 256 |
126 | } | 126 | } |
127 | }, | 127 | }, |
128 | { | ||
129 | .name = "rfc4543(gcm(aes))", | ||
130 | |||
131 | .uinfo = { | ||
132 | .aead = { | ||
133 | .icv_truncbits = 128, | ||
134 | } | ||
135 | }, | ||
136 | |||
137 | .desc = { | ||
138 | .sadb_alg_id = SADB_X_EALG_NULL_AES_GMAC, | ||
139 | .sadb_alg_ivlen = 8, | ||
140 | .sadb_alg_minbits = 128, | ||
141 | .sadb_alg_maxbits = 256 | ||
142 | } | ||
143 | }, | ||
128 | }; | 144 | }; |
129 | 145 | ||
130 | static struct xfrm_algo_desc aalg_list[] = { | 146 | static struct xfrm_algo_desc aalg_list[] = { |
@@ -200,6 +216,40 @@ static struct xfrm_algo_desc aalg_list[] = { | |||
200 | } | 216 | } |
201 | }, | 217 | }, |
202 | { | 218 | { |
219 | .name = "hmac(sha384)", | ||
220 | |||
221 | .uinfo = { | ||
222 | .auth = { | ||
223 | .icv_truncbits = 192, | ||
224 | .icv_fullbits = 384, | ||
225 | } | ||
226 | }, | ||
227 | |||
228 | .desc = { | ||
229 | .sadb_alg_id = SADB_X_AALG_SHA2_384HMAC, | ||
230 | .sadb_alg_ivlen = 0, | ||
231 | .sadb_alg_minbits = 384, | ||
232 | .sadb_alg_maxbits = 384 | ||
233 | } | ||
234 | }, | ||
235 | { | ||
236 | .name = "hmac(sha512)", | ||
237 | |||
238 | .uinfo = { | ||
239 | .auth = { | ||
240 | .icv_truncbits = 256, | ||
241 | .icv_fullbits = 512, | ||
242 | } | ||
243 | }, | ||
244 | |||
245 | .desc = { | ||
246 | .sadb_alg_id = SADB_X_AALG_SHA2_512HMAC, | ||
247 | .sadb_alg_ivlen = 0, | ||
248 | .sadb_alg_minbits = 512, | ||
249 | .sadb_alg_maxbits = 512 | ||
250 | } | ||
251 | }, | ||
252 | { | ||
203 | .name = "hmac(rmd160)", | 253 | .name = "hmac(rmd160)", |
204 | .compat = "rmd160", | 254 | .compat = "rmd160", |
205 | 255 | ||
@@ -365,6 +415,7 @@ static struct xfrm_algo_desc ealg_list[] = { | |||
365 | }, | 415 | }, |
366 | { | 416 | { |
367 | .name = "cbc(camellia)", | 417 | .name = "cbc(camellia)", |
418 | .compat = "camellia", | ||
368 | 419 | ||
369 | .uinfo = { | 420 | .uinfo = { |
370 | .encr = { | 421 | .encr = { |
@@ -689,84 +740,6 @@ int xfrm_count_enc_supported(void) | |||
689 | } | 740 | } |
690 | EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); | 741 | EXPORT_SYMBOL_GPL(xfrm_count_enc_supported); |
691 | 742 | ||
692 | /* Move to common area: it is shared with AH. */ | ||
693 | |||
694 | int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc, | ||
695 | int offset, int len, icv_update_fn_t icv_update) | ||
696 | { | ||
697 | int start = skb_headlen(skb); | ||
698 | int i, copy = start - offset; | ||
699 | struct sk_buff *frag_iter; | ||
700 | struct scatterlist sg; | ||
701 | int err; | ||
702 | |||
703 | /* Checksum header. */ | ||
704 | if (copy > 0) { | ||
705 | if (copy > len) | ||
706 | copy = len; | ||
707 | |||
708 | sg_init_one(&sg, skb->data + offset, copy); | ||
709 | |||
710 | err = icv_update(desc, &sg, copy); | ||
711 | if (unlikely(err)) | ||
712 | return err; | ||
713 | |||
714 | if ((len -= copy) == 0) | ||
715 | return 0; | ||
716 | offset += copy; | ||
717 | } | ||
718 | |||
719 | for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | ||
720 | int end; | ||
721 | |||
722 | WARN_ON(start > offset + len); | ||
723 | |||
724 | end = start + skb_shinfo(skb)->frags[i].size; | ||
725 | if ((copy = end - offset) > 0) { | ||
726 | skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | ||
727 | |||
728 | if (copy > len) | ||
729 | copy = len; | ||
730 | |||
731 | sg_init_table(&sg, 1); | ||
732 | sg_set_page(&sg, frag->page, copy, | ||
733 | frag->page_offset + offset-start); | ||
734 | |||
735 | err = icv_update(desc, &sg, copy); | ||
736 | if (unlikely(err)) | ||
737 | return err; | ||
738 | |||
739 | if (!(len -= copy)) | ||
740 | return 0; | ||
741 | offset += copy; | ||
742 | } | ||
743 | start = end; | ||
744 | } | ||
745 | |||
746 | skb_walk_frags(skb, frag_iter) { | ||
747 | int end; | ||
748 | |||
749 | WARN_ON(start > offset + len); | ||
750 | |||
751 | end = start + frag_iter->len; | ||
752 | if ((copy = end - offset) > 0) { | ||
753 | if (copy > len) | ||
754 | copy = len; | ||
755 | err = skb_icv_walk(frag_iter, desc, offset-start, | ||
756 | copy, icv_update); | ||
757 | if (unlikely(err)) | ||
758 | return err; | ||
759 | if ((len -= copy) == 0) | ||
760 | return 0; | ||
761 | offset += copy; | ||
762 | } | ||
763 | start = end; | ||
764 | } | ||
765 | BUG_ON(len); | ||
766 | return 0; | ||
767 | } | ||
768 | EXPORT_SYMBOL_GPL(skb_icv_walk); | ||
769 | |||
770 | #if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) | 743 | #if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE) |
771 | 744 | ||
772 | void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len) | 745 | void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len) |
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index e0009c17d809..45f1c98d4fce 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -152,7 +152,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
152 | goto drop; | 152 | goto drop; |
153 | } | 153 | } |
154 | 154 | ||
155 | x = xfrm_state_lookup(net, daddr, spi, nexthdr, family); | 155 | x = xfrm_state_lookup(net, skb->mark, daddr, spi, nexthdr, family); |
156 | if (x == NULL) { | 156 | if (x == NULL) { |
157 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); | 157 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); |
158 | xfrm_audit_state_notfound(skb, family, spi, seq); | 158 | xfrm_audit_state_notfound(skb, family, spi, seq); |
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c index 42cd18391f46..fc91ad7ee26e 100644 --- a/net/xfrm/xfrm_ipcomp.c +++ b/net/xfrm/xfrm_ipcomp.c | |||
@@ -17,11 +17,11 @@ | |||
17 | 17 | ||
18 | #include <linux/crypto.h> | 18 | #include <linux/crypto.h> |
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/gfp.h> | ||
21 | #include <linux/list.h> | 20 | #include <linux/list.h> |
22 | #include <linux/module.h> | 21 | #include <linux/module.h> |
23 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
24 | #include <linux/percpu.h> | 23 | #include <linux/percpu.h> |
24 | #include <linux/slab.h> | ||
25 | #include <linux/smp.h> | 25 | #include <linux/smp.h> |
26 | #include <linux/vmalloc.h> | 26 | #include <linux/vmalloc.h> |
27 | #include <net/ip.h> | 27 | #include <net/ip.h> |
@@ -30,12 +30,12 @@ | |||
30 | 30 | ||
31 | struct ipcomp_tfms { | 31 | struct ipcomp_tfms { |
32 | struct list_head list; | 32 | struct list_head list; |
33 | struct crypto_comp **tfms; | 33 | struct crypto_comp * __percpu *tfms; |
34 | int users; | 34 | int users; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | static DEFINE_MUTEX(ipcomp_resource_mutex); | 37 | static DEFINE_MUTEX(ipcomp_resource_mutex); |
38 | static void **ipcomp_scratches; | 38 | static void * __percpu *ipcomp_scratches; |
39 | static int ipcomp_scratch_users; | 39 | static int ipcomp_scratch_users; |
40 | static LIST_HEAD(ipcomp_tfms_list); | 40 | static LIST_HEAD(ipcomp_tfms_list); |
41 | 41 | ||
@@ -200,7 +200,7 @@ EXPORT_SYMBOL_GPL(ipcomp_output); | |||
200 | static void ipcomp_free_scratches(void) | 200 | static void ipcomp_free_scratches(void) |
201 | { | 201 | { |
202 | int i; | 202 | int i; |
203 | void **scratches; | 203 | void * __percpu *scratches; |
204 | 204 | ||
205 | if (--ipcomp_scratch_users) | 205 | if (--ipcomp_scratch_users) |
206 | return; | 206 | return; |
@@ -215,10 +215,10 @@ static void ipcomp_free_scratches(void) | |||
215 | free_percpu(scratches); | 215 | free_percpu(scratches); |
216 | } | 216 | } |
217 | 217 | ||
218 | static void **ipcomp_alloc_scratches(void) | 218 | static void * __percpu *ipcomp_alloc_scratches(void) |
219 | { | 219 | { |
220 | int i; | 220 | int i; |
221 | void **scratches; | 221 | void * __percpu *scratches; |
222 | 222 | ||
223 | if (ipcomp_scratch_users++) | 223 | if (ipcomp_scratch_users++) |
224 | return ipcomp_scratches; | 224 | return ipcomp_scratches; |
@@ -239,7 +239,7 @@ static void **ipcomp_alloc_scratches(void) | |||
239 | return scratches; | 239 | return scratches; |
240 | } | 240 | } |
241 | 241 | ||
242 | static void ipcomp_free_tfms(struct crypto_comp **tfms) | 242 | static void ipcomp_free_tfms(struct crypto_comp * __percpu *tfms) |
243 | { | 243 | { |
244 | struct ipcomp_tfms *pos; | 244 | struct ipcomp_tfms *pos; |
245 | int cpu; | 245 | int cpu; |
@@ -267,10 +267,10 @@ static void ipcomp_free_tfms(struct crypto_comp **tfms) | |||
267 | free_percpu(tfms); | 267 | free_percpu(tfms); |
268 | } | 268 | } |
269 | 269 | ||
270 | static struct crypto_comp **ipcomp_alloc_tfms(const char *alg_name) | 270 | static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name) |
271 | { | 271 | { |
272 | struct ipcomp_tfms *pos; | 272 | struct ipcomp_tfms *pos; |
273 | struct crypto_comp **tfms; | 273 | struct crypto_comp * __percpu *tfms; |
274 | int cpu; | 274 | int cpu; |
275 | 275 | ||
276 | /* This can be any valid CPU ID so we don't need locking. */ | 276 | /* This can be any valid CPU ID so we don't need locking. */ |
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index b9fe13138c07..6a329158bdfa 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/netdevice.h> | 14 | #include <linux/netdevice.h> |
15 | #include <linux/netfilter.h> | 15 | #include <linux/netfilter.h> |
16 | #include <linux/skbuff.h> | 16 | #include <linux/skbuff.h> |
17 | #include <linux/slab.h> | ||
17 | #include <linux/spinlock.h> | 18 | #include <linux/spinlock.h> |
18 | #include <net/dst.h> | 19 | #include <net/dst.h> |
19 | #include <net/xfrm.h> | 20 | #include <net/xfrm.h> |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index cb81ca35b0d6..843e066649cb 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -469,16 +469,16 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total) | |||
469 | return 0; | 469 | return 0; |
470 | } | 470 | } |
471 | 471 | ||
472 | void xfrm_spd_getinfo(struct xfrmk_spdinfo *si) | 472 | void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) |
473 | { | 473 | { |
474 | read_lock_bh(&xfrm_policy_lock); | 474 | read_lock_bh(&xfrm_policy_lock); |
475 | si->incnt = init_net.xfrm.policy_count[XFRM_POLICY_IN]; | 475 | si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN]; |
476 | si->outcnt = init_net.xfrm.policy_count[XFRM_POLICY_OUT]; | 476 | si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT]; |
477 | si->fwdcnt = init_net.xfrm.policy_count[XFRM_POLICY_FWD]; | 477 | si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD]; |
478 | si->inscnt = init_net.xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; | 478 | si->inscnt = net->xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; |
479 | si->outscnt = init_net.xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; | 479 | si->outscnt = net->xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; |
480 | si->fwdscnt = init_net.xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; | 480 | si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; |
481 | si->spdhcnt = init_net.xfrm.policy_idx_hmask; | 481 | si->spdhcnt = net->xfrm.policy_idx_hmask; |
482 | si->spdhmcnt = xfrm_policy_hashmax; | 482 | si->spdhmcnt = xfrm_policy_hashmax; |
483 | read_unlock_bh(&xfrm_policy_lock); | 483 | read_unlock_bh(&xfrm_policy_lock); |
484 | } | 484 | } |
@@ -556,6 +556,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
556 | struct hlist_head *chain; | 556 | struct hlist_head *chain; |
557 | struct hlist_node *entry, *newpos; | 557 | struct hlist_node *entry, *newpos; |
558 | struct dst_entry *gc_list; | 558 | struct dst_entry *gc_list; |
559 | u32 mark = policy->mark.v & policy->mark.m; | ||
559 | 560 | ||
560 | write_lock_bh(&xfrm_policy_lock); | 561 | write_lock_bh(&xfrm_policy_lock); |
561 | chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); | 562 | chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); |
@@ -564,6 +565,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
564 | hlist_for_each_entry(pol, entry, chain, bydst) { | 565 | hlist_for_each_entry(pol, entry, chain, bydst) { |
565 | if (pol->type == policy->type && | 566 | if (pol->type == policy->type && |
566 | !selector_cmp(&pol->selector, &policy->selector) && | 567 | !selector_cmp(&pol->selector, &policy->selector) && |
568 | (mark & pol->mark.m) == pol->mark.v && | ||
567 | xfrm_sec_ctx_match(pol->security, policy->security) && | 569 | xfrm_sec_ctx_match(pol->security, policy->security) && |
568 | !WARN_ON(delpol)) { | 570 | !WARN_ON(delpol)) { |
569 | if (excl) { | 571 | if (excl) { |
@@ -635,8 +637,8 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
635 | } | 637 | } |
636 | EXPORT_SYMBOL(xfrm_policy_insert); | 638 | EXPORT_SYMBOL(xfrm_policy_insert); |
637 | 639 | ||
638 | struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, | 640 | struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, |
639 | struct xfrm_selector *sel, | 641 | int dir, struct xfrm_selector *sel, |
640 | struct xfrm_sec_ctx *ctx, int delete, | 642 | struct xfrm_sec_ctx *ctx, int delete, |
641 | int *err) | 643 | int *err) |
642 | { | 644 | { |
@@ -650,6 +652,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, | |||
650 | ret = NULL; | 652 | ret = NULL; |
651 | hlist_for_each_entry(pol, entry, chain, bydst) { | 653 | hlist_for_each_entry(pol, entry, chain, bydst) { |
652 | if (pol->type == type && | 654 | if (pol->type == type && |
655 | (mark & pol->mark.m) == pol->mark.v && | ||
653 | !selector_cmp(sel, &pol->selector) && | 656 | !selector_cmp(sel, &pol->selector) && |
654 | xfrm_sec_ctx_match(ctx, pol->security)) { | 657 | xfrm_sec_ctx_match(ctx, pol->security)) { |
655 | xfrm_pol_hold(pol); | 658 | xfrm_pol_hold(pol); |
@@ -676,8 +679,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, | |||
676 | } | 679 | } |
677 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | 680 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
678 | 681 | ||
679 | struct xfrm_policy *xfrm_policy_byid(struct net *net, u8 type, int dir, u32 id, | 682 | struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, |
680 | int delete, int *err) | 683 | int dir, u32 id, int delete, int *err) |
681 | { | 684 | { |
682 | struct xfrm_policy *pol, *ret; | 685 | struct xfrm_policy *pol, *ret; |
683 | struct hlist_head *chain; | 686 | struct hlist_head *chain; |
@@ -692,7 +695,8 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u8 type, int dir, u32 id, | |||
692 | chain = net->xfrm.policy_byidx + idx_hash(net, id); | 695 | chain = net->xfrm.policy_byidx + idx_hash(net, id); |
693 | ret = NULL; | 696 | ret = NULL; |
694 | hlist_for_each_entry(pol, entry, chain, byidx) { | 697 | hlist_for_each_entry(pol, entry, chain, byidx) { |
695 | if (pol->type == type && pol->index == id) { | 698 | if (pol->type == type && pol->index == id && |
699 | (mark & pol->mark.m) == pol->mark.v) { | ||
696 | xfrm_pol_hold(pol); | 700 | xfrm_pol_hold(pol); |
697 | if (delete) { | 701 | if (delete) { |
698 | *err = security_xfrm_policy_delete( | 702 | *err = security_xfrm_policy_delete( |
@@ -771,7 +775,8 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi | |||
771 | 775 | ||
772 | int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | 776 | int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) |
773 | { | 777 | { |
774 | int dir, err = 0; | 778 | int dir, err = 0, cnt = 0; |
779 | struct xfrm_policy *dp; | ||
775 | 780 | ||
776 | write_lock_bh(&xfrm_policy_lock); | 781 | write_lock_bh(&xfrm_policy_lock); |
777 | 782 | ||
@@ -789,8 +794,10 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
789 | &net->xfrm.policy_inexact[dir], bydst) { | 794 | &net->xfrm.policy_inexact[dir], bydst) { |
790 | if (pol->type != type) | 795 | if (pol->type != type) |
791 | continue; | 796 | continue; |
792 | __xfrm_policy_unlink(pol, dir); | 797 | dp = __xfrm_policy_unlink(pol, dir); |
793 | write_unlock_bh(&xfrm_policy_lock); | 798 | write_unlock_bh(&xfrm_policy_lock); |
799 | if (dp) | ||
800 | cnt++; | ||
794 | 801 | ||
795 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, | 802 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, |
796 | audit_info->sessionid, | 803 | audit_info->sessionid, |
@@ -809,8 +816,10 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
809 | bydst) { | 816 | bydst) { |
810 | if (pol->type != type) | 817 | if (pol->type != type) |
811 | continue; | 818 | continue; |
812 | __xfrm_policy_unlink(pol, dir); | 819 | dp = __xfrm_policy_unlink(pol, dir); |
813 | write_unlock_bh(&xfrm_policy_lock); | 820 | write_unlock_bh(&xfrm_policy_lock); |
821 | if (dp) | ||
822 | cnt++; | ||
814 | 823 | ||
815 | xfrm_audit_policy_delete(pol, 1, | 824 | xfrm_audit_policy_delete(pol, 1, |
816 | audit_info->loginuid, | 825 | audit_info->loginuid, |
@@ -824,6 +833,8 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
824 | } | 833 | } |
825 | 834 | ||
826 | } | 835 | } |
836 | if (!cnt) | ||
837 | err = -ESRCH; | ||
827 | atomic_inc(&flow_cache_genid); | 838 | atomic_inc(&flow_cache_genid); |
828 | out: | 839 | out: |
829 | write_unlock_bh(&xfrm_policy_lock); | 840 | write_unlock_bh(&xfrm_policy_lock); |
@@ -909,6 +920,7 @@ static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, | |||
909 | int match, ret = -ESRCH; | 920 | int match, ret = -ESRCH; |
910 | 921 | ||
911 | if (pol->family != family || | 922 | if (pol->family != family || |
923 | (fl->mark & pol->mark.m) != pol->mark.v || | ||
912 | pol->type != type) | 924 | pol->type != type) |
913 | return ret; | 925 | return ret; |
914 | 926 | ||
@@ -1033,6 +1045,10 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
1033 | int err = 0; | 1045 | int err = 0; |
1034 | 1046 | ||
1035 | if (match) { | 1047 | if (match) { |
1048 | if ((sk->sk_mark & pol->mark.m) != pol->mark.v) { | ||
1049 | pol = NULL; | ||
1050 | goto out; | ||
1051 | } | ||
1036 | err = security_xfrm_policy_lookup(pol->security, | 1052 | err = security_xfrm_policy_lookup(pol->security, |
1037 | fl->secid, | 1053 | fl->secid, |
1038 | policy_to_flow_dir(dir)); | 1054 | policy_to_flow_dir(dir)); |
@@ -1045,6 +1061,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
1045 | } else | 1061 | } else |
1046 | pol = NULL; | 1062 | pol = NULL; |
1047 | } | 1063 | } |
1064 | out: | ||
1048 | read_unlock_bh(&xfrm_policy_lock); | 1065 | read_unlock_bh(&xfrm_policy_lock); |
1049 | return pol; | 1066 | return pol; |
1050 | } | 1067 | } |
@@ -1137,6 +1154,7 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
1137 | } | 1154 | } |
1138 | newp->lft = old->lft; | 1155 | newp->lft = old->lft; |
1139 | newp->curlft = old->curlft; | 1156 | newp->curlft = old->curlft; |
1157 | newp->mark = old->mark; | ||
1140 | newp->action = old->action; | 1158 | newp->action = old->action; |
1141 | newp->flags = old->flags; | 1159 | newp->flags = old->flags; |
1142 | newp->xfrm_nr = old->xfrm_nr; | 1160 | newp->xfrm_nr = old->xfrm_nr; |
@@ -1309,15 +1327,28 @@ static inline int xfrm_get_tos(struct flowi *fl, int family) | |||
1309 | return tos; | 1327 | return tos; |
1310 | } | 1328 | } |
1311 | 1329 | ||
1312 | static inline struct xfrm_dst *xfrm_alloc_dst(int family) | 1330 | static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) |
1313 | { | 1331 | { |
1314 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 1332 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
1333 | struct dst_ops *dst_ops; | ||
1315 | struct xfrm_dst *xdst; | 1334 | struct xfrm_dst *xdst; |
1316 | 1335 | ||
1317 | if (!afinfo) | 1336 | if (!afinfo) |
1318 | return ERR_PTR(-EINVAL); | 1337 | return ERR_PTR(-EINVAL); |
1319 | 1338 | ||
1320 | xdst = dst_alloc(afinfo->dst_ops) ?: ERR_PTR(-ENOBUFS); | 1339 | switch (family) { |
1340 | case AF_INET: | ||
1341 | dst_ops = &net->xfrm.xfrm4_dst_ops; | ||
1342 | break; | ||
1343 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
1344 | case AF_INET6: | ||
1345 | dst_ops = &net->xfrm.xfrm6_dst_ops; | ||
1346 | break; | ||
1347 | #endif | ||
1348 | default: | ||
1349 | BUG(); | ||
1350 | } | ||
1351 | xdst = dst_alloc(dst_ops) ?: ERR_PTR(-ENOBUFS); | ||
1321 | 1352 | ||
1322 | xfrm_policy_put_afinfo(afinfo); | 1353 | xfrm_policy_put_afinfo(afinfo); |
1323 | 1354 | ||
@@ -1341,7 +1372,8 @@ static inline int xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst, | |||
1341 | return err; | 1372 | return err; |
1342 | } | 1373 | } |
1343 | 1374 | ||
1344 | static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | 1375 | static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
1376 | struct flowi *fl) | ||
1345 | { | 1377 | { |
1346 | struct xfrm_policy_afinfo *afinfo = | 1378 | struct xfrm_policy_afinfo *afinfo = |
1347 | xfrm_policy_get_afinfo(xdst->u.dst.ops->family); | 1379 | xfrm_policy_get_afinfo(xdst->u.dst.ops->family); |
@@ -1350,7 +1382,7 @@ static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | |||
1350 | if (!afinfo) | 1382 | if (!afinfo) |
1351 | return -EINVAL; | 1383 | return -EINVAL; |
1352 | 1384 | ||
1353 | err = afinfo->fill_dst(xdst, dev); | 1385 | err = afinfo->fill_dst(xdst, dev, fl); |
1354 | 1386 | ||
1355 | xfrm_policy_put_afinfo(afinfo); | 1387 | xfrm_policy_put_afinfo(afinfo); |
1356 | 1388 | ||
@@ -1366,6 +1398,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1366 | struct flowi *fl, | 1398 | struct flowi *fl, |
1367 | struct dst_entry *dst) | 1399 | struct dst_entry *dst) |
1368 | { | 1400 | { |
1401 | struct net *net = xp_net(policy); | ||
1369 | unsigned long now = jiffies; | 1402 | unsigned long now = jiffies; |
1370 | struct net_device *dev; | 1403 | struct net_device *dev; |
1371 | struct dst_entry *dst_prev = NULL; | 1404 | struct dst_entry *dst_prev = NULL; |
@@ -1389,7 +1422,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1389 | dst_hold(dst); | 1422 | dst_hold(dst); |
1390 | 1423 | ||
1391 | for (; i < nx; i++) { | 1424 | for (; i < nx; i++) { |
1392 | struct xfrm_dst *xdst = xfrm_alloc_dst(family); | 1425 | struct xfrm_dst *xdst = xfrm_alloc_dst(net, family); |
1393 | struct dst_entry *dst1 = &xdst->u.dst; | 1426 | struct dst_entry *dst1 = &xdst->u.dst; |
1394 | 1427 | ||
1395 | err = PTR_ERR(xdst); | 1428 | err = PTR_ERR(xdst); |
@@ -1445,7 +1478,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1445 | if (!dev) | 1478 | if (!dev) |
1446 | goto free_dst; | 1479 | goto free_dst; |
1447 | 1480 | ||
1448 | /* Copy neighbout for reachability confirmation */ | 1481 | /* Copy neighbour for reachability confirmation */ |
1449 | dst0->neighbour = neigh_clone(dst->neighbour); | 1482 | dst0->neighbour = neigh_clone(dst->neighbour); |
1450 | 1483 | ||
1451 | xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len); | 1484 | xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len); |
@@ -1454,7 +1487,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1454 | for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) { | 1487 | for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) { |
1455 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev; | 1488 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev; |
1456 | 1489 | ||
1457 | err = xfrm_fill_dst(xdst, dev); | 1490 | err = xfrm_fill_dst(xdst, dev, fl); |
1458 | if (err) | 1491 | if (err) |
1459 | goto free_dst; | 1492 | goto free_dst; |
1460 | 1493 | ||
@@ -2031,8 +2064,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) | |||
2031 | int res; | 2064 | int res; |
2032 | 2065 | ||
2033 | if (xfrm_decode_session(skb, &fl, family) < 0) { | 2066 | if (xfrm_decode_session(skb, &fl, family) < 0) { |
2034 | /* XXX: we should have something like FWDHDRERROR here. */ | 2067 | XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); |
2035 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); | ||
2036 | return 0; | 2068 | return 0; |
2037 | } | 2069 | } |
2038 | 2070 | ||
@@ -2279,6 +2311,7 @@ EXPORT_SYMBOL(xfrm_bundle_ok); | |||
2279 | 2311 | ||
2280 | int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | 2312 | int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) |
2281 | { | 2313 | { |
2314 | struct net *net; | ||
2282 | int err = 0; | 2315 | int err = 0; |
2283 | if (unlikely(afinfo == NULL)) | 2316 | if (unlikely(afinfo == NULL)) |
2284 | return -EINVAL; | 2317 | return -EINVAL; |
@@ -2302,6 +2335,27 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
2302 | xfrm_policy_afinfo[afinfo->family] = afinfo; | 2335 | xfrm_policy_afinfo[afinfo->family] = afinfo; |
2303 | } | 2336 | } |
2304 | write_unlock_bh(&xfrm_policy_afinfo_lock); | 2337 | write_unlock_bh(&xfrm_policy_afinfo_lock); |
2338 | |||
2339 | rtnl_lock(); | ||
2340 | for_each_net(net) { | ||
2341 | struct dst_ops *xfrm_dst_ops; | ||
2342 | |||
2343 | switch (afinfo->family) { | ||
2344 | case AF_INET: | ||
2345 | xfrm_dst_ops = &net->xfrm.xfrm4_dst_ops; | ||
2346 | break; | ||
2347 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
2348 | case AF_INET6: | ||
2349 | xfrm_dst_ops = &net->xfrm.xfrm6_dst_ops; | ||
2350 | break; | ||
2351 | #endif | ||
2352 | default: | ||
2353 | BUG(); | ||
2354 | } | ||
2355 | *xfrm_dst_ops = *afinfo->dst_ops; | ||
2356 | } | ||
2357 | rtnl_unlock(); | ||
2358 | |||
2305 | return err; | 2359 | return err; |
2306 | } | 2360 | } |
2307 | EXPORT_SYMBOL(xfrm_policy_register_afinfo); | 2361 | EXPORT_SYMBOL(xfrm_policy_register_afinfo); |
@@ -2332,6 +2386,22 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
2332 | } | 2386 | } |
2333 | EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); | 2387 | EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); |
2334 | 2388 | ||
2389 | static void __net_init xfrm_dst_ops_init(struct net *net) | ||
2390 | { | ||
2391 | struct xfrm_policy_afinfo *afinfo; | ||
2392 | |||
2393 | read_lock_bh(&xfrm_policy_afinfo_lock); | ||
2394 | afinfo = xfrm_policy_afinfo[AF_INET]; | ||
2395 | if (afinfo) | ||
2396 | net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops; | ||
2397 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
2398 | afinfo = xfrm_policy_afinfo[AF_INET6]; | ||
2399 | if (afinfo) | ||
2400 | net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops; | ||
2401 | #endif | ||
2402 | read_unlock_bh(&xfrm_policy_afinfo_lock); | ||
2403 | } | ||
2404 | |||
2335 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) | 2405 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) |
2336 | { | 2406 | { |
2337 | struct xfrm_policy_afinfo *afinfo; | 2407 | struct xfrm_policy_afinfo *afinfo; |
@@ -2369,19 +2439,19 @@ static int __net_init xfrm_statistics_init(struct net *net) | |||
2369 | { | 2439 | { |
2370 | int rv; | 2440 | int rv; |
2371 | 2441 | ||
2372 | if (snmp_mib_init((void **)net->mib.xfrm_statistics, | 2442 | if (snmp_mib_init((void __percpu **)net->mib.xfrm_statistics, |
2373 | sizeof(struct linux_xfrm_mib)) < 0) | 2443 | sizeof(struct linux_xfrm_mib)) < 0) |
2374 | return -ENOMEM; | 2444 | return -ENOMEM; |
2375 | rv = xfrm_proc_init(net); | 2445 | rv = xfrm_proc_init(net); |
2376 | if (rv < 0) | 2446 | if (rv < 0) |
2377 | snmp_mib_free((void **)net->mib.xfrm_statistics); | 2447 | snmp_mib_free((void __percpu **)net->mib.xfrm_statistics); |
2378 | return rv; | 2448 | return rv; |
2379 | } | 2449 | } |
2380 | 2450 | ||
2381 | static void xfrm_statistics_fini(struct net *net) | 2451 | static void xfrm_statistics_fini(struct net *net) |
2382 | { | 2452 | { |
2383 | xfrm_proc_fini(net); | 2453 | xfrm_proc_fini(net); |
2384 | snmp_mib_free((void **)net->mib.xfrm_statistics); | 2454 | snmp_mib_free((void __percpu **)net->mib.xfrm_statistics); |
2385 | } | 2455 | } |
2386 | #else | 2456 | #else |
2387 | static int __net_init xfrm_statistics_init(struct net *net) | 2457 | static int __net_init xfrm_statistics_init(struct net *net) |
@@ -2494,6 +2564,7 @@ static int __net_init xfrm_net_init(struct net *net) | |||
2494 | rv = xfrm_policy_init(net); | 2564 | rv = xfrm_policy_init(net); |
2495 | if (rv < 0) | 2565 | if (rv < 0) |
2496 | goto out_policy; | 2566 | goto out_policy; |
2567 | xfrm_dst_ops_init(net); | ||
2497 | rv = xfrm_sysctl_init(net); | 2568 | rv = xfrm_sysctl_init(net); |
2498 | if (rv < 0) | 2569 | if (rv < 0) |
2499 | goto out_sysctl; | 2570 | goto out_sysctl; |
diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c index fef8db553e8d..58d9ae005597 100644 --- a/net/xfrm/xfrm_proc.c +++ b/net/xfrm/xfrm_proc.c | |||
@@ -15,7 +15,7 @@ | |||
15 | #include <net/snmp.h> | 15 | #include <net/snmp.h> |
16 | #include <net/xfrm.h> | 16 | #include <net/xfrm.h> |
17 | 17 | ||
18 | static struct snmp_mib xfrm_mib_list[] = { | 18 | static const struct snmp_mib xfrm_mib_list[] = { |
19 | SNMP_MIB_ITEM("XfrmInError", LINUX_MIB_XFRMINERROR), | 19 | SNMP_MIB_ITEM("XfrmInError", LINUX_MIB_XFRMINERROR), |
20 | SNMP_MIB_ITEM("XfrmInBufferError", LINUX_MIB_XFRMINBUFFERERROR), | 20 | SNMP_MIB_ITEM("XfrmInBufferError", LINUX_MIB_XFRMINBUFFERERROR), |
21 | SNMP_MIB_ITEM("XfrmInHdrError", LINUX_MIB_XFRMINHDRERROR), | 21 | SNMP_MIB_ITEM("XfrmInHdrError", LINUX_MIB_XFRMINHDRERROR), |
@@ -41,6 +41,7 @@ static struct snmp_mib xfrm_mib_list[] = { | |||
41 | SNMP_MIB_ITEM("XfrmOutPolBlock", LINUX_MIB_XFRMOUTPOLBLOCK), | 41 | SNMP_MIB_ITEM("XfrmOutPolBlock", LINUX_MIB_XFRMOUTPOLBLOCK), |
42 | SNMP_MIB_ITEM("XfrmOutPolDead", LINUX_MIB_XFRMOUTPOLDEAD), | 42 | SNMP_MIB_ITEM("XfrmOutPolDead", LINUX_MIB_XFRMOUTPOLDEAD), |
43 | SNMP_MIB_ITEM("XfrmOutPolError", LINUX_MIB_XFRMOUTPOLERROR), | 43 | SNMP_MIB_ITEM("XfrmOutPolError", LINUX_MIB_XFRMOUTPOLERROR), |
44 | SNMP_MIB_ITEM("XfrmFwdHdrError", LINUX_MIB_XFRMFWDHDRERROR), | ||
44 | SNMP_MIB_SENTINEL | 45 | SNMP_MIB_SENTINEL |
45 | }; | 46 | }; |
46 | 47 | ||
@@ -50,7 +51,8 @@ static int xfrm_statistics_seq_show(struct seq_file *seq, void *v) | |||
50 | int i; | 51 | int i; |
51 | for (i=0; xfrm_mib_list[i].name; i++) | 52 | for (i=0; xfrm_mib_list[i].name; i++) |
52 | seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name, | 53 | seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name, |
53 | snmp_fold_field((void **)net->mib.xfrm_statistics, | 54 | snmp_fold_field((void __percpu **) |
55 | net->mib.xfrm_statistics, | ||
54 | xfrm_mib_list[i].entry)); | 56 | xfrm_mib_list[i].entry)); |
55 | return 0; | 57 | return 0; |
56 | } | 58 | } |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index f2f7c638083e..add77ecb8ac4 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -21,6 +21,10 @@ | |||
21 | #include <linux/cache.h> | 21 | #include <linux/cache.h> |
22 | #include <linux/audit.h> | 22 | #include <linux/audit.h> |
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <linux/ktime.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/kernel.h> | ||
24 | 28 | ||
25 | #include "xfrm_hash.h" | 29 | #include "xfrm_hash.h" |
26 | 30 | ||
@@ -352,7 +356,7 @@ static void xfrm_put_mode(struct xfrm_mode *mode) | |||
352 | 356 | ||
353 | static void xfrm_state_gc_destroy(struct xfrm_state *x) | 357 | static void xfrm_state_gc_destroy(struct xfrm_state *x) |
354 | { | 358 | { |
355 | del_timer_sync(&x->timer); | 359 | tasklet_hrtimer_cancel(&x->mtimer); |
356 | del_timer_sync(&x->rtimer); | 360 | del_timer_sync(&x->rtimer); |
357 | kfree(x->aalg); | 361 | kfree(x->aalg); |
358 | kfree(x->ealg); | 362 | kfree(x->ealg); |
@@ -398,9 +402,10 @@ static inline unsigned long make_jiffies(long secs) | |||
398 | return secs*HZ; | 402 | return secs*HZ; |
399 | } | 403 | } |
400 | 404 | ||
401 | static void xfrm_timer_handler(unsigned long data) | 405 | static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me) |
402 | { | 406 | { |
403 | struct xfrm_state *x = (struct xfrm_state*)data; | 407 | struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer); |
408 | struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer); | ||
404 | struct net *net = xs_net(x); | 409 | struct net *net = xs_net(x); |
405 | unsigned long now = get_seconds(); | 410 | unsigned long now = get_seconds(); |
406 | long next = LONG_MAX; | 411 | long next = LONG_MAX; |
@@ -451,8 +456,9 @@ static void xfrm_timer_handler(unsigned long data) | |||
451 | if (warn) | 456 | if (warn) |
452 | km_state_expired(x, 0, 0); | 457 | km_state_expired(x, 0, 0); |
453 | resched: | 458 | resched: |
454 | if (next != LONG_MAX) | 459 | if (next != LONG_MAX){ |
455 | mod_timer(&x->timer, jiffies + make_jiffies(next)); | 460 | tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL); |
461 | } | ||
456 | 462 | ||
457 | goto out; | 463 | goto out; |
458 | 464 | ||
@@ -474,6 +480,7 @@ expired: | |||
474 | 480 | ||
475 | out: | 481 | out: |
476 | spin_unlock(&x->lock); | 482 | spin_unlock(&x->lock); |
483 | return HRTIMER_NORESTART; | ||
477 | } | 484 | } |
478 | 485 | ||
479 | static void xfrm_replay_timer_handler(unsigned long data); | 486 | static void xfrm_replay_timer_handler(unsigned long data); |
@@ -492,7 +499,7 @@ struct xfrm_state *xfrm_state_alloc(struct net *net) | |||
492 | INIT_HLIST_NODE(&x->bydst); | 499 | INIT_HLIST_NODE(&x->bydst); |
493 | INIT_HLIST_NODE(&x->bysrc); | 500 | INIT_HLIST_NODE(&x->bysrc); |
494 | INIT_HLIST_NODE(&x->byspi); | 501 | INIT_HLIST_NODE(&x->byspi); |
495 | setup_timer(&x->timer, xfrm_timer_handler, (unsigned long)x); | 502 | tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler, CLOCK_REALTIME, HRTIMER_MODE_ABS); |
496 | setup_timer(&x->rtimer, xfrm_replay_timer_handler, | 503 | setup_timer(&x->rtimer, xfrm_replay_timer_handler, |
497 | (unsigned long)x); | 504 | (unsigned long)x); |
498 | x->curlft.add_time = get_seconds(); | 505 | x->curlft.add_time = get_seconds(); |
@@ -597,13 +604,14 @@ xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audi | |||
597 | 604 | ||
598 | int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) | 605 | int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) |
599 | { | 606 | { |
600 | int i, err = 0; | 607 | int i, err = 0, cnt = 0; |
601 | 608 | ||
602 | spin_lock_bh(&xfrm_state_lock); | 609 | spin_lock_bh(&xfrm_state_lock); |
603 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); | 610 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); |
604 | if (err) | 611 | if (err) |
605 | goto out; | 612 | goto out; |
606 | 613 | ||
614 | err = -ESRCH; | ||
607 | for (i = 0; i <= net->xfrm.state_hmask; i++) { | 615 | for (i = 0; i <= net->xfrm.state_hmask; i++) { |
608 | struct hlist_node *entry; | 616 | struct hlist_node *entry; |
609 | struct xfrm_state *x; | 617 | struct xfrm_state *x; |
@@ -620,13 +628,16 @@ restart: | |||
620 | audit_info->sessionid, | 628 | audit_info->sessionid, |
621 | audit_info->secid); | 629 | audit_info->secid); |
622 | xfrm_state_put(x); | 630 | xfrm_state_put(x); |
631 | if (!err) | ||
632 | cnt++; | ||
623 | 633 | ||
624 | spin_lock_bh(&xfrm_state_lock); | 634 | spin_lock_bh(&xfrm_state_lock); |
625 | goto restart; | 635 | goto restart; |
626 | } | 636 | } |
627 | } | 637 | } |
628 | } | 638 | } |
629 | err = 0; | 639 | if (cnt) |
640 | err = 0; | ||
630 | 641 | ||
631 | out: | 642 | out: |
632 | spin_unlock_bh(&xfrm_state_lock); | 643 | spin_unlock_bh(&xfrm_state_lock); |
@@ -635,11 +646,11 @@ out: | |||
635 | } | 646 | } |
636 | EXPORT_SYMBOL(xfrm_state_flush); | 647 | EXPORT_SYMBOL(xfrm_state_flush); |
637 | 648 | ||
638 | void xfrm_sad_getinfo(struct xfrmk_sadinfo *si) | 649 | void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) |
639 | { | 650 | { |
640 | spin_lock_bh(&xfrm_state_lock); | 651 | spin_lock_bh(&xfrm_state_lock); |
641 | si->sadcnt = init_net.xfrm.state_num; | 652 | si->sadcnt = net->xfrm.state_num; |
642 | si->sadhcnt = init_net.xfrm.state_hmask; | 653 | si->sadhcnt = net->xfrm.state_hmask; |
643 | si->sadhmcnt = xfrm_state_hashmax; | 654 | si->sadhmcnt = xfrm_state_hashmax; |
644 | spin_unlock_bh(&xfrm_state_lock); | 655 | spin_unlock_bh(&xfrm_state_lock); |
645 | } | 656 | } |
@@ -659,7 +670,7 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
659 | return 0; | 670 | return 0; |
660 | } | 671 | } |
661 | 672 | ||
662 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) | 673 | static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) |
663 | { | 674 | { |
664 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); | 675 | unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); |
665 | struct xfrm_state *x; | 676 | struct xfrm_state *x; |
@@ -672,6 +683,8 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d | |||
672 | xfrm_addr_cmp(&x->id.daddr, daddr, family)) | 683 | xfrm_addr_cmp(&x->id.daddr, daddr, family)) |
673 | continue; | 684 | continue; |
674 | 685 | ||
686 | if ((mark & x->mark.m) != x->mark.v) | ||
687 | continue; | ||
675 | xfrm_state_hold(x); | 688 | xfrm_state_hold(x); |
676 | return x; | 689 | return x; |
677 | } | 690 | } |
@@ -679,7 +692,7 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *d | |||
679 | return NULL; | 692 | return NULL; |
680 | } | 693 | } |
681 | 694 | ||
682 | static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) | 695 | static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) |
683 | { | 696 | { |
684 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); | 697 | unsigned int h = xfrm_src_hash(net, daddr, saddr, family); |
685 | struct xfrm_state *x; | 698 | struct xfrm_state *x; |
@@ -692,6 +705,8 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_addre | |||
692 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 705 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) |
693 | continue; | 706 | continue; |
694 | 707 | ||
708 | if ((mark & x->mark.m) != x->mark.v) | ||
709 | continue; | ||
695 | xfrm_state_hold(x); | 710 | xfrm_state_hold(x); |
696 | return x; | 711 | return x; |
697 | } | 712 | } |
@@ -703,12 +718,14 @@ static inline struct xfrm_state * | |||
703 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) | 718 | __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) |
704 | { | 719 | { |
705 | struct net *net = xs_net(x); | 720 | struct net *net = xs_net(x); |
721 | u32 mark = x->mark.v & x->mark.m; | ||
706 | 722 | ||
707 | if (use_spi) | 723 | if (use_spi) |
708 | return __xfrm_state_lookup(net, &x->id.daddr, x->id.spi, | 724 | return __xfrm_state_lookup(net, mark, &x->id.daddr, |
709 | x->id.proto, family); | 725 | x->id.spi, x->id.proto, family); |
710 | else | 726 | else |
711 | return __xfrm_state_lookup_byaddr(net, &x->id.daddr, | 727 | return __xfrm_state_lookup_byaddr(net, mark, |
728 | &x->id.daddr, | ||
712 | &x->props.saddr, | 729 | &x->props.saddr, |
713 | x->id.proto, family); | 730 | x->id.proto, family); |
714 | } | 731 | } |
@@ -773,6 +790,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
773 | int acquire_in_progress = 0; | 790 | int acquire_in_progress = 0; |
774 | int error = 0; | 791 | int error = 0; |
775 | struct xfrm_state *best = NULL; | 792 | struct xfrm_state *best = NULL; |
793 | u32 mark = pol->mark.v & pol->mark.m; | ||
776 | 794 | ||
777 | to_put = NULL; | 795 | to_put = NULL; |
778 | 796 | ||
@@ -781,6 +799,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
781 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 799 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
782 | if (x->props.family == family && | 800 | if (x->props.family == family && |
783 | x->props.reqid == tmpl->reqid && | 801 | x->props.reqid == tmpl->reqid && |
802 | (mark & x->mark.m) == x->mark.v && | ||
784 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 803 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
785 | xfrm_state_addr_check(x, daddr, saddr, family) && | 804 | xfrm_state_addr_check(x, daddr, saddr, family) && |
786 | tmpl->mode == x->props.mode && | 805 | tmpl->mode == x->props.mode && |
@@ -796,6 +815,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
796 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { | 815 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) { |
797 | if (x->props.family == family && | 816 | if (x->props.family == family && |
798 | x->props.reqid == tmpl->reqid && | 817 | x->props.reqid == tmpl->reqid && |
818 | (mark & x->mark.m) == x->mark.v && | ||
799 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 819 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
800 | xfrm_state_addr_check(x, daddr, saddr, family) && | 820 | xfrm_state_addr_check(x, daddr, saddr, family) && |
801 | tmpl->mode == x->props.mode && | 821 | tmpl->mode == x->props.mode && |
@@ -809,7 +829,7 @@ found: | |||
809 | x = best; | 829 | x = best; |
810 | if (!x && !error && !acquire_in_progress) { | 830 | if (!x && !error && !acquire_in_progress) { |
811 | if (tmpl->id.spi && | 831 | if (tmpl->id.spi && |
812 | (x0 = __xfrm_state_lookup(net, daddr, tmpl->id.spi, | 832 | (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, |
813 | tmpl->id.proto, family)) != NULL) { | 833 | tmpl->id.proto, family)) != NULL) { |
814 | to_put = x0; | 834 | to_put = x0; |
815 | error = -EEXIST; | 835 | error = -EEXIST; |
@@ -823,6 +843,7 @@ found: | |||
823 | /* Initialize temporary selector matching only | 843 | /* Initialize temporary selector matching only |
824 | * to current session. */ | 844 | * to current session. */ |
825 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); | 845 | xfrm_init_tempsel(x, fl, tmpl, daddr, saddr, family); |
846 | memcpy(&x->mark, &pol->mark, sizeof(x->mark)); | ||
826 | 847 | ||
827 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); | 848 | error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); |
828 | if (error) { | 849 | if (error) { |
@@ -843,8 +864,7 @@ found: | |||
843 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); | 864 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); |
844 | } | 865 | } |
845 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 866 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
846 | x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; | 867 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); |
847 | add_timer(&x->timer); | ||
848 | net->xfrm.state_num++; | 868 | net->xfrm.state_num++; |
849 | xfrm_hash_grow_check(net, x->bydst.next != NULL); | 869 | xfrm_hash_grow_check(net, x->bydst.next != NULL); |
850 | } else { | 870 | } else { |
@@ -866,7 +886,7 @@ out: | |||
866 | } | 886 | } |
867 | 887 | ||
868 | struct xfrm_state * | 888 | struct xfrm_state * |
869 | xfrm_stateonly_find(struct net *net, | 889 | xfrm_stateonly_find(struct net *net, u32 mark, |
870 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 890 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
871 | unsigned short family, u8 mode, u8 proto, u32 reqid) | 891 | unsigned short family, u8 mode, u8 proto, u32 reqid) |
872 | { | 892 | { |
@@ -879,6 +899,7 @@ xfrm_stateonly_find(struct net *net, | |||
879 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 899 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
880 | if (x->props.family == family && | 900 | if (x->props.family == family && |
881 | x->props.reqid == reqid && | 901 | x->props.reqid == reqid && |
902 | (mark & x->mark.m) == x->mark.v && | ||
882 | !(x->props.flags & XFRM_STATE_WILDRECV) && | 903 | !(x->props.flags & XFRM_STATE_WILDRECV) && |
883 | xfrm_state_addr_check(x, daddr, saddr, family) && | 904 | xfrm_state_addr_check(x, daddr, saddr, family) && |
884 | mode == x->props.mode && | 905 | mode == x->props.mode && |
@@ -921,7 +942,7 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
921 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); | 942 | hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); |
922 | } | 943 | } |
923 | 944 | ||
924 | mod_timer(&x->timer, jiffies + HZ); | 945 | tasklet_hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); |
925 | if (x->replay_maxage) | 946 | if (x->replay_maxage) |
926 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); | 947 | mod_timer(&x->rtimer, jiffies + x->replay_maxage); |
927 | 948 | ||
@@ -941,11 +962,13 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | |||
941 | struct xfrm_state *x; | 962 | struct xfrm_state *x; |
942 | struct hlist_node *entry; | 963 | struct hlist_node *entry; |
943 | unsigned int h; | 964 | unsigned int h; |
965 | u32 mark = xnew->mark.v & xnew->mark.m; | ||
944 | 966 | ||
945 | h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); | 967 | h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); |
946 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 968 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
947 | if (x->props.family == family && | 969 | if (x->props.family == family && |
948 | x->props.reqid == reqid && | 970 | x->props.reqid == reqid && |
971 | (mark & x->mark.m) == x->mark.v && | ||
949 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && | 972 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && |
950 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) | 973 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) |
951 | x->genid = xfrm_state_genid; | 974 | x->genid = xfrm_state_genid; |
@@ -962,11 +985,12 @@ void xfrm_state_insert(struct xfrm_state *x) | |||
962 | EXPORT_SYMBOL(xfrm_state_insert); | 985 | EXPORT_SYMBOL(xfrm_state_insert); |
963 | 986 | ||
964 | /* xfrm_state_lock is held */ | 987 | /* xfrm_state_lock is held */ |
965 | static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) | 988 | static struct xfrm_state *__find_acq_core(struct net *net, struct xfrm_mark *m, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) |
966 | { | 989 | { |
967 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); | 990 | unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); |
968 | struct hlist_node *entry; | 991 | struct hlist_node *entry; |
969 | struct xfrm_state *x; | 992 | struct xfrm_state *x; |
993 | u32 mark = m->v & m->m; | ||
970 | 994 | ||
971 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { | 995 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { |
972 | if (x->props.reqid != reqid || | 996 | if (x->props.reqid != reqid || |
@@ -975,6 +999,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
975 | x->km.state != XFRM_STATE_ACQ || | 999 | x->km.state != XFRM_STATE_ACQ || |
976 | x->id.spi != 0 || | 1000 | x->id.spi != 0 || |
977 | x->id.proto != proto || | 1001 | x->id.proto != proto || |
1002 | (mark & x->mark.m) != x->mark.v || | ||
978 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || | 1003 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || |
979 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 1004 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) |
980 | continue; | 1005 | continue; |
@@ -1017,10 +1042,11 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
1017 | x->props.family = family; | 1042 | x->props.family = family; |
1018 | x->props.mode = mode; | 1043 | x->props.mode = mode; |
1019 | x->props.reqid = reqid; | 1044 | x->props.reqid = reqid; |
1045 | x->mark.v = m->v; | ||
1046 | x->mark.m = m->m; | ||
1020 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; | 1047 | x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; |
1021 | xfrm_state_hold(x); | 1048 | xfrm_state_hold(x); |
1022 | x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; | 1049 | tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); |
1023 | add_timer(&x->timer); | ||
1024 | list_add(&x->km.all, &net->xfrm.state_all); | 1050 | list_add(&x->km.all, &net->xfrm.state_all); |
1025 | hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); | 1051 | hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); |
1026 | h = xfrm_src_hash(net, daddr, saddr, family); | 1052 | h = xfrm_src_hash(net, daddr, saddr, family); |
@@ -1034,7 +1060,7 @@ static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family | |||
1034 | return x; | 1060 | return x; |
1035 | } | 1061 | } |
1036 | 1062 | ||
1037 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq); | 1063 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); |
1038 | 1064 | ||
1039 | int xfrm_state_add(struct xfrm_state *x) | 1065 | int xfrm_state_add(struct xfrm_state *x) |
1040 | { | 1066 | { |
@@ -1042,6 +1068,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1042 | struct xfrm_state *x1, *to_put; | 1068 | struct xfrm_state *x1, *to_put; |
1043 | int family; | 1069 | int family; |
1044 | int err; | 1070 | int err; |
1071 | u32 mark = x->mark.v & x->mark.m; | ||
1045 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); | 1072 | int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); |
1046 | 1073 | ||
1047 | family = x->props.family; | 1074 | family = x->props.family; |
@@ -1059,7 +1086,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1059 | } | 1086 | } |
1060 | 1087 | ||
1061 | if (use_spi && x->km.seq) { | 1088 | if (use_spi && x->km.seq) { |
1062 | x1 = __xfrm_find_acq_byseq(net, x->km.seq); | 1089 | x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); |
1063 | if (x1 && ((x1->id.proto != x->id.proto) || | 1090 | if (x1 && ((x1->id.proto != x->id.proto) || |
1064 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { | 1091 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { |
1065 | to_put = x1; | 1092 | to_put = x1; |
@@ -1068,8 +1095,8 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1068 | } | 1095 | } |
1069 | 1096 | ||
1070 | if (use_spi && !x1) | 1097 | if (use_spi && !x1) |
1071 | x1 = __find_acq_core(net, family, x->props.mode, x->props.reqid, | 1098 | x1 = __find_acq_core(net, &x->mark, family, x->props.mode, |
1072 | x->id.proto, | 1099 | x->props.reqid, x->id.proto, |
1073 | &x->id.daddr, &x->props.saddr, 0); | 1100 | &x->id.daddr, &x->props.saddr, 0); |
1074 | 1101 | ||
1075 | __xfrm_state_bump_genids(x); | 1102 | __xfrm_state_bump_genids(x); |
@@ -1098,7 +1125,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1098 | int err = -ENOMEM; | 1125 | int err = -ENOMEM; |
1099 | struct xfrm_state *x = xfrm_state_alloc(net); | 1126 | struct xfrm_state *x = xfrm_state_alloc(net); |
1100 | if (!x) | 1127 | if (!x) |
1101 | goto error; | 1128 | goto out; |
1102 | 1129 | ||
1103 | memcpy(&x->id, &orig->id, sizeof(x->id)); | 1130 | memcpy(&x->id, &orig->id, sizeof(x->id)); |
1104 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); | 1131 | memcpy(&x->sel, &orig->sel, sizeof(x->sel)); |
@@ -1110,7 +1137,7 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1110 | x->props.saddr = orig->props.saddr; | 1137 | x->props.saddr = orig->props.saddr; |
1111 | 1138 | ||
1112 | if (orig->aalg) { | 1139 | if (orig->aalg) { |
1113 | x->aalg = xfrm_algo_clone(orig->aalg); | 1140 | x->aalg = xfrm_algo_auth_clone(orig->aalg); |
1114 | if (!x->aalg) | 1141 | if (!x->aalg) |
1115 | goto error; | 1142 | goto error; |
1116 | } | 1143 | } |
@@ -1143,6 +1170,8 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1143 | goto error; | 1170 | goto error; |
1144 | } | 1171 | } |
1145 | 1172 | ||
1173 | memcpy(&x->mark, &orig->mark, sizeof(x->mark)); | ||
1174 | |||
1146 | err = xfrm_init_state(x); | 1175 | err = xfrm_init_state(x); |
1147 | if (err) | 1176 | if (err) |
1148 | goto error; | 1177 | goto error; |
@@ -1156,16 +1185,10 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) | |||
1156 | return x; | 1185 | return x; |
1157 | 1186 | ||
1158 | error: | 1187 | error: |
1188 | xfrm_state_put(x); | ||
1189 | out: | ||
1159 | if (errp) | 1190 | if (errp) |
1160 | *errp = err; | 1191 | *errp = err; |
1161 | if (x) { | ||
1162 | kfree(x->aalg); | ||
1163 | kfree(x->ealg); | ||
1164 | kfree(x->calg); | ||
1165 | kfree(x->encap); | ||
1166 | kfree(x->coaddr); | ||
1167 | } | ||
1168 | kfree(x); | ||
1169 | return NULL; | 1192 | return NULL; |
1170 | } | 1193 | } |
1171 | 1194 | ||
@@ -1300,7 +1323,7 @@ out: | |||
1300 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); | 1323 | memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); |
1301 | x1->km.dying = 0; | 1324 | x1->km.dying = 0; |
1302 | 1325 | ||
1303 | mod_timer(&x1->timer, jiffies + HZ); | 1326 | tasklet_hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); |
1304 | if (x1->curlft.use_time) | 1327 | if (x1->curlft.use_time) |
1305 | xfrm_state_check_expire(x1); | 1328 | xfrm_state_check_expire(x1); |
1306 | 1329 | ||
@@ -1325,7 +1348,7 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
1325 | if (x->curlft.bytes >= x->lft.hard_byte_limit || | 1348 | if (x->curlft.bytes >= x->lft.hard_byte_limit || |
1326 | x->curlft.packets >= x->lft.hard_packet_limit) { | 1349 | x->curlft.packets >= x->lft.hard_packet_limit) { |
1327 | x->km.state = XFRM_STATE_EXPIRED; | 1350 | x->km.state = XFRM_STATE_EXPIRED; |
1328 | mod_timer(&x->timer, jiffies); | 1351 | tasklet_hrtimer_start(&x->mtimer, ktime_set(0,0), HRTIMER_MODE_REL); |
1329 | return -EINVAL; | 1352 | return -EINVAL; |
1330 | } | 1353 | } |
1331 | 1354 | ||
@@ -1340,41 +1363,41 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
1340 | EXPORT_SYMBOL(xfrm_state_check_expire); | 1363 | EXPORT_SYMBOL(xfrm_state_check_expire); |
1341 | 1364 | ||
1342 | struct xfrm_state * | 1365 | struct xfrm_state * |
1343 | xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, | 1366 | xfrm_state_lookup(struct net *net, u32 mark, xfrm_address_t *daddr, __be32 spi, |
1344 | unsigned short family) | 1367 | u8 proto, unsigned short family) |
1345 | { | 1368 | { |
1346 | struct xfrm_state *x; | 1369 | struct xfrm_state *x; |
1347 | 1370 | ||
1348 | spin_lock_bh(&xfrm_state_lock); | 1371 | spin_lock_bh(&xfrm_state_lock); |
1349 | x = __xfrm_state_lookup(net, daddr, spi, proto, family); | 1372 | x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); |
1350 | spin_unlock_bh(&xfrm_state_lock); | 1373 | spin_unlock_bh(&xfrm_state_lock); |
1351 | return x; | 1374 | return x; |
1352 | } | 1375 | } |
1353 | EXPORT_SYMBOL(xfrm_state_lookup); | 1376 | EXPORT_SYMBOL(xfrm_state_lookup); |
1354 | 1377 | ||
1355 | struct xfrm_state * | 1378 | struct xfrm_state * |
1356 | xfrm_state_lookup_byaddr(struct net *net, | 1379 | xfrm_state_lookup_byaddr(struct net *net, u32 mark, |
1357 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1380 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
1358 | u8 proto, unsigned short family) | 1381 | u8 proto, unsigned short family) |
1359 | { | 1382 | { |
1360 | struct xfrm_state *x; | 1383 | struct xfrm_state *x; |
1361 | 1384 | ||
1362 | spin_lock_bh(&xfrm_state_lock); | 1385 | spin_lock_bh(&xfrm_state_lock); |
1363 | x = __xfrm_state_lookup_byaddr(net, daddr, saddr, proto, family); | 1386 | x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); |
1364 | spin_unlock_bh(&xfrm_state_lock); | 1387 | spin_unlock_bh(&xfrm_state_lock); |
1365 | return x; | 1388 | return x; |
1366 | } | 1389 | } |
1367 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); | 1390 | EXPORT_SYMBOL(xfrm_state_lookup_byaddr); |
1368 | 1391 | ||
1369 | struct xfrm_state * | 1392 | struct xfrm_state * |
1370 | xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto, | 1393 | xfrm_find_acq(struct net *net, struct xfrm_mark *mark, u8 mode, u32 reqid, u8 proto, |
1371 | xfrm_address_t *daddr, xfrm_address_t *saddr, | 1394 | xfrm_address_t *daddr, xfrm_address_t *saddr, |
1372 | int create, unsigned short family) | 1395 | int create, unsigned short family) |
1373 | { | 1396 | { |
1374 | struct xfrm_state *x; | 1397 | struct xfrm_state *x; |
1375 | 1398 | ||
1376 | spin_lock_bh(&xfrm_state_lock); | 1399 | spin_lock_bh(&xfrm_state_lock); |
1377 | x = __find_acq_core(net, family, mode, reqid, proto, daddr, saddr, create); | 1400 | x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); |
1378 | spin_unlock_bh(&xfrm_state_lock); | 1401 | spin_unlock_bh(&xfrm_state_lock); |
1379 | 1402 | ||
1380 | return x; | 1403 | return x; |
@@ -1421,7 +1444,7 @@ EXPORT_SYMBOL(xfrm_state_sort); | |||
1421 | 1444 | ||
1422 | /* Silly enough, but I'm lazy to build resolution list */ | 1445 | /* Silly enough, but I'm lazy to build resolution list */ |
1423 | 1446 | ||
1424 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | 1447 | static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
1425 | { | 1448 | { |
1426 | int i; | 1449 | int i; |
1427 | 1450 | ||
@@ -1431,6 +1454,7 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | |||
1431 | 1454 | ||
1432 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { | 1455 | hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { |
1433 | if (x->km.seq == seq && | 1456 | if (x->km.seq == seq && |
1457 | (mark & x->mark.m) == x->mark.v && | ||
1434 | x->km.state == XFRM_STATE_ACQ) { | 1458 | x->km.state == XFRM_STATE_ACQ) { |
1435 | xfrm_state_hold(x); | 1459 | xfrm_state_hold(x); |
1436 | return x; | 1460 | return x; |
@@ -1440,12 +1464,12 @@ static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) | |||
1440 | return NULL; | 1464 | return NULL; |
1441 | } | 1465 | } |
1442 | 1466 | ||
1443 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq) | 1467 | struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) |
1444 | { | 1468 | { |
1445 | struct xfrm_state *x; | 1469 | struct xfrm_state *x; |
1446 | 1470 | ||
1447 | spin_lock_bh(&xfrm_state_lock); | 1471 | spin_lock_bh(&xfrm_state_lock); |
1448 | x = __xfrm_find_acq_byseq(net, seq); | 1472 | x = __xfrm_find_acq_byseq(net, mark, seq); |
1449 | spin_unlock_bh(&xfrm_state_lock); | 1473 | spin_unlock_bh(&xfrm_state_lock); |
1450 | return x; | 1474 | return x; |
1451 | } | 1475 | } |
@@ -1454,12 +1478,12 @@ EXPORT_SYMBOL(xfrm_find_acq_byseq); | |||
1454 | u32 xfrm_get_acqseq(void) | 1478 | u32 xfrm_get_acqseq(void) |
1455 | { | 1479 | { |
1456 | u32 res; | 1480 | u32 res; |
1457 | static u32 acqseq; | 1481 | static atomic_t acqseq; |
1458 | static DEFINE_SPINLOCK(acqseq_lock); | 1482 | |
1483 | do { | ||
1484 | res = atomic_inc_return(&acqseq); | ||
1485 | } while (!res); | ||
1459 | 1486 | ||
1460 | spin_lock_bh(&acqseq_lock); | ||
1461 | res = (++acqseq ? : ++acqseq); | ||
1462 | spin_unlock_bh(&acqseq_lock); | ||
1463 | return res; | 1487 | return res; |
1464 | } | 1488 | } |
1465 | EXPORT_SYMBOL(xfrm_get_acqseq); | 1489 | EXPORT_SYMBOL(xfrm_get_acqseq); |
@@ -1472,6 +1496,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
1472 | int err = -ENOENT; | 1496 | int err = -ENOENT; |
1473 | __be32 minspi = htonl(low); | 1497 | __be32 minspi = htonl(low); |
1474 | __be32 maxspi = htonl(high); | 1498 | __be32 maxspi = htonl(high); |
1499 | u32 mark = x->mark.v & x->mark.m; | ||
1475 | 1500 | ||
1476 | spin_lock_bh(&x->lock); | 1501 | spin_lock_bh(&x->lock); |
1477 | if (x->km.state == XFRM_STATE_DEAD) | 1502 | if (x->km.state == XFRM_STATE_DEAD) |
@@ -1484,7 +1509,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
1484 | err = -ENOENT; | 1509 | err = -ENOENT; |
1485 | 1510 | ||
1486 | if (minspi == maxspi) { | 1511 | if (minspi == maxspi) { |
1487 | x0 = xfrm_state_lookup(net, &x->id.daddr, minspi, x->id.proto, x->props.family); | 1512 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); |
1488 | if (x0) { | 1513 | if (x0) { |
1489 | xfrm_state_put(x0); | 1514 | xfrm_state_put(x0); |
1490 | goto unlock; | 1515 | goto unlock; |
@@ -1494,7 +1519,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) | |||
1494 | u32 spi = 0; | 1519 | u32 spi = 0; |
1495 | for (h=0; h<high-low+1; h++) { | 1520 | for (h=0; h<high-low+1; h++) { |
1496 | spi = low + net_random()%(high-low+1); | 1521 | spi = low + net_random()%(high-low+1); |
1497 | x0 = xfrm_state_lookup(net, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); | 1522 | x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); |
1498 | if (x0 == NULL) { | 1523 | if (x0 == NULL) { |
1499 | x->id.spi = htonl(spi); | 1524 | x->id.spi = htonl(spi); |
1500 | break; | 1525 | break; |
diff --git a/net/xfrm/xfrm_sysctl.c b/net/xfrm/xfrm_sysctl.c index 2e6ffb66f06f..05640bc9594b 100644 --- a/net/xfrm/xfrm_sysctl.c +++ b/net/xfrm/xfrm_sysctl.c | |||
@@ -1,8 +1,9 @@ | |||
1 | #include <linux/sysctl.h> | 1 | #include <linux/sysctl.h> |
2 | #include <linux/slab.h> | ||
2 | #include <net/net_namespace.h> | 3 | #include <net/net_namespace.h> |
3 | #include <net/xfrm.h> | 4 | #include <net/xfrm.h> |
4 | 5 | ||
5 | static void __xfrm_sysctl_init(struct net *net) | 6 | static void __net_init __xfrm_sysctl_init(struct net *net) |
6 | { | 7 | { |
7 | net->xfrm.sysctl_aevent_etime = XFRM_AE_ETIME; | 8 | net->xfrm.sysctl_aevent_etime = XFRM_AE_ETIME; |
8 | net->xfrm.sysctl_aevent_rseqth = XFRM_AE_SEQT_SIZE; | 9 | net->xfrm.sysctl_aevent_rseqth = XFRM_AE_SEQT_SIZE; |
@@ -13,28 +14,24 @@ static void __xfrm_sysctl_init(struct net *net) | |||
13 | #ifdef CONFIG_SYSCTL | 14 | #ifdef CONFIG_SYSCTL |
14 | static struct ctl_table xfrm_table[] = { | 15 | static struct ctl_table xfrm_table[] = { |
15 | { | 16 | { |
16 | .ctl_name = NET_CORE_AEVENT_ETIME, | ||
17 | .procname = "xfrm_aevent_etime", | 17 | .procname = "xfrm_aevent_etime", |
18 | .maxlen = sizeof(u32), | 18 | .maxlen = sizeof(u32), |
19 | .mode = 0644, | 19 | .mode = 0644, |
20 | .proc_handler = proc_dointvec | 20 | .proc_handler = proc_dointvec |
21 | }, | 21 | }, |
22 | { | 22 | { |
23 | .ctl_name = NET_CORE_AEVENT_RSEQTH, | ||
24 | .procname = "xfrm_aevent_rseqth", | 23 | .procname = "xfrm_aevent_rseqth", |
25 | .maxlen = sizeof(u32), | 24 | .maxlen = sizeof(u32), |
26 | .mode = 0644, | 25 | .mode = 0644, |
27 | .proc_handler = proc_dointvec | 26 | .proc_handler = proc_dointvec |
28 | }, | 27 | }, |
29 | { | 28 | { |
30 | .ctl_name = CTL_UNNUMBERED, | ||
31 | .procname = "xfrm_larval_drop", | 29 | .procname = "xfrm_larval_drop", |
32 | .maxlen = sizeof(int), | 30 | .maxlen = sizeof(int), |
33 | .mode = 0644, | 31 | .mode = 0644, |
34 | .proc_handler = proc_dointvec | 32 | .proc_handler = proc_dointvec |
35 | }, | 33 | }, |
36 | { | 34 | { |
37 | .ctl_name = CTL_UNNUMBERED, | ||
38 | .procname = "xfrm_acq_expires", | 35 | .procname = "xfrm_acq_expires", |
39 | .maxlen = sizeof(int), | 36 | .maxlen = sizeof(int), |
40 | .mode = 0644, | 37 | .mode = 0644, |
@@ -68,7 +65,7 @@ out_kmemdup: | |||
68 | return -ENOMEM; | 65 | return -ENOMEM; |
69 | } | 66 | } |
70 | 67 | ||
71 | void xfrm_sysctl_fini(struct net *net) | 68 | void __net_exit xfrm_sysctl_fini(struct net *net) |
72 | { | 69 | { |
73 | struct ctl_table *table; | 70 | struct ctl_table *table; |
74 | 71 | ||
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index b95a2d64eb59..6106b72826d3 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -62,6 +62,22 @@ static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) | |||
62 | return 0; | 62 | return 0; |
63 | } | 63 | } |
64 | 64 | ||
65 | static int verify_auth_trunc(struct nlattr **attrs) | ||
66 | { | ||
67 | struct nlattr *rt = attrs[XFRMA_ALG_AUTH_TRUNC]; | ||
68 | struct xfrm_algo_auth *algp; | ||
69 | |||
70 | if (!rt) | ||
71 | return 0; | ||
72 | |||
73 | algp = nla_data(rt); | ||
74 | if (nla_len(rt) < xfrm_alg_auth_len(algp)) | ||
75 | return -EINVAL; | ||
76 | |||
77 | algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; | ||
78 | return 0; | ||
79 | } | ||
80 | |||
65 | static int verify_aead(struct nlattr **attrs) | 81 | static int verify_aead(struct nlattr **attrs) |
66 | { | 82 | { |
67 | struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; | 83 | struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; |
@@ -128,7 +144,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
128 | err = -EINVAL; | 144 | err = -EINVAL; |
129 | switch (p->id.proto) { | 145 | switch (p->id.proto) { |
130 | case IPPROTO_AH: | 146 | case IPPROTO_AH: |
131 | if (!attrs[XFRMA_ALG_AUTH] || | 147 | if ((!attrs[XFRMA_ALG_AUTH] && |
148 | !attrs[XFRMA_ALG_AUTH_TRUNC]) || | ||
132 | attrs[XFRMA_ALG_AEAD] || | 149 | attrs[XFRMA_ALG_AEAD] || |
133 | attrs[XFRMA_ALG_CRYPT] || | 150 | attrs[XFRMA_ALG_CRYPT] || |
134 | attrs[XFRMA_ALG_COMP]) | 151 | attrs[XFRMA_ALG_COMP]) |
@@ -139,10 +156,12 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
139 | if (attrs[XFRMA_ALG_COMP]) | 156 | if (attrs[XFRMA_ALG_COMP]) |
140 | goto out; | 157 | goto out; |
141 | if (!attrs[XFRMA_ALG_AUTH] && | 158 | if (!attrs[XFRMA_ALG_AUTH] && |
159 | !attrs[XFRMA_ALG_AUTH_TRUNC] && | ||
142 | !attrs[XFRMA_ALG_CRYPT] && | 160 | !attrs[XFRMA_ALG_CRYPT] && |
143 | !attrs[XFRMA_ALG_AEAD]) | 161 | !attrs[XFRMA_ALG_AEAD]) |
144 | goto out; | 162 | goto out; |
145 | if ((attrs[XFRMA_ALG_AUTH] || | 163 | if ((attrs[XFRMA_ALG_AUTH] || |
164 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
146 | attrs[XFRMA_ALG_CRYPT]) && | 165 | attrs[XFRMA_ALG_CRYPT]) && |
147 | attrs[XFRMA_ALG_AEAD]) | 166 | attrs[XFRMA_ALG_AEAD]) |
148 | goto out; | 167 | goto out; |
@@ -152,6 +171,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
152 | if (!attrs[XFRMA_ALG_COMP] || | 171 | if (!attrs[XFRMA_ALG_COMP] || |
153 | attrs[XFRMA_ALG_AEAD] || | 172 | attrs[XFRMA_ALG_AEAD] || |
154 | attrs[XFRMA_ALG_AUTH] || | 173 | attrs[XFRMA_ALG_AUTH] || |
174 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
155 | attrs[XFRMA_ALG_CRYPT]) | 175 | attrs[XFRMA_ALG_CRYPT]) |
156 | goto out; | 176 | goto out; |
157 | break; | 177 | break; |
@@ -161,6 +181,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
161 | case IPPROTO_ROUTING: | 181 | case IPPROTO_ROUTING: |
162 | if (attrs[XFRMA_ALG_COMP] || | 182 | if (attrs[XFRMA_ALG_COMP] || |
163 | attrs[XFRMA_ALG_AUTH] || | 183 | attrs[XFRMA_ALG_AUTH] || |
184 | attrs[XFRMA_ALG_AUTH_TRUNC] || | ||
164 | attrs[XFRMA_ALG_AEAD] || | 185 | attrs[XFRMA_ALG_AEAD] || |
165 | attrs[XFRMA_ALG_CRYPT] || | 186 | attrs[XFRMA_ALG_CRYPT] || |
166 | attrs[XFRMA_ENCAP] || | 187 | attrs[XFRMA_ENCAP] || |
@@ -176,6 +197,8 @@ static int verify_newsa_info(struct xfrm_usersa_info *p, | |||
176 | 197 | ||
177 | if ((err = verify_aead(attrs))) | 198 | if ((err = verify_aead(attrs))) |
178 | goto out; | 199 | goto out; |
200 | if ((err = verify_auth_trunc(attrs))) | ||
201 | goto out; | ||
179 | if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) | 202 | if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) |
180 | goto out; | 203 | goto out; |
181 | if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) | 204 | if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) |
@@ -229,6 +252,66 @@ static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, | |||
229 | return 0; | 252 | return 0; |
230 | } | 253 | } |
231 | 254 | ||
255 | static int attach_auth(struct xfrm_algo_auth **algpp, u8 *props, | ||
256 | struct nlattr *rta) | ||
257 | { | ||
258 | struct xfrm_algo *ualg; | ||
259 | struct xfrm_algo_auth *p; | ||
260 | struct xfrm_algo_desc *algo; | ||
261 | |||
262 | if (!rta) | ||
263 | return 0; | ||
264 | |||
265 | ualg = nla_data(rta); | ||
266 | |||
267 | algo = xfrm_aalg_get_byname(ualg->alg_name, 1); | ||
268 | if (!algo) | ||
269 | return -ENOSYS; | ||
270 | *props = algo->desc.sadb_alg_id; | ||
271 | |||
272 | p = kmalloc(sizeof(*p) + (ualg->alg_key_len + 7) / 8, GFP_KERNEL); | ||
273 | if (!p) | ||
274 | return -ENOMEM; | ||
275 | |||
276 | strcpy(p->alg_name, algo->name); | ||
277 | p->alg_key_len = ualg->alg_key_len; | ||
278 | p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; | ||
279 | memcpy(p->alg_key, ualg->alg_key, (ualg->alg_key_len + 7) / 8); | ||
280 | |||
281 | *algpp = p; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int attach_auth_trunc(struct xfrm_algo_auth **algpp, u8 *props, | ||
286 | struct nlattr *rta) | ||
287 | { | ||
288 | struct xfrm_algo_auth *p, *ualg; | ||
289 | struct xfrm_algo_desc *algo; | ||
290 | |||
291 | if (!rta) | ||
292 | return 0; | ||
293 | |||
294 | ualg = nla_data(rta); | ||
295 | |||
296 | algo = xfrm_aalg_get_byname(ualg->alg_name, 1); | ||
297 | if (!algo) | ||
298 | return -ENOSYS; | ||
299 | if (ualg->alg_trunc_len > algo->uinfo.auth.icv_fullbits) | ||
300 | return -EINVAL; | ||
301 | *props = algo->desc.sadb_alg_id; | ||
302 | |||
303 | p = kmemdup(ualg, xfrm_alg_auth_len(ualg), GFP_KERNEL); | ||
304 | if (!p) | ||
305 | return -ENOMEM; | ||
306 | |||
307 | strcpy(p->alg_name, algo->name); | ||
308 | if (!p->alg_trunc_len) | ||
309 | p->alg_trunc_len = algo->uinfo.auth.icv_truncbits; | ||
310 | |||
311 | *algpp = p; | ||
312 | return 0; | ||
313 | } | ||
314 | |||
232 | static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, | 315 | static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, |
233 | struct nlattr *rta) | 316 | struct nlattr *rta) |
234 | { | 317 | { |
@@ -332,10 +415,14 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, | |||
332 | if ((err = attach_aead(&x->aead, &x->props.ealgo, | 415 | if ((err = attach_aead(&x->aead, &x->props.ealgo, |
333 | attrs[XFRMA_ALG_AEAD]))) | 416 | attrs[XFRMA_ALG_AEAD]))) |
334 | goto error; | 417 | goto error; |
335 | if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, | 418 | if ((err = attach_auth_trunc(&x->aalg, &x->props.aalgo, |
336 | xfrm_aalg_get_byname, | 419 | attrs[XFRMA_ALG_AUTH_TRUNC]))) |
337 | attrs[XFRMA_ALG_AUTH]))) | ||
338 | goto error; | 420 | goto error; |
421 | if (!x->props.aalgo) { | ||
422 | if ((err = attach_auth(&x->aalg, &x->props.aalgo, | ||
423 | attrs[XFRMA_ALG_AUTH]))) | ||
424 | goto error; | ||
425 | } | ||
339 | if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, | 426 | if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, |
340 | xfrm_ealg_get_byname, | 427 | xfrm_ealg_get_byname, |
341 | attrs[XFRMA_ALG_CRYPT]))) | 428 | attrs[XFRMA_ALG_CRYPT]))) |
@@ -359,6 +446,8 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, | |||
359 | goto error; | 446 | goto error; |
360 | } | 447 | } |
361 | 448 | ||
449 | xfrm_mark_get(attrs, &x->mark); | ||
450 | |||
362 | err = xfrm_init_state(x); | 451 | err = xfrm_init_state(x); |
363 | if (err) | 452 | if (err) |
364 | goto error; | 453 | goto error; |
@@ -439,11 +528,13 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net, | |||
439 | int *errp) | 528 | int *errp) |
440 | { | 529 | { |
441 | struct xfrm_state *x = NULL; | 530 | struct xfrm_state *x = NULL; |
531 | struct xfrm_mark m; | ||
442 | int err; | 532 | int err; |
533 | u32 mark = xfrm_mark_get(attrs, &m); | ||
443 | 534 | ||
444 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { | 535 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { |
445 | err = -ESRCH; | 536 | err = -ESRCH; |
446 | x = xfrm_state_lookup(net, &p->daddr, p->spi, p->proto, p->family); | 537 | x = xfrm_state_lookup(net, mark, &p->daddr, p->spi, p->proto, p->family); |
447 | } else { | 538 | } else { |
448 | xfrm_address_t *saddr = NULL; | 539 | xfrm_address_t *saddr = NULL; |
449 | 540 | ||
@@ -454,7 +545,8 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net, | |||
454 | } | 545 | } |
455 | 546 | ||
456 | err = -ESRCH; | 547 | err = -ESRCH; |
457 | x = xfrm_state_lookup_byaddr(net, &p->daddr, saddr, | 548 | x = xfrm_state_lookup_byaddr(net, mark, |
549 | &p->daddr, saddr, | ||
458 | p->proto, p->family); | 550 | p->proto, p->family); |
459 | } | 551 | } |
460 | 552 | ||
@@ -548,6 +640,24 @@ static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) | |||
548 | return 0; | 640 | return 0; |
549 | } | 641 | } |
550 | 642 | ||
643 | static int copy_to_user_auth(struct xfrm_algo_auth *auth, struct sk_buff *skb) | ||
644 | { | ||
645 | struct xfrm_algo *algo; | ||
646 | struct nlattr *nla; | ||
647 | |||
648 | nla = nla_reserve(skb, XFRMA_ALG_AUTH, | ||
649 | sizeof(*algo) + (auth->alg_key_len + 7) / 8); | ||
650 | if (!nla) | ||
651 | return -EMSGSIZE; | ||
652 | |||
653 | algo = nla_data(nla); | ||
654 | strcpy(algo->alg_name, auth->alg_name); | ||
655 | memcpy(algo->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8); | ||
656 | algo->alg_key_len = auth->alg_key_len; | ||
657 | |||
658 | return 0; | ||
659 | } | ||
660 | |||
551 | /* Don't change this without updating xfrm_sa_len! */ | 661 | /* Don't change this without updating xfrm_sa_len! */ |
552 | static int copy_to_user_state_extra(struct xfrm_state *x, | 662 | static int copy_to_user_state_extra(struct xfrm_state *x, |
553 | struct xfrm_usersa_info *p, | 663 | struct xfrm_usersa_info *p, |
@@ -563,8 +673,13 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
563 | 673 | ||
564 | if (x->aead) | 674 | if (x->aead) |
565 | NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); | 675 | NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); |
566 | if (x->aalg) | 676 | if (x->aalg) { |
567 | NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg); | 677 | if (copy_to_user_auth(x->aalg, skb)) |
678 | goto nla_put_failure; | ||
679 | |||
680 | NLA_PUT(skb, XFRMA_ALG_AUTH_TRUNC, | ||
681 | xfrm_alg_auth_len(x->aalg), x->aalg); | ||
682 | } | ||
568 | if (x->ealg) | 683 | if (x->ealg) |
569 | NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); | 684 | NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); |
570 | if (x->calg) | 685 | if (x->calg) |
@@ -573,6 +688,9 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
573 | if (x->encap) | 688 | if (x->encap) |
574 | NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); | 689 | NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); |
575 | 690 | ||
691 | if (xfrm_mark_put(skb, &x->mark)) | ||
692 | goto nla_put_failure; | ||
693 | |||
576 | if (x->security && copy_sec_ctx(x->security, skb) < 0) | 694 | if (x->security && copy_sec_ctx(x->security, skb) < 0) |
577 | goto nla_put_failure; | 695 | goto nla_put_failure; |
578 | 696 | ||
@@ -671,7 +789,8 @@ static inline size_t xfrm_spdinfo_msgsize(void) | |||
671 | + nla_total_size(sizeof(struct xfrmu_spdhinfo)); | 789 | + nla_total_size(sizeof(struct xfrmu_spdhinfo)); |
672 | } | 790 | } |
673 | 791 | ||
674 | static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) | 792 | static int build_spdinfo(struct sk_buff *skb, struct net *net, |
793 | u32 pid, u32 seq, u32 flags) | ||
675 | { | 794 | { |
676 | struct xfrmk_spdinfo si; | 795 | struct xfrmk_spdinfo si; |
677 | struct xfrmu_spdinfo spc; | 796 | struct xfrmu_spdinfo spc; |
@@ -685,7 +804,7 @@ static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) | |||
685 | 804 | ||
686 | f = nlmsg_data(nlh); | 805 | f = nlmsg_data(nlh); |
687 | *f = flags; | 806 | *f = flags; |
688 | xfrm_spd_getinfo(&si); | 807 | xfrm_spd_getinfo(net, &si); |
689 | spc.incnt = si.incnt; | 808 | spc.incnt = si.incnt; |
690 | spc.outcnt = si.outcnt; | 809 | spc.outcnt = si.outcnt; |
691 | spc.fwdcnt = si.fwdcnt; | 810 | spc.fwdcnt = si.fwdcnt; |
@@ -718,7 +837,7 @@ static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
718 | if (r_skb == NULL) | 837 | if (r_skb == NULL) |
719 | return -ENOMEM; | 838 | return -ENOMEM; |
720 | 839 | ||
721 | if (build_spdinfo(r_skb, spid, seq, *flags) < 0) | 840 | if (build_spdinfo(r_skb, net, spid, seq, *flags) < 0) |
722 | BUG(); | 841 | BUG(); |
723 | 842 | ||
724 | return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); | 843 | return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); |
@@ -731,7 +850,8 @@ static inline size_t xfrm_sadinfo_msgsize(void) | |||
731 | + nla_total_size(4); /* XFRMA_SAD_CNT */ | 850 | + nla_total_size(4); /* XFRMA_SAD_CNT */ |
732 | } | 851 | } |
733 | 852 | ||
734 | static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) | 853 | static int build_sadinfo(struct sk_buff *skb, struct net *net, |
854 | u32 pid, u32 seq, u32 flags) | ||
735 | { | 855 | { |
736 | struct xfrmk_sadinfo si; | 856 | struct xfrmk_sadinfo si; |
737 | struct xfrmu_sadhinfo sh; | 857 | struct xfrmu_sadhinfo sh; |
@@ -744,7 +864,7 @@ static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) | |||
744 | 864 | ||
745 | f = nlmsg_data(nlh); | 865 | f = nlmsg_data(nlh); |
746 | *f = flags; | 866 | *f = flags; |
747 | xfrm_sad_getinfo(&si); | 867 | xfrm_sad_getinfo(net, &si); |
748 | 868 | ||
749 | sh.sadhmcnt = si.sadhmcnt; | 869 | sh.sadhmcnt = si.sadhmcnt; |
750 | sh.sadhcnt = si.sadhcnt; | 870 | sh.sadhcnt = si.sadhcnt; |
@@ -772,7 +892,7 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
772 | if (r_skb == NULL) | 892 | if (r_skb == NULL) |
773 | return -ENOMEM; | 893 | return -ENOMEM; |
774 | 894 | ||
775 | if (build_sadinfo(r_skb, spid, seq, *flags) < 0) | 895 | if (build_sadinfo(r_skb, net, spid, seq, *flags) < 0) |
776 | BUG(); | 896 | BUG(); |
777 | 897 | ||
778 | return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); | 898 | return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); |
@@ -835,6 +955,8 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
835 | xfrm_address_t *daddr; | 955 | xfrm_address_t *daddr; |
836 | int family; | 956 | int family; |
837 | int err; | 957 | int err; |
958 | u32 mark; | ||
959 | struct xfrm_mark m; | ||
838 | 960 | ||
839 | p = nlmsg_data(nlh); | 961 | p = nlmsg_data(nlh); |
840 | err = verify_userspi_info(p); | 962 | err = verify_userspi_info(p); |
@@ -845,8 +967,10 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
845 | daddr = &p->info.id.daddr; | 967 | daddr = &p->info.id.daddr; |
846 | 968 | ||
847 | x = NULL; | 969 | x = NULL; |
970 | |||
971 | mark = xfrm_mark_get(attrs, &m); | ||
848 | if (p->info.seq) { | 972 | if (p->info.seq) { |
849 | x = xfrm_find_acq_byseq(net, p->info.seq); | 973 | x = xfrm_find_acq_byseq(net, mark, p->info.seq); |
850 | if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { | 974 | if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { |
851 | xfrm_state_put(x); | 975 | xfrm_state_put(x); |
852 | x = NULL; | 976 | x = NULL; |
@@ -854,7 +978,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
854 | } | 978 | } |
855 | 979 | ||
856 | if (!x) | 980 | if (!x) |
857 | x = xfrm_find_acq(net, p->info.mode, p->info.reqid, | 981 | x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid, |
858 | p->info.id.proto, daddr, | 982 | p->info.id.proto, daddr, |
859 | &p->info.saddr, 1, | 983 | &p->info.saddr, 1, |
860 | family); | 984 | family); |
@@ -1108,6 +1232,8 @@ static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_us | |||
1108 | if (err) | 1232 | if (err) |
1109 | goto error; | 1233 | goto error; |
1110 | 1234 | ||
1235 | xfrm_mark_get(attrs, &xp->mark); | ||
1236 | |||
1111 | return xp; | 1237 | return xp; |
1112 | error: | 1238 | error: |
1113 | *errp = err; | 1239 | *errp = err; |
@@ -1254,10 +1380,13 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr | |||
1254 | goto nlmsg_failure; | 1380 | goto nlmsg_failure; |
1255 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 1381 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
1256 | goto nlmsg_failure; | 1382 | goto nlmsg_failure; |
1383 | if (xfrm_mark_put(skb, &xp->mark)) | ||
1384 | goto nla_put_failure; | ||
1257 | 1385 | ||
1258 | nlmsg_end(skb, nlh); | 1386 | nlmsg_end(skb, nlh); |
1259 | return 0; | 1387 | return 0; |
1260 | 1388 | ||
1389 | nla_put_failure: | ||
1261 | nlmsg_failure: | 1390 | nlmsg_failure: |
1262 | nlmsg_cancel(skb, nlh); | 1391 | nlmsg_cancel(skb, nlh); |
1263 | return -EMSGSIZE; | 1392 | return -EMSGSIZE; |
@@ -1329,6 +1458,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1329 | int err; | 1458 | int err; |
1330 | struct km_event c; | 1459 | struct km_event c; |
1331 | int delete; | 1460 | int delete; |
1461 | struct xfrm_mark m; | ||
1462 | u32 mark = xfrm_mark_get(attrs, &m); | ||
1332 | 1463 | ||
1333 | p = nlmsg_data(nlh); | 1464 | p = nlmsg_data(nlh); |
1334 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; | 1465 | delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; |
@@ -1342,7 +1473,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1342 | return err; | 1473 | return err; |
1343 | 1474 | ||
1344 | if (p->index) | 1475 | if (p->index) |
1345 | xp = xfrm_policy_byid(net, type, p->dir, p->index, delete, &err); | 1476 | xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, delete, &err); |
1346 | else { | 1477 | else { |
1347 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; | 1478 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
1348 | struct xfrm_sec_ctx *ctx; | 1479 | struct xfrm_sec_ctx *ctx; |
@@ -1359,8 +1490,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1359 | if (err) | 1490 | if (err) |
1360 | return err; | 1491 | return err; |
1361 | } | 1492 | } |
1362 | xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx, | 1493 | xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, &p->sel, |
1363 | delete, &err); | 1494 | ctx, delete, &err); |
1364 | security_xfrm_policy_free(ctx); | 1495 | security_xfrm_policy_free(ctx); |
1365 | } | 1496 | } |
1366 | if (xp == NULL) | 1497 | if (xp == NULL) |
@@ -1412,8 +1543,11 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1412 | audit_info.sessionid = NETLINK_CB(skb).sessionid; | 1543 | audit_info.sessionid = NETLINK_CB(skb).sessionid; |
1413 | audit_info.secid = NETLINK_CB(skb).sid; | 1544 | audit_info.secid = NETLINK_CB(skb).sid; |
1414 | err = xfrm_state_flush(net, p->proto, &audit_info); | 1545 | err = xfrm_state_flush(net, p->proto, &audit_info); |
1415 | if (err) | 1546 | if (err) { |
1547 | if (err == -ESRCH) /* empty table */ | ||
1548 | return 0; | ||
1416 | return err; | 1549 | return err; |
1550 | } | ||
1417 | c.data.proto = p->proto; | 1551 | c.data.proto = p->proto; |
1418 | c.event = nlh->nlmsg_type; | 1552 | c.event = nlh->nlmsg_type; |
1419 | c.seq = nlh->nlmsg_seq; | 1553 | c.seq = nlh->nlmsg_seq; |
@@ -1429,6 +1563,7 @@ static inline size_t xfrm_aevent_msgsize(void) | |||
1429 | return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) | 1563 | return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) |
1430 | + nla_total_size(sizeof(struct xfrm_replay_state)) | 1564 | + nla_total_size(sizeof(struct xfrm_replay_state)) |
1431 | + nla_total_size(sizeof(struct xfrm_lifetime_cur)) | 1565 | + nla_total_size(sizeof(struct xfrm_lifetime_cur)) |
1566 | + nla_total_size(sizeof(struct xfrm_mark)) | ||
1432 | + nla_total_size(4) /* XFRM_AE_RTHR */ | 1567 | + nla_total_size(4) /* XFRM_AE_RTHR */ |
1433 | + nla_total_size(4); /* XFRM_AE_ETHR */ | 1568 | + nla_total_size(4); /* XFRM_AE_ETHR */ |
1434 | } | 1569 | } |
@@ -1461,6 +1596,9 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve | |||
1461 | NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH, | 1596 | NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH, |
1462 | x->replay_maxage * 10 / HZ); | 1597 | x->replay_maxage * 10 / HZ); |
1463 | 1598 | ||
1599 | if (xfrm_mark_put(skb, &x->mark)) | ||
1600 | goto nla_put_failure; | ||
1601 | |||
1464 | return nlmsg_end(skb, nlh); | 1602 | return nlmsg_end(skb, nlh); |
1465 | 1603 | ||
1466 | nla_put_failure: | 1604 | nla_put_failure: |
@@ -1476,6 +1614,8 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1476 | struct sk_buff *r_skb; | 1614 | struct sk_buff *r_skb; |
1477 | int err; | 1615 | int err; |
1478 | struct km_event c; | 1616 | struct km_event c; |
1617 | u32 mark; | ||
1618 | struct xfrm_mark m; | ||
1479 | struct xfrm_aevent_id *p = nlmsg_data(nlh); | 1619 | struct xfrm_aevent_id *p = nlmsg_data(nlh); |
1480 | struct xfrm_usersa_id *id = &p->sa_id; | 1620 | struct xfrm_usersa_id *id = &p->sa_id; |
1481 | 1621 | ||
@@ -1483,7 +1623,9 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1483 | if (r_skb == NULL) | 1623 | if (r_skb == NULL) |
1484 | return -ENOMEM; | 1624 | return -ENOMEM; |
1485 | 1625 | ||
1486 | x = xfrm_state_lookup(net, &id->daddr, id->spi, id->proto, id->family); | 1626 | mark = xfrm_mark_get(attrs, &m); |
1627 | |||
1628 | x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family); | ||
1487 | if (x == NULL) { | 1629 | if (x == NULL) { |
1488 | kfree_skb(r_skb); | 1630 | kfree_skb(r_skb); |
1489 | return -ESRCH; | 1631 | return -ESRCH; |
@@ -1514,6 +1656,8 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1514 | struct xfrm_state *x; | 1656 | struct xfrm_state *x; |
1515 | struct km_event c; | 1657 | struct km_event c; |
1516 | int err = - EINVAL; | 1658 | int err = - EINVAL; |
1659 | u32 mark = 0; | ||
1660 | struct xfrm_mark m; | ||
1517 | struct xfrm_aevent_id *p = nlmsg_data(nlh); | 1661 | struct xfrm_aevent_id *p = nlmsg_data(nlh); |
1518 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; | 1662 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; |
1519 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; | 1663 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; |
@@ -1525,7 +1669,9 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1525 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) | 1669 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) |
1526 | return err; | 1670 | return err; |
1527 | 1671 | ||
1528 | x = xfrm_state_lookup(net, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | 1672 | mark = xfrm_mark_get(attrs, &m); |
1673 | |||
1674 | x = xfrm_state_lookup(net, mark, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | ||
1529 | if (x == NULL) | 1675 | if (x == NULL) |
1530 | return -ESRCH; | 1676 | return -ESRCH; |
1531 | 1677 | ||
@@ -1564,8 +1710,12 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1564 | audit_info.sessionid = NETLINK_CB(skb).sessionid; | 1710 | audit_info.sessionid = NETLINK_CB(skb).sessionid; |
1565 | audit_info.secid = NETLINK_CB(skb).sid; | 1711 | audit_info.secid = NETLINK_CB(skb).sid; |
1566 | err = xfrm_policy_flush(net, type, &audit_info); | 1712 | err = xfrm_policy_flush(net, type, &audit_info); |
1567 | if (err) | 1713 | if (err) { |
1714 | if (err == -ESRCH) /* empty table */ | ||
1715 | return 0; | ||
1568 | return err; | 1716 | return err; |
1717 | } | ||
1718 | |||
1569 | c.data.type = type; | 1719 | c.data.type = type; |
1570 | c.event = nlh->nlmsg_type; | 1720 | c.event = nlh->nlmsg_type; |
1571 | c.seq = nlh->nlmsg_seq; | 1721 | c.seq = nlh->nlmsg_seq; |
@@ -1584,13 +1734,15 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1584 | struct xfrm_userpolicy_info *p = &up->pol; | 1734 | struct xfrm_userpolicy_info *p = &up->pol; |
1585 | u8 type = XFRM_POLICY_TYPE_MAIN; | 1735 | u8 type = XFRM_POLICY_TYPE_MAIN; |
1586 | int err = -ENOENT; | 1736 | int err = -ENOENT; |
1737 | struct xfrm_mark m; | ||
1738 | u32 mark = xfrm_mark_get(attrs, &m); | ||
1587 | 1739 | ||
1588 | err = copy_from_user_policy_type(&type, attrs); | 1740 | err = copy_from_user_policy_type(&type, attrs); |
1589 | if (err) | 1741 | if (err) |
1590 | return err; | 1742 | return err; |
1591 | 1743 | ||
1592 | if (p->index) | 1744 | if (p->index) |
1593 | xp = xfrm_policy_byid(net, type, p->dir, p->index, 0, &err); | 1745 | xp = xfrm_policy_byid(net, mark, type, p->dir, p->index, 0, &err); |
1594 | else { | 1746 | else { |
1595 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; | 1747 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
1596 | struct xfrm_sec_ctx *ctx; | 1748 | struct xfrm_sec_ctx *ctx; |
@@ -1607,7 +1759,8 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1607 | if (err) | 1759 | if (err) |
1608 | return err; | 1760 | return err; |
1609 | } | 1761 | } |
1610 | xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx, 0, &err); | 1762 | xp = xfrm_policy_bysel_ctx(net, mark, type, p->dir, |
1763 | &p->sel, ctx, 0, &err); | ||
1611 | security_xfrm_policy_free(ctx); | 1764 | security_xfrm_policy_free(ctx); |
1612 | } | 1765 | } |
1613 | if (xp == NULL) | 1766 | if (xp == NULL) |
@@ -1647,8 +1800,10 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1647 | int err; | 1800 | int err; |
1648 | struct xfrm_user_expire *ue = nlmsg_data(nlh); | 1801 | struct xfrm_user_expire *ue = nlmsg_data(nlh); |
1649 | struct xfrm_usersa_info *p = &ue->state; | 1802 | struct xfrm_usersa_info *p = &ue->state; |
1803 | struct xfrm_mark m; | ||
1804 | u32 mark = xfrm_mark_get(attrs, &m);; | ||
1650 | 1805 | ||
1651 | x = xfrm_state_lookup(net, &p->id.daddr, p->id.spi, p->id.proto, p->family); | 1806 | x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family); |
1652 | 1807 | ||
1653 | err = -ENOENT; | 1808 | err = -ENOENT; |
1654 | if (x == NULL) | 1809 | if (x == NULL) |
@@ -1682,6 +1837,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1682 | struct xfrm_user_tmpl *ut; | 1837 | struct xfrm_user_tmpl *ut; |
1683 | int i; | 1838 | int i; |
1684 | struct nlattr *rt = attrs[XFRMA_TMPL]; | 1839 | struct nlattr *rt = attrs[XFRMA_TMPL]; |
1840 | struct xfrm_mark mark; | ||
1685 | 1841 | ||
1686 | struct xfrm_user_acquire *ua = nlmsg_data(nlh); | 1842 | struct xfrm_user_acquire *ua = nlmsg_data(nlh); |
1687 | struct xfrm_state *x = xfrm_state_alloc(net); | 1843 | struct xfrm_state *x = xfrm_state_alloc(net); |
@@ -1690,6 +1846,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1690 | if (!x) | 1846 | if (!x) |
1691 | goto nomem; | 1847 | goto nomem; |
1692 | 1848 | ||
1849 | xfrm_mark_get(attrs, &mark); | ||
1850 | |||
1693 | err = verify_newpolicy_info(&ua->policy); | 1851 | err = verify_newpolicy_info(&ua->policy); |
1694 | if (err) | 1852 | if (err) |
1695 | goto bad_policy; | 1853 | goto bad_policy; |
@@ -1702,7 +1860,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1702 | memcpy(&x->id, &ua->id, sizeof(ua->id)); | 1860 | memcpy(&x->id, &ua->id, sizeof(ua->id)); |
1703 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); | 1861 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); |
1704 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); | 1862 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); |
1705 | 1863 | xp->mark.m = x->mark.m = mark.m; | |
1864 | xp->mark.v = x->mark.v = mark.v; | ||
1706 | ut = nla_data(rt); | 1865 | ut = nla_data(rt); |
1707 | /* extract the templates and for each call km_key */ | 1866 | /* extract the templates and for each call km_key */ |
1708 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { | 1867 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { |
@@ -1942,6 +2101,10 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
1942 | #undef XMSGSIZE | 2101 | #undef XMSGSIZE |
1943 | 2102 | ||
1944 | static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | 2103 | static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { |
2104 | [XFRMA_SA] = { .len = sizeof(struct xfrm_usersa_info)}, | ||
2105 | [XFRMA_POLICY] = { .len = sizeof(struct xfrm_userpolicy_info)}, | ||
2106 | [XFRMA_LASTUSED] = { .type = NLA_U64}, | ||
2107 | [XFRMA_ALG_AUTH_TRUNC] = { .len = sizeof(struct xfrm_algo_auth)}, | ||
1945 | [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, | 2108 | [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, |
1946 | [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, | 2109 | [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, |
1947 | [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, | 2110 | [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, |
@@ -1958,6 +2121,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
1958 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, | 2121 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, |
1959 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, | 2122 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, |
1960 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, | 2123 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, |
2124 | [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, | ||
1961 | }; | 2125 | }; |
1962 | 2126 | ||
1963 | static struct xfrm_link { | 2127 | static struct xfrm_link { |
@@ -2037,7 +2201,8 @@ static void xfrm_netlink_rcv(struct sk_buff *skb) | |||
2037 | 2201 | ||
2038 | static inline size_t xfrm_expire_msgsize(void) | 2202 | static inline size_t xfrm_expire_msgsize(void) |
2039 | { | 2203 | { |
2040 | return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)); | 2204 | return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) |
2205 | + nla_total_size(sizeof(struct xfrm_mark)); | ||
2041 | } | 2206 | } |
2042 | 2207 | ||
2043 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) | 2208 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) |
@@ -2053,7 +2218,13 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve | |||
2053 | copy_to_user_state(x, &ue->state); | 2218 | copy_to_user_state(x, &ue->state); |
2054 | ue->hard = (c->data.hard != 0) ? 1 : 0; | 2219 | ue->hard = (c->data.hard != 0) ? 1 : 0; |
2055 | 2220 | ||
2221 | if (xfrm_mark_put(skb, &x->mark)) | ||
2222 | goto nla_put_failure; | ||
2223 | |||
2056 | return nlmsg_end(skb, nlh); | 2224 | return nlmsg_end(skb, nlh); |
2225 | |||
2226 | nla_put_failure: | ||
2227 | return -EMSGSIZE; | ||
2057 | } | 2228 | } |
2058 | 2229 | ||
2059 | static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | 2230 | static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) |
@@ -2065,8 +2236,10 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | |||
2065 | if (skb == NULL) | 2236 | if (skb == NULL) |
2066 | return -ENOMEM; | 2237 | return -ENOMEM; |
2067 | 2238 | ||
2068 | if (build_expire(skb, x, c) < 0) | 2239 | if (build_expire(skb, x, c) < 0) { |
2069 | BUG(); | 2240 | kfree_skb(skb); |
2241 | return -EMSGSIZE; | ||
2242 | } | ||
2070 | 2243 | ||
2071 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 2244 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); |
2072 | } | 2245 | } |
@@ -2117,8 +2290,11 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) | |||
2117 | size_t l = 0; | 2290 | size_t l = 0; |
2118 | if (x->aead) | 2291 | if (x->aead) |
2119 | l += nla_total_size(aead_len(x->aead)); | 2292 | l += nla_total_size(aead_len(x->aead)); |
2120 | if (x->aalg) | 2293 | if (x->aalg) { |
2121 | l += nla_total_size(xfrm_alg_len(x->aalg)); | 2294 | l += nla_total_size(sizeof(struct xfrm_algo) + |
2295 | (x->aalg->alg_key_len + 7) / 8); | ||
2296 | l += nla_total_size(xfrm_alg_auth_len(x->aalg)); | ||
2297 | } | ||
2122 | if (x->ealg) | 2298 | if (x->ealg) |
2123 | l += nla_total_size(xfrm_alg_len(x->ealg)); | 2299 | l += nla_total_size(xfrm_alg_len(x->ealg)); |
2124 | if (x->calg) | 2300 | if (x->calg) |
@@ -2151,6 +2327,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) | |||
2151 | if (c->event == XFRM_MSG_DELSA) { | 2327 | if (c->event == XFRM_MSG_DELSA) { |
2152 | len += nla_total_size(headlen); | 2328 | len += nla_total_size(headlen); |
2153 | headlen = sizeof(*id); | 2329 | headlen = sizeof(*id); |
2330 | len += nla_total_size(sizeof(struct xfrm_mark)); | ||
2154 | } | 2331 | } |
2155 | len += NLMSG_ALIGN(headlen); | 2332 | len += NLMSG_ALIGN(headlen); |
2156 | 2333 | ||
@@ -2221,6 +2398,7 @@ static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x, | |||
2221 | { | 2398 | { |
2222 | return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) | 2399 | return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) |
2223 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) | 2400 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) |
2401 | + nla_total_size(sizeof(struct xfrm_mark)) | ||
2224 | + nla_total_size(xfrm_user_sec_ctx_size(x->security)) | 2402 | + nla_total_size(xfrm_user_sec_ctx_size(x->security)) |
2225 | + userpolicy_type_attrsize(); | 2403 | + userpolicy_type_attrsize(); |
2226 | } | 2404 | } |
@@ -2253,9 +2431,12 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, | |||
2253 | goto nlmsg_failure; | 2431 | goto nlmsg_failure; |
2254 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 2432 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
2255 | goto nlmsg_failure; | 2433 | goto nlmsg_failure; |
2434 | if (xfrm_mark_put(skb, &xp->mark)) | ||
2435 | goto nla_put_failure; | ||
2256 | 2436 | ||
2257 | return nlmsg_end(skb, nlh); | 2437 | return nlmsg_end(skb, nlh); |
2258 | 2438 | ||
2439 | nla_put_failure: | ||
2259 | nlmsg_failure: | 2440 | nlmsg_failure: |
2260 | nlmsg_cancel(skb, nlh); | 2441 | nlmsg_cancel(skb, nlh); |
2261 | return -EMSGSIZE; | 2442 | return -EMSGSIZE; |
@@ -2342,6 +2523,7 @@ static inline size_t xfrm_polexpire_msgsize(struct xfrm_policy *xp) | |||
2342 | return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire)) | 2523 | return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire)) |
2343 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) | 2524 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) |
2344 | + nla_total_size(xfrm_user_sec_ctx_size(xp->security)) | 2525 | + nla_total_size(xfrm_user_sec_ctx_size(xp->security)) |
2526 | + nla_total_size(sizeof(struct xfrm_mark)) | ||
2345 | + userpolicy_type_attrsize(); | 2527 | + userpolicy_type_attrsize(); |
2346 | } | 2528 | } |
2347 | 2529 | ||
@@ -2364,10 +2546,13 @@ static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, | |||
2364 | goto nlmsg_failure; | 2546 | goto nlmsg_failure; |
2365 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 2547 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
2366 | goto nlmsg_failure; | 2548 | goto nlmsg_failure; |
2549 | if (xfrm_mark_put(skb, &xp->mark)) | ||
2550 | goto nla_put_failure; | ||
2367 | upe->hard = !!hard; | 2551 | upe->hard = !!hard; |
2368 | 2552 | ||
2369 | return nlmsg_end(skb, nlh); | 2553 | return nlmsg_end(skb, nlh); |
2370 | 2554 | ||
2555 | nla_put_failure: | ||
2371 | nlmsg_failure: | 2556 | nlmsg_failure: |
2372 | nlmsg_cancel(skb, nlh); | 2557 | nlmsg_cancel(skb, nlh); |
2373 | return -EMSGSIZE; | 2558 | return -EMSGSIZE; |
@@ -2404,6 +2589,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * | |||
2404 | headlen = sizeof(*id); | 2589 | headlen = sizeof(*id); |
2405 | } | 2590 | } |
2406 | len += userpolicy_type_attrsize(); | 2591 | len += userpolicy_type_attrsize(); |
2592 | len += nla_total_size(sizeof(struct xfrm_mark)); | ||
2407 | len += NLMSG_ALIGN(headlen); | 2593 | len += NLMSG_ALIGN(headlen); |
2408 | 2594 | ||
2409 | skb = nlmsg_new(len, GFP_ATOMIC); | 2595 | skb = nlmsg_new(len, GFP_ATOMIC); |
@@ -2439,10 +2625,14 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * | |||
2439 | if (copy_to_user_policy_type(xp->type, skb) < 0) | 2625 | if (copy_to_user_policy_type(xp->type, skb) < 0) |
2440 | goto nlmsg_failure; | 2626 | goto nlmsg_failure; |
2441 | 2627 | ||
2628 | if (xfrm_mark_put(skb, &xp->mark)) | ||
2629 | goto nla_put_failure; | ||
2630 | |||
2442 | nlmsg_end(skb, nlh); | 2631 | nlmsg_end(skb, nlh); |
2443 | 2632 | ||
2444 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); | 2633 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); |
2445 | 2634 | ||
2635 | nla_put_failure: | ||
2446 | nlmsg_failure: | 2636 | nlmsg_failure: |
2447 | kfree_skb(skb); | 2637 | kfree_skb(skb); |
2448 | return -1; | 2638 | return -1; |
@@ -2608,22 +2798,24 @@ static int __net_init xfrm_user_net_init(struct net *net) | |||
2608 | xfrm_netlink_rcv, NULL, THIS_MODULE); | 2798 | xfrm_netlink_rcv, NULL, THIS_MODULE); |
2609 | if (nlsk == NULL) | 2799 | if (nlsk == NULL) |
2610 | return -ENOMEM; | 2800 | return -ENOMEM; |
2801 | net->xfrm.nlsk_stash = nlsk; /* Don't set to NULL */ | ||
2611 | rcu_assign_pointer(net->xfrm.nlsk, nlsk); | 2802 | rcu_assign_pointer(net->xfrm.nlsk, nlsk); |
2612 | return 0; | 2803 | return 0; |
2613 | } | 2804 | } |
2614 | 2805 | ||
2615 | static void __net_exit xfrm_user_net_exit(struct net *net) | 2806 | static void __net_exit xfrm_user_net_exit(struct list_head *net_exit_list) |
2616 | { | 2807 | { |
2617 | struct sock *nlsk = net->xfrm.nlsk; | 2808 | struct net *net; |
2618 | 2809 | list_for_each_entry(net, net_exit_list, exit_list) | |
2619 | rcu_assign_pointer(net->xfrm.nlsk, NULL); | 2810 | rcu_assign_pointer(net->xfrm.nlsk, NULL); |
2620 | synchronize_rcu(); | 2811 | synchronize_net(); |
2621 | netlink_kernel_release(nlsk); | 2812 | list_for_each_entry(net, net_exit_list, exit_list) |
2813 | netlink_kernel_release(net->xfrm.nlsk_stash); | ||
2622 | } | 2814 | } |
2623 | 2815 | ||
2624 | static struct pernet_operations xfrm_user_net_ops = { | 2816 | static struct pernet_operations xfrm_user_net_ops = { |
2625 | .init = xfrm_user_net_init, | 2817 | .init = xfrm_user_net_init, |
2626 | .exit = xfrm_user_net_exit, | 2818 | .exit_batch = xfrm_user_net_exit, |
2627 | }; | 2819 | }; |
2628 | 2820 | ||
2629 | static int __init xfrm_user_init(void) | 2821 | static int __init xfrm_user_init(void) |