diff options
-rw-r--r-- | net/ipv4/tcp_input.c | 56 |
1 files changed, 36 insertions, 20 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0aa17243d369..5187870d0333 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -960,6 +960,39 @@ static void tcp_update_reordering(struct sock *sk, const int metric, | |||
960 | * Both of these heuristics are not used in Loss state, when we cannot | 960 | * Both of these heuristics are not used in Loss state, when we cannot |
961 | * account for retransmits accurately. | 961 | * account for retransmits accurately. |
962 | */ | 962 | */ |
963 | static int tcp_check_dsack(struct tcp_sock *tp, struct sk_buff *ack_skb, | ||
964 | struct tcp_sack_block_wire *sp, int num_sacks, | ||
965 | u32 prior_snd_una) | ||
966 | { | ||
967 | u32 start_seq_0 = ntohl(get_unaligned(&sp[0].start_seq)); | ||
968 | u32 end_seq_0 = ntohl(get_unaligned(&sp[0].end_seq)); | ||
969 | int dup_sack = 0; | ||
970 | |||
971 | if (before(start_seq_0, TCP_SKB_CB(ack_skb)->ack_seq)) { | ||
972 | dup_sack = 1; | ||
973 | tp->rx_opt.sack_ok |= 4; | ||
974 | NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV); | ||
975 | } else if (num_sacks > 1) { | ||
976 | u32 end_seq_1 = ntohl(get_unaligned(&sp[1].end_seq)); | ||
977 | u32 start_seq_1 = ntohl(get_unaligned(&sp[1].start_seq)); | ||
978 | |||
979 | if (!after(end_seq_0, end_seq_1) && | ||
980 | !before(start_seq_0, start_seq_1)) { | ||
981 | dup_sack = 1; | ||
982 | tp->rx_opt.sack_ok |= 4; | ||
983 | NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV); | ||
984 | } | ||
985 | } | ||
986 | |||
987 | /* D-SACK for already forgotten data... Do dumb counting. */ | ||
988 | if (dup_sack && | ||
989 | !after(end_seq_0, prior_snd_una) && | ||
990 | after(end_seq_0, tp->undo_marker)) | ||
991 | tp->undo_retrans--; | ||
992 | |||
993 | return dup_sack; | ||
994 | } | ||
995 | |||
963 | static int | 996 | static int |
964 | tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una) | 997 | tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_una) |
965 | { | 998 | { |
@@ -985,27 +1018,10 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ | |||
985 | } | 1018 | } |
986 | prior_fackets = tp->fackets_out; | 1019 | prior_fackets = tp->fackets_out; |
987 | 1020 | ||
988 | /* Check for D-SACK. */ | 1021 | found_dup_sack = tcp_check_dsack(tp, ack_skb, sp, |
989 | if (before(ntohl(sp[0].start_seq), TCP_SKB_CB(ack_skb)->ack_seq)) { | 1022 | num_sacks, prior_snd_una); |
990 | flag |= FLAG_DSACKING_ACK; | 1023 | if (found_dup_sack) |
991 | found_dup_sack = 1; | ||
992 | tp->rx_opt.sack_ok |= 4; | ||
993 | NET_INC_STATS_BH(LINUX_MIB_TCPDSACKRECV); | ||
994 | } else if (num_sacks > 1 && | ||
995 | !after(ntohl(sp[0].end_seq), ntohl(sp[1].end_seq)) && | ||
996 | !before(ntohl(sp[0].start_seq), ntohl(sp[1].start_seq))) { | ||
997 | flag |= FLAG_DSACKING_ACK; | 1024 | flag |= FLAG_DSACKING_ACK; |
998 | found_dup_sack = 1; | ||
999 | tp->rx_opt.sack_ok |= 4; | ||
1000 | NET_INC_STATS_BH(LINUX_MIB_TCPDSACKOFORECV); | ||
1001 | } | ||
1002 | |||
1003 | /* D-SACK for already forgotten data... | ||
1004 | * Do dumb counting. */ | ||
1005 | if (found_dup_sack && | ||
1006 | !after(ntohl(sp[0].end_seq), prior_snd_una) && | ||
1007 | after(ntohl(sp[0].end_seq), tp->undo_marker)) | ||
1008 | tp->undo_retrans--; | ||
1009 | 1025 | ||
1010 | /* Eliminate too old ACKs, but take into | 1026 | /* Eliminate too old ACKs, but take into |
1011 | * account more or less fresh ones, they can | 1027 | * account more or less fresh ones, they can |