diff options
Diffstat (limited to 'net/ipv6/reassembly.c')
-rw-r--r-- | net/ipv6/reassembly.c | 65 |
1 files changed, 34 insertions, 31 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 89184b576e23..af12de071f4c 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -99,8 +99,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
99 | * callers should be careful not to use the hash value outside the ipfrag_lock | 99 | * callers should be careful not to use the hash value outside the ipfrag_lock |
100 | * as doing so could race with ipfrag_hash_rnd being recalculated. | 100 | * as doing so could race with ipfrag_hash_rnd being recalculated. |
101 | */ | 101 | */ |
102 | static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr, | 102 | unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, |
103 | struct in6_addr *daddr) | 103 | const struct in6_addr *daddr, u32 rnd) |
104 | { | 104 | { |
105 | u32 a, b, c; | 105 | u32 a, b, c; |
106 | 106 | ||
@@ -110,7 +110,7 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr, | |||
110 | 110 | ||
111 | a += JHASH_GOLDEN_RATIO; | 111 | a += JHASH_GOLDEN_RATIO; |
112 | b += JHASH_GOLDEN_RATIO; | 112 | b += JHASH_GOLDEN_RATIO; |
113 | c += ip6_frags.rnd; | 113 | c += rnd; |
114 | __jhash_mix(a, b, c); | 114 | __jhash_mix(a, b, c); |
115 | 115 | ||
116 | a += (__force u32)saddr->s6_addr32[3]; | 116 | a += (__force u32)saddr->s6_addr32[3]; |
@@ -125,13 +125,14 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr, | |||
125 | 125 | ||
126 | return c & (INETFRAGS_HASHSZ - 1); | 126 | return c & (INETFRAGS_HASHSZ - 1); |
127 | } | 127 | } |
128 | EXPORT_SYMBOL_GPL(inet6_hash_frag); | ||
128 | 129 | ||
129 | static unsigned int ip6_hashfn(struct inet_frag_queue *q) | 130 | static unsigned int ip6_hashfn(struct inet_frag_queue *q) |
130 | { | 131 | { |
131 | struct frag_queue *fq; | 132 | struct frag_queue *fq; |
132 | 133 | ||
133 | fq = container_of(q, struct frag_queue, q); | 134 | fq = container_of(q, struct frag_queue, q); |
134 | return ip6qhashfn(fq->id, &fq->saddr, &fq->daddr); | 135 | return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr, ip6_frags.rnd); |
135 | } | 136 | } |
136 | 137 | ||
137 | int ip6_frag_match(struct inet_frag_queue *q, void *a) | 138 | int ip6_frag_match(struct inet_frag_queue *q, void *a) |
@@ -188,7 +189,7 @@ static void ip6_evictor(struct net *net, struct inet6_dev *idev) | |||
188 | 189 | ||
189 | evicted = inet_frag_evictor(&net->ipv6.frags, &ip6_frags); | 190 | evicted = inet_frag_evictor(&net->ipv6.frags, &ip6_frags); |
190 | if (evicted) | 191 | if (evicted) |
191 | IP6_ADD_STATS_BH(idev, IPSTATS_MIB_REASMFAILS, evicted); | 192 | IP6_ADD_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS, evicted); |
192 | } | 193 | } |
193 | 194 | ||
194 | static void ip6_frag_expire(unsigned long data) | 195 | static void ip6_frag_expire(unsigned long data) |
@@ -212,8 +213,8 @@ static void ip6_frag_expire(unsigned long data) | |||
212 | goto out; | 213 | goto out; |
213 | 214 | ||
214 | rcu_read_lock(); | 215 | rcu_read_lock(); |
215 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); | 216 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); |
216 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); | 217 | IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); |
217 | rcu_read_unlock(); | 218 | rcu_read_unlock(); |
218 | 219 | ||
219 | /* Don't send error if the first segment did not arrive. */ | 220 | /* Don't send error if the first segment did not arrive. */ |
@@ -247,7 +248,7 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | |||
247 | arg.dst = dst; | 248 | arg.dst = dst; |
248 | 249 | ||
249 | read_lock(&ip6_frags.lock); | 250 | read_lock(&ip6_frags.lock); |
250 | hash = ip6qhashfn(id, src, dst); | 251 | hash = inet6_hash_frag(id, src, dst, ip6_frags.rnd); |
251 | 252 | ||
252 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); | 253 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); |
253 | if (q == NULL) | 254 | if (q == NULL) |
@@ -256,7 +257,7 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | |||
256 | return container_of(q, struct frag_queue, q); | 257 | return container_of(q, struct frag_queue, q); |
257 | 258 | ||
258 | oom: | 259 | oom: |
259 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS); | 260 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS); |
260 | return NULL; | 261 | return NULL; |
261 | } | 262 | } |
262 | 263 | ||
@@ -266,6 +267,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
266 | struct sk_buff *prev, *next; | 267 | struct sk_buff *prev, *next; |
267 | struct net_device *dev; | 268 | struct net_device *dev; |
268 | int offset, end; | 269 | int offset, end; |
270 | struct net *net = dev_net(skb->dst->dev); | ||
269 | 271 | ||
270 | if (fq->q.last_in & INET_FRAG_COMPLETE) | 272 | if (fq->q.last_in & INET_FRAG_COMPLETE) |
271 | goto err; | 273 | goto err; |
@@ -275,7 +277,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
275 | ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); | 277 | ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); |
276 | 278 | ||
277 | if ((unsigned int)end > IPV6_MAXPLEN) { | 279 | if ((unsigned int)end > IPV6_MAXPLEN) { |
278 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | 280 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), |
279 | IPSTATS_MIB_INHDRERRORS); | 281 | IPSTATS_MIB_INHDRERRORS); |
280 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, | 282 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
281 | ((u8 *)&fhdr->frag_off - | 283 | ((u8 *)&fhdr->frag_off - |
@@ -308,7 +310,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
308 | /* RFC2460 says always send parameter problem in | 310 | /* RFC2460 says always send parameter problem in |
309 | * this case. -DaveM | 311 | * this case. -DaveM |
310 | */ | 312 | */ |
311 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), | 313 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), |
312 | IPSTATS_MIB_INHDRERRORS); | 314 | IPSTATS_MIB_INHDRERRORS); |
313 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, | 315 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, |
314 | offsetof(struct ipv6hdr, payload_len)); | 316 | offsetof(struct ipv6hdr, payload_len)); |
@@ -432,7 +434,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
432 | return -1; | 434 | return -1; |
433 | 435 | ||
434 | err: | 436 | err: |
435 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS); | 437 | IP6_INC_STATS(net, ip6_dst_idev(skb->dst), |
438 | IPSTATS_MIB_REASMFAILS); | ||
436 | kfree_skb(skb); | 439 | kfree_skb(skb); |
437 | return -1; | 440 | return -1; |
438 | } | 441 | } |
@@ -548,7 +551,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
548 | head->csum); | 551 | head->csum); |
549 | 552 | ||
550 | rcu_read_lock(); | 553 | rcu_read_lock(); |
551 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMOKS); | 554 | IP6_INC_STATS_BH(dev_net(dev), |
555 | __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); | ||
552 | rcu_read_unlock(); | 556 | rcu_read_unlock(); |
553 | fq->q.fragments = NULL; | 557 | fq->q.fragments = NULL; |
554 | return 1; | 558 | return 1; |
@@ -562,7 +566,8 @@ out_oom: | |||
562 | printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n"); | 566 | printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n"); |
563 | out_fail: | 567 | out_fail: |
564 | rcu_read_lock(); | 568 | rcu_read_lock(); |
565 | IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); | 569 | IP6_INC_STATS_BH(dev_net(dev), |
570 | __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); | ||
566 | rcu_read_unlock(); | 571 | rcu_read_unlock(); |
567 | return -1; | 572 | return -1; |
568 | } | 573 | } |
@@ -572,24 +577,17 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
572 | struct frag_hdr *fhdr; | 577 | struct frag_hdr *fhdr; |
573 | struct frag_queue *fq; | 578 | struct frag_queue *fq; |
574 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 579 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
575 | struct net *net; | 580 | struct net *net = dev_net(skb->dst->dev); |
576 | 581 | ||
577 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS); | 582 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMREQDS); |
578 | 583 | ||
579 | /* Jumbo payload inhibits frag. header */ | 584 | /* Jumbo payload inhibits frag. header */ |
580 | if (hdr->payload_len==0) { | 585 | if (hdr->payload_len==0) |
581 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); | 586 | goto fail_hdr; |
582 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, | 587 | |
583 | skb_network_header_len(skb)); | ||
584 | return -1; | ||
585 | } | ||
586 | if (!pskb_may_pull(skb, (skb_transport_offset(skb) + | 588 | if (!pskb_may_pull(skb, (skb_transport_offset(skb) + |
587 | sizeof(struct frag_hdr)))) { | 589 | sizeof(struct frag_hdr)))) |
588 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); | 590 | goto fail_hdr; |
589 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, | ||
590 | skb_network_header_len(skb)); | ||
591 | return -1; | ||
592 | } | ||
593 | 591 | ||
594 | hdr = ipv6_hdr(skb); | 592 | hdr = ipv6_hdr(skb); |
595 | fhdr = (struct frag_hdr *)skb_transport_header(skb); | 593 | fhdr = (struct frag_hdr *)skb_transport_header(skb); |
@@ -597,13 +595,13 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
597 | if (!(fhdr->frag_off & htons(0xFFF9))) { | 595 | if (!(fhdr->frag_off & htons(0xFFF9))) { |
598 | /* It is not a fragmented frame */ | 596 | /* It is not a fragmented frame */ |
599 | skb->transport_header += sizeof(struct frag_hdr); | 597 | skb->transport_header += sizeof(struct frag_hdr); |
600 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS); | 598 | IP6_INC_STATS_BH(net, |
599 | ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMOKS); | ||
601 | 600 | ||
602 | IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb); | 601 | IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb); |
603 | return 1; | 602 | return 1; |
604 | } | 603 | } |
605 | 604 | ||
606 | net = dev_net(skb->dev); | ||
607 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) | 605 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) |
608 | ip6_evictor(net, ip6_dst_idev(skb->dst)); | 606 | ip6_evictor(net, ip6_dst_idev(skb->dst)); |
609 | 607 | ||
@@ -620,9 +618,14 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
620 | return ret; | 618 | return ret; |
621 | } | 619 | } |
622 | 620 | ||
623 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS); | 621 | IP6_INC_STATS_BH(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_REASMFAILS); |
624 | kfree_skb(skb); | 622 | kfree_skb(skb); |
625 | return -1; | 623 | return -1; |
624 | |||
625 | fail_hdr: | ||
626 | IP6_INC_STATS(net, ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS); | ||
627 | icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb)); | ||
628 | return -1; | ||
626 | } | 629 | } |
627 | 630 | ||
628 | static struct inet6_protocol frag_protocol = | 631 | static struct inet6_protocol frag_protocol = |