|
@@ -1330,12 +1330,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
|
|
|
cached_fack_count = 0;
|
|
|
}
|
|
|
|
|
|
- for (i=0; i<num_sacks; i++, sp++) {
|
|
|
+ for (i = 0; i < num_sacks; i++) {
|
|
|
struct sk_buff *skb;
|
|
|
__u32 start_seq = ntohl(sp->start_seq);
|
|
|
__u32 end_seq = ntohl(sp->end_seq);
|
|
|
int fack_count;
|
|
|
int dup_sack = (found_dup_sack && (i == first_sack_index));
|
|
|
+ int next_dup = (found_dup_sack && (i+1 == first_sack_index));
|
|
|
+
|
|
|
+ sp++;
|
|
|
|
|
|
if (!tcp_is_sackblock_valid(tp, dup_sack, start_seq, end_seq)) {
|
|
|
if (dup_sack) {
|
|
@@ -1361,7 +1364,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
|
|
|
flag |= FLAG_DATA_LOST;
|
|
|
|
|
|
tcp_for_write_queue_from(skb, sk) {
|
|
|
- int in_sack;
|
|
|
+ int in_sack = 0;
|
|
|
u8 sacked;
|
|
|
|
|
|
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_
|
|
|
if (!before(TCP_SKB_CB(skb)->seq, end_seq))
|
|
|
break;
|
|
|
|
|
|
- in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq);
|
|
|
+ dup_sack = (found_dup_sack && (i == first_sack_index));
|
|
|
+
|
|
|
+ /* Due to sorting DSACK may reside within this SACK block! */
|
|
|
+ if (next_dup) {
|
|
|
+ u32 dup_start = ntohl(sp->start_seq);
|
|
|
+ u32 dup_end = ntohl(sp->end_seq);
|
|
|
+
|
|
|
+ if (before(TCP_SKB_CB(skb)->seq, dup_end)) {
|
|
|
+ in_sack = tcp_match_skb_to_sack(sk, skb, dup_start, dup_end);
|
|
|
+ if (in_sack > 0)
|
|
|
+ dup_sack = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* DSACK info lost if out-of-mem, try SACK still */
|
|
|
+ if (in_sack <= 0)
|
|
|
+ in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, end_seq);
|
|
|
if (in_sack < 0)
|
|
|
break;
|
|
|
|