text: #include <stdio.h>
  #include <stdint.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
  #include <fcntl.h>
  #include <errno.h>
  #include <sys/types.h>
  #include <sys/socket.h>
  #include <sys/ioctl.h>
  #include <sys/poll.h>
  #include <linux/if.h>
  #include <linux/if_tun.h>
  
  #include "util.h"
  #include "net.h"
  #include "ether.h"
  
  #include "ether_tap.h"
  
  #define CLONE_DEVICE "/dev/net/tun"
  
  //TAPデバイスはEthernetデバイスをエミュレートする
  //write => Ethernetフレームを OS のプロトコルスタックへ Inject
  //read => OS のプロトコルスタックが書き込んだフレームを読み出す
  struct ether_tap {
    char name[IFNAMSIZ];
    int fd;
  };
  
  #define PRIV(x) ((struct ether_tap *)x->priv)
  
  //ハードウェアアドレスの取得
  static int ether_tap_addr(struct net_device *dev) {
    int soc;
    struct ifreq ifr = {};
  
    soc = socket(AF_INET, SOCK_DGRAM, 0);
    if (soc == -1) {
      errorf("socket: %s, dev=%s", strerror(errno), dev->name);
      return -1;
    }
    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, PRIV(dev)->name, sizeof(ifr.ifr_name) - 1);
    if (ioctl(soc, SIOCGIFHWADDR, &ifr) == -1) {
      errorf("ioctl [SIOCGIFHWADDR]: %s, dev=%s", strerror(errno), dev->name);
      close(soc);
      return -1;
    }
    memcpy(dev->addr, ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
    close(soc);
    return 0;
  }
  
  static int ether_tap_open(struct net_device *dev) {
    struct ether_tap *tap;
    struct ifreq ifr = {};
  
    tap = PRIV(dev);
    tap->fd = open(CLONE_DEVICE, O_RDWR);
    if (tap->fd == -1) {
      errorf("open: %s, dev=%s", strerror(errno), dev->name);
      return -1;
    }
    strncpy(ifr.ifr_name, tap->name, sizeof(ifr.ifr_name) - 1);
    ifr.ifr_flags = IFF_TAP | IFF_NO_PI; // フラグ設定（IFF_TAP … TAPモード / IFF_NO_PI … パケット情報のヘッダを付けない）
  
    // TAPデバイスの生成を要求
    if (ioctl(tap->fd, TUNSETIFF, &ifr) == -1) {
      errorf("ioctl [TUNSETIFF]: %s, dev=%s", strerror(errno), dev->name);
      close(tap->fd);
      return -1;
    }
  
    // ハードウェアアドレスが指定されていなかったら、OS側から見えているTAPデバイスのハードウェアアドレスを取得して使う
    if (memcmp(dev->addr, ETHER_ADDR_ANY, ETHER_ADDR_LEN) == 0) {
      if (ether_tap_addr(dev) == -1) {
        errorf("ether_tap_addr() failure, dev=%s", dev->name);
        close(tap->fd);
        return -1;
      }
    }
    return 0;
  }
  
  static int ether_tap_close(struct net_device *dev) {
    close(PRIV(dev)->fd);
    return 0;
  }
  
  static ssize_t ether_tap_write(struct net_device *dev, const uint8_t *frame, size_t flen) {
    return write(PRIV(dev)->fd, frame, flen);
  }
  
  int ether_tap_transmit(struct net_device *dev, uint16_t type, const uint8_t *buf, size_t len, const void *dst) {
    return ether_transmit_helper(dev, type, buf, len, dst, ether_tap_write);
  }
  
  static ssize_t ether_tap_read(struct net_device *dev, uint8_t *buf, size_t size) {
    ssize_t len;
  
    len = read(PRIV(dev)->fd, buf, size);
    if (len <= 0) {
      if (len == -1 && errno != EINTR) errorf("read: %s, dev=%s", strerror(errno), dev->name);
      return -1;
    }
    return len;
  }
  
  static int ether_tap_poll(struct net_device *dev) {
    struct pollfd pfd;
    int ret;
  
    pfd.fd = PRIV(dev)->fd;
    pfd.events = POLLIN;
    // ディスクリプタが読み込み可能になるのを待つ
    ret = poll(&pfd, 1, 0);
    switch (ret) {
      case -1:
        if (errno != EINTR) {
          errorf("poll: %s, dev=%s", strerror(errno), dev->name);
        }
        /* fall through */
      case 0: /* timeout */
        return -1;
    }
    return ether_poll_helper(dev, ether_tap_read);
  }
  
  static struct net_device_ops ether_tap_ops = {
      .open = ether_tap_open,
      .close = ether_tap_close,
      .transmit = ether_tap_transmit,
      .poll = ether_tap_poll,
  };
  
  struct net_device *ether_tap_init(const char *name, const char *addr) {
    struct net_device *dev;
    struct ether_tap *tap;
  
    dev = net_device_alloc();
    if (!dev) {
      errorf("net_device_alloc() failure");
      return NULL;
    }
    ether_setup_helper(dev);
    if (addr) {
      if (ether_addr_pton(addr, dev->addr) == -1) {
        errorf("invalid address, addr=%s", addr);
        return NULL;
      }
    }
    dev->ops = &ether_tap_ops;
    tap = calloc(1, sizeof(*tap));
    if (!tap) {
      errorf("calloc() failure");
      return NULL;
    }
    strncpy(tap->name, name, sizeof(tap->name) - 1);
    tap->fd = -1;
    dev->priv = tap;
    if (net_device_register(dev) == -1) {
      errorf("net_device_register() failure");
      free(tap);
      return NULL;
    }
    debugf("ethernet device initialized, dev=%s", dev->name);
    return dev;
  }
  