mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-08-24 23:25:58 +00:00
tcp: fix FIN ACK handling with unsent data
TCP's snd_nxt represents the next sequence number after sent data, and as such does not cover any unsent data queued on the connection. The current implementation does not take the latter point into account when processing FIN acknowledgments, mistakenly assuming that an outgoing FIN is ACK'ed when the acknowledgment covers up to snd_nxt while there is still unsent data. This patch adds a check for unsent data to correct this, effectively preventing that TCP connections are closed prematurely.
This commit is contained in:
parent
9ba9dee2aa
commit
0d7805a86a
@ -886,7 +886,8 @@ tcp_process(struct tcp_pcb *pcb)
|
|||||||
case FIN_WAIT_1:
|
case FIN_WAIT_1:
|
||||||
tcp_receive(pcb);
|
tcp_receive(pcb);
|
||||||
if (recv_flags & TF_GOT_FIN) {
|
if (recv_flags & TF_GOT_FIN) {
|
||||||
if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
|
if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) &&
|
||||||
|
pcb->unsent == NULL) {
|
||||||
LWIP_DEBUGF(TCP_DEBUG,
|
LWIP_DEBUGF(TCP_DEBUG,
|
||||||
("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
@ -898,7 +899,8 @@ tcp_process(struct tcp_pcb *pcb)
|
|||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
pcb->state = CLOSING;
|
pcb->state = CLOSING;
|
||||||
}
|
}
|
||||||
} else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
|
} else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) &&
|
||||||
|
pcb->unsent == NULL) {
|
||||||
pcb->state = FIN_WAIT_2;
|
pcb->state = FIN_WAIT_2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -915,7 +917,7 @@ tcp_process(struct tcp_pcb *pcb)
|
|||||||
break;
|
break;
|
||||||
case CLOSING:
|
case CLOSING:
|
||||||
tcp_receive(pcb);
|
tcp_receive(pcb);
|
||||||
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
if (flags & TCP_ACK && ackno == pcb->snd_nxt && pcb->unsent == NULL) {
|
||||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||||
tcp_pcb_purge(pcb);
|
tcp_pcb_purge(pcb);
|
||||||
TCP_RMV_ACTIVE(pcb);
|
TCP_RMV_ACTIVE(pcb);
|
||||||
@ -925,7 +927,7 @@ tcp_process(struct tcp_pcb *pcb)
|
|||||||
break;
|
break;
|
||||||
case LAST_ACK:
|
case LAST_ACK:
|
||||||
tcp_receive(pcb);
|
tcp_receive(pcb);
|
||||||
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
|
if (flags & TCP_ACK && ackno == pcb->snd_nxt && pcb->unsent == NULL) {
|
||||||
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
|
||||||
/* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
|
/* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
|
||||||
recv_flags |= TF_CLOSED;
|
recv_flags |= TF_CLOSED;
|
||||||
|
Loading…
Reference in New Issue
Block a user