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.c65
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 */
102static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr, 102unsigned 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}
128EXPORT_SYMBOL_GPL(inet6_hash_frag);
128 129
129static unsigned int ip6_hashfn(struct inet_frag_queue *q) 130static 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
137int ip6_frag_match(struct inet_frag_queue *q, void *a) 138int 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
194static void ip6_frag_expire(unsigned long data) 195static 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
258oom: 259oom:
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
434err: 436err:
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");
563out_fail: 567out_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
625fail_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
628static struct inet6_protocol frag_protocol = 631static struct inet6_protocol frag_protocol =