aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/inet_frag.h1
-rw-r--r--net/ipv4/ip_fragment.c12
-rw-r--r--net/ipv6/reassembly.c11
3 files changed, 24 insertions, 0 deletions
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 39f2dc943908..16ff29a7bb30 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -20,6 +20,7 @@ struct inet_frag_queue {
20 atomic_t refcnt; 20 atomic_t refcnt;
21 struct timer_list timer; /* when will this queue expire? */ 21 struct timer_list timer; /* when will this queue expire? */
22 struct sk_buff *fragments; /* list of received fragments */ 22 struct sk_buff *fragments; /* list of received fragments */
23 struct sk_buff *fragments_tail;
23 ktime_t stamp; 24 ktime_t stamp;
24 int len; /* total length of orig datagram */ 25 int len; /* total length of orig datagram */
25 int meat; 26 int meat;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 858d34648eee..dd0dbf0c6b7f 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -314,6 +314,7 @@ static int ip_frag_reinit(struct ipq *qp)
314 qp->q.len = 0; 314 qp->q.len = 0;
315 qp->q.meat = 0; 315 qp->q.meat = 0;
316 qp->q.fragments = NULL; 316 qp->q.fragments = NULL;
317 qp->q.fragments_tail = NULL;
317 qp->iif = 0; 318 qp->iif = 0;
318 319
319 return 0; 320 return 0;
@@ -386,6 +387,11 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
386 * in the chain of fragments so far. We must know where to put 387 * in the chain of fragments so far. We must know where to put
387 * this fragment, right? 388 * this fragment, right?
388 */ 389 */
390 prev = qp->q.fragments_tail;
391 if (!prev || FRAG_CB(prev)->offset < offset) {
392 next = NULL;
393 goto found;
394 }
389 prev = NULL; 395 prev = NULL;
390 for (next = qp->q.fragments; next != NULL; next = next->next) { 396 for (next = qp->q.fragments; next != NULL; next = next->next) {
391 if (FRAG_CB(next)->offset >= offset) 397 if (FRAG_CB(next)->offset >= offset)
@@ -393,6 +399,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
393 prev = next; 399 prev = next;
394 } 400 }
395 401
402found:
396 /* We found where to put this one. Check for overlap with 403 /* We found where to put this one. Check for overlap with
397 * preceding fragment, and, if needed, align things so that 404 * preceding fragment, and, if needed, align things so that
398 * any overlaps are eliminated. 405 * any overlaps are eliminated.
@@ -451,6 +458,8 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
451 458
452 /* Insert this fragment in the chain of fragments. */ 459 /* Insert this fragment in the chain of fragments. */
453 skb->next = next; 460 skb->next = next;
461 if (!next)
462 qp->q.fragments_tail = skb;
454 if (prev) 463 if (prev)
455 prev->next = skb; 464 prev->next = skb;
456 else 465 else
@@ -504,6 +513,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
504 goto out_nomem; 513 goto out_nomem;
505 514
506 fp->next = head->next; 515 fp->next = head->next;
516 if (!fp->next)
517 qp->q.fragments_tail = fp;
507 prev->next = fp; 518 prev->next = fp;
508 519
509 skb_morph(head, qp->q.fragments); 520 skb_morph(head, qp->q.fragments);
@@ -574,6 +585,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
574 iph->tot_len = htons(len); 585 iph->tot_len = htons(len);
575 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); 586 IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
576 qp->q.fragments = NULL; 587 qp->q.fragments = NULL;
588 qp->q.fragments_tail = NULL;
577 return 0; 589 return 0;
578 590
579out_nomem: 591out_nomem:
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 0b97230a3251..545c4141b755 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -333,6 +333,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
333 * in the chain of fragments so far. We must know where to put 333 * in the chain of fragments so far. We must know where to put
334 * this fragment, right? 334 * this fragment, right?
335 */ 335 */
336 prev = fq->q.fragments_tail;
337 if (!prev || FRAG6_CB(prev)->offset < offset) {
338 next = NULL;
339 goto found;
340 }
336 prev = NULL; 341 prev = NULL;
337 for(next = fq->q.fragments; next != NULL; next = next->next) { 342 for(next = fq->q.fragments; next != NULL; next = next->next) {
338 if (FRAG6_CB(next)->offset >= offset) 343 if (FRAG6_CB(next)->offset >= offset)
@@ -340,6 +345,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
340 prev = next; 345 prev = next;
341 } 346 }
342 347
348found:
343 /* We found where to put this one. Check for overlap with 349 /* We found where to put this one. Check for overlap with
344 * preceding fragment, and, if needed, align things so that 350 * preceding fragment, and, if needed, align things so that
345 * any overlaps are eliminated. 351 * any overlaps are eliminated.
@@ -397,6 +403,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
397 403
398 /* Insert this fragment in the chain of fragments. */ 404 /* Insert this fragment in the chain of fragments. */
399 skb->next = next; 405 skb->next = next;
406 if (!next)
407 fq->q.fragments_tail = skb;
400 if (prev) 408 if (prev)
401 prev->next = skb; 409 prev->next = skb;
402 else 410 else
@@ -463,6 +471,8 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
463 goto out_oom; 471 goto out_oom;
464 472
465 fp->next = head->next; 473 fp->next = head->next;
474 if (!fp->next)
475 fq->q.fragments_tail = fp;
466 prev->next = fp; 476 prev->next = fp;
467 477
468 skb_morph(head, fq->q.fragments); 478 skb_morph(head, fq->q.fragments);
@@ -549,6 +559,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
549 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); 559 IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
550 rcu_read_unlock(); 560 rcu_read_unlock();
551 fq->q.fragments = NULL; 561 fq->q.fragments = NULL;
562 fq->q.fragments_tail = NULL;
552 return 1; 563 return 1;
553 564
554out_oversize: 565out_oversize: