aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c14
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 /*