tcp_input: update tx_unack before reorder_ofosegs

After the sack is enabled and the ofosegs has gap, tcp cannot update the
tx_unacked, so the peer received packets are retransmitted after the
timer timeout.
So update tx_unacked first.

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2023-08-30 20:45:55 +08:00 committed by Petro Karashchenko
parent e7f160bbe9
commit 3f927b63b7

View File

@ -1017,55 +1017,6 @@ found:
}
#endif
/* Check if the sequence number of the incoming packet is what we are
* expecting next. If not, we send out an ACK with the correct numbers
* in, unless we are in the SYN_RCVD state and receive a SYN, in which
* case we should retransmit our SYNACK (which is done further down).
*/
if (!((((conn->tcpstateflags & TCP_STATE_MASK) == TCP_SYN_SENT) &&
((tcp->flags & TCP_CTL) == (TCP_SYN | TCP_ACK))) ||
(((conn->tcpstateflags & TCP_STATE_MASK) == TCP_SYN_RCVD) &&
((tcp->flags & TCP_CTL) == TCP_SYN))))
{
uint32_t seq;
uint32_t rcvseq;
seq = tcp_getsequence(tcp->seqno);
rcvseq = tcp_getsequence(conn->rcvseq);
if (seq != rcvseq)
{
/* Trim the head of the segment */
if (TCP_SEQ_LT(seq, rcvseq))
{
uint32_t trimlen = TCP_SEQ_SUB(rcvseq, seq);
if (tcp_trim_head(dev, tcp, trimlen))
{
/* The segment was completely out of the window.
* E.g. a retransmit which was not necessary.
* E.g. a keep-alive segment.
*/
tcp_send(dev, conn, TCP_ACK, tcpiplen);
return;
}
}
else
{
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
/* Queue out-of-order segments. */
tcp_input_ofosegs(dev, conn, iplen);
#endif
tcp_send(dev, conn, TCP_ACK, tcpiplen);
return;
}
}
}
/* Check if the incoming segment acknowledges any outstanding data. If so,
* we update the sequence number, reset the length of the outstanding
* data, calculate RTT estimations, and reset the retransmission timer.
@ -1189,6 +1140,55 @@ found:
tcp_update_retrantimer(conn, conn->rto);
}
/* Check if the sequence number of the incoming packet is what we are
* expecting next. If not, we send out an ACK with the correct numbers
* in, unless we are in the SYN_RCVD state and receive a SYN, in which
* case we should retransmit our SYNACK (which is done further down).
*/
if (!((((conn->tcpstateflags & TCP_STATE_MASK) == TCP_SYN_SENT) &&
((tcp->flags & TCP_CTL) == (TCP_SYN | TCP_ACK))) ||
(((conn->tcpstateflags & TCP_STATE_MASK) == TCP_SYN_RCVD) &&
((tcp->flags & TCP_CTL) == TCP_SYN))))
{
uint32_t seq;
uint32_t rcvseq;
seq = tcp_getsequence(tcp->seqno);
rcvseq = tcp_getsequence(conn->rcvseq);
if (seq != rcvseq)
{
/* Trim the head of the segment */
if (TCP_SEQ_LT(seq, rcvseq))
{
uint32_t trimlen = TCP_SEQ_SUB(rcvseq, seq);
if (tcp_trim_head(dev, tcp, trimlen))
{
/* The segment was completely out of the window.
* E.g. a retransmit which was not necessary.
* E.g. a keep-alive segment.
*/
tcp_send(dev, conn, TCP_ACK, tcpiplen);
return;
}
}
else
{
#ifdef CONFIG_NET_TCP_OUT_OF_ORDER
/* Queue out-of-order segments. */
tcp_input_ofosegs(dev, conn, iplen);
#endif
tcp_send(dev, conn, TCP_ACK, tcpiplen);
return;
}
}
}
tcp_clear_zero_probe(conn, tcp);
/* Update the connection's window size */