mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-09 04:25:32 +00:00
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.
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include <stdlib.h>
|
||||
#include "esp_netif.h"
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <lwip/sys.h>
|
||||
#include "errno.h"
|
||||
|
||||
#define LWIP_HDR_LINUX_SYS_SOCKETS_H
|
||||
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <esp_netif_net_stack.h>
|
||||
|
||||
#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;
|
||||
}
|
Reference in New Issue
Block a user