tapio.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /*
  2. * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdlib.h>
  7. #include "esp_err.h"
  8. #include "esp_log.h"
  9. #include <stdlib.h>
  10. #include "esp_netif.h"
  11. #include <fcntl.h>
  12. #include <stdlib.h>
  13. #include <stdio.h>
  14. #include <unistd.h>
  15. #include <string.h>
  16. #include <sys/ioctl.h>
  17. #include <sys/types.h>
  18. #include <sys/ioctl.h>
  19. #include <lwip/sys.h>
  20. #include "errno.h"
  21. #define LWIP_HDR_LINUX_SYS_SOCKETS_H
  22. #include <linux/if.h>
  23. #include <linux/if_tun.h>
  24. #include <esp_netif_net_stack.h>
  25. #define DEVTAP "/dev/net/tun"
  26. #define DEVTAP_NAME "tap0"
  27. typedef struct tap_io {
  28. esp_netif_driver_base_t base;
  29. int fd;
  30. } tap_io_t;
  31. static const char *TAG = "tap-netif";
  32. static void tapio_input_task(void *arg)
  33. {
  34. tap_io_t *io = arg;
  35. fd_set fdset;
  36. int ret;
  37. while (1) {
  38. FD_ZERO(&fdset);
  39. FD_SET(io->fd, &fdset);
  40. /* Wait for a packet to arrive. */
  41. ret = select(io->fd + 1, &fdset, NULL, NULL, NULL);
  42. if (ret == 1) {
  43. /* Handle incoming packet. */
  44. ssize_t readlen;
  45. char buf[1518]; /* max packet size including VLAN excluding CRC */
  46. /* Obtain the size of the packet and put it into the "len"
  47. variable. */
  48. readlen = read(io->fd, buf, sizeof(buf));
  49. if (readlen < 0) {
  50. ESP_LOGE(TAG, "Failed to read from tap fd: returned %ld", readlen);
  51. exit(1);
  52. }
  53. #if CONFIG_EXAMPLE_CONNECT_TAPIF_IN_LOSS
  54. if (((double)rand()/(double)RAND_MAX) < ((double)CONFIG_EXAMPLE_CONNECT_TAPIF_IN_LOSS)/100.0) {
  55. ESP_LOGW(TAG, "Simulated packet drop on input");
  56. continue;
  57. }
  58. #endif
  59. esp_netif_receive(io->base.netif, buf, readlen, NULL);
  60. } else if (ret == -1) {
  61. if (errno == EINTR /* Interrupted system call (used by FreeRTOS simulated interrupts) */) {
  62. vTaskDelay(1); // yield to the FreeRTOS simulator
  63. } else {
  64. ESP_LOGE(TAG, "tapif_thread: select() error(%d), %s", errno, strerror(errno));
  65. }
  66. }
  67. }
  68. }
  69. static esp_err_t tapio_start(esp_netif_t *esp_netif, void *arg)
  70. {
  71. tap_io_t *io = arg;
  72. io->base.netif = esp_netif;
  73. esp_netif_action_start(esp_netif, 0, 0, 0);
  74. sys_thread_new("tapio_rx", tapio_input_task, io, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
  75. return ESP_OK;
  76. }
  77. void *tapio_create(void)
  78. {
  79. static tap_io_t tap_io = {};
  80. tap_io.base.post_attach = tapio_start;
  81. tap_io.fd = open(DEVTAP, O_RDWR);
  82. if (tap_io.fd == -1) {
  83. ESP_LOGE(TAG, "Cannot open tap device %s", DEVTAP);
  84. return NULL;
  85. }
  86. struct ifreq ifr = {};
  87. memset(&ifr, 0, sizeof(ifr));
  88. strncpy(ifr.ifr_name, DEVTAP_NAME, sizeof(ifr.ifr_name));
  89. ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0; /* ensure \0 termination */
  90. ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
  91. if (ioctl(tap_io.fd, TUNSETIFF, (void *) &ifr) < 0) {
  92. ESP_LOGE(TAG, "Cannot configure ioctl(TUNSETIFF) for \"%s\"", DEVTAP);
  93. return NULL;
  94. }
  95. return &tap_io;
  96. }
  97. esp_err_t tapio_output(void *h, void *buffer, size_t len)
  98. {
  99. tap_io_t *io = h;
  100. ssize_t written;
  101. #if CONFIG_EXAMPLE_CONNECT_TAPIF_OUT_LOSS
  102. if (((double)rand()/(double)RAND_MAX) < ((double)CONFIG_EXAMPLE_CONNECT_TAPIF_OUT_LOSS)/100.0) {
  103. ESP_LOGW(TAG, "Simulated packet drop on output");
  104. return ESP_OK; /* ESP_OK because we simulate packet loss on cable */
  105. }
  106. #endif
  107. /* signal that packet should be sent(); */
  108. written = write(io->fd, buffer, len);
  109. if (written < len) {
  110. ESP_LOGE(TAG, "Failed to write from tap fd: returned %ld", written);
  111. return ESP_FAIL;
  112. }
  113. return ESP_OK;
  114. }