Add sources for my original BeOS BONE tun/tap config driver
as a starting point. Change-Id: I9c3b1027a7fda4ab1eaced486eb2455a19571fee
This commit is contained in:
parent
b5d2337330
commit
b110fce124
64
headers/posix/net/if_tun.h
Normal file
64
headers/posix/net/if_tun.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2018 Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NET_IF_TUN_H
|
||||||
|
#define _NET_IF_TUN_H
|
||||||
|
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* public API for tun/tap device.
|
||||||
|
* This API is compatible with the Linux tun/tap driver from
|
||||||
|
* http://vtun.sourceforge.net/tun/index.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* max of each type */
|
||||||
|
#define TUN_MAX_DEV 10
|
||||||
|
/*255*/
|
||||||
|
|
||||||
|
/* TX queue size */
|
||||||
|
#define TUN_TXQ_SIZE 10
|
||||||
|
|
||||||
|
/* Max frame size */
|
||||||
|
#define TUN_MAX_FRAME 4096
|
||||||
|
|
||||||
|
/* TUN device flags */
|
||||||
|
#define TUN_TUN_DEV 0x0001
|
||||||
|
#define TUN_TAP_DEV 0x0002
|
||||||
|
#define TUN_TYPE_MASK 0x000f
|
||||||
|
|
||||||
|
/* not yet*//*#define TUN_FASYNC 0x0010*/
|
||||||
|
#define TUN_NOCHECKSUM 0x0020
|
||||||
|
#define TUN_NO_PI 0x0040
|
||||||
|
|
||||||
|
#define TUN_IFF_SET 0x1000
|
||||||
|
|
||||||
|
/* Ioctl defines */
|
||||||
|
/* XXX: NOT OFFICIAL */
|
||||||
|
#define TUNSETNOCSUM (B_DEVICE_OP_CODES_END+0x90)
|
||||||
|
#define TUNSETDEBUG (B_DEVICE_OP_CODES_END+0x91)
|
||||||
|
#define TUNSETIFF (B_DEVICE_OP_CODES_END+0x92)
|
||||||
|
|
||||||
|
/* get/set MAC address */
|
||||||
|
//#define SIOCGIFHWADDR (BONE_SOCKIO_IOCTL_BASE+0x95)
|
||||||
|
//#define SIOCSIFHWADDR (BONE_SOCKIO_IOCTL_BASE+0x96)
|
||||||
|
|
||||||
|
/* TUNSETIFF ifr flags */
|
||||||
|
#define IFF_TUN 0x0001
|
||||||
|
#define IFF_TAP 0x0002
|
||||||
|
#define IFF_NO_PI 0x1000
|
||||||
|
/* XXX: fix the confusion about which *NO_PI go where ! */
|
||||||
|
|
||||||
|
struct tun_pi {
|
||||||
|
unsigned short flags;
|
||||||
|
unsigned short proto;
|
||||||
|
};
|
||||||
|
/* tun_pi::flags */
|
||||||
|
#define TUN_PKT_STRIP 0x0001
|
||||||
|
|
||||||
|
#define TUN_DEVICE "/dev/config/tun"
|
||||||
|
|
||||||
|
#endif /* __IF_TUN_H */
|
12
src/add-ons/kernel/drivers/network/tun/Jamfile
Normal file
12
src/add-ons/kernel/drivers/network/tun/Jamfile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel drivers network tun ;
|
||||||
|
|
||||||
|
UsePrivateSystemHeaders ;
|
||||||
|
# For net_tun.h
|
||||||
|
UsePrivateHeaders net ;
|
||||||
|
|
||||||
|
KernelAddon tun_config :
|
||||||
|
driver.c
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
|
335
src/add-ons/kernel/drivers/network/tun/driver.c
Normal file
335
src/add-ons/kernel/drivers/network/tun/driver.c
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
#include <Drivers.h>
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <OS.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <fsproto.h>
|
||||||
|
#include "bone_tun.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* /dev/config/tun network tunnel driver for BeOS
|
||||||
|
* (c) 2003, mmu_man, revol@free.fr
|
||||||
|
* licenced under MIT licence.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
const char * device_names[]={TUN_DRIVER_NAME, NULL};
|
||||||
|
extern device_hooks tun_hooks;
|
||||||
|
|
||||||
|
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
||||||
|
|
||||||
|
vint32 if_mod_ref_count = 0;
|
||||||
|
bone_tun_interface_info_t *gIfaceModule = NULL;
|
||||||
|
bone_util_info_t *gUtil = NULL;
|
||||||
|
|
||||||
|
status_t init_hardware(void) {
|
||||||
|
dprintf("tun:init_hardware()\n");
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t init_driver(void) {
|
||||||
|
dprintf("tun:init_driver()\n");
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uninit_driver(void) {
|
||||||
|
dprintf("tun:uninit_driver()\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char **publish_devices() {
|
||||||
|
return device_names;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_hooks *find_device(const char *name) {
|
||||||
|
(void)name;
|
||||||
|
return &tun_hooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t tun_open(const char *name, uint32 flags, cookie_t **cookie) {
|
||||||
|
status_t err = B_OK;
|
||||||
|
(void)name; (void)flags;
|
||||||
|
/* XXX: add O_NONBLOCK + FIONBIO */
|
||||||
|
#if DEBUG > 1
|
||||||
|
dprintf("tun:open(%s, 0x%08lx,)\n", name, flags);
|
||||||
|
#endif
|
||||||
|
err = get_module(BONE_UTIL_MOD_NAME, (struct module_info **)&gUtil);
|
||||||
|
if (err < B_OK)
|
||||||
|
return err;
|
||||||
|
err = get_module(TUN_INTERFACE_MODULE, (struct module_info **)&gIfaceModule);
|
||||||
|
if (err < B_OK) {
|
||||||
|
put_module(BONE_UTIL_MOD_NAME);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: FIXME, still not ok (rescan) */
|
||||||
|
if (atomic_add(&if_mod_ref_count, 1) < 1) /* force one more open to keep loaded */
|
||||||
|
get_module(TUN_INTERFACE_MODULE, (struct module_info **)&gIfaceModule);
|
||||||
|
|
||||||
|
*cookie = (void*)malloc(sizeof(cookie_t));
|
||||||
|
if (*cookie == NULL) {
|
||||||
|
dprintf("tun_open : error allocating cookie\n");
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
memset(*cookie, 0, sizeof(cookie_t));
|
||||||
|
(*cookie)->blocking_io = true;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
err1:
|
||||||
|
dprintf("tun_open : cleanup : will free cookie\n");
|
||||||
|
free(*cookie);
|
||||||
|
*cookie = NULL;
|
||||||
|
put_module(TUN_INTERFACE_MODULE);
|
||||||
|
put_module(BONE_UTIL_MOD_NAME);
|
||||||
|
err0:
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t tun_close(void *cookie) {
|
||||||
|
(void)cookie;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t tun_free(cookie_t *cookie) {
|
||||||
|
status_t err = B_OK;
|
||||||
|
#if DEBUG > 1
|
||||||
|
dprintf("tun_close()\n");
|
||||||
|
#endif
|
||||||
|
if (cookie->iface)
|
||||||
|
err = gIfaceModule->tun_detach_driver(cookie->iface, true);
|
||||||
|
free(cookie);
|
||||||
|
atomic_add(&if_mod_ref_count, -1);
|
||||||
|
put_module(TUN_INTERFACE_MODULE);
|
||||||
|
put_module(BONE_UTIL_MOD_NAME);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t tun_ioctl(cookie_t *cookie, uint32 op, void *data, size_t len) {
|
||||||
|
ifreq_t *ifr;
|
||||||
|
bone_tun_if_interface_t *iface;
|
||||||
|
(void)cookie; (void)op; (void)data; (void)len;
|
||||||
|
iface = cookie->iface;
|
||||||
|
#if DEBUG > 1
|
||||||
|
dprintf("tun_ioctl(%d(0x%08lx), , %d)\n", op, op, len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case B_SET_NONBLOCKING_IO:
|
||||||
|
cookie->blocking_io = false;
|
||||||
|
return B_OK;
|
||||||
|
case B_SET_BLOCKING_IO:
|
||||||
|
cookie->blocking_io = true;
|
||||||
|
return B_OK;
|
||||||
|
case TUNSETNOCSUM:
|
||||||
|
return B_OK;//EOPNOTSUPP;
|
||||||
|
case TUNSETDEBUG:
|
||||||
|
return B_OK;//EOPNOTSUPP;
|
||||||
|
case TUNSETIFF:
|
||||||
|
if (data == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
ifr = (ifreq_t *)data;
|
||||||
|
|
||||||
|
iface = gIfaceModule->tun_reuse_or_create(ifr, cookie);
|
||||||
|
if (iface != NULL) {
|
||||||
|
dprintf("tun: new tunnel created: %s, flags: 0x%08lx\n", ifr->ifr_name, iface->flags);
|
||||||
|
return B_OK;
|
||||||
|
} else
|
||||||
|
dprintf("tun: can't allocate a new tunnel!\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIOCGIFHWADDR:
|
||||||
|
if (data == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
ifr = (ifreq_t *)data;
|
||||||
|
if (iface == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
if (strncmp(ifr->ifr_name, iface->ifn->if_name, IFNAMSIZ) != 0)
|
||||||
|
return EINVAL;
|
||||||
|
memcpy(ifr->ifr_hwaddr, iface->fakemac.octet, 6);
|
||||||
|
return B_OK;
|
||||||
|
case SIOCSIFHWADDR:
|
||||||
|
if (data == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
ifr = (ifreq_t *)data;
|
||||||
|
if (iface == NULL)
|
||||||
|
return EINVAL;
|
||||||
|
if (strncmp(ifr->ifr_name, iface->ifn->if_name, IFNAMSIZ) != 0)
|
||||||
|
return EINVAL;
|
||||||
|
memcpy(iface->fakemac.octet, ifr->ifr_hwaddr, 6);
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
}
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t tun_read(cookie_t *cookie, off_t position, void *data, size_t *numbytes) {
|
||||||
|
bone_data_t *bdata;
|
||||||
|
uint32 got;
|
||||||
|
ssize_t pktsize;
|
||||||
|
if (cookie->iface == NULL)
|
||||||
|
return EBUSY;
|
||||||
|
|
||||||
|
//if ((pktsize = gUtil->dequeue_fifo_data(cookie->iface->wfifo, &bdata, B_INFINITE_TIMEOUT, false)) < 0)
|
||||||
|
pktsize = gUtil->dequeue_fifo_data(cookie->iface->wfifo, &bdata, cookie->blocking_io?B_INFINITE_TIMEOUT:0LL, false);
|
||||||
|
|
||||||
|
if (pktsize < 0) {
|
||||||
|
*numbytes = 0;
|
||||||
|
return pktsize;
|
||||||
|
}
|
||||||
|
#if DEBUG > 2
|
||||||
|
dprintf("tun: dequeue = %ld, datalen = %ld, \n", pktsize, bdata?bdata->datalen:0);
|
||||||
|
#endif
|
||||||
|
pktsize = (ssize_t)bdata->datalen;
|
||||||
|
|
||||||
|
got = gUtil->copy_from_data(bdata, 0L, data, MIN((bdata->datalen), (*numbytes)));
|
||||||
|
//got = MIN((*numbytes), bdata->datalen);
|
||||||
|
if ((pktsize > *numbytes) && !(cookie->iface->flags & TUN_NO_PI))
|
||||||
|
((struct tun_pi *)data)->flags |= TUN_PKT_STRIP;
|
||||||
|
gUtil->delete_data(bdata);
|
||||||
|
#if DEBUG > 2
|
||||||
|
dprintf("tun: read() got %ld bytes, buf is %ld\n", got, *numbytes);
|
||||||
|
dump_data(bdata);
|
||||||
|
iovec_dump_data(bdata);
|
||||||
|
#endif
|
||||||
|
*numbytes = got;
|
||||||
|
return B_OK;
|
||||||
|
ERROR_EOF:
|
||||||
|
*numbytes = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t tun_write(cookie_t *cookie, off_t position, const void *data, size_t *numbytes) {
|
||||||
|
bone_data_t *bdata = NULL;
|
||||||
|
void *buf;
|
||||||
|
status_t err = B_NO_MEMORY;
|
||||||
|
(void)position;
|
||||||
|
|
||||||
|
/* XXX: max for *numbytes ? */
|
||||||
|
|
||||||
|
if (cookie->iface == NULL)
|
||||||
|
return EBUSY;
|
||||||
|
bdata = gUtil->new_data();
|
||||||
|
if (bdata == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
buf = gUtil->falloc(*numbytes);
|
||||||
|
if (buf == NULL)
|
||||||
|
goto ERROR_1;
|
||||||
|
memcpy(buf, data, *numbytes);
|
||||||
|
|
||||||
|
if (gUtil->prepend_data(bdata, buf, *numbytes, gUtil->free) < 0) {
|
||||||
|
gUtil->free(buf);
|
||||||
|
goto ERROR_1;
|
||||||
|
}
|
||||||
|
if ((err = gUtil->enqueue_fifo_data(cookie->iface->rfifo, bdata)) < B_OK)
|
||||||
|
goto ERROR_1;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
ERROR_1:
|
||||||
|
if (bdata)
|
||||||
|
gUtil->delete_data(bdata);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t tun_select(cookie_t *cookie, uint8 event, uint32 ref, selectsync *sync)
|
||||||
|
{
|
||||||
|
status_t err = B_OK;
|
||||||
|
#if DEBUG > 1
|
||||||
|
dprintf("tun: select(, %d, %ld, )\n", event, ref);
|
||||||
|
#endif
|
||||||
|
if (cookie->iface == NULL)
|
||||||
|
return B_NO_INIT;
|
||||||
|
if (event > B_SELECT_EXCEPTION || !event)
|
||||||
|
return EINVAL;
|
||||||
|
err = gUtil->lock_benaphore(&cookie->iface->lock);
|
||||||
|
if (err < B_OK)
|
||||||
|
return err;
|
||||||
|
/* iface LOCKED */
|
||||||
|
if (cookie->iface->sel[event].sync)
|
||||||
|
err = EALREADY;
|
||||||
|
else {
|
||||||
|
bone_fifo_t *fifo = NULL;
|
||||||
|
switch (event) {
|
||||||
|
case B_SELECT_READ:
|
||||||
|
fifo = cookie->iface->wfifo;
|
||||||
|
break;
|
||||||
|
case B_SELECT_WRITE:
|
||||||
|
fifo = cookie->iface->rfifo;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fifo) {
|
||||||
|
/* XXX: is it safe ??? shouldn't we dequeue(peek=true) ? */
|
||||||
|
err = gUtil->lock_benaphore(&fifo->lock);
|
||||||
|
if (err >= B_OK) {
|
||||||
|
bool avail;
|
||||||
|
switch (event) {
|
||||||
|
case B_SELECT_READ:
|
||||||
|
avail = (fifo->current_bytes > 1);
|
||||||
|
break;
|
||||||
|
case B_SELECT_WRITE:
|
||||||
|
avail = ((fifo->max_bytes - fifo->current_bytes) > cookie->iface->ifn->if_mtu);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* check if we don't already have the event */
|
||||||
|
if (avail) {
|
||||||
|
notify_select_event(sync, ref);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cookie->iface->sel[event].sync = sync;
|
||||||
|
cookie->iface->sel[event].ref = ref;
|
||||||
|
}
|
||||||
|
gUtil->unlock_benaphore(&fifo->lock);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cookie->iface->sel[event].sync = sync;
|
||||||
|
cookie->iface->sel[event].ref = ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gUtil->unlock_benaphore(&cookie->iface->lock);
|
||||||
|
/* iface UNLOCKED */
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
status_t tun_deselect(cookie_t *cookie, uint8 event, selectsync *sync)
|
||||||
|
{
|
||||||
|
status_t err = B_OK;
|
||||||
|
#if DEBUG > 1
|
||||||
|
dprintf("tun: deselect(, %d, )\n", event);
|
||||||
|
#endif
|
||||||
|
if (cookie->iface == NULL)
|
||||||
|
return B_NO_INIT;
|
||||||
|
if (event > B_SELECT_EXCEPTION || !event)
|
||||||
|
return EINVAL;
|
||||||
|
err = gUtil->lock_benaphore(&cookie->iface->lock);
|
||||||
|
if (err < B_OK)
|
||||||
|
return err;
|
||||||
|
cookie->iface->sel[event].sync = NULL;
|
||||||
|
cookie->iface->sel[event].ref = 0;
|
||||||
|
gUtil->unlock_benaphore(&cookie->iface->lock);
|
||||||
|
/* iface LOCKED */
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
status_t tun_readv(cookie_t *cookie, off_t position, const iovec *vec, size_t count, size_t *numBytes)
|
||||||
|
{
|
||||||
|
dprintf("tun: readv(, %Ld, , %ld)\n", position, count);
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
status_t tun_writev(cookie_t *cookie, off_t position, const iovec *vec, size_t count, size_t *numBytes)
|
||||||
|
{
|
||||||
|
dprintf("tun: writev(, %Ld, , %ld)\n", position, count);
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_hooks tun_hooks={
|
||||||
|
(device_open_hook)tun_open,
|
||||||
|
tun_close,
|
||||||
|
(device_free_hook)tun_free,
|
||||||
|
(device_control_hook)tun_ioctl,
|
||||||
|
(device_read_hook)tun_read,
|
||||||
|
(device_write_hook)tun_write,
|
||||||
|
(device_select_hook)tun_select,
|
||||||
|
(device_deselect_hook)tun_deselect,
|
||||||
|
(device_readv_hook)tun_readv,
|
||||||
|
(device_writev_hook)tun_writev
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user