From b5f4bf922f8fa3d0414cfd178637e3c65793c6fd Mon Sep 17 00:00:00 2001 From: zhangyanjiao Date: Thu, 7 Jun 2018 11:24:03 +0800 Subject: [PATCH] fix the bug that TCP connections don't abort when IP changed --- components/lwip/Kconfig | 10 ++++ components/lwip/core/netif.c | 4 +- components/lwip/core/tcp.c | 60 ++++++++++++++++---- components/lwip/include/lwip/port/lwipopts.h | 6 ++ 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index efd053b5f..ab1e477bc 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -329,6 +329,16 @@ config TCP_QUEUE_OOSEQ Disable this option to save some RAM during TCP sessions, at the expense of increased retransmissions if segments arrive out of order. +config ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES + bool "Keep TCP connections when IP changed" + default n + help + This option is enabled when the following scenario happen: + network dropped and reconnected, IP changes is like: 192.168.0.2->0.0.0.0->192.168.0.2 + + Disable this option to keep consistent with the original LWIP code behavior. + + choice TCP_OVERSIZE prompt "Pre-allocate transmit PBUF size" default TCP_OVERSIZE_MSS diff --git a/components/lwip/core/netif.c b/components/lwip/core/netif.c index 2b25143c6..b5995f26f 100644 --- a/components/lwip/core/netif.c +++ b/components/lwip/core/netif.c @@ -453,10 +453,10 @@ void netif_set_ipaddr(struct netif *netif, const ip4_addr_t *ipaddr) { ip4_addr_t new_addr = (ipaddr ? *ipaddr : *IP4_ADDR_ANY); -#if ESP_LWIP +#if ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES ip4_addr_t *last_addr = ip_2_ip4(&netif->last_ip_addr); #else - ip4_addr_t *last_addr = netif_ip4_addr(netif); + ip4_addr_t *last_addr = ip_2_ip4(&(netif->ip_addr)); #endif /* address is actually being changed? */ diff --git a/components/lwip/core/tcp.c b/components/lwip/core/tcp.c index 35649f12f..96e35d0df 100644 --- a/components/lwip/core/tcp.c +++ b/components/lwip/core/tcp.c @@ -1929,6 +1929,31 @@ tcp_eff_send_mss_impl(u16_t sendmss, const ip_addr_t *dest } #endif /* TCP_CALCULATE_EFF_SEND_MSS */ +/** Helper function for tcp_netif_ip4_addr_changed() that iterates a pcb list */ +static void +tcp_netif_ip_addr_changed_pcblist(const ip4_addr_t* old_addr, struct tcp_pcb* pcb_list) +{ + struct tcp_pcb *pcb; + pcb = pcb_list; + while (pcb != NULL) { + /* PCB bound to current local interface address? */ + if (ip4_addr_cmp(ip_2_ip4(&pcb->local_ip), old_addr) +#if LWIP_AUTOIP + /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ + && (!IP_IS_V4_VAL(pcb->local_ip) || !ip4_addr_islinklocal(ip_2_ip4(&pcb->local_ip))) +#endif /* LWIP_AUTOIP */ + ) { + /* this connection must be aborted */ + struct tcp_pcb *next = pcb->next; + LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); + tcp_abort(pcb); + pcb = next; + } else { + pcb = pcb->next; + } + } +} + #if LWIP_IPV4 /** This function is called from netif.c when address is changed or netif is removed * @@ -1939,18 +1964,29 @@ void tcp_netif_ipv4_addr_changed(const ip4_addr_t* old_addr, const ip4_addr_t* n { struct tcp_pcb_listen *lpcb, *next; - if (!ip4_addr_isany(new_addr)) { - /* PCB bound to current local interface address? */ - for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = next) { - next = lpcb->next; - /* Is this an IPv4 pcb? */ - if (!IP_IS_V6_VAL(lpcb->local_ip)) { - /* PCB bound to current local interface address? */ - if ((!(ip4_addr_isany(ip_2_ip4(&lpcb->local_ip)))) && - (ip4_addr_cmp(ip_2_ip4(&lpcb->local_ip), old_addr))) { - /* The PCB is listening to the old ipaddr and - * is set to listen to the new one instead */ - ip_addr_copy_from_ip4(lpcb->local_ip, *new_addr); + if (!ip4_addr_isany(old_addr)) { +#if ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES + if ((new_addr == NULL) || ((!ip4_addr_isany_val(*new_addr)) && (!ip4_addr_cmp(old_addr, new_addr)))) { +#endif + tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_active_pcbs); + tcp_netif_ip_addr_changed_pcblist(old_addr, tcp_bound_pcbs); +#if ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES + } +#endif + + if (!ip4_addr_isany(new_addr)) { + /* PCB bound to current local interface address? */ + for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = next) { + next = lpcb->next; + /* Is this an IPv4 pcb? */ + if (!IP_IS_V6_VAL(lpcb->local_ip)) { + /* PCB bound to current local interface address? */ + if ((!(ip4_addr_isany(ip_2_ip4(&lpcb->local_ip)))) && + (ip4_addr_cmp(ip_2_ip4(&lpcb->local_ip), old_addr))) { + /* The PCB is listening to the old ipaddr and + * is set to listen to the new one instead */ + ip_addr_copy_from_ip4(lpcb->local_ip, *new_addr); + } } } } diff --git a/components/lwip/include/lwip/port/lwipopts.h b/components/lwip/include/lwip/port/lwipopts.h index 4d4ceb564..8f1dd44ff 100644 --- a/components/lwip/include/lwip/port/lwipopts.h +++ b/components/lwip/include/lwip/port/lwipopts.h @@ -296,6 +296,12 @@ */ #define TCP_QUEUE_OOSEQ CONFIG_TCP_QUEUE_OOSEQ +/** + * ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES==1: Keep TCP connection when IP changed + * scenario happens: 192.168.0.2 -> 0.0.0.0 -> 192.168.0.2 or 192.168.0.2 -> 0.0.0.0 + */ + +#define ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES /* * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all * events (accept, sent, etc) that happen in the system.