Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tuntap driver imported from http://jungerl.sourceforge.net/.
- Loading branch information
0 parents
commit 54694ab
Showing
9 changed files
with
534 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
include ../../support/subdir.mk | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
|
||
Copy of the tuntap Erlang driver from Jungerl, by Luke Gorrie. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
include ../../../support/include.mk | ||
|
||
CFLAGS += -I $(ERL_C_INCLUDE_DIR) -I../../../support | ||
|
||
TUN_DRV_SO = ../priv/tun_drv.so | ||
TUNCTL = ../priv/tunctl | ||
|
||
all: $(TUN_DRV_SO) $(TUNCTL) | ||
|
||
$(TUN_DRV_SO): tun_drv.o | ||
ld -G -o $@ $< | ||
|
||
tun_drv.o: tun_drv.c | ||
$(CC) $(CFLAGS) -o $@ -c -fpic $(ERL_INCLUDE) $< | ||
|
||
$(TUNCTL): tunctl.c | ||
$(CC) $(CFLAGS) -o $@ $< | ||
|
||
clean: | ||
-rm $(TUN_DRV_SO) $(TUNCTL) | ||
|
||
.INTERMEDIATE: tun_drv.o | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
/* Tunnel device linked-in driver. | ||
See /usr/src/linux/Documentation/networking/tuntap.txt | ||
Written by Luke Gorrie <luke@bluetail.com> in November 2001, and | ||
updated in February 2003 to support TAP interfaces and the new | ||
Erlang driver interface. */ | ||
|
||
#include <stdio.h> | ||
#include <fcntl.h> | ||
#include <unistd.h> | ||
#include <errno.h> | ||
#include <sys/time.h> | ||
#include <sys/types.h> | ||
#include <net/if.h> | ||
#include <sys/ioctl.h> | ||
#include <assert.h> | ||
|
||
#include <linux/if_tun.h> | ||
|
||
#include "erl_driver.h" | ||
|
||
#define REPLY_ERROR 0 | ||
#define REPLY_OK 1 | ||
|
||
#define REQUEST_GET_DEVICE 0 | ||
#define REQUEST_ACTIVE 2 | ||
|
||
#define ACTIVE_FALSE 0 | ||
#define ACTIVE_TRUE 1 | ||
#define ACTIVE_ONCE 2 | ||
|
||
/* Generous buffer size for reading single ethernet frames. | ||
FIXME: Do we need to worry about bigger packets, e.g. if we have a | ||
giant MTU in 'tap' or receive pre-defragmented IP packets in | ||
'tun'? */ | ||
#define TUNNEL_BUF_SIZE 2048 | ||
|
||
/* | ||
* | ||
* Helpers | ||
* | ||
*/ | ||
|
||
/* parse driver argument string: "tunnel_drv <tun|tap> [device_name]" */ | ||
static int parse_args(char *str, int *mode, char *dev_name, int max_name_len) | ||
{ | ||
/* skip to start of first argument */ | ||
for (; *str != ' '; str++) { if (*str == '\0') return 0; } | ||
for (; *str == ' '; str++) { if (*str == '\0') return 0; } | ||
|
||
/* looking at "tun" or "tap" - parse and move over */ | ||
if (strncmp(str, "tun", 3) == 0) { | ||
*mode = IFF_TUN; | ||
} else if (strncmp(str, "tap", 3) == 0) { | ||
*mode = IFF_TAP; | ||
} else { | ||
return 0; | ||
} | ||
str += 3; | ||
/* optional device name - skip any whitespace, then copy */ | ||
while (*str == ' ') str++; | ||
strncpy(dev_name, str, max_name_len); | ||
|
||
return 1; | ||
} | ||
|
||
/* make a tunnel interface */ | ||
static int make_if(int mode, char *dev) { | ||
struct ifreq ifr; | ||
int fd, err; | ||
|
||
if ((fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0) return -1; | ||
|
||
memset(&ifr, 0, sizeof(ifr)); | ||
ifr.ifr_flags = mode | IFF_NO_PI; | ||
if( *dev ) | ||
strncpy(ifr.ifr_name, dev, IFNAMSIZ); | ||
|
||
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){ | ||
close(fd); | ||
return err; | ||
} | ||
strcpy(dev, ifr.ifr_name); | ||
return fd; | ||
} | ||
|
||
|
||
/* | ||
* | ||
* erl_driver interface | ||
* | ||
*/ | ||
|
||
struct tun_state { | ||
ErlDrvPort port; | ||
int fd; | ||
char dev[IFNAMSIZ]; | ||
char buf[TUNNEL_BUF_SIZE]; | ||
int active; | ||
}; | ||
|
||
static int ctl_reply(int rep, char *buf, int len, char **rbuf, int rsize) | ||
{ | ||
char* ptr; | ||
|
||
if ((len+1) > rsize) { | ||
ptr = (char *)sys_alloc(len+1); | ||
assert(ptr); | ||
*rbuf = ptr; | ||
} | ||
else | ||
ptr = *rbuf; | ||
*ptr++ = rep; | ||
memcpy(ptr, buf, len); | ||
return len+1; | ||
} | ||
|
||
static void set_input(struct tun_state *state, int flag) | ||
{ | ||
driver_select(state->port, (ErlDrvEvent)state->fd, DO_READ, flag); | ||
} | ||
|
||
static int tun_ctl(ErlDrvData data, | ||
unsigned int cmd, | ||
char *buf, | ||
int len, | ||
char **rbuf, | ||
int rsize) | ||
{ | ||
struct tun_state *state = (struct tun_state *)data; | ||
int read_len; | ||
switch (cmd) { | ||
case REQUEST_GET_DEVICE: | ||
return ctl_reply(REPLY_OK, state->dev, strlen(state->dev), rbuf, rsize); | ||
case REQUEST_ACTIVE: | ||
state->active = (int)*buf; | ||
switch (state->active) { | ||
case ACTIVE_FALSE: | ||
set_input(state, 0); | ||
break; | ||
case ACTIVE_TRUE: | ||
set_input(state, 1); | ||
break; | ||
case ACTIVE_ONCE: | ||
/* optimization: try to read a packet immediately if it | ||
exists, to avoid going back to select() */ | ||
read_len = read(state->fd, state->buf, TUNNEL_BUF_SIZE); | ||
if (read_len > 0) { | ||
/* got a packet */ | ||
driver_output(state->port, state->buf, read_len); | ||
state->active = ACTIVE_FALSE; | ||
set_input(state, 0); | ||
} else { | ||
/* no packet available yet */ | ||
set_input(state, 1); | ||
} | ||
break; | ||
default: | ||
assert(0); | ||
} | ||
return ctl_reply(REPLY_OK, "", 0, rbuf, rsize); | ||
default: | ||
return ctl_reply(REPLY_ERROR, "", 0, rbuf, rsize); | ||
} | ||
} | ||
|
||
static void tun_output(ErlDrvData data, char* buf, int len) | ||
{ | ||
struct tun_state *state = (struct tun_state *)data; | ||
if (write(state->fd, buf, len) < 0) | ||
driver_failure_posix(state->port, errno); | ||
} | ||
|
||
static void tun_input(ErlDrvData data, ErlDrvEvent nil) | ||
{ | ||
struct tun_state *state = (struct tun_state *)data; | ||
int len; | ||
|
||
len = read(state->fd, state->buf, TUNNEL_BUF_SIZE); | ||
if (len > 0) { | ||
driver_output(state->port, state->buf, len); | ||
} | ||
if (state->active == ACTIVE_ONCE) { | ||
state->active = ACTIVE_FALSE; | ||
set_input(state, 0); | ||
} | ||
} | ||
|
||
static void tun_stop(ErlDrvData data) | ||
{ | ||
struct tun_state *state = (struct tun_state *)data; | ||
set_input(state, 0); | ||
close(state->fd); | ||
sys_free(state); | ||
} | ||
|
||
static ErlDrvData tun_start(ErlDrvPort port, char *args) | ||
{ | ||
struct tun_state *state; | ||
int fd; | ||
|
||
int mode; | ||
char dev_name[IFNAMSIZ]; | ||
|
||
state = (struct tun_state*) sys_alloc(sizeof(struct tun_state)); | ||
if (state == NULL) { | ||
errno = ENOMEM; /* appropriate to set errno? */ | ||
return ERL_DRV_ERROR_ERRNO; | ||
} | ||
|
||
if (!parse_args(args, &mode, state->dev, IFNAMSIZ - 1)) { | ||
return ERL_DRV_ERROR_BADARG; | ||
} | ||
|
||
fd = make_if(mode, state->dev); | ||
if (fd < 0) { | ||
return ERL_DRV_ERROR_GENERAL; | ||
} | ||
state->port = port; | ||
state->fd = fd; | ||
state->active = ACTIVE_FALSE; | ||
set_input(state, 0); | ||
|
||
return (ErlDrvData)state; | ||
} | ||
|
||
static int tun_init(void) | ||
{ | ||
return 0; | ||
} | ||
|
||
ErlDrvEntry tun_driver_entry; | ||
|
||
ErlDrvEntry *driver_init(void) | ||
{ | ||
memset(&tun_driver_entry, 0, sizeof(tun_driver_entry)); | ||
tun_driver_entry.init = tun_init; | ||
tun_driver_entry.start = tun_start; | ||
tun_driver_entry.stop = tun_stop; | ||
tun_driver_entry.ready_input = tun_input; | ||
tun_driver_entry.control = tun_ctl; | ||
tun_driver_entry.output = tun_output; | ||
tun_driver_entry.driver_name = "tun_drv"; | ||
return &tun_driver_entry; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* Copyright 2002 Jeff Dike | ||
* Licensed under the GPL | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <unistd.h> | ||
#include <pwd.h> | ||
#include <net/if.h> | ||
#include <sys/ioctl.h> | ||
#include <linux/if_tun.h> | ||
|
||
static void Usage(char *name) | ||
{ | ||
fprintf(stderr, "Create: %s [-b] [-u owner] [-t device-name] " | ||
"[-f tun-clone-device]\n", name); | ||
fprintf(stderr, "Delete: %s -d device-name [-f tun-clone-device]\n\n", | ||
name); | ||
fprintf(stderr, "The default tun clone device is /dev/net/tun - some systems" | ||
" use\n/dev/misc/net/tun instead\n\n"); | ||
fprintf(stderr, "-b will result in brief output (just the device name)\n"); | ||
exit(1); | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
struct ifreq ifr; | ||
struct passwd *pw; | ||
long owner = geteuid(); | ||
int tap_fd, opt, delete = 0, brief = 0; | ||
char *tun = "", *file = "/dev/net/tun", *name = argv[0], *end; | ||
|
||
while((opt = getopt(argc, argv, "bd:f:t:u:")) > 0){ | ||
switch(opt) { | ||
case 'b': | ||
brief = 1; | ||
break; | ||
case 'd': | ||
delete = 1; | ||
tun = optarg; | ||
break; | ||
case 'f': | ||
file = optarg; | ||
break; | ||
case 'u': | ||
pw = getpwnam(optarg); | ||
if(pw != NULL){ | ||
owner = pw->pw_uid; | ||
break; | ||
} | ||
owner = strtol(optarg, &end, 0); | ||
if(*end != '\0'){ | ||
fprintf(stderr, "'%s' is neither a username nor a numeric uid.\n", | ||
optarg); | ||
Usage(name); | ||
} | ||
break; | ||
case 't': | ||
tun = optarg; | ||
break; | ||
case 'h': | ||
default: | ||
Usage(name); | ||
} | ||
} | ||
|
||
argv += optind; | ||
argc -= optind; | ||
|
||
if(argc > 0) | ||
Usage(name); | ||
|
||
if((tap_fd = open(file, O_RDWR)) < 0){ | ||
perror("opening tun device"); | ||
exit(1); | ||
} | ||
|
||
memset(&ifr, 0, sizeof(ifr)); | ||
|
||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; | ||
strncpy(ifr.ifr_name, tun, sizeof(ifr.ifr_name) - 1); | ||
if(ioctl(tap_fd, TUNSETIFF, (void *) &ifr) < 0){ | ||
perror("TUNSETIFF"); | ||
exit(1); | ||
} | ||
|
||
if(delete){ | ||
if(ioctl(tap_fd, TUNSETPERSIST, 0) < 0){ | ||
perror("TUNSETPERSIST"); | ||
exit(1); | ||
} | ||
printf("Set '%s' nonpersistent\n", ifr.ifr_name); | ||
} | ||
else { | ||
if(ioctl(tap_fd, TUNSETPERSIST, 1) < 0){ | ||
perror("TUNSETPERSIST"); | ||
exit(1); | ||
} | ||
if(ioctl(tap_fd, TUNSETOWNER, owner) < 0){ | ||
perror("TUNSETPERSIST"); | ||
exit(1); | ||
} | ||
if(brief) | ||
printf("%s\n", ifr.ifr_name); | ||
else printf("Set '%s' persistent and owned by uid %ld\n", ifr.ifr_name, | ||
owner); | ||
} | ||
return(0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Linux "Universal TUN/TAP device" driver |
Oops, something went wrong.