diff options
Diffstat (limited to 'net/ipv4/tcp_input.c')
-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 69d8c38ccd39..ca9590f4f520 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -1330,12 +1330,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1330 | cached_fack_count = 0; | 1330 | cached_fack_count = 0; |
1331 | } | 1331 | } |
1332 | 1332 | ||
1333 | for (i=0; i<num_sacks; i++, sp++) { | 1333 | for (i = 0; i < num_sacks; i++) { |
1334 | struct sk_buff *skb; | 1334 | struct sk_buff *skb; |
1335 | __u32 start_seq = ntohl(sp->start_seq); | 1335 | __u32 start_seq = ntohl(sp->start_seq); |
1336 | __u32 end_seq = ntohl(sp->end_seq); | 1336 | __u32 end_seq = ntohl(sp->end_seq); |
1337 | int fack_count; | 1337 | int fack_count; |
1338 | int dup_sack = (found_dup_sack && (i == first_sack_index)); | 1338 | int dup_sack = (found_dup_sack && (i == first_sack_index)); |
1339 | int next_dup = (found_dup_sack && (i+1 == first_sack_index)); | ||
1340 | |||
1341 | sp++; | ||
1339 | 1342 | ||
1340 | if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) { | 1343 | if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) { |
1341 | if (dup_sack) { | 1344 | if (dup_sack) { |
@@ -1361,7 +1364,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1361 | flag |= FLAG_DATA_LOST; | 1364 | flag |= FLAG_DATA_LOST; |
1362 | 1365 | ||
1363 | tcp_for_write_queue_from(skb, sk) { | 1366 | tcp_for_write_queue_from(skb, sk) { |
1364 | int in_sack; | 1367 | int in_sack = 0; |
1365 | u8 sacked; | 1368 | u8 sacked; |
1366 | 1369 | ||
1367 | if (skb == tcp_send_head(sk)) | 1370 | if (skb == tcp_send_head(sk)) |
@@ -1380,7 +1383,23 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
1380 | if (!before(TCP_SKB_CB(skb)->seq, end_seq)) | 1383 | if (!before(TCP_SKB_CB(skb)->seq, end_seq)) |
1381 | break; | 1384 | break; |
1382 | 1385 | ||
1383 | in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq); | 1386 | dup_sack = (found_dup_sack && (i == first_sack_index)); |
1387 | |||
1388 | /* Due to sorting DSACK may reside within this SACK block! */ | ||
1389 | if (next_dup) { | ||
1390 | u32 dup_start = ntohl(sp->start_seq); | ||
1391 | u32 dup_end = ntohl(sp->end_seq); | ||
1392 | |||
1393 | if (before(TCP_SKB_CB(skb)->seq, dup_end)) { | ||
1394 | in_sack = tcp_match_skb_to_sack(sk, skb, dup_start, dup_end); | ||
1395 | if (in_sack > 0) | ||
1396 | dup_sack = 1; | ||
1397 | } | ||
1398 | } | ||
1399 | |||
1400 | /* DSACK info lost if out-of-mem, try SACK still */ | ||
1401 | if (in_sack <= 0) | ||
1402 | in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq); | ||
1384 | if (in_sack < 0) | 1403 | if (in_sack < 0) |
1385 | break; | 1404 | break; |
1386 | 1405 | ||
@@ -2059,7 +2078,7 @@ static void tcp_update_scoreboard(struct sock *sk) | |||
2059 | if (!tcp_skb_timedout(sk, skb)) | 2078 | if (!tcp_skb_timedout(sk, skb)) |
2060 | break; | 2079 | break; |
2061 | 2080 | ||
2062 | if (!(TCP_SKB_CB(skb)->sacked&TCPCB_TAGBITS)) { | 2081 | if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_SACKED_ACKED|TCPCB_LOST))) { |
2063 | TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; | 2082 | TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; |
2064 | tp->lost_out += tcp_skb_pcount(skb); | 2083 | tp->lost_out += tcp_skb_pcount(skb); |
2065 | tcp_verify_retransmit_hint(tp, skb); | 2084 | tcp_verify_retransmit_hint(tp, skb); |