diff options
Diffstat (limited to 'net/ipv4')
| -rw-r--r-- | net/ipv4/tcp.c | 1 | ||||
| -rw-r--r-- | net/ipv4/tcp_input.c | 28 | ||||
| -rw-r--r-- | net/ipv4/tcp_output.c | 6 | 
3 files changed, 26 insertions, 9 deletions
| diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 00ae9a1d44ed..d51571be9eac 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3480,6 +3480,7 @@ void __init tcp_init(void)  	unsigned long limit;  	unsigned int i; +	BUILD_BUG_ON(TCP_MIN_SND_MSS <= MAX_TCP_OPTION_SPACE);  	BUILD_BUG_ON(sizeof(struct tcp_skb_cb) >  		     FIELD_SIZEOF(struct sk_buff, cb)); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 03bfec5a388a..8e080f3b75bd 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1329,7 +1329,7 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,  	TCP_SKB_CB(skb)->seq += shifted;  	tcp_skb_pcount_add(prev, pcount); -	BUG_ON(tcp_skb_pcount(skb) < pcount); +	WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount);  	tcp_skb_pcount_add(skb, -pcount);  	/* When we're adding to gso_segs == 1, gso_size will be zero, @@ -1396,6 +1396,21 @@ static int skb_can_shift(const struct sk_buff *skb)  	return !skb_headlen(skb) && skb_is_nonlinear(skb);  } +int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from, +		  int pcount, int shiftlen) +{ +	/* TCP min gso_size is 8 bytes (TCP_MIN_GSO_SIZE) +	 * Since TCP_SKB_CB(skb)->tcp_gso_segs is 16 bits, we need +	 * to make sure not storing more than 65535 * 8 bytes per skb, +	 * even if current MSS is bigger. +	 */ +	if (unlikely(to->len + shiftlen >= 65535 * TCP_MIN_GSO_SIZE)) +		return 0; +	if (unlikely(tcp_skb_pcount(to) + pcount > 65535)) +		return 0; +	return skb_shift(to, from, shiftlen); +} +  /* Try collapsing SACK blocks spanning across multiple skbs to a single   * skb.   */ @@ -1407,6 +1422,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,  	struct tcp_sock *tp = tcp_sk(sk);  	struct sk_buff *prev;  	int mss; +	int next_pcount;  	int pcount = 0;  	int len;  	int in_sack; @@ -1504,7 +1520,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,  	if (!after(TCP_SKB_CB(skb)->seq + len, tp->snd_una))  		goto fallback; -	if (!skb_shift(prev, skb, len)) +	if (!tcp_skb_shift(prev, skb, pcount, len))  		goto fallback;  	if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack))  		goto out; @@ -1523,11 +1539,11 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,  		goto out;  	len = skb->len; -	if (skb_shift(prev, skb, len)) { -		pcount += tcp_skb_pcount(skb); -		tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss, 0); +	next_pcount = tcp_skb_pcount(skb); +	if (tcp_skb_shift(prev, skb, next_pcount, len)) { +		pcount += next_pcount; +		tcp_shifted_skb(sk, skb, state, next_pcount, len, mss, 0);  	} -  out:  	state->fack_count += pcount;  	return prev; diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 24bad638c2ec..def09d1fd0e1 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1442,8 +1442,8 @@ static inline int __tcp_mtu_to_mss(struct sock *sk, int pmtu)  	mss_now -= icsk->icsk_ext_hdr_len;  	/* Then reserve room for full set of TCP options and 8 bytes of data */ -	if (mss_now < 48) -		mss_now = 48; +	if (mss_now < TCP_MIN_SND_MSS) +		mss_now = TCP_MIN_SND_MSS;  	return mss_now;  } @@ -2724,7 +2724,7 @@ static bool tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)  		if (next_skb_size <= skb_availroom(skb))  			skb_copy_bits(next_skb, 0, skb_put(skb, next_skb_size),  				      next_skb_size); -		else if (!skb_shift(skb, next_skb, next_skb_size)) +		else if (!tcp_skb_shift(skb, next_skb, 1, next_skb_size))  			return false;  	}  	tcp_highest_sack_replace(sk, next_skb, skb); | 
