mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-01-29 00:32:51 +00:00
fixed bug #33871: rejecting TCP_EVENT_RECV() for the last packet including FIN can lose data
This commit is contained in:
parent
e145c1d31c
commit
918470affc
@ -65,6 +65,10 @@ HISTORY
|
|||||||
|
|
||||||
++ Bugfixes:
|
++ Bugfixes:
|
||||||
|
|
||||||
|
2011-09-23: Simon Goldschmidt
|
||||||
|
* pbuf.h, tcp.c, tcp_in.c: fixed bug #33871: rejecting TCP_EVENT_RECV() for
|
||||||
|
the last packet including FIN can lose data
|
||||||
|
|
||||||
2011-09-22: Simon Goldschmidt
|
2011-09-22: Simon Goldschmidt
|
||||||
* tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into
|
* tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into
|
||||||
account
|
account
|
||||||
|
@ -1054,13 +1054,32 @@ tcp_fasttmr(void)
|
|||||||
if (pcb->refused_data != NULL) {
|
if (pcb->refused_data != NULL) {
|
||||||
/* Notify again application with data previously received. */
|
/* Notify again application with data previously received. */
|
||||||
err_t err;
|
err_t err;
|
||||||
|
u8_t refused_flags = pcb->refused_data->flags;
|
||||||
|
/* set pcb->refused_data to NULL in case the callback frees it and then
|
||||||
|
closes the pcb */
|
||||||
|
struct pbuf *refused_data = pcb->refused_data;
|
||||||
|
pcb->refused_data = NULL;
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
|
||||||
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
|
TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err);
|
||||||
if (err == ERR_OK) {
|
if (err == ERR_OK) {
|
||||||
pcb->refused_data = NULL;
|
/* did refused_data include a FIN? If so, handle it now. */
|
||||||
|
if (refused_flags & PBUF_FLAG_TCP_FIN) {
|
||||||
|
/* correct rcv_wnd as the application won't call tcp_recved()
|
||||||
|
for the FIN's seqno */
|
||||||
|
if (pcb->rcv_wnd != TCP_WND) {
|
||||||
|
pcb->rcv_wnd++;
|
||||||
|
}
|
||||||
|
TCP_EVENT_CLOSED(pcb, err);
|
||||||
|
if (err == ERR_ABRT) {
|
||||||
|
pcb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (err == ERR_ABRT) {
|
} else if (err == ERR_ABRT) {
|
||||||
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
||||||
pcb = NULL;
|
pcb = NULL;
|
||||||
|
} else {
|
||||||
|
/* data is still refused */
|
||||||
|
pcb->refused_data = refused_data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,17 +306,36 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
|||||||
|
|
||||||
/* If there is data which was previously "refused" by upper layer */
|
/* If there is data which was previously "refused" by upper layer */
|
||||||
if (pcb->refused_data != NULL) {
|
if (pcb->refused_data != NULL) {
|
||||||
|
u8_t refused_flags = pcb->refused_data->flags;
|
||||||
|
/* set pcb->refused_data to NULL in case the callback frees it and then
|
||||||
|
closes the pcb */
|
||||||
|
struct pbuf *refused_data = pcb->refused_data;
|
||||||
|
pcb->refused_data = NULL;
|
||||||
/* Notify again application with data previously received. */
|
/* Notify again application with data previously received. */
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
|
||||||
TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
|
TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err);
|
||||||
if (err == ERR_OK) {
|
if (err == ERR_OK) {
|
||||||
pcb->refused_data = NULL;
|
/* did refused_data include a FIN? */
|
||||||
|
if (refused_flags & PBUF_FLAG_TCP_FIN) {
|
||||||
|
/* correct rcv_wnd as the application won't call tcp_recved()
|
||||||
|
for the FIN's seqno */
|
||||||
|
if (pcb->rcv_wnd != TCP_WND) {
|
||||||
|
pcb->rcv_wnd++;
|
||||||
|
}
|
||||||
|
TCP_EVENT_CLOSED(pcb, err);
|
||||||
|
if (err == ERR_ABRT) {
|
||||||
|
goto dropped;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if ((err == ERR_ABRT) || (tcplen > 0)) {
|
} else if ((err == ERR_ABRT) || (tcplen > 0)) {
|
||||||
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
||||||
/* Drop incoming packets because pcb is "full" (only if the incoming
|
/* Drop incoming packets because pcb is "full" (only if the incoming
|
||||||
segment contains data). */
|
segment contains data). */
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
|
||||||
goto dropped;
|
goto dropped;
|
||||||
|
} else {
|
||||||
|
/* data is still refused, pbuf is still valid (go on for ACK-only packets) */
|
||||||
|
pcb->refused_data = refused_data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tcp_input_pcb = pcb;
|
tcp_input_pcb = pcb;
|
||||||
@ -375,14 +394,19 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
|||||||
/* If a FIN segment was received, we call the callback
|
/* If a FIN segment was received, we call the callback
|
||||||
function with a NULL buffer to indicate EOF. */
|
function with a NULL buffer to indicate EOF. */
|
||||||
if (recv_flags & TF_GOT_FIN) {
|
if (recv_flags & TF_GOT_FIN) {
|
||||||
/* correct rcv_wnd as the application won't call tcp_recved()
|
if (pcb->refused_data != NULL) {
|
||||||
for the FIN's seqno */
|
/* Delay this if we have refused data. */
|
||||||
if (pcb->rcv_wnd != TCP_WND) {
|
pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN;
|
||||||
pcb->rcv_wnd++;
|
} else {
|
||||||
}
|
/* correct rcv_wnd as the application won't call tcp_recved()
|
||||||
TCP_EVENT_CLOSED(pcb, err);
|
for the FIN's seqno */
|
||||||
if (err == ERR_ABRT) {
|
if (pcb->rcv_wnd != TCP_WND) {
|
||||||
goto aborted;
|
pcb->rcv_wnd++;
|
||||||
|
}
|
||||||
|
TCP_EVENT_CLOSED(pcb, err);
|
||||||
|
if (err == ERR_ABRT) {
|
||||||
|
goto aborted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,6 +80,8 @@ typedef enum {
|
|||||||
#define PBUF_FLAG_LLBCAST 0x08U
|
#define PBUF_FLAG_LLBCAST 0x08U
|
||||||
/** indicates this pbuf was received as link-level multicast */
|
/** indicates this pbuf was received as link-level multicast */
|
||||||
#define PBUF_FLAG_LLMCAST 0x10U
|
#define PBUF_FLAG_LLMCAST 0x10U
|
||||||
|
/** indicates this pbuf includes a TCP FIN flag */
|
||||||
|
#define PBUF_FLAG_TCP_FIN 0x20U
|
||||||
|
|
||||||
struct pbuf {
|
struct pbuf {
|
||||||
/** next pbuf in singly linked pbuf chain */
|
/** next pbuf in singly linked pbuf chain */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user