From ef2c714c06dc63cd4fac872d6bbb2e496fdbde3a Mon Sep 17 00:00:00 2001 From: yuanjm Date: Thu, 16 Jul 2020 20:23:43 +0800 Subject: [PATCH] feat(lwip): update lwip component according to IDF commit ID: 79a5b0b5 --- components/lwip/CMakeLists.txt | 5 +- components/lwip/Kconfig | 100 +++- components/lwip/apps/dhcpserver/dhcpserver.c | 78 +-- components/lwip/apps/ping/ping_sock.c | 5 +- components/lwip/apps/sntp/sntp.c | 26 + components/lwip/include/apps/ping/ping_sock.h | 2 +- components/lwip/include/apps/sntp/sntp.h | 27 + components/lwip/lwip | 2 +- .../lwip/port/esp8266/freertos/sys_arch.c | 478 ++++++++++-------- .../lwip/port/esp8266/include/arch/cc.h | 4 + .../lwip/port/esp8266/include/arch/sys_arch.h | 23 +- .../lwip/port/esp8266/include/arpa/inet.h | 2 +- .../lwip/port/esp8266/include/lwipopts.h | 72 ++- .../{netif/nettestif.h => netinet/tcp.h} | 24 +- .../lwip/port/esp8266/netif/nettestif.c | 105 ---- components/lwip/port/esp8266/netif/wlanif.c | 15 +- .../lwip/weekend_test/net_suite_test.py | 26 +- .../tcpip_adapter/include/tcpip_adapter.h | 1 + components/tcpip_adapter/tcpip_adapter_lwip.c | 9 +- .../Kconfig.projbuild | 27 +- .../protocol_examples_common/connect.c | 13 +- .../sockets/tcp_client/main/tcp_client.c | 3 + .../sockets/udp_client/main/udp_client.c | 1 + 23 files changed, 613 insertions(+), 435 deletions(-) rename components/lwip/port/esp8266/include/{netif/nettestif.h => netinet/tcp.h} (62%) delete mode 100644 components/lwip/port/esp8266/netif/nettestif.c diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index 9cf6db58..9d286ec7 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -47,6 +47,7 @@ set(srcs "lwip/src/core/ipv4/icmp.c" "lwip/src/core/ipv4/igmp.c" "lwip/src/core/ipv4/ip4.c" + "lwip/src/core/ipv4/ip4_napt.c" "lwip/src/core/ipv4/ip4_addr.c" "lwip/src/core/ipv4/ip4_frag.c" "lwip/src/core/ipv6/dhcp6.c" @@ -92,10 +93,6 @@ set(srcs "port/${target}/netif/dhcp_state.c" "port/${target}/netif/wlanif.c") -if(CONFIG_IDF_TARGET_ESP32) - list(APPEND srcs - "port/${target}/netif/nettestif.c") -endif() if(CONFIG_LWIP_PPP_SUPPORT) list(APPEND srcs diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index de890988..a35c94bd 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -71,6 +71,20 @@ menu "LWIP" will be redirected to lwip_select(), therefore, select can be used for sockets only. + config LWIP_SO_LINGER + bool "Enable SO_LINGER processing" + default n + help + Enabling this option allows SO_LINGER processing. + l_onoff = 1,l_linger can set the timeout. + + If l_linger=0, When a connection is closed, TCP will terminate the connection. + This means that TCP will discard any data packets stored in the socket send buffer + and send an RST to the peer. + + If l_linger!=0,Then closesocket() calls to block the process until + the remaining data packets has been sent or timed out. + config LWIP_SO_REUSE bool "Enable SO_REUSEADDR option" default y @@ -105,18 +119,45 @@ menu "LWIP" Enabling this option allows checking for the destination address of a received IPv4 Packet. - config LWIP_IP_FRAG - bool "Enable fragment outgoing IP packets" - default n + config LWIP_IP4_FRAG + bool "Enable fragment outgoing IP4 packets" + default y help - Enabling this option allows fragmenting outgoing IP packets if their size + Enabling this option allows fragmenting outgoing IP4 packets if their size exceeds MTU. - config LWIP_IP_REASSEMBLY - bool "Enable reassembly incoming fragmented IP packets" + config LWIP_IP6_FRAG + bool "Enable fragment outgoing IP6 packets" + default y + help + Enabling this option allows fragmenting outgoing IP6 packets if their size + exceeds MTU. + + config LWIP_IP4_REASSEMBLY + bool "Enable reassembly incoming fragmented IP4 packets" default n help - Enabling this option allows reassemblying incoming fragmented IP packets. + Enabling this option allows reassemblying incoming fragmented IP4 packets. + + config LWIP_IP6_REASSEMBLY + bool "Enable reassembly incoming fragmented IP6 packets" + default n + help + Enabling this option allows reassemblying incoming fragmented IP6 packets. + + config LWIP_IP_FORWARD + bool "Enable IP forwarding" + default n + help + Enabling this option allows packets forwarding across multiple interfaces. + + config LWIP_IPV4_NAPT + bool "Enable NAT (new/experimental)" + depends on LWIP_IP_FORWARD + select LWIP_L2_TO_L3_COPY + default n + help + Enabling this option allows Network Address and Port Translation. config LWIP_STATS bool "Enable LWIP statistics" @@ -254,6 +295,14 @@ menu "LWIP" If rate limiting self-assignment requests, wait this long between each request. + config LWIP_IPV6_AUTOCONFIG + bool "Enable IPV6 stateless address autoconfiguration" + default n + help + Enabling this option allows the devices to IPV6 stateless address autoconfiguration. + + See RFC 4862. + menuconfig LWIP_NETIF_LOOPBACK bool "Support per-interface loopback" default y @@ -344,7 +393,8 @@ menu "LWIP" config LWIP_TCP_SND_BUF_DEFAULT int "Default send buffer size" default 5744 # 4 * default MSS - range 2440 65535 + range 2440 65535 if !LWIP_WND_SCALE + range 2440 1024000 if LWIP_WND_SCALE help Set default send buffer size for new TCP sockets. @@ -360,7 +410,8 @@ menu "LWIP" config LWIP_TCP_WND_DEFAULT int "Default receive window size" default 5744 # 4 * default MSS - range 2440 65535 + range 2440 65535 if !LWIP_WND_SCALE + range 2440 1024000 if LWIP_WND_SCALE help Set default TCP receive window size for new TCP sockets. @@ -400,6 +451,12 @@ menu "LWIP" Disable this option to save some RAM during TCP sessions, at the expense of increased retransmissions if segments arrive out of order. + config LWIP_TCP_SACK_OUT + bool "Support sending selective acknowledgements" + default n + help + TCP will support sending selective acknowledgements (SACKs). + config LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES bool "Keep TCP connections when IP changed" default n @@ -449,6 +506,13 @@ menu "LWIP" help Enable this feature to support TCP window scaling. + config LWIP_TCP_RTO_TIME + int "Default TCP rto time" + default 3000 + help + Set default TCP rto time for a reasonable initial rto. + In bad network environment, recommend set value of rto time to 1500. + endmenu # TCP menu "UDP" @@ -526,6 +590,17 @@ menu "LWIP" PPP over serial support is experimental and unsupported. + config LWIP_PPP_ENABLE_IPV6 + bool "Enable IPV6 support for PPP connections (IPV6CP)" + depends on LWIP_PPP_SUPPORT && LWIP_IPV6 + default y + help + Enable IPV6 support in PPP for the local link between the DTE (processor) and DCE (modem). + There are some modems which do not support the IPV6 addressing in the local link. + If they are requested for IPV6CP negotiation, they may time out. + This would in turn fail the configuration for the whole link. + If your modem is not responding correctly to PPP Phase Network, try to disable IPV6 support. + config LWIP_PPP_NOTIFY_PHASE_SUPPORT bool "Enable Notify Phase Callback" depends on LWIP_PPP_SUPPORT @@ -621,4 +696,11 @@ menu "LWIP" endmenu # SNTP + config LWIP_ESP_LWIP_ASSERT + bool "Enable LWIP ASSERT checks" + default y + help + Enable this option allows lwip to check assert. + It is recommended to keep it open, do not close it. + endmenu diff --git a/components/lwip/apps/dhcpserver/dhcpserver.c b/components/lwip/apps/dhcpserver/dhcpserver.c index 48adc3b9..64e78a32 100644 --- a/components/lwip/apps/dhcpserver/dhcpserver.c +++ b/components/lwip/apps/dhcpserver/dhcpserver.c @@ -81,12 +81,19 @@ typedef struct _list_node { static const u32_t magic_cookie = 0x63538263; -static struct udp_pcb *pcb_dhcps = NULL; +static struct netif *dhcps_netif = NULL; static ip4_addr_t broadcast_dhcps; static ip4_addr_t server_address; static ip4_addr_t dns_server = {0}; static ip4_addr_t client_address; //added static ip4_addr_t client_address_plus; +static ip4_addr_t s_dhcps_mask = { +#ifdef USE_CLASS_B_NET + .addr = PP_HTONL(LWIP_MAKEU32(255, 240, 0, 0)) +#else + .addr = PP_HTONL(LWIP_MAKEU32(255, 255, 255, 0)) +#endif + }; static list_node *plist = NULL; static bool renew = false; @@ -136,7 +143,12 @@ void *dhcps_option_info(u8_t op_id, u32_t opt_len) } break; + case SUBNET_MASK: + if (opt_len == sizeof(s_dhcps_mask)) { + option_arg = &s_dhcps_mask; + } + break; default: break; } @@ -185,6 +197,12 @@ void dhcps_set_option_info(u8_t op_id, void *opt_info, u32_t opt_len) } break; + case SUBNET_MASK: + if (opt_len == sizeof(s_dhcps_mask)) { + s_dhcps_mask = *(ip4_addr_t *)opt_info; + } + + default: break; } @@ -253,11 +271,13 @@ void node_remove_from_list(list_node **phead, list_node *pdelete) *phead = NULL; } else { if (plist == pdelete) { - *phead = plist->pnext; + // Note: Ignoring the "use after free" warnings, as it could only happen + // if the linked list contains loops + *phead = plist->pnext; // NOLINT(clang-analyzer-unix.Malloc) pdelete->pnext = NULL; } else { while (plist != NULL) { - if (plist->pnext == pdelete) { + if (plist->pnext == pdelete) { // NOLINT(clang-analyzer-unix.Malloc) plist->pnext = pdelete->pnext; pdelete->pnext = NULL; } @@ -294,21 +314,12 @@ static u8_t *add_offer_options(u8_t *optptr) ipadd.addr = *((u32_t *) &server_address); -#ifdef USE_CLASS_B_NET - *optptr++ = DHCP_OPTION_SUBNET_MASK; - *optptr++ = 4; //length - *optptr++ = 255; - *optptr++ = 240; - *optptr++ = 0; - *optptr++ = 0; -#else *optptr++ = DHCP_OPTION_SUBNET_MASK; *optptr++ = 4; - *optptr++ = 255; - *optptr++ = 255; - *optptr++ = 255; - *optptr++ = 0; -#endif + *optptr++ = ip4_addr1(&s_dhcps_mask); + *optptr++ = ip4_addr2(&s_dhcps_mask); + *optptr++ = ip4_addr3(&s_dhcps_mask); + *optptr++ = ip4_addr4(&s_dhcps_mask); *optptr++ = DHCP_OPTION_LEASE_TIME; *optptr++ = 4; @@ -355,21 +366,13 @@ static u8_t *add_offer_options(u8_t *optptr) *optptr++ = ip4_addr4(&ipadd); } -#ifdef CLASS_B_NET + ip4_addr_t broadcast_addr = { .addr = (ipadd.addr & s_dhcps_mask.addr) | ~s_dhcps_mask.addr }; *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; *optptr++ = 4; - *optptr++ = ip4_addr1(&ipadd); - *optptr++ = 255; - *optptr++ = 255; - *optptr++ = 255; -#else - *optptr++ = DHCP_OPTION_BROADCAST_ADDRESS; - *optptr++ = 4; - *optptr++ = ip4_addr1(&ipadd); - *optptr++ = ip4_addr2(&ipadd); - *optptr++ = ip4_addr3(&ipadd); - *optptr++ = 255; -#endif + *optptr++ = ip4_addr1(&broadcast_addr); + *optptr++ = ip4_addr2(&broadcast_addr); + *optptr++ = ip4_addr3(&broadcast_addr); + *optptr++ = ip4_addr4(&broadcast_addr); *optptr++ = DHCP_OPTION_INTERFACE_MTU; *optptr++ = 2; @@ -525,6 +528,7 @@ static void send_offer(struct dhcps_msg *m, u16_t len) ip_addr_t ip_temp = IPADDR4_INIT(0x0); ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps); + struct udp_pcb *pcb_dhcps = dhcps_netif->dhcps_pcb; #if DHCPS_DEBUG SendOffer_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT); DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n", SendOffer_err_t); @@ -602,6 +606,7 @@ static void send_nak(struct dhcps_msg *m, u16_t len) ip_addr_t ip_temp = IPADDR4_INIT(0x0); ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps); + struct udp_pcb *pcb_dhcps = dhcps_netif->dhcps_pcb; #if DHCPS_DEBUG SendNak_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT); DHCPS_LOG("dhcps: send_nak>>udp_sendto result %x\n", SendNak_err_t); @@ -678,6 +683,7 @@ static void send_ack(struct dhcps_msg *m, u16_t len) ip_addr_t ip_temp = IPADDR4_INIT(0x0); ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps); + struct udp_pcb *pcb_dhcps = dhcps_netif->dhcps_pcb; SendAck_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT); #if DHCPS_DEBUG DHCPS_LOG("dhcps: send_ack>>udp_sendto result %x\n", SendAck_err_t); @@ -1135,19 +1141,20 @@ void dhcps_set_new_lease_cb(dhcps_cb_t cb) *******************************************************************************/ void dhcps_start(struct netif *netif, ip4_addr_t ip) { - struct netif *apnetif = netif; + dhcps_netif = netif; - if (apnetif->dhcps_pcb != NULL) { - udp_remove(apnetif->dhcps_pcb); + if (dhcps_netif->dhcps_pcb != NULL) { + udp_remove(dhcps_netif->dhcps_pcb); } - pcb_dhcps = udp_new(); + dhcps_netif->dhcps_pcb = udp_new(); + struct udp_pcb *pcb_dhcps = dhcps_netif->dhcps_pcb; if (pcb_dhcps == NULL || ip4_addr_isany_val(ip)) { printf("dhcps_start(): could not obtain pcb\n"); } - apnetif->dhcps_pcb = pcb_dhcps; + dhcps_netif->dhcps_pcb = pcb_dhcps; IP4_ADDR(&broadcast_dhcps, 255, 255, 255, 255); @@ -1212,6 +1219,7 @@ static void kill_oldest_dhcps_pool(void) list_node *minpre = NULL, *minp = NULL; struct dhcps_pool *pdhcps_pool = NULL, *pmin_pool = NULL; pre = plist; + assert(pre != NULL && pre->pnext != NULL); // Expect the list to have at least 2 nodes p = pre->pnext; minpre = pre; minp = p; @@ -1326,5 +1334,5 @@ dhcps_dns_getserver(void) { return dns_server; } -#endif +#endif // ESP_DHCP diff --git a/components/lwip/apps/ping/ping_sock.c b/components/lwip/apps/ping/ping_sock.c index 8450a11a..e7e15cc7 100644 --- a/components/lwip/apps/ping/ping_sock.c +++ b/components/lwip/apps/ping/ping_sock.c @@ -103,10 +103,10 @@ static int esp_ping_receive(esp_ping_t *ep) int len = 0; struct sockaddr_storage from; int fromlen = sizeof(from); + uint16_t data_head = (uint16_t)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr)); while ((len = recvfrom(ep->sock, buf, sizeof(buf), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen)) > 0) { - if (len >= (int)(sizeof(struct ip_hdr) + sizeof(struct icmp_echo_hdr))) { - ep->recv_len = (uint32_t)len; + if (len >= data_head) { if (from.ss_family == AF_INET) { // IPv4 struct sockaddr_in *from4 = (struct sockaddr_in *)&from; @@ -128,6 +128,7 @@ static int esp_ping_receive(esp_ping_t *ep) if ((iecho->id == ep->packet_hdr->id) && (iecho->seqno == ep->packet_hdr->seqno)) { ep->received++; ep->ttl = iphdr->_ttl; + ep->recv_len = lwip_ntohs(IPH_LEN(iphdr)) - data_head; // The data portion of ICMP return len; } } diff --git a/components/lwip/apps/sntp/sntp.c b/components/lwip/apps/sntp/sntp.c index 58b84f5a..d6ff2993 100644 --- a/components/lwip/apps/sntp/sntp.c +++ b/components/lwip/apps/sntp/sntp.c @@ -18,12 +18,14 @@ #include #include "esp_log.h" #include "sntp.h" +#include "lwip/apps/sntp.h" static const char *TAG = "sntp"; static volatile sntp_sync_mode_t sntp_sync_mode = SNTP_SYNC_MODE_IMMED; static volatile sntp_sync_status_t sntp_sync_status = SNTP_SYNC_STATUS_RESET; static sntp_sync_time_cb_t time_sync_notification_cb = NULL; +static uint32_t s_sync_interval = CONFIG_LWIP_SNTP_UPDATE_DELAY; inline void sntp_set_sync_status(sntp_sync_status_t sync_status) { @@ -91,3 +93,27 @@ sntp_sync_status_t sntp_get_sync_status(void) } return ret_sync_status; } + +void sntp_set_sync_interval(uint32_t interval_ms) +{ + if (interval_ms < 15000) { + // SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds + interval_ms = 15000; + } + s_sync_interval = interval_ms; +} + +uint32_t sntp_get_sync_interval(void) +{ + return s_sync_interval; +} + +bool sntp_restart(void) +{ + if (sntp_enabled()) { + sntp_stop(); + sntp_init(); + return true; + } + return false; +} diff --git a/components/lwip/include/apps/ping/ping_sock.h b/components/lwip/include/apps/ping/ping_sock.h index 0c448030..62eb8bdb 100644 --- a/components/lwip/include/apps/ping/ping_sock.h +++ b/components/lwip/include/apps/ping/ping_sock.h @@ -87,7 +87,7 @@ typedef struct { .count = 5, \ .interval_ms = 1000, \ .timeout_ms = 1000, \ - .data_size = 56, \ + .data_size = 64, \ .tos = 0, \ .target_addr = PING_TARGET_ADDR, \ .task_stack_size = 2048, \ diff --git a/components/lwip/include/apps/sntp/sntp.h b/components/lwip/include/apps/sntp/sntp.h index a94981b5..b4c0939f 100644 --- a/components/lwip/include/apps/sntp/sntp.h +++ b/components/lwip/include/apps/sntp/sntp.h @@ -120,6 +120,33 @@ void sntp_set_sync_status(sntp_sync_status_t sync_status); */ void sntp_set_time_sync_notification_cb(sntp_sync_time_cb_t callback); +/** + * @brief Set the sync interval of SNTP operation + * + * Note: SNTPv4 RFC 4330 enforces a minimum sync interval of 15 seconds. + * This sync interval will be used in the next attempt update time throught SNTP. + * To apply the new sync interval call the sntp_restart() function, + * otherwise, it will be applied after the last interval expired. + * + * @param interval_ms The sync interval in ms. It cannot be lower than 15 seconds, otherwise 15 seconds will be set. + */ +void sntp_set_sync_interval(uint32_t interval_ms); + +/** + * @brief Get the sync interval of SNTP operation + * + * @return the sync interval + */ +uint32_t sntp_get_sync_interval(void); + +/** + * @brief Restart SNTP + * + * @return True - Restart + * False - SNTP was not initialized yet + */ +bool sntp_restart(void); + #ifdef __cplusplus } #endif diff --git a/components/lwip/lwip b/components/lwip/lwip index c9e3b53c..ffd1059c 160000 --- a/components/lwip/lwip +++ b/components/lwip/lwip @@ -1 +1 @@ -Subproject commit c9e3b53c6f04052943f97210b858cec805cc98d9 +Subproject commit ffd1059c9adfd9aece3578a030a74eb0b67c552e diff --git a/components/lwip/port/esp8266/freertos/sys_arch.c b/components/lwip/port/esp8266/freertos/sys_arch.c index a3776d59..8338a348 100644 --- a/components/lwip/port/esp8266/freertos/sys_arch.c +++ b/components/lwip/port/esp8266/freertos/sys_arch.c @@ -41,9 +41,7 @@ #include "lwip/stats.h" #include "esp_log.h" -/* This is the number of threads that can be started with sys_thread_new() */ -#define SYS_THREAD_MAX 4 -#define TAG "lwip_arch" +static const char* TAG = "lwip_arch"; static sys_mutex_t g_lwip_protect_mutex = NULL; @@ -51,160 +49,167 @@ static pthread_key_t sys_thread_sem_key; static void sys_thread_sem_free(void* data); #if !LWIP_COMPAT_MUTEX -/** Create a new mutex - * @param mutex pointer to the mutex to create - * @return a new mutex */ + +/** + * @brief Create a new mutex + * + * @param pxMutex pointer of the mutex to create + * @return ERR_OK on success, ERR_MEM when out of memory + */ err_t sys_mutex_new(sys_mutex_t *pxMutex) { - err_t xReturn = ERR_MEM; - *pxMutex = xSemaphoreCreateMutex(); - - if (*pxMutex != NULL) { - xReturn = ERR_OK; + if (*pxMutex == NULL) { + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: out of mem\r\n")); + return ERR_MEM; } LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_new: m=%p\n", *pxMutex)); - return xReturn; + return ERR_OK; } -/** Lock a mutex - * @param mutex the mutex to lock */ -void ESP_IRAM_ATTR +/** + * @brief Lock a mutex + * + * @param pxMutex pointer of mutex to lock + */ +void sys_mutex_lock(sys_mutex_t *pxMutex) { - while (xSemaphoreTake(*pxMutex, portMAX_DELAY) != pdPASS); + BaseType_t ret = xSemaphoreTake(*pxMutex, portMAX_DELAY); + + LWIP_ASSERT("failed to take the mutex", ret == pdTRUE); } -err_t -sys_mutex_trylock(sys_mutex_t *pxMutex) -{ - if (xSemaphoreTake(*pxMutex, 0) == pdPASS) return 0; - else return -1; -} - -/** Unlock a mutex - * @param mutex the mutex to unlock */ -void ESP_IRAM_ATTR +/** + * @brief Unlock a mutex + * + * @param pxMutex pointer of mutex to unlock + */ +void sys_mutex_unlock(sys_mutex_t *pxMutex) { - xSemaphoreGive(*pxMutex); + BaseType_t ret = xSemaphoreGive(*pxMutex); + + LWIP_ASSERT("failed to give the mutex", ret == pdTRUE); } -/** Delete a semaphore - * @param mutex the mutex to delete */ +/** + * @brief Delete a mutex + * + * @param pxMutex pointer of mutex to delete + */ void sys_mutex_free(sys_mutex_t *pxMutex) { LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_mutex_free: m=%p\n", *pxMutex)); - vQueueDelete(*pxMutex); + vSemaphoreDelete(*pxMutex); + *pxMutex = NULL; } -#endif -/*-----------------------------------------------------------------------------------*/ -// Creates and returns a new semaphore. The "count" argument specifies -// the initial state of the semaphore. TBD finish and test +#endif /* !LWIP_COMPAT_MUTEX */ + +/** + * @brief Creates a new semaphore + * + * @param sem pointer of the semaphore + * @param count initial state of the semaphore + * @return err_t + */ err_t sys_sem_new(sys_sem_t *sem, u8_t count) { - err_t xReturn = ERR_MEM; - vSemaphoreCreateBinary(*sem); + LWIP_ASSERT("initial_count invalid (neither 0 nor 1)", + (count == 0) || (count == 1)); - if ((*sem) != NULL) { - if (count == 0) { // Means it can't be taken - xSemaphoreTake(*sem, 1); - } - - xReturn = ERR_OK; - } else { - ; // TBD need assert + *sem = xSemaphoreCreateBinary(); + if (*sem == NULL) { + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("sys_sem_new: out of mem\r\n")); + return ERR_MEM; } - return xReturn; + if (count == 1) { + BaseType_t ret = xSemaphoreGive(*sem); + LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE); + } + + return ERR_OK; } -/*-----------------------------------------------------------------------------------*/ -// Signals a semaphore -void ESP_IRAM_ATTR +/** + * @brief Signals a semaphore + * + * @param sem pointer of the semaphore + */ +void sys_sem_signal(sys_sem_t *sem) { - xSemaphoreGive(*sem); + BaseType_t ret = xSemaphoreGive(*sem); + /* queue full is OK, this is a signal only... */ + LWIP_ASSERT("sys_sem_signal: sane return value", + (ret == pdTRUE) || (ret == errQUEUE_FULL)); } /*-----------------------------------------------------------------------------------*/ // Signals a semaphore (from ISR) -int sys_sem_signal_isr(sys_sem_t *sem) +int +sys_sem_signal_isr(sys_sem_t *sem) { BaseType_t woken = pdFALSE; xSemaphoreGiveFromISR(*sem, &woken); return woken == pdTRUE; } -/*-----------------------------------------------------------------------------------*/ -/* - Blocks the thread while waiting for the semaphore to be - signaled. If the "timeout" argument is non-zero, the thread should - only be blocked for the specified time (measured in - milliseconds). - - If the timeout argument is non-zero, the return value is the number of - milliseconds spent waiting for the semaphore to be signaled. If the - semaphore wasn't signaled within the specified time, the return value is - SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore - (i.e., it was already signaled), the function may return zero. - - Notice that lwIP implements a function with a similar name, - sys_sem_wait(), that uses the sys_arch_sem_wait() function. -*/ -u32_t ESP_IRAM_ATTR +/** + * @brief Wait for a semaphore to be signaled + * + * @param sem pointer of the semaphore + * @param timeout if zero, will wait infinitely, or will wait for milliseconds specify by this argument + * @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise + */ +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) { - portTickType StartTime, EndTime, Elapsed; - unsigned long ulReturn; + BaseType_t ret; - StartTime = xTaskGetTickCount(); - - if (timeout != 0) { - if (xSemaphoreTake(*sem, timeout / portTICK_PERIOD_MS) == pdTRUE) { - EndTime = xTaskGetTickCount(); - Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS; - - if (Elapsed == 0) { - Elapsed = 1; - } - - ulReturn = Elapsed; - } else { - ulReturn = SYS_ARCH_TIMEOUT; + if (!timeout) { + /* wait infinite */ + ret = xSemaphoreTake(*sem, portMAX_DELAY); + LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); + } else { + TickType_t timeout_ticks = timeout / portTICK_RATE_MS; + ret = xSemaphoreTake(*sem, timeout_ticks); + if (ret == errQUEUE_EMPTY) { + /* timed out */ + return SYS_ARCH_TIMEOUT; } - } else { // must block without a timeout - while (xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE); - - EndTime = xTaskGetTickCount(); - Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS; - - if (Elapsed == 0) { - Elapsed = 1; - } - - ulReturn = Elapsed; + LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); } - return ulReturn ; // return time blocked + return 0; } -/*-----------------------------------------------------------------------------------*/ -// Deallocates a semaphore +/** + * @brief Delete a semaphore + * + * @param sem pointer of the semaphore to delete + */ void sys_sem_free(sys_sem_t *sem) { vSemaphoreDelete(*sem); + *sem = NULL; } -/*-----------------------------------------------------------------------------------*/ -// Creates an empty mailbox. +/** + * @brief Create an empty mailbox. + * + * @param mbox pointer of the mailbox + * @param size size of the mailbox + * @return ERR_OK on success, ERR_MEM when out of memory + */ err_t sys_mbox_new(sys_mbox_t *mbox, int size) { @@ -217,7 +222,7 @@ sys_mbox_new(sys_mbox_t *mbox, int size) (*mbox)->os_mbox = xQueueCreate(size, sizeof(void *)); if ((*mbox)->os_mbox == NULL) { - LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new *mbox->os_mbox\n")); + LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("fail to new (*mbox)->os_mbox\n")); free(*mbox); return ERR_MEM; } @@ -230,21 +235,32 @@ sys_mbox_new(sys_mbox_t *mbox, int size) return ERR_OK; } -/*-----------------------------------------------------------------------------------*/ -// Posts the "msg" to the mailbox. -void ESP_IRAM_ATTR +/** + * @brief Send message to mailbox + * + * @param mbox pointer of the mailbox + * @param msg pointer of the message to send + */ +void sys_mbox_post(sys_mbox_t *mbox, void *msg) { - while (xQueueSendToBack((*mbox)->os_mbox, &msg, portMAX_DELAY) != pdTRUE); + BaseType_t ret = xQueueSendToBack((*mbox)->os_mbox, &msg, portMAX_DELAY); + LWIP_ASSERT("mbox post failed", ret == pdTRUE); } -/*-----------------------------------------------------------------------------------*/ -err_t ESP_IRAM_ATTR +/** + * @brief Try to post a message to mailbox + * + * @param mbox pointer of the mailbox + * @param msg pointer of the message to send + * @return ERR_OK on success, ERR_MEM when mailbox is full + */ +err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) { err_t xReturn; - if (xQueueSend((*mbox)->os_mbox, &msg, (portTickType)0) == pdPASS) { + if (xQueueSend((*mbox)->os_mbox, &msg, 0) == pdTRUE) { xReturn = ERR_OK; } else { LWIP_DEBUGF(ESP_THREAD_SAFE_DEBUG, ("trypost mbox=%p fail\n", (*mbox)->os_mbox)); @@ -254,83 +270,95 @@ sys_mbox_trypost(sys_mbox_t *mbox, void *msg) return xReturn; } -/*-----------------------------------------------------------------------------------*/ -/* - Blocks the thread until a message arrives in the mailbox, but does - not block the thread longer than "timeout" milliseconds (similar to - the sys_arch_sem_wait() function). The "msg" argument is a result - parameter that is set by the function (i.e., by doing "*msg = - ptr"). The "msg" parameter maybe NULL to indicate that the message - should be dropped. +/** + * @brief Try to post a message to mailbox from ISR + * + * @param mbox pointer of the mailbox + * @param msg pointer of the message to send + * @return ERR_OK on success + * ERR_MEM when mailbox is full + * ERR_NEED_SCHED when high priority task wakes up + */ +err_t +sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg) +{ + BaseType_t ret; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; - The return values are the same as for the sys_arch_sem_wait() function: - Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a - timeout. + ret = xQueueSendFromISR((*mbox)->os_mbox, &msg, &xHigherPriorityTaskWoken); + if (ret == pdTRUE) { + if (xHigherPriorityTaskWoken == pdTRUE) { + return ERR_NEED_SCHED; + } + return ERR_OK; + } else { + LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); + return ERR_MEM; + } +} - Note that a function with a similar name, sys_mbox_fetch(), is - implemented by lwIP. -*/ -u32_t ESP_IRAM_ATTR +/** + * @brief Fetch message from mailbox + * + * @param mbox pointer of mailbox + * @param msg pointer of the received message, could be NULL to indicate the message should be dropped + * @param timeout if zero, will wait infinitely; or will wait milliseconds specify by this argument + * @return SYS_ARCH_TIMEOUT when timeout, 0 otherwise + */ +u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) { - void *dummyptr; - portTickType StartTime, EndTime, Elapsed; - unsigned long ulReturn; + BaseType_t ret; + void *msg_dummy; - StartTime = xTaskGetTickCount(); if (msg == NULL) { - msg = &dummyptr; - } - - if (*mbox == NULL){ - *msg = NULL; - return -1; + msg = &msg_dummy; } if (timeout == 0) { - timeout = portMAX_DELAY; + /* wait infinite */ + ret = xQueueReceive((*mbox)->os_mbox, &(*msg), portMAX_DELAY); + LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); } else { - timeout = timeout / portTICK_PERIOD_MS; - } - - *msg = NULL; - if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), timeout)) { - EndTime = xTaskGetTickCount(); - Elapsed = (EndTime - StartTime) * portTICK_PERIOD_MS; - - if (Elapsed == 0) { - Elapsed = 1; + TickType_t timeout_ticks = timeout / portTICK_RATE_MS; + ret = xQueueReceive((*mbox)->os_mbox, &(*msg), timeout_ticks); + if (ret == errQUEUE_EMPTY) { + /* timed out */ + *msg = NULL; + return SYS_ARCH_TIMEOUT; } - - ulReturn = Elapsed; - } else { // timed out blocking for message - ulReturn = SYS_ARCH_TIMEOUT; + LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); } - return ulReturn ; // return time blocked TBD test + return 0; } -/*-----------------------------------------------------------------------------------*/ +/** + * @brief try to fetch message from mailbox + * + * @param mbox pointer of mailbox + * @param msg pointer of the received message + * @return SYS_MBOX_EMPTY if mailbox is empty, 1 otherwise + */ u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) { - void *pvDummy; - unsigned long ulReturn; + BaseType_t ret; + void *msg_dummy; if (msg == NULL) { - msg = &pvDummy; + msg = &msg_dummy; } - if (pdTRUE == xQueueReceive((*mbox)->os_mbox, &(*msg), 0)) { - ulReturn = ERR_OK; - } else { - ulReturn = SYS_MBOX_EMPTY; + ret = xQueueReceive((*mbox)->os_mbox, &(*msg), 0); + if (ret == errQUEUE_EMPTY) { + *msg = NULL; + return SYS_MBOX_EMPTY; } + LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); - return ulReturn; + return 0; } -/*-----------------------------------------------------------------------------------*/ - void sys_mbox_set_owner(sys_mbox_t *mbox, void* owner) { @@ -340,112 +368,128 @@ sys_mbox_set_owner(sys_mbox_t *mbox, void* owner) } } -/* - Deallocates a mailbox. If there are messages still present in the - mailbox when the mailbox is deallocated, it is an indication of a - programming error in lwIP and the developer should be notified. -*/ +/** + * @brief Delete a mailbox + * + * @param mbox pointer of the mailbox to delete + */ void sys_mbox_free(sys_mbox_t *mbox) { - if ( (NULL == mbox) || (NULL == *mbox) ) { - return; + if ((NULL == mbox) || (NULL == *mbox)) { + return; } + UBaseType_t msgs_waiting = uxQueueMessagesWaiting((*mbox)->os_mbox); + LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0); + vQueueDelete((*mbox)->os_mbox); free(*mbox); *mbox = NULL; - } -/*-----------------------------------------------------------------------------------*/ -/* - Starts a new thread with priority "prio" that will begin its execution in the - function "thread()". The "arg" argument will be passed as an argument to the - thread() function. The id of the new thread is returned. Both the id and - the priority are system dependent. -*/ +/** + * @brief Create a new thread + * + * @param name thread name + * @param thread thread function + * @param arg thread arguments + * @param stacksize stacksize of the thread + * @param prio priority of the thread + * @return thread ID + */ sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio) { - xTaskHandle created_task; - portBASE_TYPE result; + TaskHandle_t rtos_task; + BaseType_t ret; - result = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &created_task, + /* LwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the + thread function without adaption here. */ + ret = xTaskCreatePinnedToCore(thread, name, stacksize, arg, prio, &rtos_task, CONFIG_LWIP_TCPIP_TASK_AFFINITY); - if (result != pdPASS) { + if (ret != pdTRUE) { return NULL; } - return created_task; + return (sys_thread_t)rtos_task; } -/*-----------------------------------------------------------------------------------*/ -// Initialize sys arch +/** + * @brief Initialize the sys_arch layer + * + */ void sys_init(void) { + if (!g_lwip_protect_mutex) { if (ERR_OK != sys_mutex_new(&g_lwip_protect_mutex)) { - ESP_LOGE(TAG, "sys_init: failed to init lwip protect mutex\n"); + ESP_LOGE(TAG, "sys_init: failed to init lwip protect mutex\n"); } + } - // Create the pthreads key for the per-thread semaphore storage - pthread_key_create(&sys_thread_sem_key, sys_thread_sem_free); + // Create the pthreads key for the per-thread semaphore storage + pthread_key_create(&sys_thread_sem_key, sys_thread_sem_free); - esp_vfs_lwip_sockets_register(); + esp_vfs_lwip_sockets_register(); } -/*-----------------------------------------------------------------------------------*/ +/** + * @brief Get system ticks + * + * @return system tick counts + */ u32_t sys_jiffies(void) { return xTaskGetTickCount(); } -/*-----------------------------------------------------------------------------------*/ +/** + * @brief Get current time, in miliseconds + * + * @return current time + */ u32_t sys_now(void) { - return (xTaskGetTickCount()*portTICK_PERIOD_MS); + return xTaskGetTickCount() * portTICK_PERIOD_MS; } -/* - This optional function does a "fast" critical region protection and returns - the previous protection level. This function is only called during very short - critical regions. An embedded system which supports ISR-based drivers might - want to implement this function by disabling interrupts. Task-based systems - might want to implement this by using a mutex or disabling tasking. This - function should support recursive calls from the same task or interrupt. In - other words, sys_arch_protect() could be called while already protected. In - that case the return value indicates that it is already protected. - - sys_arch_protect() is only required if your port is supporting an operating - system. -*/ +/** + * @brief Protect critical region + * + * @note This function is only called during very short critical regions. + * + * @return previous protection level + */ sys_prot_t sys_arch_protect(void) { + if (!g_lwip_protect_mutex) { + sys_mutex_new(&g_lwip_protect_mutex); + } sys_mutex_lock(&g_lwip_protect_mutex); return (sys_prot_t) 1; } -/*-----------------------------------------------------------------------------------*/ -/* - This optional function does a "fast" set of critical region protection to the - value specified by pval. See the documentation for sys_arch_protect() for - more information. This function is only required if your port is supporting - an operating system. -*/ +/** + * @brief Unprotect critical region + * + * @param pval protection level + */ void sys_arch_unprotect(sys_prot_t pval) { + LWIP_UNUSED_ARG(pval); sys_mutex_unlock(&g_lwip_protect_mutex); } /* - * get per thread semphore + * get per thread semaphore */ -sys_sem_t* sys_thread_sem_get(void) +sys_sem_t* +sys_thread_sem_get(void) { sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key); @@ -456,7 +500,8 @@ sys_sem_t* sys_thread_sem_get(void) return sem; } -static void sys_thread_sem_free(void* data) // destructor for TLS semaphore +static void +sys_thread_sem_free(void* data) // destructor for TLS semaphore { sys_sem_t *sem = (sys_sem_t*)(data); @@ -471,7 +516,8 @@ static void sys_thread_sem_free(void* data) // destructor for TLS semaphore } } -sys_sem_t* sys_thread_sem_init(void) +sys_sem_t* +sys_thread_sem_init(void) { sys_sem_t *sem = (sys_sem_t*)mem_malloc(sizeof(sys_sem_t*)); @@ -491,7 +537,8 @@ sys_sem_t* sys_thread_sem_init(void) return sem; } -void sys_thread_sem_deinit(void) +void +sys_thread_sem_deinit(void) { sys_sem_t *sem = pthread_getspecific(sys_thread_sem_key); if (sem != NULL) { @@ -500,9 +547,8 @@ void sys_thread_sem_deinit(void) } } -void sys_delay_ms(uint32_t ms) +void +sys_delay_ms(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } - - diff --git a/components/lwip/port/esp8266/include/arch/cc.h b/components/lwip/port/esp8266/include/arch/cc.h index 300291f3..348cae35 100644 --- a/components/lwip/port/esp8266/include/arch/cc.h +++ b/components/lwip/port/esp8266/include/arch/cc.h @@ -45,6 +45,10 @@ #define BYTE_ORDER LITTLE_ENDIAN #endif // BYTE_ORDER +#ifndef CONFIG_LWIP_ESP_LWIP_ASSERT +#define LWIP_NOASSERT 1 +#endif + typedef uint8_t u8_t; typedef int8_t s8_t; typedef uint16_t u16_t; diff --git a/components/lwip/port/esp8266/include/arch/sys_arch.h b/components/lwip/port/esp8266/include/arch/sys_arch.h index 5fea8eb5..d6c5216a 100644 --- a/components/lwip/port/esp8266/include/arch/sys_arch.h +++ b/components/lwip/port/esp8266/include/arch/sys_arch.h @@ -29,7 +29,7 @@ * Author: Adam Dunkels * */ - + #ifndef __SYS_ARCH_H__ #define __SYS_ARCH_H__ @@ -44,15 +44,22 @@ extern "C" { #endif -typedef xSemaphoreHandle sys_sem_t; -typedef xSemaphoreHandle sys_mutex_t; -typedef xTaskHandle sys_thread_t; +typedef SemaphoreHandle_t sys_sem_t; +typedef SemaphoreHandle_t sys_mutex_t; +typedef TaskHandle_t sys_thread_t; typedef struct sys_mbox_s { - xQueueHandle os_mbox; + QueueHandle_t os_mbox; void *owner; }* sys_mbox_t; +/** This is returned by _fromisr() sys functions to tell the outermost function + * that a higher priority task was woken and the scheduler needs to be invoked. + */ +#define ERR_NEED_SCHED 123 + +void sys_delay_ms(uint32_t ms); +#define sys_msleep(ms) sys_delay_ms(ms) #define LWIP_COMPAT_MUTEX 0 @@ -64,7 +71,7 @@ typedef struct sys_mbox_s { #define sys_mbox_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE ) /* Define the sys_mbox_set_invalid() to empty to support lock-free mbox in ESP LWIP. - * + * * The basic idea about the lock-free mbox is that the mbox should always be valid unless * no socket APIs are using the socket and the socket is closed. ESP LWIP achieves this by * following two changes to official LWIP: @@ -72,9 +79,9 @@ typedef struct sys_mbox_s { * no one is using the socket. * 2. Define the sys_mbox_set_invalid() to empty if the mbox is not actually freed. - * The second change is necessary. Consider a common scenario: the application task calls + * The second change is necessary. Consider a common scenario: the application task calls * recv() to receive packets from the socket, the sys_mbox_valid() returns true. Because there - * is no lock for the mbox, the LWIP CORE can call sys_mbox_set_invalid() to set the mbox at + * is no lock for the mbox, the LWIP CORE can call sys_mbox_set_invalid() to set the mbox at * anytime and the thread-safe issue may happen. * * However, if the sys_mbox_set_invalid() is not called after sys_mbox_free(), e.g. in netconn_alloc(), diff --git a/components/lwip/port/esp8266/include/arpa/inet.h b/components/lwip/port/esp8266/include/arpa/inet.h index 90428f68..94c6c17e 100644 --- a/components/lwip/port/esp8266/include/arpa/inet.h +++ b/components/lwip/port/esp8266/include/arpa/inet.h @@ -15,6 +15,6 @@ #ifndef INET_H_ #define INET_H_ -#include "../../../lwip/src/include/lwip/inet.h" +#include "lwip/inet.h" #endif /* INET_H_ */ diff --git a/components/lwip/port/esp8266/include/lwipopts.h b/components/lwip/port/esp8266/include/lwipopts.h index fc6b19b5..e85d4288 100644 --- a/components/lwip/port/esp8266/include/lwipopts.h +++ b/components/lwip/port/esp8266/include/lwipopts.h @@ -169,18 +169,32 @@ -------------------------------- */ /** - * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP4 packets. Note that * this option does not affect outgoing packet sizes, which can be controlled * via IP_FRAG. */ -#define IP_REASSEMBLY CONFIG_LWIP_IP_REASSEMBLY +#define IP_REASSEMBLY CONFIG_LWIP_IP4_REASSEMBLY /** - * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * LWIP_IPV6_REASS==1: reassemble incoming IP6 packets that fragmented. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via LWIP_IPV6_FRAG. + */ +#define LWIP_IPV6_REASS CONFIG_LWIP_IP6_REASSEMBLY + +/** + * IP_FRAG==1: Fragment outgoing IP4 packets if their size exceeds MTU. Note * that this option does not affect incoming packet sizes, which can be * controlled via IP_REASSEMBLY. */ -#define IP_FRAG CONFIG_LWIP_IP_FRAG +#define IP_FRAG CONFIG_LWIP_IP4_FRAG + +/** + * LWIP_IPV6_FRAG==1: Fragment outgoing IP6 packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#define LWIP_IPV6_FRAG CONFIG_LWIP_IP6_FRAG /** * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) @@ -197,6 +211,20 @@ */ #define IP_REASS_MAX_PBUFS 10 +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#define IP_FORWARD CONFIG_LWIP_IP_FORWARD + +/** + * IP_NAPT==1: Enables IPv4 Network Address and Port Translation. + * Note that both CONFIG_LWIP_IP_FORWARD and CONFIG_LWIP_L2_TO_L3_COPY options + * need to be enabled in system configuration for the NAPT to work on ESP platform + */ +#define IP_NAPT CONFIG_LWIP_IPV4_NAPT + /* ---------------------------------- ---------- ICMP options ---------- @@ -323,6 +351,11 @@ */ #define TCP_QUEUE_OOSEQ CONFIG_LWIP_TCP_QUEUE_OOSEQ +/** + * LWIP_TCP_SACK_OUT==1: TCP will support sending selective acknowledgements (SACKs). + */ +#define LWIP_TCP_SACK_OUT CONFIG_LWIP_TCP_SACK_OUT + /** * 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 @@ -393,6 +426,12 @@ #define TCP_RCV_SCALE CONFIG_LWIP_TCP_RCV_SCALE #endif +/** + * LWIP_TCP_RTO_TIME: TCP rto time. + * Default is 3 second. + */ +#define LWIP_TCP_RTO_TIME CONFIG_LWIP_TCP_RTO_TIME + /* ---------------------------------- ---------- Pbuf options ---------- @@ -562,6 +601,11 @@ */ #define LWIP_TCP_KEEPALIVE 1 +/** + * LWIP_SO_LINGER==1: Enable SO_LINGER processing. + */ +#define LWIP_SO_LINGER CONFIG_LWIP_SO_LINGER + /** * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. */ @@ -625,6 +669,14 @@ #if PPP_SUPPORT +/** + * PPP_IPV6_SUPPORT == 1: Enable IPV6 support for local link + * between modem and lwIP stack. + * Some modems do not support IPV6 addressing in local link and + * the only option available is to disable IPV6 address negotiation. + */ +#define PPP_IPV6_SUPPORT CONFIG_LWIP_PPP_ENABLE_IPV6 + /** * PPP_NOTIFY_PHASE==1: Support PPP notify phase. */ @@ -667,6 +719,8 @@ #if PPP_DEBUG_ON #define PPP_DEBUG LWIP_DBG_ON +#define PRINTPKT_SUPPORT 1 +#define PPP_PROTOCOLNAME 1 #else #define PPP_DEBUG LWIP_DBG_OFF #endif @@ -793,7 +847,6 @@ #define ESP_THREAD_SAFE_DEBUG LWIP_DBG_OFF #define ESP_DHCP 1 #define ESP_DNS 1 -#define ESP_IPV6_AUTOCONFIG LWIP_IPV6 #define ESP_PERF 0 #define ESP_RANDOM_TCP_PORT 1 #define ESP_IP4_ATON 1 @@ -817,6 +870,10 @@ #define ESP_LWIP_SELECT 1 #define ESP_LWIP_LOCK 1 +#ifdef CONFIG_LWIP_IPV6_AUTOCONFIG +#define ESP_IPV6_AUTOCONFIG CONFIG_LWIP_IPV6_AUTOCONFIG +#endif + #ifdef ESP_IRAM_ATTR #undef ESP_IRAM_ATTR #endif @@ -873,7 +930,10 @@ void tcp_print_status(int status, void* p, uint32_t tmp1, uint32_t tmp2, uint32_ */ #define SNTP_SERVER_DNS 1 -#define SNTP_UPDATE_DELAY CONFIG_LWIP_SNTP_UPDATE_DELAY +// It disables a check of SNTP_UPDATE_DELAY it is done in sntp_set_sync_interval +#define SNTP_SUPPRESS_DELAY_CHECK + +#define SNTP_UPDATE_DELAY (sntp_get_sync_interval()) #define SNTP_SET_SYSTEM_TIME_US(sec, us) \ do { \ diff --git a/components/lwip/port/esp8266/include/netif/nettestif.h b/components/lwip/port/esp8266/include/netinet/tcp.h similarity index 62% rename from components/lwip/port/esp8266/include/netif/nettestif.h rename to components/lwip/port/esp8266/include/netinet/tcp.h index aa76ed80..f2555cfb 100644 --- a/components/lwip/port/esp8266/include/netif/nettestif.h +++ b/components/lwip/port/esp8266/include/netinet/tcp.h @@ -1,4 +1,5 @@ -// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2020 Francesco Giancane // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,22 +13,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +#ifndef _NETINET_TCP_H +#define _NETINET_TCP_H -#ifndef _NETTEST_LWIP_IF_H_ -#define _NETTEST_LWIP_IF_H_ +#include "lwip/tcp.h" -#include "lwip/err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -err_t nettestif_init(struct netif *netif); - -void nettestif_input(void *buffer, u16_t len); - -#ifdef __cplusplus -} -#endif - -#endif /* _NETTEST_LWIP_IF_H_ */ \ No newline at end of file +#endif /* _NETINET_TCP_H */ diff --git a/components/lwip/port/esp8266/netif/nettestif.c b/components/lwip/port/esp8266/netif/nettestif.c deleted file mode 100644 index 4422c219..00000000 --- a/components/lwip/port/esp8266/netif/nettestif.c +++ /dev/null @@ -1,105 +0,0 @@ - -#include "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/pbuf.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "lwip/ethip6.h" -#include "netif/etharp.h" -#include "netif/wlanif.h" - -#include -#include - -#include "tcpip_adapter.h" - -static struct netif *g_last_netif = NULL; - - -err_t nettestif_output(struct netif *netif, struct pbuf *p) -{ - int i; - char *dat = p->payload; - - /* output the packet to stdout */ - printf("\nPacketOut:["); - for (i=0; ilen; i++) { - printf("%02x", *dat++); - } - printf("]\n"); - - return ERR_OK; -} - - -err_t nettestif_init(struct netif *netif) -{ - - g_last_netif = netif; - - netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; - - /* - * Initialize the snmp variables and counters inside the struct netif. - * The last argument should be replaced with your link speed, in units - * of bits per second. - */ - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100); - - /* We directly use etharp_output() here to save a function call. - * You can instead declare your own function an call etharp_output() - * from it if you have to do some checks before sending (e.g. if link - * is available...) */ - netif->output = etharp_output; -#if LWIP_IPV6 - netif->output_ip6 = ethip6_output; -#endif /* LWIP_IPV6 */ - netif->linkoutput = nettestif_output; - /* set MAC hardware address length */ - netif->hwaddr_len = ETHARP_HWADDR_LEN; - - /* set MAC hardware address */ - - /* maximum transfer unit */ - netif->mtu = 1500; - - /* device capabilities */ - /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ - netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; - -#if ESP_LWIP -#if LWIP_IGMP - netif->flags |= NETIF_FLAG_IGMP; -#endif -#endif - return ERR_OK; - -} - -void nettestif_input(void *buffer, u16_t len) -{ - struct pbuf *p; - if (g_last_netif == NULL) { - printf("error!"); - return; - } - - printf("simul in: %d\n", len); - if (len==0) return; - - p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); - p->l2_owner = NULL; - memcpy(p->payload, buffer, len); - - /* full packet send to tcpip_thread to process - * on success - the packet is processed and deallocated in tcpip stack - * on failure - log error and deallocate the packet - */ - if (g_last_netif->input(p, g_last_netif) != ERR_OK) { - LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); - pbuf_free(p); - } - -} diff --git a/components/lwip/port/esp8266/netif/wlanif.c b/components/lwip/port/esp8266/netif/wlanif.c index 3c4e2704..cec9ae3b 100644 --- a/components/lwip/port/esp8266/netif/wlanif.c +++ b/components/lwip/port/esp8266/netif/wlanif.c @@ -319,12 +319,17 @@ static void low_level_init(struct netif* netif) /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; +#if ESP_LWIP #if LWIP_IGMP netif->flags |= NETIF_FLAG_IGMP; #endif -#if LWIP_IPV6_AUTOCONFIG - netif->ip6_autoconfig_enabled = 1; -#endif /* LWIP_IPV6_AUTOCONFIG */ +#endif + +#if ESP_IPV6 +#if LWIP_IPV6 && LWIP_IPV6_MLD + netif->flags |= NETIF_FLAG_MLD6; +#endif +#endif /* Do whatever else is needed to initialize interface. */ } @@ -593,7 +598,9 @@ int8_t ethernetif_init(struct netif* netif) /* Initialize interface hostname */ #if ESP_LWIP - netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; + if (tcpip_adapter_get_hostname(tcpip_adapter_get_esp_if(netif), &netif->hostname) != ESP_OK) { + netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME; + } #else netif->hostname = "lwip"; #endif diff --git a/components/lwip/weekend_test/net_suite_test.py b/components/lwip/weekend_test/net_suite_test.py index 59e763b4..2c8d6c31 100644 --- a/components/lwip/weekend_test/net_suite_test.py +++ b/components/lwip/weekend_test/net_suite_test.py @@ -1,27 +1,13 @@ import re import os -import sys import socket from threading import Thread, Event import subprocess import time from shutil import copyfile -try: - import IDF - from IDF.IDFDUT import ESP32DUT -except ImportError: - # this is a test case write with tiny-test-fw. - # to run test cases outside tiny-test-fw, - # we need to set environment variable `TEST_FW_PATH`, - # then get and insert `TEST_FW_PATH` to sys path before import FW module - test_fw_path = os.getenv("TEST_FW_PATH") - if test_fw_path and test_fw_path not in sys.path: - sys.path.insert(0, test_fw_path) - import IDF - -import DUT -import Utility +from tiny_test_fw import Utility, DUT +import ttfw_idf stop_sock_listener = Event() stop_io_listener = Event() @@ -73,7 +59,7 @@ def sock_listener(dut1): sock = None -@IDF.idf_example_test(env_tag="Example_WIFI") +@ttfw_idf.idf_example_test(env_tag="Example_WIFI") def lwip_test_suite(env, extra_data): global stop_io_listener global stop_sock_listener @@ -84,12 +70,12 @@ def lwip_test_suite(env, extra_data): 3. Execute ttcn3 test suite 4. Collect result from ttcn3 """ - dut1 = env.get_dut("net_suite", "examples/system/network_tests", dut_class=ESP32DUT) + dut1 = env.get_dut("net_suite", "examples/system/network_tests", dut_class=ttfw_idf.ESP32DUT) # check and log bin size binary_file = os.path.join(dut1.app.binary_path, "net_suite.bin") bin_size = os.path.getsize(binary_file) - IDF.log_performance("net_suite", "{}KB".format(bin_size // 1024)) - IDF.check_performance("net_suite", bin_size // 1024) + ttfw_idf.log_performance("net_suite", "{}KB".format(bin_size // 1024)) + ttfw_idf.check_performance("net_suite", bin_size // 1024, dut1.TARGET) dut1.start_app() thread1 = Thread(target=sock_listener, args=(dut1, )) thread2 = Thread(target=io_listener, args=(dut1, )) diff --git a/components/tcpip_adapter/include/tcpip_adapter.h b/components/tcpip_adapter/include/tcpip_adapter.h index b7dac087..8f3a76bc 100644 --- a/components/tcpip_adapter/include/tcpip_adapter.h +++ b/components/tcpip_adapter/include/tcpip_adapter.h @@ -168,6 +168,7 @@ typedef enum{ } tcpip_adapter_option_mode_t; typedef enum{ + TCPIP_ADAPTER_SUBNET_MASK = 1, /**< network mask */ TCPIP_ADAPTER_DOMAIN_NAME_SERVER = 6, /**< domain name server */ TCPIP_ADAPTER_ROUTER_SOLICITATION_ADDRESS = 32, /**< solicitation router address */ TCPIP_ADAPTER_REQUESTED_IP_ADDRESS = 50, /**< request IP address pool */ diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index ae2853e9..35ab7ac4 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -719,6 +719,7 @@ esp_err_t tcpip_adapter_dhcps_option(tcpip_adapter_option_mode_t opt_op, tcpip_a *(uint32_t *)opt_val = *(uint32_t *)opt_info; break; } + case SUBNET_MASK: case REQUESTED_IP_ADDRESS: { memcpy(opt_val, opt_info, opt_len); break; @@ -756,6 +757,10 @@ esp_err_t tcpip_adapter_dhcps_option(tcpip_adapter_option_mode_t opt_op, tcpip_a } break; } + case SUBNET_MASK: { + memcpy(opt_info, opt_val, opt_len); + break; + } case REQUESTED_IP_ADDRESS: { tcpip_adapter_ip_info_t info; uint32_t softap_ip = 0; @@ -1226,11 +1231,11 @@ esp_err_t tcpip_adapter_get_hostname(tcpip_adapter_if_t tcpip_if, const char **h } p_netif = esp_netif[tcpip_if]; - if (p_netif != NULL) { + if (p_netif != NULL && p_netif->hostname != NULL) { *hostname = p_netif->hostname; return ESP_OK; } else { - return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; + return ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY; } #else return ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY; diff --git a/examples/common_components/protocol_examples_common/Kconfig.projbuild b/examples/common_components/protocol_examples_common/Kconfig.projbuild index 8a0b4ada..0eb3fb30 100644 --- a/examples/common_components/protocol_examples_common/Kconfig.projbuild +++ b/examples/common_components/protocol_examples_common/Kconfig.projbuild @@ -13,10 +13,33 @@ menu "Example Connection Configuration" Can be left blank if the network has no security set. config EXAMPLE_CONNECT_IPV6 - bool "Obtain IPv6 link-local address" + bool "Obtain IPv6 address" default n select LWIP_IPV6 help - By default, examples will wait until IPv4 and IPv6 addresses are obtained. + By default, examples will wait until IPv4 and IPv6 local link addresses are obtained. Disable this option if the network does not support IPv6. + Choose the preferred IPv6 address type if the connection code should wait until other than + the local link address gets assigned. + + if EXAMPLE_CONNECT_IPV6 + choice EXAMPLE_CONNECT_PREFERRED_IPV6 + prompt "Preferred IPv6 Type" + default EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK + help + Select which kind of IPv6 address the connect logic waits for. + + config EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK + bool "Local Link Address" + help + Blocks until Local link address assigned. + + config EXAMPLE_CONNECT_IPV6_PREF_GLOBAL + bool "Global Address" + select LWIP_IPV6_AUTOCONFIG + help + Blocks until Global address assigned. + endchoice + + endif endmenu diff --git a/examples/common_components/protocol_examples_common/connect.c b/examples/common_components/protocol_examples_common/connect.c index 8d8b2bb4..6c98b5e7 100644 --- a/examples/common_components/protocol_examples_common/connect.c +++ b/examples/common_components/protocol_examples_common/connect.c @@ -27,6 +27,11 @@ #ifdef CONFIG_EXAMPLE_CONNECT_IPV6 #define CONNECTED_BITS (GOT_IPV4_BIT | GOT_IPV6_BIT) +#if defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK) +#define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE 0 +#elif defined(CONFIG_EXAMPLE_CONNECT_IPV6_PREF_GLOBAL) +#define EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE 1 +#endif #else #define CONNECTED_BITS (GOT_IPV4_BIT) #endif @@ -78,7 +83,13 @@ static void on_got_ipv6(void *arg, esp_event_base_t event_base, { ip_event_got_ip6_t *event = (ip_event_got_ip6_t *)event_data; memcpy(&s_ipv6_addr, &event->ip6_info.ip, sizeof(s_ipv6_addr)); - xEventGroupSetBits(s_connect_event_group, GOT_IPV6_BIT); + if (EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE) { + if (ip6_addr_isglobal(&s_ipv6_addr)) { + xEventGroupSetBits(s_connect_event_group, GOT_IPV6_BIT); + } + } else { + xEventGroupSetBits(s_connect_event_group, GOT_IPV6_BIT); + } } #endif // CONFIG_EXAMPLE_CONNECT_IPV6 diff --git a/examples/protocols/sockets/tcp_client/main/tcp_client.c b/examples/protocols/sockets/tcp_client/main/tcp_client.c index f7bc6eab..048d4977 100644 --- a/examples/protocols/sockets/tcp_client/main/tcp_client.c +++ b/examples/protocols/sockets/tcp_client/main/tcp_client.c @@ -57,6 +57,7 @@ static void tcp_client_task(void *pvParameters) inet6_aton(HOST_IP_ADDR, &destAddr.sin6_addr); destAddr.sin6_family = AF_INET6; destAddr.sin6_port = htons(PORT); + destAddr.sin6_scope_id = tcpip_adapter_get_netif_index(TCPIP_ADAPTER_IF_STA); addr_family = AF_INET6; ip_protocol = IPPROTO_IPV6; inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); @@ -72,6 +73,8 @@ static void tcp_client_task(void *pvParameters) int err = connect(sock, (struct sockaddr *)&destAddr, sizeof(destAddr)); if (err != 0) { ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno); + close(sock); + continue; } ESP_LOGI(TAG, "Successfully connected"); diff --git a/examples/protocols/sockets/udp_client/main/udp_client.c b/examples/protocols/sockets/udp_client/main/udp_client.c index caae111e..04bf004d 100644 --- a/examples/protocols/sockets/udp_client/main/udp_client.c +++ b/examples/protocols/sockets/udp_client/main/udp_client.c @@ -57,6 +57,7 @@ static void udp_client_task(void *pvParameters) inet6_aton(HOST_IP_ADDR, &destAddr.sin6_addr); destAddr.sin6_family = AF_INET6; destAddr.sin6_port = htons(PORT); + destAddr.sin6_scope_id = tcpip_adapter_get_netif_index(TCPIP_ADAPTER_IF_STA); addr_family = AF_INET6; ip_protocol = IPPROTO_IPV6; inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1);