diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/tcp_input.c | 27 |
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 | } |