aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2013-04-19 03:19:48 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-19 14:21:53 -0400
commit12fb3dd9dc3c64ba7d64cec977cca9b5fb7b1d4e (patch)
tree81a5445ca74dfe73c0ecee78f9f5c16a4eef843f /net
parent4394542ca4ec9f28c3c8405063d200b1e7c347d7 (diff)
tcp: call tcp_replace_ts_recent() from tcp_ack()
commit bd090dfc634d (tcp: tcp_replace_ts_recent() should not be called from tcp_validate_incoming()) introduced a TS ecr bug in slow path processing. 1 A > B P. 1:10001(10000) ack 1 <nop,nop,TS val 1001 ecr 200> 2 B < A . 1:1(0) ack 1 win 257 <sack 9001:10001,TS val 300 ecr 1001> 3 A > B . 1:1001(1000) ack 1 win 227 <nop,nop,TS val 1002 ecr 200> 4 A > B . 1001:2001(1000) ack 1 win 227 <nop,nop,TS val 1002 ecr 200> (ecr 200 should be ecr 300 in packets 3 & 4) Problem is tcp_ack() can trigger send of new packets (retransmits), reflecting the prior TSval, instead of the TSval contained in the currently processed incoming packet. Fix this by calling tcp_replace_ts_recent() from tcp_ack() after the checks, but before the actions. Reported-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Neal Cardwell <ncardwell@google.com> Acked-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_input.c64
1 files changed, 31 insertions, 33 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3bd55bad230a..13b9c08fc158 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -113,6 +113,7 @@ int sysctl_tcp_early_retrans __read_mostly = 2;
113#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ 113#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */
114#define FLAG_NONHEAD_RETRANS_ACKED 0x1000 /* Non-head rexmitted data was ACKed */ 114#define FLAG_NONHEAD_RETRANS_ACKED 0x1000 /* Non-head rexmitted data was ACKed */
115#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ 115#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */
116#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */
116 117
117#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) 118#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED)
118#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) 119#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
@@ -3564,6 +3565,27 @@ static void tcp_send_challenge_ack(struct sock *sk)
3564 } 3565 }
3565} 3566}
3566 3567
3568static void tcp_store_ts_recent(struct tcp_sock *tp)
3569{
3570 tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
3571 tp->rx_opt.ts_recent_stamp = get_seconds();
3572}
3573
3574static void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
3575{
3576 if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) {
3577 /* PAWS bug workaround wrt. ACK frames, the PAWS discard
3578 * extra check below makes sure this can only happen
3579 * for pure ACK frames. -DaveM
3580 *
3581 * Not only, also it occurs for expired timestamps.
3582 */
3583
3584 if (tcp_paws_check(&tp->rx_opt, 0))
3585 tcp_store_ts_recent(tp);
3586 }
3587}
3588
3567/* This routine deals with incoming acks, but not outgoing ones. */ 3589/* This routine deals with incoming acks, but not outgoing ones. */
3568static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) 3590static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3569{ 3591{
@@ -3607,6 +3629,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3607 prior_fackets = tp->fackets_out; 3629 prior_fackets = tp->fackets_out;
3608 prior_in_flight = tcp_packets_in_flight(tp); 3630 prior_in_flight = tcp_packets_in_flight(tp);
3609 3631
3632 /* ts_recent update must be made after we are sure that the packet
3633 * is in window.
3634 */
3635 if (flag & FLAG_UPDATE_TS_RECENT)
3636 tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
3637
3610 if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) { 3638 if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
3611 /* Window is constant, pure forward advance. 3639 /* Window is constant, pure forward advance.
3612 * No more checks are required. 3640 * No more checks are required.
@@ -3927,27 +3955,6 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
3927EXPORT_SYMBOL(tcp_parse_md5sig_option); 3955EXPORT_SYMBOL(tcp_parse_md5sig_option);
3928#endif 3956#endif
3929 3957
3930static inline void tcp_store_ts_recent(struct tcp_sock *tp)
3931{
3932 tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
3933 tp->rx_opt.ts_recent_stamp = get_seconds();
3934}
3935
3936static inline void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
3937{
3938 if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) {
3939 /* PAWS bug workaround wrt. ACK frames, the PAWS discard
3940 * extra check below makes sure this can only happen
3941 * for pure ACK frames. -DaveM
3942 *
3943 * Not only, also it occurs for expired timestamps.
3944 */
3945
3946 if (tcp_paws_check(&tp->rx_opt, 0))
3947 tcp_store_ts_recent(tp);
3948 }
3949}
3950
3951/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM 3958/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM
3952 * 3959 *
3953 * It is not fatal. If this ACK does _not_ change critical state (seqs, window) 3960 * It is not fatal. If this ACK does _not_ change critical state (seqs, window)
@@ -5543,14 +5550,9 @@ slow_path:
5543 return 0; 5550 return 0;
5544 5551
5545step5: 5552step5:
5546 if (tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) 5553 if (tcp_ack(sk, skb, FLAG_SLOWPATH | FLAG_UPDATE_TS_RECENT) < 0)
5547 goto discard; 5554 goto discard;
5548 5555
5549 /* ts_recent update must be made after we are sure that the packet
5550 * is in window.
5551 */
5552 tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
5553
5554 tcp_rcv_rtt_measure_ts(sk, skb); 5556 tcp_rcv_rtt_measure_ts(sk, skb);
5555 5557
5556 /* Process urgent data. */ 5558 /* Process urgent data. */
@@ -5986,7 +5988,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
5986 5988
5987 /* step 5: check the ACK field */ 5989 /* step 5: check the ACK field */
5988 if (true) { 5990 if (true) {
5989 int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0; 5991 int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH |
5992 FLAG_UPDATE_TS_RECENT) > 0;
5990 5993
5991 switch (sk->sk_state) { 5994 switch (sk->sk_state) {
5992 case TCP_SYN_RECV: 5995 case TCP_SYN_RECV:
@@ -6137,11 +6140,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
6137 } 6140 }
6138 } 6141 }
6139 6142
6140 /* ts_recent update must be made after we are sure that the packet
6141 * is in window.
6142 */
6143 tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
6144
6145 /* step 6: check the URG bit */ 6143 /* step 6: check the URG bit */
6146 tcp_urg(sk, skb, th); 6144 tcp_urg(sk, skb, th);
6147 6145