Skip to content

Commit 96e0bf4

Browse files
jdykstradavem330
authored andcommitted
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>
1 parent 763dccd commit 96e0bf4

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

net/ipv4/tcp_input.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3585,15 +3585,18 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
35853585
int prior_packets;
35863586
int frto_cwnd = 0;
35873587

3588-
/* If the ack is newer than sent or older than previous acks
3588+
/* If the ack is older than previous acks
35893589
* then we can probably ignore it.
35903590
*/
3591-
if (after(ack, tp->snd_nxt))
3592-
goto uninteresting_ack;
3593-
35943591
if (before(ack, prior_snd_una))
35953592
goto old_ack;
35963593

3594+
/* If the ack includes data we haven't sent yet, discard
3595+
* this segment (RFC793 Section 3.9).
3596+
*/
3597+
if (after(ack, tp->snd_nxt))
3598+
goto invalid_ack;
3599+
35973600
if (after(ack, prior_snd_una))
35983601
flag |= FLAG_SND_UNA_ADVANCED;
35993602

@@ -3683,15 +3686,18 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
36833686
tcp_ack_probe(sk);
36843687
return 1;
36853688

3689+
invalid_ack:
3690+
SOCK_DEBUG(sk, "Ack %u after %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
3691+
return -1;
3692+
36863693
old_ack:
36873694
if (TCP_SKB_CB(skb)->sacked) {
36883695
tcp_sacktag_write_queue(sk, skb, prior_snd_una);
36893696
if (icsk->icsk_ca_state == TCP_CA_Open)
36903697
tcp_try_keep_open(sk);
36913698
}
36923699

3693-
uninteresting_ack:
3694-
SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
3700+
SOCK_DEBUG(sk, "Ack %u before %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
36953701
return 0;
36963702
}
36973703

@@ -5141,7 +5147,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
51415147
*/
51425148

51435149
if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
5144-
TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
5150+
TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
5151+
!after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
51455152
int tcp_header_len = tp->tcp_header_len;
51465153

51475154
/* Timestamp header prediction: tcp_header_len
@@ -5294,8 +5301,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
52945301
return -res;
52955302

52965303
step5:
5297-
if (th->ack)
5298-
tcp_ack(sk, skb, FLAG_SLOWPATH);
5304+
if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
5305+
goto discard;
52995306

53005307
tcp_rcv_rtt_measure_ts(sk, skb);
53015308

@@ -5632,7 +5639,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
56325639

56335640
/* step 5: check the ACK field */
56345641
if (th->ack) {
5635-
int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH);
5642+
int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;
56365643

56375644
switch (sk->sk_state) {
56385645
case TCP_SYN_RECV:

0 commit comments

Comments
 (0)