aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorIlpo Järvinen <ilpo.jarvinen@helsinki.fi>2008-11-25 00:13:50 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-25 00:13:50 -0500
commitadb92db857ee2a0a2b925ccfbd560203c3f88aae (patch)
treefac842e439d3a6bcd54aef5ab72a53fa831119a9 /net
parente8bae275d9354104f7ae24a48a90d1a6286e7bd9 (diff)
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>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_input.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3f26599ddc88..ca46eb9151f8 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1248,20 +1248,39 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb,
1248{ 1248{
1249 int in_sack, err; 1249 int in_sack, err;
1250 unsigned int pkt_len; 1250 unsigned int pkt_len;
1251 unsigned int mss;
1251 1252
1252 in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && 1253 in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
1253 !before(end_seq, TCP_SKB_CB(skb)->end_seq); 1254 !before(end_seq, TCP_SKB_CB(skb)->end_seq);
1254 1255
1255 if (tcp_skb_pcount(skb) > 1 && !in_sack && 1256 if (tcp_skb_pcount(skb) > 1 && !in_sack &&
1256 after(TCP_SKB_CB(skb)->end_seq, start_seq)) { 1257 after(TCP_SKB_CB(skb)->end_seq, start_seq)) {
1257 1258 mss = tcp_skb_mss(skb);
1258 in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq); 1259 in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq);
1259 1260
1260 if (!in_sack) 1261 if (!in_sack) {
1261 pkt_len = start_seq - TCP_SKB_CB(skb)->seq; 1262 pkt_len = start_seq - TCP_SKB_CB(skb)->seq;
1262 else 1263 if (pkt_len < mss)
1264 pkt_len = mss;
1265 } else {
1263 pkt_len = end_seq - TCP_SKB_CB(skb)->seq; 1266 pkt_len = end_seq - TCP_SKB_CB(skb)->seq;
1264 err = tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size); 1267 if (pkt_len < mss)
1268 return -EINVAL;
1269 }
1270
1271 /* Round if necessary so that SACKs cover only full MSSes
1272 * and/or the remaining small portion (if present)
1273 */
1274 if (pkt_len > mss) {
1275 unsigned int new_len = (pkt_len / mss) * mss;
1276 if (!in_sack && new_len < pkt_len) {
1277 new_len += mss;
1278 if (new_len > skb->len)
1279 return 0;
1280 }
1281 pkt_len = new_len;
1282 }
1283 err = tcp_fragment(sk, skb, pkt_len, mss);
1265 if (err < 0) 1284 if (err < 0)
1266 return err; 1285 return err;
1267 } 1286 }