aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-06-08 23:06:56 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-08 23:06:56 -0400
commit941742f49762ba4c908510f036b09a46c1b14513 (patch)
treeaafb7a72c2072f98889406668003234bed56df02 /net/ipv6
parentac7ba51c215db5739eb640f2f26025ced8668285 (diff)
parent5879ae5fd052a63d5ac0684320cb7df3e83da7de (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/addrconf_core.c11
-rw-r--r--net/ipv6/ip6_input.c8
2 files changed, 14 insertions, 5 deletions
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
index d873ceea86e6..ca09bf49ac68 100644
--- a/net/ipv6/addrconf_core.c
+++ b/net/ipv6/addrconf_core.c
@@ -133,6 +133,14 @@ static void snmp6_free_dev(struct inet6_dev *idev)
133 free_percpu(idev->stats.ipv6); 133 free_percpu(idev->stats.ipv6);
134} 134}
135 135
136static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
137{
138 struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
139
140 snmp6_free_dev(idev);
141 kfree(idev);
142}
143
136/* Nobody refers to this device, we may destroy it. */ 144/* Nobody refers to this device, we may destroy it. */
137 145
138void in6_dev_finish_destroy(struct inet6_dev *idev) 146void in6_dev_finish_destroy(struct inet6_dev *idev)
@@ -151,7 +159,6 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
151 pr_warn("Freeing alive inet6 device %p\n", idev); 159 pr_warn("Freeing alive inet6 device %p\n", idev);
152 return; 160 return;
153 } 161 }
154 snmp6_free_dev(idev); 162 call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
155 kfree_rcu(idev, rcu);
156} 163}
157EXPORT_SYMBOL(in6_dev_finish_destroy); 164EXPORT_SYMBOL(in6_dev_finish_destroy);
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index f2e464eba5ef..41a73da371a9 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -212,13 +212,13 @@ static int ip6_input_finish(struct sock *sk, struct sk_buff *skb)
212 */ 212 */
213 213
214 rcu_read_lock(); 214 rcu_read_lock();
215resubmit:
216 idev = ip6_dst_idev(skb_dst(skb)); 215 idev = ip6_dst_idev(skb_dst(skb));
217 if (!pskb_pull(skb, skb_transport_offset(skb))) 216 if (!pskb_pull(skb, skb_transport_offset(skb)))
218 goto discard; 217 goto discard;
219 nhoff = IP6CB(skb)->nhoff; 218 nhoff = IP6CB(skb)->nhoff;
220 nexthdr = skb_network_header(skb)[nhoff]; 219 nexthdr = skb_network_header(skb)[nhoff];
221 220
221resubmit:
222 raw = raw6_local_deliver(skb, nexthdr); 222 raw = raw6_local_deliver(skb, nexthdr);
223 ipprot = rcu_dereference(inet6_protos[nexthdr]); 223 ipprot = rcu_dereference(inet6_protos[nexthdr]);
224 if (ipprot) { 224 if (ipprot) {
@@ -246,10 +246,12 @@ resubmit:
246 goto discard; 246 goto discard;
247 247
248 ret = ipprot->handler(skb); 248 ret = ipprot->handler(skb);
249 if (ret > 0) 249 if (ret < 0) {
250 nexthdr = -ret;
250 goto resubmit; 251 goto resubmit;
251 else if (ret == 0) 252 } else if (ret == 0) {
252 IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS); 253 IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_INDELIVERS);
254 }
253 } else { 255 } else {
254 if (!raw) { 256 if (!raw) {
255 if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { 257 if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {