diff options
Diffstat (limited to 'net/ipv6/reassembly.c')
-rw-r--r-- | net/ipv6/reassembly.c | 28 |
1 files changed, 12 insertions, 16 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index da5bd0ed83df..3b3a95607125 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -72,6 +72,7 @@ struct frag_queue | |||
72 | struct inet_frag_queue q; | 72 | struct inet_frag_queue q; |
73 | 73 | ||
74 | __be32 id; /* fragment id */ | 74 | __be32 id; /* fragment id */ |
75 | u32 user; | ||
75 | struct in6_addr saddr; | 76 | struct in6_addr saddr; |
76 | struct in6_addr daddr; | 77 | struct in6_addr daddr; |
77 | 78 | ||
@@ -141,7 +142,7 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a) | |||
141 | struct ip6_create_arg *arg = a; | 142 | struct ip6_create_arg *arg = a; |
142 | 143 | ||
143 | fq = container_of(q, struct frag_queue, q); | 144 | fq = container_of(q, struct frag_queue, q); |
144 | return (fq->id == arg->id && | 145 | return (fq->id == arg->id && fq->user == arg->user && |
145 | ipv6_addr_equal(&fq->saddr, arg->src) && | 146 | ipv6_addr_equal(&fq->saddr, arg->src) && |
146 | ipv6_addr_equal(&fq->daddr, arg->dst)); | 147 | ipv6_addr_equal(&fq->daddr, arg->dst)); |
147 | } | 148 | } |
@@ -163,6 +164,7 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a) | |||
163 | struct ip6_create_arg *arg = a; | 164 | struct ip6_create_arg *arg = a; |
164 | 165 | ||
165 | fq->id = arg->id; | 166 | fq->id = arg->id; |
167 | fq->user = arg->user; | ||
166 | ipv6_addr_copy(&fq->saddr, arg->src); | 168 | ipv6_addr_copy(&fq->saddr, arg->src); |
167 | ipv6_addr_copy(&fq->daddr, arg->dst); | 169 | ipv6_addr_copy(&fq->daddr, arg->dst); |
168 | } | 170 | } |
@@ -208,18 +210,17 @@ static void ip6_frag_expire(unsigned long data) | |||
208 | fq_kill(fq); | 210 | fq_kill(fq); |
209 | 211 | ||
210 | net = container_of(fq->q.net, struct net, ipv6.frags); | 212 | net = container_of(fq->q.net, struct net, ipv6.frags); |
211 | dev = dev_get_by_index(net, fq->iif); | 213 | rcu_read_lock(); |
214 | dev = dev_get_by_index_rcu(net, fq->iif); | ||
212 | if (!dev) | 215 | if (!dev) |
213 | goto out; | 216 | goto out_rcu_unlock; |
214 | 217 | ||
215 | rcu_read_lock(); | ||
216 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); | 218 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); |
217 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); | 219 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); |
218 | rcu_read_unlock(); | ||
219 | 220 | ||
220 | /* Don't send error if the first segment did not arrive. */ | 221 | /* Don't send error if the first segment did not arrive. */ |
221 | if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments) | 222 | if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments) |
222 | goto out; | 223 | goto out_rcu_unlock; |
223 | 224 | ||
224 | /* | 225 | /* |
225 | But use as source device on which LAST ARRIVED | 226 | But use as source device on which LAST ARRIVED |
@@ -228,9 +229,9 @@ static void ip6_frag_expire(unsigned long data) | |||
228 | */ | 229 | */ |
229 | fq->q.fragments->dev = dev; | 230 | fq->q.fragments->dev = dev; |
230 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); | 231 | icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); |
232 | out_rcu_unlock: | ||
233 | rcu_read_unlock(); | ||
231 | out: | 234 | out: |
232 | if (dev) | ||
233 | dev_put(dev); | ||
234 | spin_unlock(&fq->q.lock); | 235 | spin_unlock(&fq->q.lock); |
235 | fq_put(fq); | 236 | fq_put(fq); |
236 | } | 237 | } |
@@ -244,6 +245,7 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | |||
244 | unsigned int hash; | 245 | unsigned int hash; |
245 | 246 | ||
246 | arg.id = id; | 247 | arg.id = id; |
248 | arg.user = IP6_DEFRAG_LOCAL_DELIVER; | ||
247 | arg.src = src; | 249 | arg.src = src; |
248 | arg.dst = dst; | 250 | arg.dst = dst; |
249 | 251 | ||
@@ -636,7 +638,6 @@ static const struct inet6_protocol frag_protocol = | |||
636 | #ifdef CONFIG_SYSCTL | 638 | #ifdef CONFIG_SYSCTL |
637 | static struct ctl_table ip6_frags_ns_ctl_table[] = { | 639 | static struct ctl_table ip6_frags_ns_ctl_table[] = { |
638 | { | 640 | { |
639 | .ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH, | ||
640 | .procname = "ip6frag_high_thresh", | 641 | .procname = "ip6frag_high_thresh", |
641 | .data = &init_net.ipv6.frags.high_thresh, | 642 | .data = &init_net.ipv6.frags.high_thresh, |
642 | .maxlen = sizeof(int), | 643 | .maxlen = sizeof(int), |
@@ -644,7 +645,6 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { | |||
644 | .proc_handler = proc_dointvec | 645 | .proc_handler = proc_dointvec |
645 | }, | 646 | }, |
646 | { | 647 | { |
647 | .ctl_name = NET_IPV6_IP6FRAG_LOW_THRESH, | ||
648 | .procname = "ip6frag_low_thresh", | 648 | .procname = "ip6frag_low_thresh", |
649 | .data = &init_net.ipv6.frags.low_thresh, | 649 | .data = &init_net.ipv6.frags.low_thresh, |
650 | .maxlen = sizeof(int), | 650 | .maxlen = sizeof(int), |
@@ -652,26 +652,22 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { | |||
652 | .proc_handler = proc_dointvec | 652 | .proc_handler = proc_dointvec |
653 | }, | 653 | }, |
654 | { | 654 | { |
655 | .ctl_name = NET_IPV6_IP6FRAG_TIME, | ||
656 | .procname = "ip6frag_time", | 655 | .procname = "ip6frag_time", |
657 | .data = &init_net.ipv6.frags.timeout, | 656 | .data = &init_net.ipv6.frags.timeout, |
658 | .maxlen = sizeof(int), | 657 | .maxlen = sizeof(int), |
659 | .mode = 0644, | 658 | .mode = 0644, |
660 | .proc_handler = proc_dointvec_jiffies, | 659 | .proc_handler = proc_dointvec_jiffies, |
661 | .strategy = sysctl_jiffies, | ||
662 | }, | 660 | }, |
663 | { } | 661 | { } |
664 | }; | 662 | }; |
665 | 663 | ||
666 | static struct ctl_table ip6_frags_ctl_table[] = { | 664 | static struct ctl_table ip6_frags_ctl_table[] = { |
667 | { | 665 | { |
668 | .ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL, | ||
669 | .procname = "ip6frag_secret_interval", | 666 | .procname = "ip6frag_secret_interval", |
670 | .data = &ip6_frags.secret_interval, | 667 | .data = &ip6_frags.secret_interval, |
671 | .maxlen = sizeof(int), | 668 | .maxlen = sizeof(int), |
672 | .mode = 0644, | 669 | .mode = 0644, |
673 | .proc_handler = proc_dointvec_jiffies, | 670 | .proc_handler = proc_dointvec_jiffies, |
674 | .strategy = sysctl_jiffies | ||
675 | }, | 671 | }, |
676 | { } | 672 | { } |
677 | }; | 673 | }; |
@@ -682,7 +678,7 @@ static int ip6_frags_ns_sysctl_register(struct net *net) | |||
682 | struct ctl_table_header *hdr; | 678 | struct ctl_table_header *hdr; |
683 | 679 | ||
684 | table = ip6_frags_ns_ctl_table; | 680 | table = ip6_frags_ns_ctl_table; |
685 | if (net != &init_net) { | 681 | if (!net_eq(net, &init_net)) { |
686 | table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL); | 682 | table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL); |
687 | if (table == NULL) | 683 | if (table == NULL) |
688 | goto err_alloc; | 684 | goto err_alloc; |
@@ -700,7 +696,7 @@ static int ip6_frags_ns_sysctl_register(struct net *net) | |||
700 | return 0; | 696 | return 0; |
701 | 697 | ||
702 | err_reg: | 698 | err_reg: |
703 | if (net != &init_net) | 699 | if (!net_eq(net, &init_net)) |
704 | kfree(table); | 700 | kfree(table); |
705 | err_alloc: | 701 | err_alloc: |
706 | return -ENOMEM; | 702 | return -ENOMEM; |