mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 22:54:05 +08:00
tcp: Discard segments that ack data not yet sent
Discard incoming packets whose ack field iincludes data not yet sent. This is consistent with RFC 793 Section 3.9. Change tcp_ack() to distinguish between too-small and too-large ack field values. Keep segments with too-large ack fields out of the fast path, and change slow path to discard them. Reported-by: Oliver Zheng <mailinglists+netdev@oliverzheng.com> Signed-off-by: John Dykstra <john.dykstra1@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
763dccdc8e
commit
96e0bf4b51
@ -3585,15 +3585,18 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
|
|||||||
int prior_packets;
|
int prior_packets;
|
||||||
int frto_cwnd = 0;
|
int frto_cwnd = 0;
|
||||||
|
|
||||||
/* If the ack is newer than sent or older than previous acks
|
/* If the ack is older than previous acks
|
||||||
* then we can probably ignore it.
|
* then we can probably ignore it.
|
||||||
*/
|
*/
|
||||||
if (after(ack, tp->snd_nxt))
|
|
||||||
goto uninteresting_ack;
|
|
||||||
|
|
||||||
if (before(ack, prior_snd_una))
|
if (before(ack, prior_snd_una))
|
||||||
goto old_ack;
|
goto old_ack;
|
||||||
|
|
||||||
|
/* If the ack includes data we haven't sent yet, discard
|
||||||
|
* this segment (RFC793 Section 3.9).
|
||||||
|
*/
|
||||||
|
if (after(ack, tp->snd_nxt))
|
||||||
|
goto invalid_ack;
|
||||||
|
|
||||||
if (after(ack, prior_snd_una))
|
if (after(ack, prior_snd_una))
|
||||||
flag |= FLAG_SND_UNA_ADVANCED;
|
flag |= FLAG_SND_UNA_ADVANCED;
|
||||||
|
|
||||||
@ -3683,6 +3686,10 @@ no_queue:
|
|||||||
tcp_ack_probe(sk);
|
tcp_ack_probe(sk);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
invalid_ack:
|
||||||
|
SOCK_DEBUG(sk, "Ack %u after %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
|
||||||
|
return -1;
|
||||||
|
|
||||||
old_ack:
|
old_ack:
|
||||||
if (TCP_SKB_CB(skb)->sacked) {
|
if (TCP_SKB_CB(skb)->sacked) {
|
||||||
tcp_sacktag_write_queue(sk, skb, prior_snd_una);
|
tcp_sacktag_write_queue(sk, skb, prior_snd_una);
|
||||||
@ -3690,8 +3697,7 @@ old_ack:
|
|||||||
tcp_try_keep_open(sk);
|
tcp_try_keep_open(sk);
|
||||||
}
|
}
|
||||||
|
|
||||||
uninteresting_ack:
|
SOCK_DEBUG(sk, "Ack %u before %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
|
||||||
SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5141,7 +5147,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
|
if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
|
||||||
TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
|
TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
|
||||||
|
!after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
|
||||||
int tcp_header_len = tp->tcp_header_len;
|
int tcp_header_len = tp->tcp_header_len;
|
||||||
|
|
||||||
/* Timestamp header prediction: tcp_header_len
|
/* Timestamp header prediction: tcp_header_len
|
||||||
@ -5294,8 +5301,8 @@ slow_path:
|
|||||||
return -res;
|
return -res;
|
||||||
|
|
||||||
step5:
|
step5:
|
||||||
if (th->ack)
|
if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
|
||||||
tcp_ack(sk, skb, FLAG_SLOWPATH);
|
goto discard;
|
||||||
|
|
||||||
tcp_rcv_rtt_measure_ts(sk, skb);
|
tcp_rcv_rtt_measure_ts(sk, skb);
|
||||||
|
|
||||||
@ -5632,7 +5639,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
|
|||||||
|
|
||||||
/* step 5: check the ACK field */
|
/* step 5: check the ACK field */
|
||||||
if (th->ack) {
|
if (th->ack) {
|
||||||
int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH);
|
int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;
|
||||||
|
|
||||||
switch (sk->sk_state) {
|
switch (sk->sk_state) {
|
||||||
case TCP_SYN_RECV:
|
case TCP_SYN_RECV:
|
||||||
|
Loading…
Reference in New Issue
Block a user