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 60c565309d0a..a598fe2c0849 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -600,20 +600,22 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, | |||
600 | frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, | 600 | frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, |
601 | &ipv6_hdr(skb)->saddr); | 601 | &ipv6_hdr(skb)->saddr); |
602 | 602 | ||
603 | hroom = LL_RESERVED_SPACE(rt->dst.dev); | ||
603 | if (skb_has_frag_list(skb)) { | 604 | if (skb_has_frag_list(skb)) { |
604 | int first_len = skb_pagelen(skb); | 605 | int first_len = skb_pagelen(skb); |
605 | struct sk_buff *frag2; | 606 | struct sk_buff *frag2; |
606 | 607 | ||
607 | if (first_len - hlen > mtu || | 608 | if (first_len - hlen > mtu || |
608 | ((first_len - hlen) & 7) || | 609 | ((first_len - hlen) & 7) || |
609 | skb_cloned(skb)) | 610 | skb_cloned(skb) || |
611 | skb_headroom(skb) < (hroom + sizeof(struct frag_hdr))) | ||
610 | goto slow_path; | 612 | goto slow_path; |
611 | 613 | ||
612 | skb_walk_frags(skb, frag) { | 614 | skb_walk_frags(skb, frag) { |
613 | /* Correct geometry. */ | 615 | /* Correct geometry. */ |
614 | if (frag->len > mtu || | 616 | if (frag->len > mtu || |
615 | ((frag->len & 7) && frag->next) || | 617 | ((frag->len & 7) && frag->next) || |
616 | skb_headroom(frag) < hlen) | 618 | skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr))) |
617 | goto slow_path_clean; | 619 | goto slow_path_clean; |
618 | 620 | ||
619 | /* Partially cloned skb? */ | 621 | /* Partially cloned skb? */ |
@@ -630,8 +632,6 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, | |||
630 | 632 | ||
631 | err = 0; | 633 | err = 0; |
632 | offset = 0; | 634 | offset = 0; |
633 | frag = skb_shinfo(skb)->frag_list; | ||
634 | skb_frag_list_init(skb); | ||
635 | /* BUILD HEADER */ | 635 | /* BUILD HEADER */ |
636 | 636 | ||
637 | *prevhdr = NEXTHDR_FRAGMENT; | 637 | *prevhdr = NEXTHDR_FRAGMENT; |
@@ -639,8 +639,11 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, | |||
639 | if (!tmp_hdr) { | 639 | if (!tmp_hdr) { |
640 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), | 640 | IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), |
641 | IPSTATS_MIB_FRAGFAILS); | 641 | IPSTATS_MIB_FRAGFAILS); |
642 | return -ENOMEM; | 642 | err = -ENOMEM; |
643 | goto fail; | ||
643 | } | 644 | } |
645 | frag = skb_shinfo(skb)->frag_list; | ||
646 | skb_frag_list_init(skb); | ||
644 | 647 | ||
645 | __skb_pull(skb, hlen); | 648 | __skb_pull(skb, hlen); |
646 | fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr)); | 649 | fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr)); |
@@ -737,7 +740,6 @@ slow_path: | |||
737 | */ | 740 | */ |
738 | 741 | ||
739 | *prevhdr = NEXTHDR_FRAGMENT; | 742 | *prevhdr = NEXTHDR_FRAGMENT; |
740 | hroom = LL_RESERVED_SPACE(rt->dst.dev); | ||
741 | troom = rt->dst.dev->needed_tailroom; | 743 | troom = rt->dst.dev->needed_tailroom; |
742 | 744 | ||
743 | /* | 745 | /* |