diff options
Diffstat (limited to 'net/ipv4/ip_fragment.c')
-rw-r--r-- | net/ipv4/ip_fragment.c | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 75347ea70ea..b7c41654dde 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
@@ -124,11 +124,8 @@ static int ip4_frag_match(struct inet_frag_queue *q, void *a) | |||
124 | } | 124 | } |
125 | 125 | ||
126 | /* Memory Tracking Functions. */ | 126 | /* Memory Tracking Functions. */ |
127 | static __inline__ void frag_kfree_skb(struct netns_frags *nf, | 127 | static void frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb) |
128 | struct sk_buff *skb, int *work) | ||
129 | { | 128 | { |
130 | if (work) | ||
131 | *work -= skb->truesize; | ||
132 | atomic_sub(skb->truesize, &nf->mem); | 129 | atomic_sub(skb->truesize, &nf->mem); |
133 | kfree_skb(skb); | 130 | kfree_skb(skb); |
134 | } | 131 | } |
@@ -309,7 +306,7 @@ static int ip_frag_reinit(struct ipq *qp) | |||
309 | fp = qp->q.fragments; | 306 | fp = qp->q.fragments; |
310 | do { | 307 | do { |
311 | struct sk_buff *xp = fp->next; | 308 | struct sk_buff *xp = fp->next; |
312 | frag_kfree_skb(qp->q.net, fp, NULL); | 309 | frag_kfree_skb(qp->q.net, fp); |
313 | fp = xp; | 310 | fp = xp; |
314 | } while (fp); | 311 | } while (fp); |
315 | 312 | ||
@@ -317,6 +314,7 @@ static int ip_frag_reinit(struct ipq *qp) | |||
317 | qp->q.len = 0; | 314 | qp->q.len = 0; |
318 | qp->q.meat = 0; | 315 | qp->q.meat = 0; |
319 | qp->q.fragments = NULL; | 316 | qp->q.fragments = NULL; |
317 | qp->q.fragments_tail = NULL; | ||
320 | qp->iif = 0; | 318 | qp->iif = 0; |
321 | 319 | ||
322 | return 0; | 320 | return 0; |
@@ -389,6 +387,11 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
389 | * 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 |
390 | * this fragment, right? | 388 | * this fragment, right? |
391 | */ | 389 | */ |
390 | prev = qp->q.fragments_tail; | ||
391 | if (!prev || FRAG_CB(prev)->offset < offset) { | ||
392 | next = NULL; | ||
393 | goto found; | ||
394 | } | ||
392 | prev = NULL; | 395 | prev = NULL; |
393 | for (next = qp->q.fragments; next != NULL; next = next->next) { | 396 | for (next = qp->q.fragments; next != NULL; next = next->next) { |
394 | if (FRAG_CB(next)->offset >= offset) | 397 | if (FRAG_CB(next)->offset >= offset) |
@@ -396,6 +399,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
396 | prev = next; | 399 | prev = next; |
397 | } | 400 | } |
398 | 401 | ||
402 | found: | ||
399 | /* We found where to put this one. Check for overlap with | 403 | /* We found where to put this one. Check for overlap with |
400 | * preceding fragment, and, if needed, align things so that | 404 | * preceding fragment, and, if needed, align things so that |
401 | * any overlaps are eliminated. | 405 | * any overlaps are eliminated. |
@@ -446,7 +450,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
446 | qp->q.fragments = next; | 450 | qp->q.fragments = next; |
447 | 451 | ||
448 | qp->q.meat -= free_it->len; | 452 | qp->q.meat -= free_it->len; |
449 | frag_kfree_skb(qp->q.net, free_it, NULL); | 453 | frag_kfree_skb(qp->q.net, free_it); |
450 | } | 454 | } |
451 | } | 455 | } |
452 | 456 | ||
@@ -454,6 +458,8 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
454 | 458 | ||
455 | /* Insert this fragment in the chain of fragments. */ | 459 | /* Insert this fragment in the chain of fragments. */ |
456 | skb->next = next; | 460 | skb->next = next; |
461 | if (!next) | ||
462 | qp->q.fragments_tail = skb; | ||
457 | if (prev) | 463 | if (prev) |
458 | prev->next = skb; | 464 | prev->next = skb; |
459 | else | 465 | else |
@@ -507,6 +513,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
507 | goto out_nomem; | 513 | goto out_nomem; |
508 | 514 | ||
509 | fp->next = head->next; | 515 | fp->next = head->next; |
516 | if (!fp->next) | ||
517 | qp->q.fragments_tail = fp; | ||
510 | prev->next = fp; | 518 | prev->next = fp; |
511 | 519 | ||
512 | skb_morph(head, qp->q.fragments); | 520 | skb_morph(head, qp->q.fragments); |
@@ -556,7 +564,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
556 | 564 | ||
557 | skb_shinfo(head)->frag_list = head->next; | 565 | skb_shinfo(head)->frag_list = head->next; |
558 | skb_push(head, head->data - skb_network_header(head)); | 566 | skb_push(head, head->data - skb_network_header(head)); |
559 | atomic_sub(head->truesize, &qp->q.net->mem); | ||
560 | 567 | ||
561 | for (fp=head->next; fp; fp = fp->next) { | 568 | for (fp=head->next; fp; fp = fp->next) { |
562 | head->data_len += fp->len; | 569 | head->data_len += fp->len; |
@@ -566,8 +573,8 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
566 | else if (head->ip_summed == CHECKSUM_COMPLETE) | 573 | else if (head->ip_summed == CHECKSUM_COMPLETE) |
567 | head->csum = csum_add(head->csum, fp->csum); | 574 | head->csum = csum_add(head->csum, fp->csum); |
568 | head->truesize += fp->truesize; | 575 | head->truesize += fp->truesize; |
569 | atomic_sub(fp->truesize, &qp->q.net->mem); | ||
570 | } | 576 | } |
577 | atomic_sub(head->truesize, &qp->q.net->mem); | ||
571 | 578 | ||
572 | head->next = NULL; | 579 | head->next = NULL; |
573 | head->dev = dev; | 580 | head->dev = dev; |
@@ -578,6 +585,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
578 | iph->tot_len = htons(len); | 585 | iph->tot_len = htons(len); |
579 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); | 586 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); |
580 | qp->q.fragments = NULL; | 587 | qp->q.fragments = NULL; |
588 | qp->q.fragments_tail = NULL; | ||
581 | return 0; | 589 | return 0; |
582 | 590 | ||
583 | out_nomem: | 591 | out_nomem: |
@@ -624,6 +632,7 @@ int ip_defrag(struct sk_buff *skb, u32 user) | |||
624 | kfree_skb(skb); | 632 | kfree_skb(skb); |
625 | return -ENOMEM; | 633 | return -ENOMEM; |
626 | } | 634 | } |
635 | EXPORT_SYMBOL(ip_defrag); | ||
627 | 636 | ||
628 | #ifdef CONFIG_SYSCTL | 637 | #ifdef CONFIG_SYSCTL |
629 | static int zero; | 638 | static int zero; |
@@ -777,5 +786,3 @@ void __init ipfrag_init(void) | |||
777 | ip4_frags.secret_interval = 10 * 60 * HZ; | 786 | ip4_frags.secret_interval = 10 * 60 * HZ; |
778 | inet_frags_init(&ip4_frags); | 787 | inet_frags_init(&ip4_frags); |
779 | } | 788 | } |
780 | |||
781 | EXPORT_SYMBOL(ip_defrag); | ||