diff options
Diffstat (limited to 'net/ipv6/exthdrs.c')
| -rw-r--r-- | net/ipv6/exthdrs.c | 29 | 
1 files changed, 11 insertions, 18 deletions
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index a8d961d3a477..5fa0e37305d9 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -569,24 +569,6 @@ looped_back:  		return -1;  	} -	if (skb_cloned(skb)) { -		if (pskb_expand_head(skb, IPV6_RPL_SRH_WORST_SWAP_SIZE, 0, -				     GFP_ATOMIC)) { -			__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), -					IPSTATS_MIB_OUTDISCARDS); -			kfree_skb(skb); -			return -1; -		} -	} else { -		err = skb_cow_head(skb, IPV6_RPL_SRH_WORST_SWAP_SIZE); -		if (unlikely(err)) { -			kfree_skb(skb); -			return -1; -		} -	} - -	hdr = (struct ipv6_rpl_sr_hdr *)skb_transport_header(skb); -  	if (!pskb_may_pull(skb, ipv6_rpl_srh_size(n, hdr->cmpri,  						  hdr->cmpre))) {  		kfree_skb(skb); @@ -630,6 +612,17 @@ looped_back:  	skb_pull(skb, ((hdr->hdrlen + 1) << 3));  	skb_postpull_rcsum(skb, oldhdr,  			   sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3)); +	if (unlikely(!hdr->segments_left)) { +		if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0, +				     GFP_ATOMIC)) { +			__IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS); +			kfree_skb(skb); +			kfree(buf); +			return -1; +		} + +		oldhdr = ipv6_hdr(skb); +	}  	skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr));  	skb_reset_network_header(skb);  	skb_mac_header_rebuild(skb);  | 
