diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 14 |
1 files changed, 8 insertions, 6 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 26ea47930740..92b1aa38f121 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -586,20 +586,22 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, | |||
586 | frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, | 586 | frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, |
587 | &ipv6_hdr(skb)->saddr); | 587 | &ipv6_hdr(skb)->saddr); |
588 | 588 | ||
589 | hroom = LL_RESERVED_SPACE(rt->dst.dev); | ||
589 | if (skb_has_frag_list(skb)) { | 590 | if (skb_has_frag_list(skb)) { |
590 | int first_len = skb_pagelen(skb); | 591 | int first_len = skb_pagelen(skb); |
591 | struct sk_buff *frag2; | 592 | struct sk_buff *frag2; |
592 | 593 | ||
593 | if (first_len - hlen > mtu || | 594 | if (first_len - hlen > mtu || |
594 | ((first_len - hlen) & 7) || | 595 | ((first_len - hlen) & 7) || |
595 | skb_cloned(skb)) | 596 | skb_cloned(skb) || |
597 | skb_headroom(skb) < (hroom + sizeof(struct frag_hdr))) | ||
596 | goto slow_path; | 598 | goto slow_path; |
597 | 599 | ||
598 | skb_walk_frags(skb, frag) { | 600 | skb_walk_frags(skb, frag) { |
599 | /* Correct geometry. */ | 601 | /* Correct geometry. */ |
600 | if (frag->len > mtu || | 602 | if (frag->len > mtu || |
601 | ((frag->len & 7) && frag->next) || | 603 | ((frag->len & 7) && frag->next) || |
602 | skb_headroom(frag) < hlen) | 604 | skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr))) |
603 | goto slow_path_clean; | 605 | goto slow_path_clean; |
604 | 606 | ||
605 | /* Partially cloned skb? */ | 607 | /* Partially cloned skb? */ |
@@ -616,8 +618,6 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, | |||
616 | 618 | ||
617 | err = 0; | 619 | err = 0; |
618 | offset = 0; | 620 | offset = 0; |
619 | frag = skb_shinfo(skb)->frag_list; | ||
620 | skb_frag_list_init(skb); | ||
621 | /* BUILD HEADER */ | 621 | /* BUILD HEADER */ |
622 | 622 | ||
623 | *prevhdr = NEXTHDR_FRAGMENT; | 623 | *prevhdr = NEXTHDR_FRAGMENT; |
@@ -625,8 +625,11 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, | |||
625 | if (!tmp_hdr) { | 625 | if (!tmp_hdr) { |
626 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), | 626 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
627 | IPSTATS_MIB_FRAGFAILS); | 627 | IPSTATS_MIB_FRAGFAILS); |
628 | return -ENOMEM; | 628 | err = -ENOMEM; |
629 | goto fail; | ||
629 | } | 630 | } |
631 | frag = skb_shinfo(skb)->frag_list; | ||
632 | skb_frag_list_init(skb); | ||
630 | 633 | ||
631 | __skb_pull(skb, hlen); | 634 | __skb_pull(skb, hlen); |
632 | fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr)); | 635 | fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr)); |
@@ -723,7 +726,6 @@ slow_path: | |||
723 | */ | 726 | */ |
724 | 727 | ||
725 | *prevhdr = NEXTHDR_FRAGMENT; | 728 | *prevhdr = NEXTHDR_FRAGMENT; |
726 | hroom = LL_RESERVED_SPACE(rt->dst.dev); | ||
727 | troom = rt->dst.dev->needed_tailroom; | 729 | troom = rt->dst.dev->needed_tailroom; |
728 | 730 | ||
729 | /* | 731 | /* |