aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/xfrm.h1
-rw-r--r--net/ipv4/xfrm4_output.c12
-rw-r--r--net/ipv6/xfrm6_output.c21
-rw-r--r--net/xfrm/xfrm_input.c34
-rw-r--r--net/xfrm/xfrm_output.c12
-rw-r--r--net/xfrm/xfrm_policy.c10
-rw-r--r--net/xfrm/xfrm_state.c4
7 files changed, 80 insertions, 14 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 4351444c10fc..8d1c9506bcf6 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -423,7 +423,6 @@ int xfrm_register_type_offload(const struct xfrm_type_offload *type, unsigned sh
423int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family); 423int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family);
424 424
425struct xfrm_mode { 425struct xfrm_mode {
426 struct xfrm_state_afinfo *afinfo;
427 struct module *owner; 426 struct module *owner;
428 u8 encap; 427 u8 encap;
429 u8 family; 428 u8 family;
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 6802d1aee424..7c3df14daef3 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -72,6 +72,8 @@ int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb)
72static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) 72static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
73{ 73{
74 struct xfrm_state *x = skb_dst(skb)->xfrm; 74 struct xfrm_state *x = skb_dst(skb)->xfrm;
75 const struct xfrm_state_afinfo *afinfo;
76 int ret = -EAFNOSUPPORT;
75 77
76#ifdef CONFIG_NETFILTER 78#ifdef CONFIG_NETFILTER
77 if (!x) { 79 if (!x) {
@@ -80,7 +82,15 @@ static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
80 } 82 }
81#endif 83#endif
82 84
83 return x->outer_mode->afinfo->output_finish(sk, skb); 85 rcu_read_lock();
86 afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
87 if (likely(afinfo))
88 ret = afinfo->output_finish(sk, skb);
89 else
90 kfree_skb(skb);
91 rcu_read_unlock();
92
93 return ret;
84} 94}
85 95
86int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) 96int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 2b663d2ffdcd..455fbf3b91cf 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -122,11 +122,28 @@ int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb)
122 return xfrm_output(sk, skb); 122 return xfrm_output(sk, skb);
123} 123}
124 124
125static int __xfrm6_output_state_finish(struct xfrm_state *x, struct sock *sk,
126 struct sk_buff *skb)
127{
128 const struct xfrm_state_afinfo *afinfo;
129 int ret = -EAFNOSUPPORT;
130
131 rcu_read_lock();
132 afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
133 if (likely(afinfo))
134 ret = afinfo->output_finish(sk, skb);
135 else
136 kfree_skb(skb);
137 rcu_read_unlock();
138
139 return ret;
140}
141
125static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb) 142static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
126{ 143{
127 struct xfrm_state *x = skb_dst(skb)->xfrm; 144 struct xfrm_state *x = skb_dst(skb)->xfrm;
128 145
129 return x->outer_mode->afinfo->output_finish(sk, skb); 146 return __xfrm6_output_state_finish(x, sk, skb);
130} 147}
131 148
132static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) 149static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
@@ -168,7 +185,7 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
168 __xfrm6_output_finish); 185 __xfrm6_output_finish);
169 186
170skip_frag: 187skip_frag:
171 return x->outer_mode->afinfo->output_finish(sk, skb); 188 return __xfrm6_output_state_finish(x, sk, skb);
172} 189}
173 190
174int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) 191int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index e0fd9561ffe5..74b53c13279b 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -352,19 +352,35 @@ xfrm_inner_mode_encap_remove(struct xfrm_state *x,
352static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) 352static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
353{ 353{
354 struct xfrm_mode *inner_mode = x->inner_mode; 354 struct xfrm_mode *inner_mode = x->inner_mode;
355 int err; 355 const struct xfrm_state_afinfo *afinfo;
356 int err = -EAFNOSUPPORT;
356 357
357 err = x->outer_mode->afinfo->extract_input(x, skb); 358 rcu_read_lock();
358 if (err) 359 afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
360 if (likely(afinfo))
361 err = afinfo->extract_input(x, skb);
362
363 if (err) {
364 rcu_read_unlock();
359 return err; 365 return err;
366 }
360 367
361 if (x->sel.family == AF_UNSPEC) { 368 if (x->sel.family == AF_UNSPEC) {
362 inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); 369 inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
363 if (inner_mode == NULL) 370 if (!inner_mode) {
371 rcu_read_unlock();
364 return -EAFNOSUPPORT; 372 return -EAFNOSUPPORT;
373 }
365 } 374 }
366 375
367 skb->protocol = inner_mode->afinfo->eth_proto; 376 afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
377 if (unlikely(!afinfo)) {
378 rcu_read_unlock();
379 return -EAFNOSUPPORT;
380 }
381
382 skb->protocol = afinfo->eth_proto;
383 rcu_read_unlock();
368 return xfrm_inner_mode_encap_remove(x, inner_mode, skb); 384 return xfrm_inner_mode_encap_remove(x, inner_mode, skb);
369} 385}
370 386
@@ -440,6 +456,7 @@ static int xfrm_inner_mode_input(struct xfrm_state *x,
440 456
441int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) 457int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
442{ 458{
459 const struct xfrm_state_afinfo *afinfo;
443 struct net *net = dev_net(skb->dev); 460 struct net *net = dev_net(skb->dev);
444 int err; 461 int err;
445 __be32 seq; 462 __be32 seq;
@@ -705,7 +722,12 @@ resume:
705 if (xo) 722 if (xo)
706 xfrm_gro = xo->flags & XFRM_GRO; 723 xfrm_gro = xo->flags & XFRM_GRO;
707 724
708 err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async); 725 err = -EAFNOSUPPORT;
726 rcu_read_lock();
727 afinfo = xfrm_state_afinfo_get_rcu(x->inner_mode->family);
728 if (likely(afinfo))
729 err = afinfo->transport_finish(skb, xfrm_gro || async);
730 rcu_read_unlock();
709 if (xfrm_gro) { 731 if (xfrm_gro) {
710 sp = skb_sec_path(skb); 732 sp = skb_sec_path(skb);
711 if (sp) 733 if (sp)
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 9bdf16f13606..17c4f58d28ea 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -623,7 +623,10 @@ EXPORT_SYMBOL_GPL(xfrm_output);
623 623
624static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) 624static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
625{ 625{
626 const struct xfrm_state_afinfo *afinfo;
626 struct xfrm_mode *inner_mode; 627 struct xfrm_mode *inner_mode;
628 int err = -EAFNOSUPPORT;
629
627 if (x->sel.family == AF_UNSPEC) 630 if (x->sel.family == AF_UNSPEC)
628 inner_mode = xfrm_ip2inner_mode(x, 631 inner_mode = xfrm_ip2inner_mode(x,
629 xfrm_af2proto(skb_dst(skb)->ops->family)); 632 xfrm_af2proto(skb_dst(skb)->ops->family));
@@ -632,7 +635,14 @@ static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
632 635
633 if (inner_mode == NULL) 636 if (inner_mode == NULL)
634 return -EAFNOSUPPORT; 637 return -EAFNOSUPPORT;
635 return inner_mode->afinfo->extract_output(x, skb); 638
639 rcu_read_lock();
640 afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
641 if (likely(afinfo))
642 err = afinfo->extract_output(x, skb);
643 rcu_read_unlock();
644
645 return err;
636} 646}
637 647
638void xfrm_local_error(struct sk_buff *skb, int mtu) 648void xfrm_local_error(struct sk_buff *skb, int mtu)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 8d1a898d0ba5..67122beb116c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2545,6 +2545,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
2545 const struct flowi *fl, 2545 const struct flowi *fl,
2546 struct dst_entry *dst) 2546 struct dst_entry *dst)
2547{ 2547{
2548 const struct xfrm_state_afinfo *afinfo;
2548 struct net *net = xp_net(policy); 2549 struct net *net = xp_net(policy);
2549 unsigned long now = jiffies; 2550 unsigned long now = jiffies;
2550 struct net_device *dev; 2551 struct net_device *dev;
@@ -2622,7 +2623,14 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
2622 dst1->lastuse = now; 2623 dst1->lastuse = now;
2623 2624
2624 dst1->input = dst_discard; 2625 dst1->input = dst_discard;
2625 dst1->output = inner_mode->afinfo->output; 2626
2627 rcu_read_lock();
2628 afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
2629 if (likely(afinfo))
2630 dst1->output = afinfo->output;
2631 else
2632 dst1->output = dst_discard_out;
2633 rcu_read_unlock();
2626 2634
2627 xdst_prev = xdst; 2635 xdst_prev = xdst;
2628 2636
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index c32394b59776..358b09f0d018 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -354,7 +354,6 @@ int xfrm_register_mode(struct xfrm_mode *mode)
354 if (!try_module_get(afinfo->owner)) 354 if (!try_module_get(afinfo->owner))
355 goto out; 355 goto out;
356 356
357 mode->afinfo = afinfo;
358 modemap[mode->encap] = mode; 357 modemap[mode->encap] = mode;
359 err = 0; 358 err = 0;
360 359
@@ -378,7 +377,7 @@ void xfrm_unregister_mode(struct xfrm_mode *mode)
378 spin_lock_bh(&xfrm_mode_lock); 377 spin_lock_bh(&xfrm_mode_lock);
379 if (likely(modemap[mode->encap] == mode)) { 378 if (likely(modemap[mode->encap] == mode)) {
380 modemap[mode->encap] = NULL; 379 modemap[mode->encap] = NULL;
381 module_put(mode->afinfo->owner); 380 module_put(afinfo->owner);
382 } 381 }
383 382
384 spin_unlock_bh(&xfrm_mode_lock); 383 spin_unlock_bh(&xfrm_mode_lock);
@@ -2188,6 +2187,7 @@ struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family)
2188 2187
2189 return rcu_dereference(xfrm_state_afinfo[family]); 2188 return rcu_dereference(xfrm_state_afinfo[family]);
2190} 2189}
2190EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu);
2191 2191
2192struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) 2192struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
2193{ 2193{