#include "kni_utils.h" #include #include #include #include #include struct kni_tun_handle{ int fd; void *logger; enum kni_tun_mode mode; }; void kni_tun_destroy(struct kni_tun_handle *tun_handle){ if(tun_handle != NULL){ close(tun_handle->fd); FREE(&tun_handle); } } struct kni_tun_handle* kni_tun_init(char *tun_name, enum kni_tun_mode mode, void *logger){ struct kni_tun_handle *tun_handle = ALLOC(struct kni_tun_handle, 1); tun_handle->logger = logger; char *tun_path = (char*)"/dev/net/tun"; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); int fd = -1, ret; ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE; if(tun_name == NULL || *tun_name == '\0'){ KNI_LOG_ERROR(logger, "Tap device name is NULL"); goto error_out; } strncpy(ifr.ifr_name, tun_name, IFNAMSIZ); fd = open(tun_path, O_RDWR); if(fd < 0){ KNI_LOG_ERROR(logger, "Failed at open file, filename = %s, errno = %d(%s)", tun_path, errno, strerror(errno)); goto error_out; } tun_handle->fd = fd; tun_handle->mode = KNI_TUN_MODE_NOBLOCK; if(tun_handle->mode == KNI_TUN_MODE_NOBLOCK){ int flags = fcntl(fd, F_GETFL, 0); ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); if(ret < 0){ KNI_LOG_ERROR(logger ,"Failed at fcntl, fd = %d, flags = F_GETFL | O_NONBLOCK, errno = %d(%s)", errno, strerror(errno)); goto error_out; } } ret = ioctl(tun_handle->fd, TUNSETIFF, (void *)&ifr); if(ret < 0){ KNI_LOG_ERROR(logger ,"Failed at ioctl, fd = %d, errno = %d(%s)", errno, strerror(errno)); goto error_out; } return tun_handle; error_out: kni_tun_destroy(tun_handle); return NULL; } int kni_tun_write(struct kni_tun_handle *handle, char *buff, uint16_t buff_len){ uint16_t ret = write(handle->fd, buff, buff_len); if(ret < 0){ KNI_LOG_ERROR(handle->logger, "Failed at write, errno = %d(%s)", errno, strerror(errno)); return -1; } if(ret < buff_len){ KNI_LOG_ERROR(handle->logger, "Failed at write: need send %dB, only send %dB", buff_len, ret); return -1; } return 0; } /* * >= 0 : read data length * = -1 : error */ int kni_tun_read(struct kni_tun_handle *handle, char *buff, uint16_t buff_len){ int ret = 0; ret = read(handle->fd, buff, buff_len); if(ret < 0){ if(ret == -1 && handle->mode == KNI_TUN_MODE_NOBLOCK){ if(errno == EWOULDBLOCK || errno == EAGAIN){ return 0; } } KNI_LOG_ERROR(handle -> logger, "Failed at read, error = %d(%s)", errno, strerror(errno)); } return ret; }