diff options
-rw-r--r-- | include/net/inet_frag.h | 1 | ||||
-rw-r--r-- | net/ipv4/ip_fragment.c | 12 | ||||
-rw-r--r-- | net/ipv6/reassembly.c | 11 |
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 | ||
402 | found: | ||
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 | ||
579 | out_nomem: | 591 | out_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 | ||
348 | found: | ||
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 | ||
554 | out_oversize: | 565 | out_oversize: |