forked from mirrors/linux
		
	tcp: Make SACK code to split only at mss boundaries
Sadly enough, this adds possible divide though we try to avoid it by checking one mss as common case. Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@helsinki.fi> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									e8bae275d9
								
							
						
					
					
						commit
						adb92db857
					
				
					 1 changed files with 23 additions and 4 deletions
				
			
		| 
						 | 
					@ -1248,20 +1248,39 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int in_sack, err;
 | 
						int in_sack, err;
 | 
				
			||||||
	unsigned int pkt_len;
 | 
						unsigned int pkt_len;
 | 
				
			||||||
 | 
						unsigned int mss;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
 | 
						in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
 | 
				
			||||||
		  !before(end_seq, TCP_SKB_CB(skb)->end_seq);
 | 
							  !before(end_seq, TCP_SKB_CB(skb)->end_seq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tcp_skb_pcount(skb) > 1 && !in_sack &&
 | 
						if (tcp_skb_pcount(skb) > 1 && !in_sack &&
 | 
				
			||||||
	    after(TCP_SKB_CB(skb)->end_seq, start_seq)) {
 | 
						    after(TCP_SKB_CB(skb)->end_seq, start_seq)) {
 | 
				
			||||||
 | 
							mss = tcp_skb_mss(skb);
 | 
				
			||||||
		in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq);
 | 
							in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!in_sack)
 | 
							if (!in_sack) {
 | 
				
			||||||
			pkt_len = start_seq - TCP_SKB_CB(skb)->seq;
 | 
								pkt_len = start_seq - TCP_SKB_CB(skb)->seq;
 | 
				
			||||||
		else
 | 
								if (pkt_len < mss)
 | 
				
			||||||
 | 
									pkt_len = mss;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
			pkt_len = end_seq - TCP_SKB_CB(skb)->seq;
 | 
								pkt_len = end_seq - TCP_SKB_CB(skb)->seq;
 | 
				
			||||||
		err = tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size);
 | 
								if (pkt_len < mss)
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Round if necessary so that SACKs cover only full MSSes
 | 
				
			||||||
 | 
							 * and/or the remaining small portion (if present)
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (pkt_len > mss) {
 | 
				
			||||||
 | 
								unsigned int new_len = (pkt_len / mss) * mss;
 | 
				
			||||||
 | 
								if (!in_sack && new_len < pkt_len) {
 | 
				
			||||||
 | 
									new_len += mss;
 | 
				
			||||||
 | 
									if (new_len > skb->len)
 | 
				
			||||||
 | 
										return 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								pkt_len = new_len;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err = tcp_fragment(sk, skb, pkt_len, mss);
 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue