diff options
| -rw-r--r-- | net/ipv6/ip6_output.c | 18 | ||||
| -rw-r--r-- | net/ipv6/raw.c | 3 | 
2 files changed, 13 insertions, 8 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 835c04b5239..1e20b64e646 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1193,6 +1193,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,  	struct sk_buff *skb;  	unsigned int maxfraglen, fragheaderlen;  	int exthdrlen; +	int dst_exthdrlen;  	int hh_len;  	int mtu;  	int copy; @@ -1248,7 +1249,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,  		np->cork.hop_limit = hlimit;  		np->cork.tclass = tclass;  		mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? -		      rt->dst.dev->mtu : dst_mtu(rt->dst.path); +		      rt->dst.dev->mtu : dst_mtu(&rt->dst);  		if (np->frag_size < mtu) {  			if (np->frag_size)  				mtu = np->frag_size; @@ -1259,16 +1260,17 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,  		cork->length = 0;  		sk->sk_sndmsg_page = NULL;  		sk->sk_sndmsg_off = 0; -		exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) - -			    rt->rt6i_nfheader_len; +		exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len;  		length += exthdrlen;  		transhdrlen += exthdrlen; +		dst_exthdrlen = rt->dst.header_len;  	} else {  		rt = (struct rt6_info *)cork->dst;  		fl6 = &inet->cork.fl.u.ip6;  		opt = np->cork.opt;  		transhdrlen = 0;  		exthdrlen = 0; +		dst_exthdrlen = 0;  		mtu = cork->fragsize;  	} @@ -1368,6 +1370,8 @@ alloc_new_skb:  			else  				alloclen = datalen + fragheaderlen; +			alloclen += dst_exthdrlen; +  			/*  			 * The last fragment gets additional space at tail.  			 * Note: we overallocate on fragments with MSG_MODE @@ -1419,9 +1423,9 @@ alloc_new_skb:  			/*  			 *	Find where to start putting bytes  			 */ -			data = skb_put(skb, fraglen); -			skb_set_network_header(skb, exthdrlen); -			data += fragheaderlen; +			data = skb_put(skb, fraglen + dst_exthdrlen); +			skb_set_network_header(skb, exthdrlen + dst_exthdrlen); +			data += fragheaderlen + dst_exthdrlen;  			skb->transport_header = (skb->network_header +  						 fragheaderlen);  			if (fraggap) { @@ -1434,6 +1438,7 @@ alloc_new_skb:  				pskb_trim_unique(skb_prev, maxfraglen);  			}  			copy = datalen - transhdrlen - fraggap; +  			if (copy < 0) {  				err = -EINVAL;  				kfree_skb(skb); @@ -1448,6 +1453,7 @@ alloc_new_skb:  			length -= datalen - fraggap;  			transhdrlen = 0;  			exthdrlen = 0; +			dst_exthdrlen = 0;  			csummode = CHECKSUM_NONE;  			/* diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 3486f62befa..6f7824e1cea 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -542,8 +542,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,  		goto out;  	offset = rp->offset; -	total_len = inet_sk(sk)->cork.base.length - (skb_network_header(skb) - -						     skb->data); +	total_len = inet_sk(sk)->cork.base.length;  	if (offset >= total_len - 1) {  		err = -EINVAL;  		ip6_flush_pending_frames(sk);  |