if (pcb->refused_data != NULL) {
/* Notify again application with data previously received. */
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"));
- TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);
+ TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err);
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) {
/* if err == ERR_ABRT, 'pcb' is already deallocated */
pcb = NULL;
+ } else {
+ /* data is still refused */
+ pcb->refused_data = refused_data;
}
}
/* If there is data which was previously "refused" by upper layer */
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. */
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) {
- 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)) {
/* if err == ERR_ABRT, 'pcb' is already deallocated */
/* Drop incoming packets because pcb is "full" (only if the incoming
segment contains data). */
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
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;
/* If a FIN segment was received, we call the callback
function with a NULL buffer to indicate EOF. */
if (recv_flags & TF_GOT_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 aborted;
+ if (pcb->refused_data != NULL) {
+ /* Delay this if we have refused data. */
+ pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN;
+ } else {
+ /* 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 aborted;
+ }
}
}