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.c116
1 files changed, 39 insertions, 77 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 2cddea3bd6be..64cfef1b0a4c 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -41,6 +41,7 @@
41#include <linux/random.h> 41#include <linux/random.h>
42#include <linux/jhash.h> 42#include <linux/jhash.h>
43#include <linux/skbuff.h> 43#include <linux/skbuff.h>
44#include <linux/slab.h>
44 45
45#include <net/sock.h> 46#include <net/sock.h>
46#include <net/snmp.h> 47#include <net/snmp.h>
@@ -148,16 +149,6 @@ int ip6_frag_match(struct inet_frag_queue *q, void *a)
148} 149}
149EXPORT_SYMBOL(ip6_frag_match); 150EXPORT_SYMBOL(ip6_frag_match);
150 151
151/* Memory Tracking Functions. */
152static inline void frag_kfree_skb(struct netns_frags *nf,
153 struct sk_buff *skb, int *work)
154{
155 if (work)
156 *work -= skb->truesize;
157 atomic_sub(skb->truesize, &nf->mem);
158 kfree_skb(skb);
159}
160
161void ip6_frag_init(struct inet_frag_queue *q, void *a) 152void ip6_frag_init(struct inet_frag_queue *q, void *a)
162{ 153{
163 struct frag_queue *fq = container_of(q, struct frag_queue, q); 154 struct frag_queue *fq = container_of(q, struct frag_queue, q);
@@ -228,7 +219,7 @@ static void ip6_frag_expire(unsigned long data)
228 pointer directly, device might already disappeared. 219 pointer directly, device might already disappeared.
229 */ 220 */
230 fq->q.fragments->dev = dev; 221 fq->q.fragments->dev = dev;
231 icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev); 222 icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0);
232out_rcu_unlock: 223out_rcu_unlock:
233 rcu_read_unlock(); 224 rcu_read_unlock();
234out: 225out:
@@ -237,8 +228,7 @@ out:
237} 228}
238 229
239static __inline__ struct frag_queue * 230static __inline__ struct frag_queue *
240fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, 231fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst)
241 struct inet6_dev *idev)
242{ 232{
243 struct inet_frag_queue *q; 233 struct inet_frag_queue *q;
244 struct ip6_create_arg arg; 234 struct ip6_create_arg arg;
@@ -254,13 +244,9 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst,
254 244
255 q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); 245 q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash);
256 if (q == NULL) 246 if (q == NULL)
257 goto oom; 247 return NULL;
258 248
259 return container_of(q, struct frag_queue, q); 249 return container_of(q, struct frag_queue, q);
260
261oom:
262 IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS);
263 return NULL;
264} 250}
265 251
266static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, 252static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
@@ -340,6 +326,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
340 * in the chain of fragments so far. We must know where to put 326 * in the chain of fragments so far. We must know where to put
341 * this fragment, right? 327 * this fragment, right?
342 */ 328 */
329 prev = fq->q.fragments_tail;
330 if (!prev || FRAG6_CB(prev)->offset < offset) {
331 next = NULL;
332 goto found;
333 }
343 prev = NULL; 334 prev = NULL;
344 for(next = fq->q.fragments; next != NULL; next = next->next) { 335 for(next = fq->q.fragments; next != NULL; next = next->next) {
345 if (FRAG6_CB(next)->offset >= offset) 336 if (FRAG6_CB(next)->offset >= offset)
@@ -347,63 +338,30 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
347 prev = next; 338 prev = next;
348 } 339 }
349 340
350 /* We found where to put this one. Check for overlap with 341found:
351 * preceding fragment, and, if needed, align things so that 342 /* RFC5722, Section 4:
352 * any overlaps are eliminated. 343 * When reassembling an IPv6 datagram, if
344 * one or more its constituent fragments is determined to be an
345 * overlapping fragment, the entire datagram (and any constituent
346 * fragments, including those not yet received) MUST be silently
347 * discarded.
353 */ 348 */
354 if (prev) {
355 int i = (FRAG6_CB(prev)->offset + prev->len) - offset;
356 349
357 if (i > 0) { 350 /* Check for overlap with preceding fragment. */
358 offset += i; 351 if (prev &&
359 if (end <= offset) 352 (FRAG6_CB(prev)->offset + prev->len) - offset > 0)
360 goto err; 353 goto discard_fq;
361 if (!pskb_pull(skb, i))
362 goto err;
363 if (skb->ip_summed != CHECKSUM_UNNECESSARY)
364 skb->ip_summed = CHECKSUM_NONE;
365 }
366 }
367 354
368 /* Look for overlap with succeeding segments. 355 /* Look for overlap with succeeding segment. */
369 * If we can merge fragments, do it. 356 if (next && FRAG6_CB(next)->offset < end)
370 */ 357 goto discard_fq;
371 while (next && FRAG6_CB(next)->offset < end) {
372 int i = end - FRAG6_CB(next)->offset; /* overlap is 'i' bytes */
373
374 if (i < next->len) {
375 /* Eat head of the next overlapped fragment
376 * and leave the loop. The next ones cannot overlap.
377 */
378 if (!pskb_pull(next, i))
379 goto err;
380 FRAG6_CB(next)->offset += i; /* next fragment */
381 fq->q.meat -= i;
382 if (next->ip_summed != CHECKSUM_UNNECESSARY)
383 next->ip_summed = CHECKSUM_NONE;
384 break;
385 } else {
386 struct sk_buff *free_it = next;
387
388 /* Old fragment is completely overridden with
389 * new one drop it.
390 */
391 next = next->next;
392
393 if (prev)
394 prev->next = next;
395 else
396 fq->q.fragments = next;
397
398 fq->q.meat -= free_it->len;
399 frag_kfree_skb(fq->q.net, free_it, NULL);
400 }
401 }
402 358
403 FRAG6_CB(skb)->offset = offset; 359 FRAG6_CB(skb)->offset = offset;
404 360
405 /* Insert this fragment in the chain of fragments. */ 361 /* Insert this fragment in the chain of fragments. */
406 skb->next = next; 362 skb->next = next;
363 if (!next)
364 fq->q.fragments_tail = skb;
407 if (prev) 365 if (prev)
408 prev->next = skb; 366 prev->next = skb;
409 else 367 else
@@ -435,6 +393,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
435 write_unlock(&ip6_frags.lock); 393 write_unlock(&ip6_frags.lock);
436 return -1; 394 return -1;
437 395
396discard_fq:
397 fq_kill(fq);
438err: 398err:
439 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 399 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
440 IPSTATS_MIB_REASMFAILS); 400 IPSTATS_MIB_REASMFAILS);
@@ -470,6 +430,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
470 goto out_oom; 430 goto out_oom;
471 431
472 fp->next = head->next; 432 fp->next = head->next;
433 if (!fp->next)
434 fq->q.fragments_tail = fp;
473 prev->next = fp; 435 prev->next = fp;
474 436
475 skb_morph(head, fq->q.fragments); 437 skb_morph(head, fq->q.fragments);
@@ -528,7 +490,6 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
528 skb_shinfo(head)->frag_list = head->next; 490 skb_shinfo(head)->frag_list = head->next;
529 skb_reset_transport_header(head); 491 skb_reset_transport_header(head);
530 skb_push(head, head->data - skb_network_header(head)); 492 skb_push(head, head->data - skb_network_header(head));
531 atomic_sub(head->truesize, &fq->q.net->mem);
532 493
533 for (fp=head->next; fp; fp = fp->next) { 494 for (fp=head->next; fp; fp = fp->next) {
534 head->data_len += fp->len; 495 head->data_len += fp->len;
@@ -538,8 +499,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
538 else if (head->ip_summed == CHECKSUM_COMPLETE) 499 else if (head->ip_summed == CHECKSUM_COMPLETE)
539 head->csum = csum_add(head->csum, fp->csum); 500 head->csum = csum_add(head->csum, fp->csum);
540 head->truesize += fp->truesize; 501 head->truesize += fp->truesize;
541 atomic_sub(fp->truesize, &fq->q.net->mem);
542 } 502 }
503 atomic_sub(head->truesize, &fq->q.net->mem);
543 504
544 head->next = NULL; 505 head->next = NULL;
545 head->dev = dev; 506 head->dev = dev;
@@ -557,6 +518,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
557 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); 518 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
558 rcu_read_unlock(); 519 rcu_read_unlock();
559 fq->q.fragments = NULL; 520 fq->q.fragments = NULL;
521 fq->q.fragments_tail = NULL;
560 return 1; 522 return 1;
561 523
562out_oversize: 524out_oversize:
@@ -606,8 +568,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
606 if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) 568 if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh)
607 ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); 569 ip6_evictor(net, ip6_dst_idev(skb_dst(skb)));
608 570
609 if ((fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, 571 fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr);
610 ip6_dst_idev(skb_dst(skb)))) != NULL) { 572 if (fq != NULL) {
611 int ret; 573 int ret;
612 574
613 spin_lock(&fq->q.lock); 575 spin_lock(&fq->q.lock);
@@ -672,7 +634,7 @@ static struct ctl_table ip6_frags_ctl_table[] = {
672 { } 634 { }
673}; 635};
674 636
675static int ip6_frags_ns_sysctl_register(struct net *net) 637static int __net_init ip6_frags_ns_sysctl_register(struct net *net)
676{ 638{
677 struct ctl_table *table; 639 struct ctl_table *table;
678 struct ctl_table_header *hdr; 640 struct ctl_table_header *hdr;
@@ -702,7 +664,7 @@ err_alloc:
702 return -ENOMEM; 664 return -ENOMEM;
703} 665}
704 666
705static void ip6_frags_ns_sysctl_unregister(struct net *net) 667static void __net_exit ip6_frags_ns_sysctl_unregister(struct net *net)
706{ 668{
707 struct ctl_table *table; 669 struct ctl_table *table;
708 670
@@ -745,10 +707,10 @@ static inline void ip6_frags_sysctl_unregister(void)
745} 707}
746#endif 708#endif
747 709
748static int ipv6_frags_init_net(struct net *net) 710static int __net_init ipv6_frags_init_net(struct net *net)
749{ 711{
750 net->ipv6.frags.high_thresh = 256 * 1024; 712 net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
751 net->ipv6.frags.low_thresh = 192 * 1024; 713 net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
752 net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; 714 net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT;
753 715
754 inet_frags_init_net(&net->ipv6.frags); 716 inet_frags_init_net(&net->ipv6.frags);
@@ -756,7 +718,7 @@ static int ipv6_frags_init_net(struct net *net)
756 return ip6_frags_ns_sysctl_register(net); 718 return ip6_frags_ns_sysctl_register(net);
757} 719}
758 720
759static void ipv6_frags_exit_net(struct net *net) 721static void __net_exit ipv6_frags_exit_net(struct net *net)
760{ 722{
761 ip6_frags_ns_sysctl_unregister(net); 723 ip6_frags_ns_sysctl_unregister(net);
762 inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); 724 inet_frags_exit_net(&net->ipv6.frags, &ip6_frags);