From 51610cc90ca5eb77464130ab2837fd4fa6e85eab Mon Sep 17 00:00:00 2001 From: Tymoteusz Bloch Date: Wed, 24 Apr 2019 18:19:39 +0200 Subject: [PATCH] Fixed TCP connection close. If TCP FSM is in ESTABLISHED state, waits for TCP close handshaking until TIME_WAIT The purpose is to prevent eth/wifi driver stop and FIN ACK corrupt. This may happend if network interface disconnect follows immediately after socket_close. --- features/lwipstack/LWIPStack.cpp | 17 +++++++++++++++-- features/lwipstack/LWIPStack.h | 2 ++ features/lwipstack/lwipopts.h | 5 +++++ features/lwipstack/mbed_lib.json | 4 ++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/features/lwipstack/LWIPStack.cpp b/features/lwipstack/LWIPStack.cpp index 2fae61e5c37..e0498e63abd 100644 --- a/features/lwipstack/LWIPStack.cpp +++ b/features/lwipstack/LWIPStack.cpp @@ -50,9 +50,12 @@ void LWIP::socket_callback(struct netconn *nc, enum netconn_evt eh, u16_t len) } LWIP &lwip = LWIP::get_instance(); - lwip.adaptation.lock(); + if (eh == NETCONN_EVT_RCVPLUS && nc->state == NETCONN_NONE) { + lwip._event_flag.set(TCP_CLOSED_FLAG); + } + for (int i = 0; i < MEMP_NUM_NETCONN; i++) { if (lwip.arena[i].in_use && lwip.arena[i].conn == nc @@ -292,7 +295,17 @@ nsapi_error_t LWIP::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto) nsapi_error_t LWIP::socket_close(nsapi_socket_t handle) { struct mbed_lwip_socket *s = (struct mbed_lwip_socket *)handle; - +#if LWIP_TCP + /* Check if TCP FSM is in ESTABLISHED state. + * Then give extra time for connection close handshaking until TIME_WAIT state. + * The purpose is to prevent eth/wifi driver stop and FIN ACK corrupt. + * This may happend if network interface disconnect follows immediately after socket_close.*/ + if (NETCONNTYPE_GROUP(s->conn->type) == NETCONN_TCP && s->conn->pcb.tcp->state == ESTABLISHED) { + _event_flag.clear(TCP_CLOSED_FLAG); + netconn_shutdown(s->conn, false, true); + _event_flag.wait_any(TCP_CLOSED_FLAG, TCP_CLOSE_TIMEOUT); + } +#endif netbuf_delete(s->buf); err_t err = netconn_delete(s->conn); arena_dealloc(s); diff --git a/features/lwipstack/LWIPStack.h b/features/lwipstack/LWIPStack.h index 6c5d9d98089..07a00c60a3f 100644 --- a/features/lwipstack/LWIPStack.h +++ b/features/lwipstack/LWIPStack.h @@ -587,6 +587,8 @@ class LWIP : public OnboardNetworkStack, private mbed::NonCopyable { LWIPMemoryManager memory_manager; osThreadId tcpip_thread_id; rtos::Mutex adaptation; + rtos::EventFlags _event_flag; + static const int TCP_CLOSED_FLAG = 0x4u; }; #endif /* LWIPSTACK_H_ */ diff --git a/features/lwipstack/lwipopts.h b/features/lwipstack/lwipopts.h index da9b6c443c6..7398f33beab 100644 --- a/features/lwipstack/lwipopts.h +++ b/features/lwipstack/lwipopts.h @@ -244,6 +244,11 @@ #define LWIP_TCP 1 #define TCP_OVERSIZE 0 #define LWIP_TCP_KEEPALIVE 1 +#ifdef MBED_CONF_TCP_CLOSE_TIMEOUT +#define TCP_CLOSE_TIMEOUT MBED_CONF_TCP_CLOSE_TIMEOUT +#else +#define TCP_CLOSE_TIMEOUT 1000 +#endif #else #define LWIP_TCP 0 #endif diff --git a/features/lwipstack/mbed_lib.json b/features/lwipstack/mbed_lib.json index 72e5efc0cdd..20287144738 100644 --- a/features/lwipstack/mbed_lib.json +++ b/features/lwipstack/mbed_lib.json @@ -100,6 +100,10 @@ "help": "Maximum number of retransmissions of SYN segments. Current default (used if null here) is set to 6 in opt.h", "value": null }, + "tcp-close-timeout": { + "help": "Maximum timeout (ms) for TCP close handshaking timeout", + "value": 1000 + }, "pbuf-pool-size": { "help": "Number of pbufs in pool - usually used for received packets, so this determines how much data can be buffered between reception and the application reading. If a driver uses PBUF_RAM for reception, less pool may be needed. Current default (used if null here) is set to 5 in lwipopts.h, unless overridden by target Ethernet drivers.", "value": null