From b2af4d9689812b716f6815cb87e39c8ee562d12a Mon Sep 17 00:00:00 2001 From: David Cermak Date: Mon, 3 Apr 2023 20:31:51 +0200 Subject: [PATCH] lwip/linux: Add lwip support for networking component under linux linux/lwip: Wrap some IO posix functions * to workaourd the FreeRTOS EINTR issue (when building without lwip) * to correctly choose the sub-system based on fd (when building with lwip) -- passing control to either linux/system or to lwip This commit also addapts tapio-if to provide DHCP client by default and configurable settings for static IP --- .gitlab/ci/host-test.yml | 2 +- components/esp-tls/CMakeLists.txt | 7 ++ components/esp-tls/esp_tls.c | 5 +- components/esp_http_client/CMakeLists.txt | 2 +- components/esp_http_server/CMakeLists.txt | 4 +- .../esp_hw_support/port/linux/chip_info.c | 13 ++++ components/freertos/CMakeLists.txt | 15 +++++ .../arch/linux/FreeRTOSSimulator_wrappers.c | 51 +++++++++++++++ components/linux/CMakeLists.txt | 3 +- components/linux/esp_event_stubs.c | 18 ----- components/linux/include/esp_linux_helper.h | 2 +- components/lwip/CMakeLists.txt | 13 ++++ .../lwip/port/linux/include/sys/fcntl.h | 14 ++-- .../lwip/port/linux/include/sys/socket.h | 10 +-- components/lwip/port/linux/vfs_lwip.c | 65 +++++++++++++++++++ components/tcp_transport/CMakeLists.txt | 10 +++ .../Kconfig.projbuild | 12 ++-- .../protocol_examples_tapif_io/README.md | 17 +++-- .../protocol_examples_tapif_io/linux/tapio.c | 19 +++--- .../linux_connect.c | 37 ++++++++++- .../protocols/esp_http_client/CMakeLists.txt | 3 +- .../esp_http_client/main/CMakeLists.txt | 2 +- .../main/esp_http_client_example.c | 2 - .../http_server/simple/CMakeLists.txt | 3 +- .../linux_stubs/esp_stubs/esp_stubs.c | 10 --- .../linux_stubs/esp_stubs/include/esp_event.h | 8 --- .../linux_stubs/esp_stubs/include/esp_netif.h | 8 +++ .../sockets/tcp_client/CMakeLists.txt | 3 +- .../sockets/tcp_client/main/CMakeLists.txt | 2 +- .../sockets/udp_client/CMakeLists.txt | 2 +- .../sockets/udp_client/sdkconfig.ci.linux | 3 + 31 files changed, 277 insertions(+), 88 deletions(-) create mode 100644 components/freertos/esp_additions/arch/linux/FreeRTOSSimulator_wrappers.c delete mode 100644 components/linux/esp_event_stubs.c create mode 100644 components/lwip/port/linux/vfs_lwip.c delete mode 100644 examples/protocols/linux_stubs/esp_stubs/include/esp_event.h create mode 100644 examples/protocols/sockets/udp_client/sdkconfig.ci.linux diff --git a/.gitlab/ci/host-test.yml b/.gitlab/ci/host-test.yml index 47e74675db..a42a25b5d7 100644 --- a/.gitlab/ci/host-test.yml +++ b/.gitlab/ci/host-test.yml @@ -282,8 +282,8 @@ test_sockets_on_host: - grep "Socket unable to connect" test.log # test the udp-client example with lwip sockets - cd ${IDF_PATH}/examples/protocols/sockets/udp_client - - echo 'CONFIG_EXAMPLE_IPV4_ADDR="127.0.0.1"' >> sdkconfig.defaults - idf.py --preview set-target linux + - cat sdkconfig.ci.linux > sdkconfig - idf.py build - timeout 5 ./build/udp_client.elf >test.log || true - grep "Message sent" test.log diff --git a/components/esp-tls/CMakeLists.txt b/components/esp-tls/CMakeLists.txt index e98f3fdeaf..b40b249c4c 100644 --- a/components/esp-tls/CMakeLists.txt +++ b/components/esp-tls/CMakeLists.txt @@ -32,8 +32,15 @@ if(NOT ${IDF_TARGET} STREQUAL "linux") # due to cyclic dependencies present in IDF for lwip/esp_netif/mbedtls idf_component_get_property(lwip lwip COMPONENT_LIB) set_property(TARGET ${lwip} APPEND PROPERTY LINK_INTERFACE_MULTIPLICITY 5) +else() + # Check if LWIP in the build for linux target to adapt esp-tls compatibility layer + idf_build_get_property(build_components BUILD_COMPONENTS) + if("lwip" IN_LIST build_components) + target_compile_definitions(${COMPONENT_LIB} PRIVATE ESP_TLS_WITH_LWIP=1) + endif() endif() + if(CONFIG_ESP_TLS_USE_SECURE_ELEMENT) idf_component_optional_requires(PRIVATE espressif__esp-cryptoauthlib esp-cryptoauthlib) endif() diff --git a/components/esp-tls/esp_tls.c b/components/esp-tls/esp_tls.c index 1461728ab1..b80edd1679 100644 --- a/components/esp-tls/esp_tls.c +++ b/components/esp-tls/esp_tls.c @@ -17,9 +17,10 @@ #include "esp_tls.h" #include "esp_tls_private.h" #include "esp_tls_error_capture_internal.h" +#include #include -#if CONFIG_IDF_TARGET_LINUX +#if CONFIG_IDF_TARGET_LINUX && !ESP_TLS_WITH_LWIP #include #include #include @@ -36,7 +37,7 @@ static inline char *ip6addr_ntoa(const ip6_addr_t *addr) return (char *)inet_ntop(AF_INET6, addr->s6_addr, str, 40); } -#endif +#endif // CONFIG_IDF_TARGET_LINUX && !ESP_TLS_WITH_LWIP static const char *TAG = "esp-tls"; diff --git a/components/esp_http_client/CMakeLists.txt b/components/esp_http_client/CMakeLists.txt index 59fd0e5763..4a353e33ca 100644 --- a/components/esp_http_client/CMakeLists.txt +++ b/components/esp_http_client/CMakeLists.txt @@ -1,7 +1,7 @@ if(NOT ${IDF_TARGET} STREQUAL "linux") set(req lwip esp_event) else() - set(req linux) + set(req linux esp_event) endif() idf_component_register(SRCS "esp_http_client.c" diff --git a/components/esp_http_server/CMakeLists.txt b/components/esp_http_server/CMakeLists.txt index 418f210acd..af0a5ad559 100644 --- a/components/esp_http_server/CMakeLists.txt +++ b/components/esp_http_server/CMakeLists.txt @@ -1,14 +1,12 @@ set(priv_req mbedtls) set(priv_inc_dir "src/util") -set(requires http_parser) +set(requires http_parser esp_event) if(NOT ${IDF_TARGET} STREQUAL "linux") list(APPEND priv_req lwip esp_timer) list(APPEND priv_inc_dir "src/port/esp32") - list(APPEND requires esp_event) else() list(APPEND priv_inc_dir "src/port/linux") list(APPEND priv_req pthread) - list(APPEND requires linux) endif() idf_component_register(SRCS "src/httpd_main.c" diff --git a/components/esp_hw_support/port/linux/chip_info.c b/components/esp_hw_support/port/linux/chip_info.c index 684886ccc4..4c8f19ac30 100644 --- a/components/esp_hw_support/port/linux/chip_info.c +++ b/components/esp_hw_support/port/linux/chip_info.c @@ -6,6 +6,7 @@ #include #include "esp_chip_info.h" +#include "esp_mac.h" void esp_chip_info(esp_chip_info_t *out_info) { @@ -18,3 +19,15 @@ void esp_chip_info(esp_chip_info_t *out_info) out_info->revision = 0; out_info->cores = 1; } + +esp_err_t esp_read_mac(uint8_t *mac, esp_mac_type_t type) +{ + // Provide Locally Administered (OUI range) MAC address on POSIX/Linux + mac[0] = 0x02; + mac[1] = 0x12; + mac[2] = 0x34; + mac[3] = 0x56; + mac[4] = 0x78; + mac[5] = 0xab; + return ESP_OK; +} diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index 483ec4ca2c..f47614403b 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -60,6 +60,18 @@ if(${target} STREQUAL "linux") if(NOT CONFIG_FREERTOS_SMP) list(APPEND srcs "${kernel_dir}/portable/${arch}/port_idf.c") endif() + + # Check if we need to address the FreeRTOS EINTR coexistence with linux system calls + # if we're building without lwIP, we need to use linux system select which will receive + # EINTR event on every FreeRTOS interrupt, we workaround this problem by wrapping select() + # to bypass and silence the EINTR events + set(BYPASS_EINTR_ISSUE 0) + idf_build_get_property(build_components BUILD_COMPONENTS) + if(NOT "lwip" IN_LIST build_components) + set(BYPASS_EINTR_ISSUE 1) + list(APPEND srcs esp_additions/arch/linux/FreeRTOSSimulator_wrappers.c) + endif() + else() list(APPEND srcs "app_startup.c" @@ -99,6 +111,9 @@ idf_component_register(SRCS "${srcs}" if(${target} STREQUAL "linux") target_compile_definitions(${COMPONENT_LIB} PUBLIC "projCOVERAGE_TEST=0") target_link_libraries(${COMPONENT_LIB} PUBLIC pthread) + if(BYPASS_EINTR_ISSUE) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=select") + endif() else() idf_component_get_property(COMPONENT_DIR freertos COMPONENT_DIR) diff --git a/components/freertos/esp_additions/arch/linux/FreeRTOSSimulator_wrappers.c b/components/freertos/esp_additions/arch/linux/FreeRTOSSimulator_wrappers.c new file mode 100644 index 0000000000..051c1840a7 --- /dev/null +++ b/components/freertos/esp_additions/arch/linux/FreeRTOSSimulator_wrappers.c @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "esp_err.h" +#include "errno.h" + +/** This module addresses the FreeRTOS simulator's coexistence with linux system calls from user apps. + * It's only included when building without lwIP, so we need to use linux system's select() which would receive + * EINTR event on every FreeRTOS interrupt; we workaround this problem by wrapping select() + * to bypass and silence these events. + */ +extern int __real_select (int fd, fd_set * rfds, fd_set * wfds, fd_set *efds, struct timeval *tval); + +static inline int64_t get_us(void) +{ + struct timespec spec; + clock_gettime(CLOCK_REALTIME, &spec); + return spec.tv_nsec / 1000 + spec.tv_sec * 1000000; +} + +int __wrap_select (int fd, fd_set * rfds, fd_set * wfds, fd_set *efds, struct timeval *tval) +{ + int ret; + struct timeval *tv = tval; + int64_t start = 0; + int64_t timeout_us = 0; + if (tv != NULL) { + start = get_us(); + timeout_us = tval->tv_sec * 1000000 + tval->tv_usec; + struct timeval timeval_local = { .tv_sec = tval->tv_sec, .tv_usec = tval->tv_usec }; + tv = &timeval_local; // this (tv != NULL) indicates that we should handle timeouts + } + while ((ret = __real_select(fd, rfds, wfds, efds, tv)) < 0 && errno == EINTR) { + if (tv != NULL) { + int64_t now = get_us(); + timeout_us -= now - start; + if (timeout_us < 0) { + errno = 0; + ret = 0; + break; + } + start = now; + tv->tv_usec = timeout_us % 1000000; + tv->tv_sec = timeout_us / 1000000; + } + } + return ret; +} diff --git a/components/linux/CMakeLists.txt b/components/linux/CMakeLists.txt index 01594e97f4..b7d2bd46a7 100644 --- a/components/linux/CMakeLists.txt +++ b/components/linux/CMakeLists.txt @@ -3,6 +3,5 @@ if(NOT "${target}" STREQUAL "linux") return() endif() -idf_component_register(SRCS esp_event_stubs.c - INCLUDE_DIRS include ${IDF_PATH}/components/esp_event/include +idf_component_register(INCLUDE_DIRS include REQUIRED_IDF_TARGETS linux) diff --git a/components/linux/esp_event_stubs.c b/components/linux/esp_event_stubs.c deleted file mode 100644 index 2b622678e0..0000000000 --- a/components/linux/esp_event_stubs.c +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include "esp_err.h" -#include "esp_event.h" - -esp_err_t esp_event_loop_create_default(void) -{ - return ESP_OK; -} - -esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id, - const void* event_data, size_t event_data_size, TickType_t ticks_to_wait) -{ - return ESP_OK; -} diff --git a/components/linux/include/esp_linux_helper.h b/components/linux/include/esp_linux_helper.h index 22bfa98518..ecc7ec50ae 100644 --- a/components/linux/include/esp_linux_helper.h +++ b/components/linux/include/esp_linux_helper.h @@ -9,7 +9,7 @@ extern "C" { #endif -#if CONFIG_IDF_TARGET_LINUX +#if CONFIG_IDF_TARGET_LINUX && !defined(__containerof) #define __containerof(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) diff --git a/components/lwip/CMakeLists.txt b/components/lwip/CMakeLists.txt index 671da81e20..2eed657791 100644 --- a/components/lwip/CMakeLists.txt +++ b/components/lwip/CMakeLists.txt @@ -13,6 +13,7 @@ set(include_dirs port/freertos/include/ port/${target}/include port/${target}/include/arch + port/${target}/include/sys ) set(srcs @@ -142,6 +143,9 @@ if(NOT ${target} STREQUAL "linux") else() list(APPEND srcs "port/${target}/no_vfs_syscalls.c") endif() +else() + # This wraps some posix IO functions to conditionally pass control to lwip + list(APPEND srcs "port/${target}/vfs_lwip.c") endif() if(CONFIG_LWIP_ICMP) @@ -206,4 +210,13 @@ if(${target} STREQUAL "linux") set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) target_link_libraries(${COMPONENT_LIB} PRIVATE Threads::Threads) + set(WRAP_FUNCTIONS select + read + fcntl + write + close) + foreach(wrap ${WRAP_FUNCTIONS}) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __wrap_${wrap}") + endforeach() endif() diff --git a/components/lwip/port/linux/include/sys/fcntl.h b/components/lwip/port/linux/include/sys/fcntl.h index 1b3a261fa8..8fed1603ca 100644 --- a/components/lwip/port/linux/include/sys/fcntl.h +++ b/components/lwip/port/linux/include/sys/fcntl.h @@ -4,9 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ #pragma once -#ifdef LWIP_HDR_ESP_LWIPOPTS_H -// ignore when included from lwipopts.h since lwip provides all necessary definitions -#else -// otherwise include system fcntl -#include_next +#include "sdkconfig.h" + +#ifdef LWIP_HDR_LINUX_SYS_SOCKETS_H +// only if we prefer linux system sockets, include from system paths +#include_next +#elif CONFIG_IDF_TARGET_LINUX +// need to declare, as on linux we bypass IDF vfs and wrap posix io functions +extern int fcntl(int s, int cmd, ...); #endif +// ignore otherwise (typically included from lwipopts.h) since lwip provides all necessary definitions diff --git a/components/lwip/port/linux/include/sys/socket.h b/components/lwip/port/linux/include/sys/socket.h index b2e6a03e09..9bb54961c8 100644 --- a/components/lwip/port/linux/include/sys/socket.h +++ b/components/lwip/port/linux/include/sys/socket.h @@ -3,11 +3,11 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#ifndef LWIP_HDR_LINUX_SYS_SOCKETS_H -#define LWIP_HDR_LINUX_SYS_SOCKETS_H +#pragma once +#ifdef LWIP_HDR_LINUX_SYS_SOCKETS_H +/* only if we prefer linux system sockets, include from system paths */ +#include_next +#else /* Include lwip sockets by default */ #include "lwip/sockets.h" -#else -/* Otherwise use system sockets if LWIP_HDR_LINUX_SYS_SOCKETS_H already defined */ -#include_next #endif /* LWIP_HDR_LINUX_SYS_SOCKETS_H */ diff --git a/components/lwip/port/linux/vfs_lwip.c b/components/lwip/port/linux/vfs_lwip.c new file mode 100644 index 0000000000..116f8bc695 --- /dev/null +++ b/components/lwip/port/linux/vfs_lwip.c @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +extern int __real_fcntl(int s, int cmd, ...); +extern int __real_close(int s); +extern ssize_t __real_write (int fd, const void *buf, size_t n); +extern ssize_t __real_read (int fd, void *buf, size_t n); +extern int __real_select (int fd, fd_set * rfds, fd_set * wfds, fd_set *efds, struct timeval *tval); + +ssize_t __wrap_write (int fd, const void *buf, size_t n) +{ +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) + return lwip_write(fd, buf, n); +#endif + return __real_write(fd, buf, n); +} + +ssize_t __wrap_read (int fd, void *buf, size_t n) +{ +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) + return lwip_read(fd, buf, n); +#endif + return __real_read(fd, buf, n); +} + +int __wrap_select (int fd, fd_set * rds, fd_set * wfds, fd_set *efds, struct timeval *tval) +{ +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) + return lwip_select(fd, rds, wfds, efds, tval); +#endif + return __real_select(fd, rds, wfds, efds, tval); +} + +int __wrap_fcntl(int fd, int cmd, ...) +{ + va_list args; +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) { + va_start(args, cmd); + int arg = va_arg(args, int); + va_end(args); + return lwip_fcntl(fd, cmd, arg); + } +#endif + + return __real_fcntl(fd, cmd, args); +} + +int __wrap_close(int fd) +{ +#ifdef CONFIG_LWIP_MAX_SOCKETS + if (fd >= LWIP_SOCKET_OFFSET) + return lwip_close(fd); +#endif + return __real_close(fd); +} diff --git a/components/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index f487c2e950..dabca0c0cc 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -22,3 +22,13 @@ idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" PRIV_INCLUDE_DIRS "private_include" REQUIRES ${req}) + +if(${IDF_TARGET} STREQUAL "linux") + # Check if LWIP in the build for linux target to add esp_timer to the dependencies + # since socks_proxy transport needs it and lwip & linux build could use it + idf_build_get_property(build_components BUILD_COMPONENTS) + if("lwip" IN_LIST build_components) + idf_component_get_property(esp_timer esp_timer COMPONENT_LIB) + target_link_libraries(${COMPONENT_LIB} PUBLIC ${esp_timer}) + endif() +endif() diff --git a/examples/common_components/protocol_examples_tapif_io/Kconfig.projbuild b/examples/common_components/protocol_examples_tapif_io/Kconfig.projbuild index 6eb2c459ee..ee60079b9b 100644 --- a/examples/common_components/protocol_examples_tapif_io/Kconfig.projbuild +++ b/examples/common_components/protocol_examples_tapif_io/Kconfig.projbuild @@ -3,7 +3,7 @@ menu "Example Connection Configuration" config EXAMPLE_CONNECT_LWIP_TAPIF bool "connect using lwip to linux tap interface" depends on IDF_TARGET_LINUX && ESP_NETIF_TCPIP_LWIP - default n + default y if EXAMPLE_CONNECT_LWIP_TAPIF config EXAMPLE_CONNECT_IPV4 @@ -18,24 +18,28 @@ menu "Example Connection Configuration" help Set to true to setup link local address and wait until it's valid + config EXAMPLE_CONNECT_WAIT_FOR_IP + bool "run DHCP and wait for IP" + default y + config EXAMPLE_CONNECT_TAPIF_IP_ADDR string "Static IP address" default "192.168.5.100" - depends on EXAMPLE_CONNECT_IPV4 + depends on EXAMPLE_CONNECT_IPV4 && !EXAMPLE_CONNECT_WAIT_FOR_IP help Set static IP address. config EXAMPLE_CONNECT_TAPIF_NETMASK string "Static netmask address" default "255.255.255.0" - depends on EXAMPLE_CONNECT_IPV4 + depends on EXAMPLE_CONNECT_IPV4 && !EXAMPLE_CONNECT_WAIT_FOR_IP help Set static netmask address. config EXAMPLE_CONNECT_TAPIF_GW string "Static gateway address" default "192.168.5.1" - depends on EXAMPLE_CONNECT_IPV4 + depends on EXAMPLE_CONNECT_IPV4 && !EXAMPLE_CONNECT_WAIT_FOR_IP help Set static gateway address. diff --git a/examples/common_components/protocol_examples_tapif_io/README.md b/examples/common_components/protocol_examples_tapif_io/README.md index 33d7d31fad..c39394aa47 100644 --- a/examples/common_components/protocol_examples_tapif_io/README.md +++ b/examples/common_components/protocol_examples_tapif_io/README.md @@ -110,6 +110,8 @@ sudo iptables -A FORWARD -i tap0 -o eth0 -j ACCEPT It's also possible to configure the lwip interface to use DHCP client (common setup for most default network interfaces, such as Ethernet or WiFi station) and set up a DHCP server on the host machine to assign the IP address dynamically. +This component sets up a DHCP client if `CONFIG_EXAMPLE_CONNECT_WAIT_FOR_IP` is enabled and waits for assigning an IP address. See below the description of DHCP client workflow for tap interface: + 1) **Configure and set the `esp-netif` up** * Same as in [API usage](#Usage-of-the-API), but update the base esp-netif config `3c)` to enable DHCP client @@ -125,14 +127,17 @@ and set up a DHCP server on the host machine to assign the IP address dynamicall esp_netif_action_connected(tap_netif, 0, 0, 0); ``` * Wait for the IP address to be assigned. -This could be implemented as a wait loop below, as the esp-event currently doesn't support IP events on Linux target. +This could be implemented using an event handler ```cpp + esp_netif_inherent_config_t base_cfg = { + ... + .get_ip_event = TAP0_GOT_IP, + ... + }; + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, TAP0_GOT_IP, event_handler, NULL)); + // wait for the IP event (e.g. using signalling semaphores from the handler) + // ... esp_netif_ip_info_t ip_info = {}; - while (ip_info.ip.addr == 0) { - ESP_LOGI("tap-init", "No IP assigned, waiting..."); - usleep(1000000); - esp_netif_get_ip_info(tap_netif, &ip_info); - } ESP_LOGI("tap-init", "Assigned IP address:"IPSTR ",", IP2STR(&ip_info.ip)); ``` diff --git a/examples/common_components/protocol_examples_tapif_io/linux/tapio.c b/examples/common_components/protocol_examples_tapif_io/linux/tapio.c index 215ed8521c..4d46f9fa59 100644 --- a/examples/common_components/protocol_examples_tapif_io/linux/tapio.c +++ b/examples/common_components/protocol_examples_tapif_io/linux/tapio.c @@ -4,26 +4,25 @@ * SPDX-License-Identifier: Apache-2.0 */ #include -#include "esp_err.h" -#include "esp_log.h" -#include -#include "esp_netif.h" -#include -#include -#include #include #include +#include "esp_err.h" +#include "esp_log.h" +#include "esp_netif.h" + +// Use linux system sockets to connect to tap interface +#define LWIP_HDR_LINUX_SYS_SOCKETS_H +#include +#include + #include #include #include #include #include "errno.h" -#define LWIP_HDR_LINUX_SYS_SOCKETS_H - #include #include -#include #define DEVTAP "/dev/net/tun" #define DEVTAP_NAME "tap0" diff --git a/examples/common_components/protocol_examples_tapif_io/linux_connect.c b/examples/common_components/protocol_examples_tapif_io/linux_connect.c index 150b2bf737..a7fce1eaf4 100644 --- a/examples/common_components/protocol_examples_tapif_io/linux_connect.c +++ b/examples/common_components/protocol_examples_tapif_io/linux_connect.c @@ -7,6 +7,26 @@ #include "esp_netif.h" // esp-netif #include "tapio.h" // esp-netif's driver side #include "lwip/tapif.h" // esp-netif's network stack side +#include "esp_log.h" + +#if CONFIG_EXAMPLE_CONNECT_WAIT_FOR_IP +#include "esp_event.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +static const char *TAG = "linux_connect"; + +static EventGroupHandle_t s_events; + +static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) +{ + xEventGroupSetBits(s_events, 1); +} + +#endif // CONFIG_EXAMPLE_CONNECT_WAIT_FOR_IP + +#define TAP0_GOT_IP (0x1234) esp_err_t example_connect(void) { @@ -25,14 +45,20 @@ esp_err_t example_connect(void) }; // configure inherent esp-netif parameters esp_netif_ip_info_t ip_info = {}; + esp_netif_flags_t netif_flags = (ESP_NETIF_FLAG_EVENT_IP_MODIFIED | ESP_NETIF_FLAG_AUTOUP); +#if !CONFIG_EXAMPLE_CONNECT_WAIT_FOR_IP ip_info.ip.addr = ipaddr_addr(CONFIG_EXAMPLE_CONNECT_TAPIF_IP_ADDR); ip_info.netmask.addr = ipaddr_addr(CONFIG_EXAMPLE_CONNECT_TAPIF_NETMASK); ip_info.gw.addr = ipaddr_addr(CONFIG_EXAMPLE_CONNECT_TAPIF_GW); +#else + netif_flags |= ESP_NETIF_DHCP_CLIENT; +#endif esp_netif_inherent_config_t base_cfg = { .if_key = "TAP", - .flags = ESP_NETIF_FLAG_AUTOUP, .ip_info = &ip_info, + .flags = netif_flags, + .get_ip_event = TAP0_GOT_IP, .route_prio = 100 }; @@ -46,6 +72,15 @@ esp_err_t example_connect(void) // create the interface and attach it to the tapio-handle esp_netif_t *tap_netif = esp_netif_new(&cfg); esp_netif_attach(tap_netif, driver_cfg.handle); +#if CONFIG_EXAMPLE_CONNECT_WAIT_FOR_IP + ESP_LOGI(TAG, "Waiting for IP addresses..."); + esp_netif_action_connected(tap_netif, 0, 0, 0); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, TAP0_GOT_IP, event_handler, NULL)); + s_events = xEventGroupCreate(); + xEventGroupWaitBits(s_events, 1, pdFALSE, pdFALSE, portMAX_DELAY); + esp_netif_get_ip_info(tap_netif, &ip_info); + ESP_LOGI(TAG, "Assigned IP address:"IPSTR ",", IP2STR(&ip_info.ip)); +#endif // CONFIG_EXAMPLE_CONNECT_WAIT_FOR_IP #endif // EXAMPLE_CONNECT_LWIP_TAPIF return ESP_OK; } diff --git a/examples/protocols/esp_http_client/CMakeLists.txt b/examples/protocols/esp_http_client/CMakeLists.txt index 3316f636e7..cf0ca4da7a 100644 --- a/examples/protocols/esp_http_client/CMakeLists.txt +++ b/examples/protocols/esp_http_client/CMakeLists.txt @@ -5,8 +5,7 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) if(${IDF_TARGET} STREQUAL "linux") - list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/" - "$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs") + list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs) set(COMPONENTS main) endif() diff --git a/examples/protocols/esp_http_client/main/CMakeLists.txt b/examples/protocols/esp_http_client/main/CMakeLists.txt index 70ed376538..23ba7fa726 100644 --- a/examples/protocols/esp_http_client/main/CMakeLists.txt +++ b/examples/protocols/esp_http_client/main/CMakeLists.txt @@ -3,7 +3,7 @@ # (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.) set(requires "") if(${IDF_TARGET} STREQUAL "linux") - list(APPEND requires esp_stubs esp-tls esp_http_client protocol_examples_common nvs_flash) + list(APPEND requires esp_stubs esp_event esp-tls esp_http_client protocol_examples_common nvs_flash) endif() idf_component_register(SRCS "esp_http_client_example.c" INCLUDE_DIRS "." diff --git a/examples/protocols/esp_http_client/main/esp_http_client_example.c b/examples/protocols/esp_http_client/main/esp_http_client_example.c index 50cebca86b..4209e8f55b 100644 --- a/examples/protocols/esp_http_client/main/esp_http_client_example.c +++ b/examples/protocols/esp_http_client/main/esp_http_client_example.c @@ -22,11 +22,9 @@ #include "esp_crt_bundle.h" #endif -#if !CONFIG_IDF_TARGET_LINUX #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" -#endif #include "esp_http_client.h" diff --git a/examples/protocols/http_server/simple/CMakeLists.txt b/examples/protocols/http_server/simple/CMakeLists.txt index 33574050bb..e6994a73fd 100644 --- a/examples/protocols/http_server/simple/CMakeLists.txt +++ b/examples/protocols/http_server/simple/CMakeLists.txt @@ -5,8 +5,7 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) if(${IDF_TARGET} STREQUAL "linux") - list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/" - "$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs") + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs") set(COMPONENTS main) endif() diff --git a/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c b/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c index cd2216f89f..fba9bc94a4 100644 --- a/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c +++ b/examples/protocols/linux_stubs/esp_stubs/esp_stubs.c @@ -6,9 +6,6 @@ #include #include "esp_err.h" #include "esp_log.h" -#include "esp_event.h" - -extern void app_main(void); esp_err_t esp_netif_init(void) { @@ -19,10 +16,3 @@ esp_err_t example_connect(void) { return ESP_OK; } - -int main(void) -{ - app_main(); - - return 0; -} diff --git a/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h b/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h deleted file mode 100644 index e909e800f6..0000000000 --- a/examples/protocols/linux_stubs/esp_stubs/include/esp_event.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Unlicense OR CC0-1.0 - */ -#include "esp_err.h" - -esp_err_t esp_event_loop_create_default(void); diff --git a/examples/protocols/linux_stubs/esp_stubs/include/esp_netif.h b/examples/protocols/linux_stubs/esp_stubs/include/esp_netif.h index 5f94c2afb7..c758d75899 100644 --- a/examples/protocols/linux_stubs/esp_stubs/include/esp_netif.h +++ b/examples/protocols/linux_stubs/esp_stubs/include/esp_netif.h @@ -8,4 +8,12 @@ #include #include "esp_err.h" +#ifdef __cplusplus +extern "C" { +#endif + esp_err_t esp_netif_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/examples/protocols/sockets/tcp_client/CMakeLists.txt b/examples/protocols/sockets/tcp_client/CMakeLists.txt index 86ed08467b..cf2f5a8895 100644 --- a/examples/protocols/sockets/tcp_client/CMakeLists.txt +++ b/examples/protocols/sockets/tcp_client/CMakeLists.txt @@ -4,8 +4,7 @@ cmake_minimum_required(VERSION 3.16) set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) if("${IDF_TARGET}" STREQUAL "linux") - list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/" - "$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs") + list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/protocols/linux_stubs/esp_stubs") set(COMPONENTS main) endif() diff --git a/examples/protocols/sockets/tcp_client/main/CMakeLists.txt b/examples/protocols/sockets/tcp_client/main/CMakeLists.txt index 721b9c9316..0ac00ed402 100644 --- a/examples/protocols/sockets/tcp_client/main/CMakeLists.txt +++ b/examples/protocols/sockets/tcp_client/main/CMakeLists.txt @@ -1,5 +1,5 @@ if(${IDF_TARGET} STREQUAL "linux") - set(requires esp_stubs protocol_examples_common nvs_flash) + set(requires esp_event esp_stubs protocol_examples_common nvs_flash) endif() if("${CONFIG_EXAMPLE_IPV4}" STREQUAL y) diff --git a/examples/protocols/sockets/udp_client/CMakeLists.txt b/examples/protocols/sockets/udp_client/CMakeLists.txt index b9b38c6afb..c2559179e1 100644 --- a/examples/protocols/sockets/udp_client/CMakeLists.txt +++ b/examples/protocols/sockets/udp_client/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.16) if("${IDF_TARGET}" STREQUAL "linux") # This example uses an extra component with common functionality for lwip's port on linux target set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_tapif_io) - set(COMPONENTS main esp_netif protocol_examples_tapif_io startup esp_hw_support esp_system nvs_flash) + set(COMPONENTS main esp_netif lwip protocol_examples_tapif_io startup esp_hw_support esp_system nvs_flash) else() # This example uses an extra component for common functions such as Wi-Fi and Ethernet connection on ESP target set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) diff --git a/examples/protocols/sockets/udp_client/sdkconfig.ci.linux b/examples/protocols/sockets/udp_client/sdkconfig.ci.linux new file mode 100644 index 0000000000..6f95c91824 --- /dev/null +++ b/examples/protocols/sockets/udp_client/sdkconfig.ci.linux @@ -0,0 +1,3 @@ +CONFIG_IDF_TARGET="linux" +CONFIG_EXAMPLE_IPV4_ADDR="127.0.0.1" +CONFIG_EXAMPLE_CONNECT_LWIP_TAPIF=n