aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/reassembly.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/reassembly.c')
-rw-r--r--net/ipv6/reassembly.c28
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);
232out_rcu_unlock:
233 rcu_read_unlock();
231out: 234out:
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
637static struct ctl_table ip6_frags_ns_ctl_table[] = { 639static 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
666static struct ctl_table ip6_frags_ctl_table[] = { 664static 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
702err_reg: 698err_reg:
703 if (net != &init_net) 699 if (!net_eq(net, &init_net))
704 kfree(table); 700 kfree(table);
705err_alloc: 701err_alloc:
706 return -ENOMEM; 702 return -ENOMEM;