2019-09-06 16:50:37 +08:00
|
|
|
#include "kni_utils.h"
|
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <net/if.h>
|
|
|
|
|
#include <linux/if_tun.h>
|
|
|
|
|
#include <kni_tun.h>
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-05 16:46:33 +08:00
|
|
|
KNI_LOG_ERROR(handle->logger, "Failed at read, error = %d(%s)", errno, strerror(errno));
|
2019-09-06 16:50:37 +08:00
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|