aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet2013-04-19 02:19:48 -0500
committerGreg Kroah-Hartman2013-05-01 11:46:19 -0500
commit72b1b8da7cb01424cbafd36bf3a7c35215eb4ec7 (patch)
treeb47dee1eda0535e44bb10dfd058ae4d000c152ec /net
parentb0914393f1e376bc55fce1bb48972966a1761d5c (diff)
downloadkernel-video-72b1b8da7cb01424cbafd36bf3a7c35215eb4ec7.tar.gz
kernel-video-72b1b8da7cb01424cbafd36bf3a7c35215eb4ec7.tar.xz
kernel-video-72b1b8da7cb01424cbafd36bf3a7c35215eb4ec7.zip
tcp: call tcp_replace_ts_recent() from tcp_ack()
[ Upstream commit 12fb3dd9dc3c64ba7d64cec977cca9b5fb7b1d4e ] 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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 9841a716370..b4e8b797a09 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -116,6 +116,7 @@ int sysctl_tcp_early_retrans __read_mostly = 2;
116#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ 116#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */
117#define FLAG_NONHEAD_RETRANS_ACKED 0x1000 /* Non-head rexmitted data was ACKed */ 117#define FLAG_NONHEAD_RETRANS_ACKED 0x1000 /* Non-head rexmitted data was ACKed */
118#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ 118#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */
119#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */
119 120
120#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) 121#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED)
121#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) 122#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
@@ -3572,6 +3573,27 @@ static void tcp_send_challenge_ack(struct sock *sk)
3572 } 3573 }
3573} 3574}
3574 3575
3576static void tcp_store_ts_recent(struct tcp_sock *tp)
3577{
3578 tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
3579 tp->rx_opt.ts_recent_stamp = get_seconds();
3580}
3581
3582static void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
3583{
3584 if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) {
3585 /* PAWS bug workaround wrt. ACK frames, the PAWS discard
3586 * extra check below makes sure this can only happen
3587 * for pure ACK frames. -DaveM
3588 *
3589 * Not only, also it occurs for expired timestamps.
3590 */
3591
3592 if (tcp_paws_check(&tp->rx_opt, 0))
3593 tcp_store_ts_recent(tp);
3594 }
3595}
3596
3575/* This routine deals with incoming acks, but not outgoing ones. */ 3597/* This routine deals with incoming acks, but not outgoing ones. */
3576static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) 3598static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3577{ 3599{
@@ -3624,6 +3646,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3624 prior_fackets = tp->fackets_out; 3646 prior_fackets = tp->fackets_out;
3625 prior_in_flight = tcp_packets_in_flight(tp); 3647 prior_in_flight = tcp_packets_in_flight(tp);
3626 3648
3649 /* ts_recent update must be made after we are sure that the packet
3650 * is in window.
3651 */
3652 if (flag & FLAG_UPDATE_TS_RECENT)
3653 tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
3654
3627 if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) { 3655 if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) {
3628 /* Window is constant, pure forward advance. 3656 /* Window is constant, pure forward advance.
3629 * No more checks are required. 3657 * No more checks are required.
@@ -3940,27 +3968,6 @@ const u8 *tcp_parse_md5sig_option(const struct tcphdr *th)
3940EXPORT_SYMBOL(tcp_parse_md5sig_option); 3968EXPORT_SYMBOL(tcp_parse_md5sig_option);
3941#endif 3969#endif
3942 3970
3943static inline void tcp_store_ts_recent(struct tcp_sock *tp)
3944{
3945 tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
3946 tp->rx_opt.ts_recent_stamp = get_seconds();
3947}
3948
3949static inline void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
3950{
3951 if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) {
3952 /* PAWS bug workaround wrt. ACK frames, the PAWS discard
3953 * extra check below makes sure this can only happen
3954 * for pure ACK frames. -DaveM
3955 *
3956 * Not only, also it occurs for expired timestamps.
3957 */
3958
3959 if (tcp_paws_check(&tp->rx_opt, 0))
3960 tcp_store_ts_recent(tp);
3961 }
3962}
3963
3964/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM 3971/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM
3965 * 3972 *
3966 * It is not fatal. If this ACK does _not_ change critical state (seqs, window) 3973 * It is not fatal. If this ACK does _not_ change critical state (seqs, window)
@@ -5556,14 +5563,9 @@ slow_path:
5556 return 0; 5563 return 0;
5557 5564
5558step5: 5565step5:
5559 if (tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) 5566 if (tcp_ack(sk, skb, FLAG_SLOWPATH | FLAG_UPDATE_TS_RECENT) < 0)
5560 goto discard; 5567 goto discard;
5561 5568
5562 /* ts_recent update must be made after we are sure that the packet
5563 * is in window.
5564 */
5565 tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
5566
5567 tcp_rcv_rtt_measure_ts(sk, skb); 5569 tcp_rcv_rtt_measure_ts(sk, skb);
5568 5570
5569 /* Process urgent data. */ 5571 /* Process urgent data. */
@@ -5997,7 +5999,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
5997 5999
5998 /* step 5: check the ACK field */ 6000 /* step 5: check the ACK field */
5999 if (true) { 6001 if (true) {
6000 int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0; 6002 int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH |
6003 FLAG_UPDATE_TS_RECENT) > 0;
6001 6004
6002 switch (sk->sk_state) { 6005 switch (sk->sk_state) {
6003 case TCP_SYN_RECV: 6006 case TCP_SYN_RECV:
@@ -6148,11 +6151,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
6148 } 6151 }
6149 } 6152 }
6150 6153
6151 /* ts_recent update must be made after we are sure that the packet
6152 * is in window.
6153 */
6154 tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq);
6155
6156 /* step 6: check the URG bit */ 6154 /* step 6: check the URG bit */
6157 tcp_urg(sk, skb, th); 6155 tcp_urg(sk, skb, th);
6158 6156