From 854e16feb31c117ff890c3e80230e727db6d8606 Mon Sep 17 00:00:00 2001 From: David Cermak Date: Tue, 31 Jan 2023 08:29:00 +0100 Subject: [PATCH] examples: Add common linux component tapif_io That can be used with linux target on lwip to pass packets from lwip to linux host networking stack, e.g. routing the trafic to internet. --- .../protocol_examples_common/CMakeLists.txt | 10 ++ .../Kconfig.projbuild | 2 + .../protocol_examples_tapif_io/CMakeLists.txt | 9 + .../Kconfig.projbuild | 44 +++++ .../protocol_examples_tapif_io/README.md | 154 ++++++++++++++++++ .../include/protocol_examples_common.h | 32 ++++ .../include/tapio.h | 27 +++ .../protocol_examples_tapif_io/linux/tapio.c | 135 +++++++++++++++ .../linux_connect.c | 51 ++++++ .../protocol_examples_tapif_io/lwip/tapif.c | 100 ++++++++++++ .../protocol_examples_tapif_io/lwip/tapif.h | 25 +++ .../protocol_examples_tapif_io/make_tap_netif | 4 + 12 files changed, 593 insertions(+) create mode 100644 examples/common_components/protocol_examples_tapif_io/CMakeLists.txt create mode 100644 examples/common_components/protocol_examples_tapif_io/Kconfig.projbuild create mode 100644 examples/common_components/protocol_examples_tapif_io/README.md create mode 100644 examples/common_components/protocol_examples_tapif_io/include/protocol_examples_common.h create mode 100644 examples/common_components/protocol_examples_tapif_io/include/tapio.h create mode 100644 examples/common_components/protocol_examples_tapif_io/linux/tapio.c create mode 100644 examples/common_components/protocol_examples_tapif_io/linux_connect.c create mode 100644 examples/common_components/protocol_examples_tapif_io/lwip/tapif.c create mode 100644 examples/common_components/protocol_examples_tapif_io/lwip/tapif.h create mode 100755 examples/common_components/protocol_examples_tapif_io/make_tap_netif diff --git a/examples/common_components/protocol_examples_common/CMakeLists.txt b/examples/common_components/protocol_examples_common/CMakeLists.txt index 15981d027cc1..2a7352d5fd0f 100644 --- a/examples/common_components/protocol_examples_common/CMakeLists.txt +++ b/examples/common_components/protocol_examples_common/CMakeLists.txt @@ -1,3 +1,13 @@ +idf_build_get_property(target IDF_TARGET) + +if(${target} STREQUAL "linux") + # Header only library for linux + + idf_component_register(INCLUDE_DIRS include + PRIV_REQUIRES tapif_io) + return() +endif() + set(srcs "stdin_out.c" "addr_from_stdin.c" "connect.c" diff --git a/examples/common_components/protocol_examples_common/Kconfig.projbuild b/examples/common_components/protocol_examples_common/Kconfig.projbuild index ed382457d7fc..f839bb5e21b1 100644 --- a/examples/common_components/protocol_examples_common/Kconfig.projbuild +++ b/examples/common_components/protocol_examples_common/Kconfig.projbuild @@ -4,6 +4,7 @@ menu "Example Connection Configuration" config EXAMPLE_CONNECT_WIFI bool "connect using WiFi interface" + depends on !IDF_TARGET_LINUX default y help Protocol examples can use Wi-Fi and/or Ethernet to connect to the network. @@ -117,6 +118,7 @@ menu "Example Connection Configuration" config EXAMPLE_CONNECT_ETHERNET bool "connect using Ethernet interface" + depends on !IDF_TARGET_LINUX default n help Protocol examples can use Wi-Fi and/or Ethernet to connect to the network. diff --git a/examples/common_components/protocol_examples_tapif_io/CMakeLists.txt b/examples/common_components/protocol_examples_tapif_io/CMakeLists.txt new file mode 100644 index 000000000000..140acc5d9d67 --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_build_get_property(target IDF_TARGET) + +if(${target} STREQUAL "linux") + idf_component_register(INCLUDE_DIRS include + SRCS linux/tapio.c linux_connect.c lwip/tapif.c + PRIV_REQUIRES esp_netif lwip) +else() + message(FATAL_ERROR "This component is currently only supported for linux target") +endif() diff --git a/examples/common_components/protocol_examples_tapif_io/Kconfig.projbuild b/examples/common_components/protocol_examples_tapif_io/Kconfig.projbuild new file mode 100644 index 000000000000..7c842a3c412b --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/Kconfig.projbuild @@ -0,0 +1,44 @@ +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 + + if EXAMPLE_CONNECT_LWIP_TAPIF + config EXAMPLE_CONNECT_TAPIF_IP_ADDR + string "Static IP address" + default "192.168.5.100" + help + Set static IP address. + + config EXAMPLE_CONNECT_TAPIF_NETMASK + string "Static netmask address" + default "255.255.255.0" + help + Set static netmask address. + + config EXAMPLE_CONNECT_TAPIF_GW + string "Static gateway address" + default "192.168.5.1" + help + Set static gateway address. + + config EXAMPLE_CONNECT_TAPIF_OUT_LOSS + int "Percentage of packets to be dropped on transmission" + default 0 + range 0 100 + help + Set non-zero number simulate packet loss when sending data. + Number represents probability between 0 and 100% + + config EXAMPLE_CONNECT_TAPIF_IN_LOSS + int "Percentage of packets to be dropped on reception" + default 0 + range 0 100 + help + Set non-zero number simulate packet loss when receiving data. + Number represents probability between 0 and 100% + endif + +endmenu diff --git a/examples/common_components/protocol_examples_tapif_io/README.md b/examples/common_components/protocol_examples_tapif_io/README.md new file mode 100644 index 000000000000..33d7d31fad6c --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/README.md @@ -0,0 +1,154 @@ +# tapif-io Component + +This component implements a tap networking interface that provides connectivity to host network using `tuntap` interface in Linux. +It could be used to route lwip traffic to host side network, typically when working with the **Linux target**. + +## How to use this component + +### Usage of the API + +1) Add the path to this component to the `EXTRA_COMPONENT_DIRS` in your project makefile +```cmake +list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/examples/common_components/tapif_io") +``` +2) Include lwip and linux side of the configuration +```cpp +#include "esp_netif.h" // esp-netif +#include "tapio.h" // esp-netif's driver side +#include "lwip/tapif.h" // esp-netif's network stack side +``` +3) Configure the esp-netif + a) setup the linux tap I/O config +```cpp + esp_netif_driver_ifconfig_t driver_cfg = { + .handle = tapio_create(), + .transmit = tapio_output, + }; +``` + + b) configure the lwip netif for the tap interface +```cpp + struct esp_netif_netstack_config stack_cfg = { + .lwip = { + .init_fn = lwip_tapif_init, + .input_fn = lwip_tapif_input, + } + }; +``` + + c) configure the esp-netif basic parameters +```cpp + esp_netif_inherent_config_t base_cfg = { + .if_key = "TAP", // unique name of the interface + .flags = ESP_NETIF_FLAG_AUTOUP, // no dhcp client, starts when it's set up + .ip_info = &ip_info, // add static IP info + .route_prio = 100 // priority for setting default gateway + }; +``` + + +4) Initialize and attach the esp_netif to the I/O handle +```cpp + esp_netif_t *tap_netif = esp_netif_new(&cfg); + esp_netif_attach(tap_netif, driver_cfg.handle); +``` + +### Host side networking + +1) Create a new tun/tap interface type named `tap0` + a) You can run the script `./make_tap_netif` + b) Update the IP address of the interface to correspond to the configured static IP in previous step + +2) Start the application and send/receive the packets via `tap0` interface + * it is possible to create server or client test application listening or connecting to this interface. + * it is also possible to route these packets to external network (using routing rules or simply by ip forwarding if using the same subnet) + +#### Common networking/routing examples + +##### Isolated internal connection + +Is useful to experiment with one interface with no intention to connect to internet or external facilities. +Typically, when we want to create a server listening on the `tap0` interface and run a client in lwip, e.g. the default `tcp_client` socket example in IDF. +* Create the tap interface using `./make_tap_netif` and set the IP address **not to overlap** with any other IPv4 network range (e.g. `ip addr add 192.168.5.1/24 dev tap0`) +* Configure the `tapif_io` component to use static address from that range (e.g. `192.168.5.x`) +* Configure the `tcp_client` example to connect to the tap interface IP address (e.g. `192.168.5.1`) +* Execute a tcp server listening on the tap interface and the configured port (e.g. `nc -l 3333`) +* Build and run the `tcp_client` example to send and receive data between the server created in the previous step. + +##### Connecting to the external network using IP forwarding + +This allows using full-featured network facilities of your host network, but a care must be taken to the selected IP addresses to avoid potential conflicts. +* Set the IP address of the `tap0` interface from the range used by your host system's default gateway (e.g. `ip addr add 192.168.0.123/24 dev tap0`, assuming the default netif is `eth0` with IP range of `192.168.0.x` and this address doesn't overlap with any other IP address in this network) +* Configure the `tapif_io` with another address from the same range, e.g. +```text +CONFIG_EXAMPLE_CONNECT_TAPIF_IP_ADDR="192.168.0.100" +CONFIG_EXAMPLE_CONNECT_TAPIF_NETMASK="255.255.255.0" +CONFIG_EXAMPLE_CONNECT_TAPIF_GW="192.168.0.1" +``` +assuming that the default gateway of your host network is configured to `192.168.0.1` +* Build and run the lwip example to interact with the host network, e.g, to send an HTTP request to a publicly available http server (if the server is reachable from your host network) + +(Note, that the IP forwarding must be enabled in the host system: +```bash +echo 1 > /proc/sys/net/ipv4/ip_forward +``` +) + +##### Routing the internal interface to the host network with IP tables + +Uses an isolated interface with routing and NAT-ing between interfaces +* Configure the `tap0` interface address **not to overlap** with any other IPv4 network range. +* Setup `MASQUERADE` target to route network traffic between `tap0` and your default network interface (`eth0` in the below example). +```bash +sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE +sudo iptables -A FORWARD -i eth0 -o tap0 -m state --state RELATED,ESTABLISHED -j ACCEPT +sudo iptables -A FORWARD -i tap0 -o eth0 -j ACCEPT +``` + +##### Using DHCP + +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. + +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 +```cpp + esp_netif_inherent_config_t base_cfg = { + .if_key = "TAP", + .flags = (esp_netif_flags_t)(ESP_NETIF_DHCP_CLIENT | ESP_NETIF_FLAG_EVENT_IP_MODIFIED | ESP_NETIF_FLAG_AUTOUP), + .route_prio = 100 + }; +``` +* After starting the netif, tell the lwIP that we're connected +```cpp + 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. +```cpp + 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)); +``` + +2) **Configure forwarding/routing** if needed based on the previous sections. + +3) **Configure the DHCP server on the host machine** + +Example for `isc-dhcp-server` + +```bash +INTERFACES="tap0"; +authoritative; + +subnet 192.168.5.0 netmask 255.255.255.0 { + range 192.168.5.2 192.168.5.200; + option routers 192.168.5.1; + option domain-name-servers 8.8.8.8; +} +``` diff --git a/examples/common_components/protocol_examples_tapif_io/include/protocol_examples_common.h b/examples/common_components/protocol_examples_tapif_io/include/protocol_examples_common.h new file mode 100644 index 000000000000..3ebfd2abebab --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/include/protocol_examples_common.h @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* Common functions for protocol examples, to establish tap interface connection + * For linux target + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. + */ +#pragma once +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Configure and connect, wait for IP + * + * @return ESP_OK on successful connection + */ +esp_err_t example_connect(void); + + +#ifdef __cplusplus +} +#endif diff --git a/examples/common_components/protocol_examples_tapif_io/include/tapio.h b/examples/common_components/protocol_examples_tapif_io/include/tapio.h new file mode 100644 index 000000000000..f646d7583de5 --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/include/tapio.h @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once +#include "esp_err.h" +#include "esp_netif.h" + +/** + * @brief Creates tapio layer as a driver interface to esp-netif + * + * @warning Implemented as singleton, can use only one tapio in the system! + * + * @return pointer to the tapio driver handle + */ +void *tapio_create(void); + +/** + * @brief esp-netif driver I/O output path + * + * @param h Driver's handle + * @param buffer Data to output + * @param len Data size + * @return ESP_OK on success + */ +esp_err_t tapio_output(void *h, void *buffer, size_t len); diff --git a/examples/common_components/protocol_examples_tapif_io/linux/tapio.c b/examples/common_components/protocol_examples_tapif_io/linux/tapio.c new file mode 100644 index 000000000000..215ed8521c00 --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/linux/tapio.c @@ -0,0 +1,135 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * 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 +#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" + + +typedef struct tap_io { + esp_netif_driver_base_t base; + int fd; +} tap_io_t; + +static const char *TAG = "tap-netif"; + +static void tapio_input_task(void *arg) +{ + tap_io_t *io = arg; + fd_set fdset; + int ret; + while (1) { + FD_ZERO(&fdset); + FD_SET(io->fd, &fdset); + + /* Wait for a packet to arrive. */ + ret = select(io->fd + 1, &fdset, NULL, NULL, NULL); + + if (ret == 1) { + /* Handle incoming packet. */ + ssize_t readlen; + char buf[1518]; /* max packet size including VLAN excluding CRC */ + + /* Obtain the size of the packet and put it into the "len" + variable. */ + readlen = read(io->fd, buf, sizeof(buf)); + if (readlen < 0) { + ESP_LOGE(TAG, "Failed to read from tap fd: returned %ld", readlen); + exit(1); + } +#if CONFIG_EXAMPLE_CONNECT_TAPIF_IN_LOSS + if (((double)rand()/(double)RAND_MAX) < ((double)CONFIG_EXAMPLE_CONNECT_TAPIF_IN_LOSS)/100.0) { + ESP_LOGW(TAG, "Simulated packet drop on input"); + continue; + } +#endif + esp_netif_receive(io->base.netif, buf, readlen, NULL); + } else if (ret == -1) { + if (errno == EINTR /* Interrupted system call (used by FreeRTOS simulated interrupts) */) { + vTaskDelay(1); // yield to the FreeRTOS simulator + } else { + ESP_LOGE(TAG, "tapif_thread: select() error(%d), %s", errno, strerror(errno)); + } + } + } +} + +static esp_err_t tapio_start(esp_netif_t *esp_netif, void *arg) +{ + tap_io_t *io = arg; + io->base.netif = esp_netif; + esp_netif_action_start(esp_netif, 0, 0, 0); + + sys_thread_new("tapio_rx", tapio_input_task, io, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); + + return ESP_OK; +} + +void *tapio_create(void) +{ + static tap_io_t tap_io = {}; + tap_io.base.post_attach = tapio_start; + tap_io.fd = open(DEVTAP, O_RDWR); + if (tap_io.fd == -1) { + ESP_LOGE(TAG, "Cannot open tap device %s", DEVTAP); + return NULL; + } + + struct ifreq ifr = {}; + memset(&ifr, 0, sizeof(ifr)); + + strncpy(ifr.ifr_name, DEVTAP_NAME, sizeof(ifr.ifr_name)); + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0; /* ensure \0 termination */ + ifr.ifr_flags = IFF_TAP|IFF_NO_PI; + if (ioctl(tap_io.fd, TUNSETIFF, (void *) &ifr) < 0) { + ESP_LOGE(TAG, "Cannot configure ioctl(TUNSETIFF) for \"%s\"", DEVTAP); + return NULL; + } + + + return &tap_io; +} + +esp_err_t tapio_output(void *h, void *buffer, size_t len) +{ + tap_io_t *io = h; + ssize_t written; + +#if CONFIG_EXAMPLE_CONNECT_TAPIF_OUT_LOSS + if (((double)rand()/(double)RAND_MAX) < ((double)CONFIG_EXAMPLE_CONNECT_TAPIF_OUT_LOSS)/100.0) { + ESP_LOGW(TAG, "Simulated packet drop on output"); + return ESP_OK; /* ESP_OK because we simulate packet loss on cable */ + } +#endif + + /* signal that packet should be sent(); */ + written = write(io->fd, buffer, len); + if (written < len) { + ESP_LOGE(TAG, "Failed to write from tap fd: returned %ld", written); + return ESP_FAIL; + } + return ESP_OK; +} diff --git a/examples/common_components/protocol_examples_tapif_io/linux_connect.c b/examples/common_components/protocol_examples_tapif_io/linux_connect.c new file mode 100644 index 000000000000..150b2bf73779 --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/linux_connect.c @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "esp_err.h" +#include "esp_netif.h" // esp-netif +#include "tapio.h" // esp-netif's driver side +#include "lwip/tapif.h" // esp-netif's network stack side + +esp_err_t example_connect(void) +{ +#if CONFIG_EXAMPLE_CONNECT_LWIP_TAPIF + // configure linux tapio + esp_netif_driver_ifconfig_t driver_cfg = { + .handle = tapio_create(), + .transmit = tapio_output, + }; + // configure lwip netif for the tapif + struct esp_netif_netstack_config stack_cfg = { + .lwip = { + .init_fn = lwip_tapif_init, + .input_fn = lwip_tapif_input, + } + }; + // configure inherent esp-netif parameters + esp_netif_ip_info_t ip_info = {}; + 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); + + esp_netif_inherent_config_t base_cfg = { + .if_key = "TAP", + .flags = ESP_NETIF_FLAG_AUTOUP, + .ip_info = &ip_info, + .route_prio = 100 + }; + + // put all configs together + esp_netif_config_t cfg = { + .base = &base_cfg, + .driver = &driver_cfg, + .stack = &stack_cfg + }; + + // 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); +#endif // EXAMPLE_CONNECT_LWIP_TAPIF + return ESP_OK; +} diff --git a/examples/common_components/protocol_examples_tapif_io/lwip/tapif.c b/examples/common_components/protocol_examples_tapif_io/lwip/tapif.c new file mode 100644 index 000000000000..a59f70a9f847 --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/lwip/tapif.c @@ -0,0 +1,100 @@ +/* + * SPDX-FileCopyrightText: 2001-2003 Swedish Institute of Computer Science + * + * SPDX-License-Identifier: BSD-3-Clause + * + * SPDX-FileContributor: 2022-2023 Espressif Systems (Shanghai) CO LTD + */ +#include +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/snmp.h" +#include "lwip/ethip6.h" +#include "netif/etharp.h" + +#include "esp_netif.h" +#include "esp_netif_net_stack.h" + +#define IFNAME0 't' +#define IFNAME1 'p' + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ + esp_netif_t *esp_netif = esp_netif_get_handle_from_netif_impl(netif); + char buf[1518]; /* max packet size including VLAN excluding CRC */ + + if (p->tot_len > sizeof(buf)) { + MIB2_STATS_NETIF_INC(netif, ifoutdiscards); + LWIP_DEBUGF(NETIF_DEBUG, ("tapif: packet too large")); + return ERR_IF; + } + + /* initiate transfer(); */ + pbuf_copy_partial(p, buf, p->tot_len, 0); + + int ret = esp_netif_transmit(esp_netif, buf, p->tot_len); + /* Check error */ + if (likely(ret == ESP_OK)) { + return ERR_OK; + } + if (ret == ESP_ERR_NO_MEM) { + return ERR_MEM; + } + return ERR_IF; +} + +static void +low_level_init(struct netif *netif) +{ + + /* Obtain MAC address from network interface. */ + netif->hwaddr[0] = 0x02; + netif->hwaddr[1] = 0x12; + netif->hwaddr[2] = 0x34; + netif->hwaddr[3] = 0x56; + netif->hwaddr[4] = 0x78; + netif->hwaddr[5] = 0xab; + netif->hwaddr_len = 6; + + /* device capabilities */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; +} + +err_t lwip_tapif_init(struct netif *netif) +{ + LWIP_ASSERT("Tried to initialize tapif with NULL netif", netif != NULL); + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; +#if LWIP_IPV4 + netif->output = etharp_output; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = low_level_output; + netif->mtu = 1500; + + low_level_init(netif); + netif_set_link_up(netif); + return ERR_OK; +} + +void lwip_tapif_input(void *h, void *buffer, size_t len, void *l2_buff) +{ + struct netif *netif = h; + struct pbuf *p; + LWIP_ASSERT("running tapif input with NULL netif", netif != NULL); + + p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); + if (p == NULL) { + return; + } + memcpy(p->payload, buffer, len); + + /* full packet send to tcpip_thread to process */ + if (unlikely(netif->input(p, netif) != ERR_OK)) { + LWIP_DEBUGF(NETIF_DEBUG, ("tapif_input: IP input error\n")); + pbuf_free(p); + } +} diff --git a/examples/common_components/protocol_examples_tapif_io/lwip/tapif.h b/examples/common_components/protocol_examples_tapif_io/lwip/tapif.h new file mode 100644 index 000000000000..30629856705b --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/lwip/tapif.h @@ -0,0 +1,25 @@ +/* + * SPDX-FileCopyrightText: 2001-2003 Swedish Institute of Computer Science + * + * SPDX-License-Identifier: BSD-3-Clause + * + * SPDX-FileContributor: 2022-2023 Espressif Systems (Shanghai) CO LTD + */ +#pragma once +#include "lwip/esp_netif_net_stack.h" + +/** + * @brief lwip netif init API + * @param netif pointer to lwip's netif + * @return ERR_OK on success + */ +err_t lwip_tapif_init(struct netif *netif); + +/** + * @brief Input data path + * @param h pointer to network stack handle (stuct netif* in our case) + * @param buffer Data + * @param len Data size + * @param l2_buff Data L2 buffer + */ +void lwip_tapif_input(void *h, void *buffer, size_t len, void *l2_buff); diff --git a/examples/common_components/protocol_examples_tapif_io/make_tap_netif b/examples/common_components/protocol_examples_tapif_io/make_tap_netif new file mode 100755 index 000000000000..3857edb657b3 --- /dev/null +++ b/examples/common_components/protocol_examples_tapif_io/make_tap_netif @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +sudo ip tuntap add dev tap0 mode tap user `whoami` +sudo ip link set tap0 up +sudo ip addr add 192.168.5.1/24 dev tap0