diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
| -rw-r--r-- | net/ipv6/ip6_output.c | 46 | 
1 files changed, 24 insertions, 22 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 89e0d5118afe..4591ca4bdbe8 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -195,37 +195,37 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,  	const struct ipv6_pinfo *np = inet6_sk(sk);  	struct in6_addr *first_hop = &fl6->daddr;  	struct dst_entry *dst = skb_dst(skb); +	unsigned int head_room;  	struct ipv6hdr *hdr;  	u8  proto = fl6->flowi6_proto;  	int seg_len = skb->len;  	int hlimit = -1;  	u32 mtu; -	if (opt) { -		unsigned int head_room; +	head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev); +	if (opt) +		head_room += opt->opt_nflen + opt->opt_flen; -		/* First: exthdrs may take lots of space (~8K for now) -		   MAX_HEADER is not enough. -		 */ -		head_room = opt->opt_nflen + opt->opt_flen; -		seg_len += head_room; -		head_room += sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev); - -		if (skb_headroom(skb) < head_room) { -			struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); -			if (!skb2) { -				IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), -					      IPSTATS_MIB_OUTDISCARDS); -				kfree_skb(skb); -				return -ENOBUFS; -			} -			if (skb->sk) -				skb_set_owner_w(skb2, skb->sk); -			consume_skb(skb); -			skb = skb2; +	if (unlikely(skb_headroom(skb) < head_room)) { +		struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); +		if (!skb2) { +			IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), +				      IPSTATS_MIB_OUTDISCARDS); +			kfree_skb(skb); +			return -ENOBUFS;  		} +		if (skb->sk) +			skb_set_owner_w(skb2, skb->sk); +		consume_skb(skb); +		skb = skb2; +	} + +	if (opt) { +		seg_len += opt->opt_nflen + opt->opt_flen; +  		if (opt->opt_flen)  			ipv6_push_frag_opts(skb, opt, &proto); +  		if (opt->opt_nflen)  			ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop,  					     &fl6->saddr); @@ -378,6 +378,7 @@ static inline int ip6_forward_finish(struct net *net, struct sock *sk,  	__IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);  	__IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len); +	skb->tstamp = 0;  	return dst_output(net, sk, skb);  } @@ -1354,7 +1355,7 @@ emsgsize:  			unsigned int fraglen;  			unsigned int fraggap;  			unsigned int alloclen; -			unsigned int pagedlen = 0; +			unsigned int pagedlen;  alloc_new_skb:  			/* There's no room in the current skb */  			if (skb) @@ -1378,6 +1379,7 @@ alloc_new_skb:  			if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)  				datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len;  			fraglen = datalen + fragheaderlen; +			pagedlen = 0;  			if ((flags & MSG_MORE) &&  			    !(rt->dst.dev->features&NETIF_F_SG))  |