Cleaned up the net_stack_driver a little bit, so it is more usable.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15500 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Waldemar Kornewald
2005-12-11 20:09:47 +00:00
parent aa782b3ed6
commit 8a1a2b3aa9
3 changed files with 298 additions and 421 deletions
@@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers network stack ;
SetSubDirSupportedPlatformsBeOSCompatible ; SetSubDirSupportedPlatformsBeOSCompatible ;
if $(TARGET_PLATFORM) != haiku { if ( $(TARGET_PLATFORM) != haiku ) {
UseHeaders [ FStandardOSHeaders ] : true ; UseHeaders [ FStandardOSHeaders ] : true ;
# Needed for <drivers/Select.h> and maybe other stuff. # Needed for <drivers/Select.h> and maybe other stuff.
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
@@ -11,7 +11,6 @@ if $(TARGET_PLATFORM) != haiku {
} }
UsePrivateHeaders net ; UsePrivateHeaders net ;
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared libkernelppp headers ] ;
# a) Userland stack version: # a) Userland stack version:
@@ -26,7 +26,6 @@
// Private includes // Private includes
#include <net_stack_driver.h> #include <net_stack_driver.h>
// #include <PPPControl.h> // for NET_STACK_CONTROL_NET_MODULE PPP support...
#include <userland_ipc.h> #include <userland_ipc.h>
#include <sys/sockio.h> #include <sys/sockio.h>
@@ -8,124 +8,88 @@
#error "This module MUST be built as a kernel driver!" #error "This module MUST be built as a kernel driver!"
#endif #endif
// Public/system includes // public/system includes
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <drivers/Drivers.h> #include <drivers/Drivers.h>
#include <drivers/KernelExport.h> #include <drivers/KernelExport.h>
#include <drivers/driver_settings.h> #include <drivers/driver_settings.h>
#include <drivers/module.h> // For get_module()/put_module() #include <drivers/module.h> // for get_module()/put_module()
#include <netinet/in_var.h> #include <netinet/in_var.h>
// Private includes // private includes
#include <net_stack_driver.h> #include <net_stack_driver.h>
#include <sys/protosw.h> #include <sys/protosw.h>
#include <core_module.h> #include <core_module.h>
// Trace support
#if defined(DEBUG) // debugging macros
#define TRACE(x) dprintf x #define LOGID "net_stack_driver: "
#define ERROR(format, args...) dprintf(LOGID "ERROR: " format, ## args)
#define WARN(format, args...) dprintf(LOGID "WARNING: " format, ## args)
#ifdef DEBUG
#define TRACE(format, args...) dprintf(format, ## args)
#else #else
#define TRACE(x) ; #define TRACE(format, args...)
#endif #endif
// Force the driver to stay loaded in memory
#define STAY_LOADED 0
/* // Local definitions
* Local definitions
* -----------------
*/
#ifndef DRIVER_NAME
#define DRIVER_NAME "net_stack_driver"
#endif
#ifndef LOGID
#define LOGID DRIVER_NAME ": "
#endif
#ifndef WARN
#define WARN "Warning: "
#endif
#ifndef ERR
#define ERR "ERROR: "
#endif
#ifdef COMPILE_FOR_R5
typedef status_t (*notify_select_event_function)(selectsync * sync, uint32 ref);
#else
typedef status_t (*notify_select_event_function)(selectsync * sync, uint32 ref, uint8 event);
#endif
struct socket; /* forward declaration */
// this struct will store one select() event to monitor per thread // this struct will store one select() event to monitor per thread
typedef struct selecter { typedef struct selecter {
struct selecter * next; struct selecter *next;
thread_id thread; thread_id thread;
uint32 event; uint32 event;
selectsync * sync; selectsync *sync;
uint32 ref; uint32 ref;
notify_select_event_function notify;
} selecter; } selecter;
// the cookie we attach to each file descriptor opened on our driver entry // the cookie we attach to each file descriptor opened on our driver entry
typedef struct { typedef struct net_stack_cookie {
struct socket * socket; // NULL before ioctl(fd, NET_STACK_SOCKET/_ACCEPT) struct socket *socket; // NULL before ioctl(fd, NET_STACK_SOCKET/_ACCEPT)
uint32 open_flags; // the open() flags (mostly for storing O_NONBLOCK mode) uint32 open_flags; // the open() flags (mostly for storing O_NONBLOCK mode)
sem_id selecters_lock; // protect the selecters linked-list sem_id selecters_lock; // protect the selecters linked-list
selecter * selecters; // the select()'ers lists (thread-aware) selecter *selecters; // the select()'ers lists (thread-aware)
notify_select_event_function notify;
} net_stack_cookie; } net_stack_cookie;
#if STAY_LOADED /* To unload this driver execute
/* to unload the driver, simply write UNLOAD_CMD to him: * $ echo unload > /dev/net/stack
* $ echo stop > /dev/net/stack * As soon as the last app stops using sockets the netstack will be unloaded.
* As soon as last app, via libnet.so, stop using it, it will unload, */
* and in turn stop the stack and unload all network kernel modules... static const char *kUnloadCommand = "unload";
*/
#define UNLOAD_CMD "unload"
#endif
#define STOP_CMD "stop"
// Prototypes of device hooks functions
static status_t net_stack_open(const char * name, uint32 flags, void ** cookie); // prototypes of device hooks functions
static status_t net_stack_close(void * cookie); static status_t net_stack_open(const char *name, uint32 flags, void **cookie);
static status_t net_stack_free_cookie(void * cookie); static status_t net_stack_close(void *cookie);
static status_t net_stack_control(void * cookie, uint32 msg,void * data, size_t datalen); static status_t net_stack_free_cookie(void *cookie);
static status_t net_stack_read(void * cookie, off_t pos, void * data, size_t * datalen); static status_t net_stack_control(void *cookie, uint32 msg, void *data, size_t datalen);
static status_t net_stack_write(void * cookie, off_t pos, const void * data, size_t * datalen); static status_t net_stack_read(void *cookie, off_t pos, void *data, size_t *datalen);
static status_t net_stack_write(void *cookie, off_t pos, const void *data, size_t *datalen);
static status_t net_stack_select(void *cookie, uint8 event, uint32 ref, selectsync *sync); static status_t net_stack_select(void *cookie, uint8 event, uint32 ref, selectsync *sync);
static status_t net_stack_deselect(void *cookie, uint8 event, selectsync *sync); static status_t net_stack_deselect(void *cookie, uint8 event, selectsync *sync);
// static status_t net_stack_readv(void * cookie, off_t pos, const iovec * vec, size_t count, size_t * len); // static status_t net_stack_readv(void *cookie, off_t pos, const iovec *vec, size_t count, size_t *len);
// static status_t net_stack_writev(void * cookie, off_t pos, const iovec * vec, size_t count, size_t * len); // static status_t net_stack_writev(void *cookie, off_t pos, const iovec *vec, size_t count, size_t *len);
// Privates prototypes // privates prototypes
static void on_socket_event(void * socket, uint32 event, void * cookie); static void on_socket_event(void *socket, uint32 event, void *cookie);
static status_t r5_notify_select_event(selectsync * sync, uint32 ref, uint8 event);
#if STAY_LOADED
static status_t keep_driver_loaded(); static status_t keep_driver_loaded();
static status_t unload_driver(); static status_t unload_driver();
#endif
static const char * opcode_name(int op); static const char *opcode_name(int op);
/* /*
* Global variables * Global variables
* ---------------- * ----------------
*/ */
const char * g_device_names_list[] = { static const char *sDevices[] = { NET_STACK_DRIVER_DEV, NULL };
NET_STACK_DRIVER_DEV,
NULL
};
device_hooks g_net_stack_driver_hooks = static device_hooks sDeviceHooks =
{ {
net_stack_open, /* -> open entry point */ net_stack_open, /* -> open entry point */
net_stack_close, /* -> close entry point */ net_stack_close, /* -> close entry point */
@@ -135,15 +99,53 @@ device_hooks g_net_stack_driver_hooks =
net_stack_write, /* -> write entry point */ net_stack_write, /* -> write entry point */
net_stack_select, /* -> select entry point */ net_stack_select, /* -> select entry point */
net_stack_deselect, /* -> deselect entry point */ net_stack_deselect, /* -> deselect entry point */
NULL, /* -> readv entry pint */ NULL, /* -> readv entry pint */
NULL /* ->writev entry point */ NULL /* ->writev entry point */
}; };
struct core_module_info *g_core = NULL; static struct core_module_info *sCore = NULL;
#if STAY_LOADED static int sStayLoadedFD = -1;
int g_stay_loaded_fd = -1;
#endif
// internal functions
static status_t
keep_driver_loaded()
{
if (sStayLoadedFD != -1)
return B_OK;
/* force the driver to stay loaded by opening himself */
TRACE("keep_driver_loaded: opening " NET_STACK_DRIVER_PATH " to stay loaded...\n");
sStayLoadedFD = open(NET_STACK_DRIVER_PATH, 0);
if (sStayLoadedFD < 0)
ERROR("keep_driver_loaded: couldn't open(" NET_STACK_DRIVER_PATH ")!\n");
return B_OK;
}
static status_t
unload_driver()
{
if (sStayLoadedFD >= 0) {
int tmp_fd;
/* we need to set sStayLoadedFD to < 0 if we don't want
* the next close enter again in this case, and so on...
*/
TRACE("unload_driver: unload requested.\n");
tmp_fd = sStayLoadedFD;
sStayLoadedFD = -1;
close(tmp_fd);
}
return B_OK;
}
/* /*
@@ -162,7 +164,8 @@ _EXPORT int32 api_version = B_CUR_DRIVER_API_VERSION;
* Also we'll turn on the serial debugger to aid in our debugging * Also we'll turn on the serial debugger to aid in our debugging
* experience. * experience.
*/ */
_EXPORT status_t init_hardware(void) _EXPORT status_t
init_hardware(void)
{ {
bool safemode = false; bool safemode = false;
void *sfmptr; void *sfmptr;
@@ -172,17 +175,18 @@ _EXPORT status_t init_hardware(void)
// only use the pointer if it's valid // only use the pointer if it's valid
if (sfmptr != NULL) { if (sfmptr != NULL) {
// we got a pointer, now get setting... // we got a pointer, now get settings...
safemode = get_driver_boolean_parameter(sfmptr, B_SAFEMODE_SAFE_MODE, false, false); safemode = get_driver_boolean_parameter(sfmptr, B_SAFEMODE_SAFE_MODE, false, false);
// now get rid of settings // now get rid of settings
unload_driver_settings(sfmptr); unload_driver_settings(sfmptr);
} }
if (safemode) { if (safemode) {
TRACE((LOGID WARN "init_hardware: declining offer to join the party.\n")); WARN("init_hardware: declining offer to join the party.\n");
return B_ERROR; return B_ERROR;
} }
TRACE((LOGID "init_hardware done.\n")); TRACE("init_hardware done.\n");
return B_OK; return B_OK;
} }
@@ -191,63 +195,64 @@ _EXPORT status_t init_hardware(void)
/* init_driver() /* init_driver()
* called every time we're loaded. * called every time we're loaded.
*/ */
_EXPORT status_t init_driver(void) _EXPORT status_t
init_driver(void)
{ {
// only get the core module if we don't have it loaded already // only get the core module if we don't have it loaded already
if (!g_core) { if (!sCore) {
int rv = 0; int rv = 0;
rv = get_module(NET_CORE_MODULE_NAME, (module_info **) &g_core); rv = get_module(NET_CORE_MODULE_NAME, (module_info **) &sCore);
if (rv < 0) { if (rv < 0) {
TRACE((LOGID ERR "init_driver: Argh, can't load " NET_CORE_MODULE_NAME " module: %d\n", rv)); ERROR("init_driver: Can't load " NET_CORE_MODULE_NAME " module: %d\n", rv);
return rv; return rv;
} }
TRACE((LOGID "init_driver: built %s %s, core = %p\n", __DATE__, __TIME__, g_core)); TRACE("init_driver: built %s %s, core = %p\n", __DATE__, __TIME__, sCore);
// start the network stack! // start the network stack
g_core->start(); sCore->start();
} }
keep_driver_loaded();
return B_OK; return B_OK;
} }
/* uninit_driver() /* uninit_driver()
* called every time the driver is unloaded * called every time the driver is unloaded
*/ */
_EXPORT void uninit_driver(void) _EXPORT void
uninit_driver(void)
{ {
TRACE((LOGID "uninit_driver\n")); TRACE("uninit_driver\n");
if (g_core) { if (sCore) {
// shutdown the network stack // shutdown the network stack
g_core->stop(); sCore->stop();
put_module(NET_CORE_MODULE_NAME); put_module(NET_CORE_MODULE_NAME);
g_core = NULL; sCore = NULL;
} }
} }
/* publish_devices() /* publish_devices()
* called to publish our device. * called to publish our device.
*/ */
_EXPORT const char ** publish_devices() _EXPORT const char**
publish_devices()
{ {
return g_device_names_list; return sDevices;
} }
_EXPORT device_hooks*
_EXPORT device_hooks * find_device(const char* device_name) find_device(const char* device_name)
{ {
return &g_net_stack_driver_hooks; return &sDeviceHooks;
} }
// #pragma mark -
/* /*
* Device hooks * Device hooks
@@ -255,7 +260,8 @@ _EXPORT device_hooks * find_device(const char* device_name)
*/ */
// the network stack functions - mainly just pass throughs... // the network stack functions - mainly just pass throughs...
static status_t net_stack_open(const char *name, uint32 flags, void **cookie) static status_t
net_stack_open(const char *name, uint32 flags, void **cookie)
{ {
net_stack_cookie *nsc; net_stack_cookie *nsc;
@@ -268,33 +274,33 @@ static status_t net_stack_open(const char *name, uint32 flags, void **cookie)
nsc->open_flags = flags; nsc->open_flags = flags;
nsc->selecters_lock = create_sem(1, "socket_selecters_lock"); nsc->selecters_lock = create_sem(1, "socket_selecters_lock");
nsc->selecters = NULL; nsc->selecters = NULL;
nsc->notify = NULL;
// attach this new net_socket_cookie to file descriptor // attach this new net_socket_cookie to file descriptor
*cookie = nsc; *cookie = nsc;
TRACE((LOGID "net_stack_open(%s, %s%s) return this cookie: %p\n", name, TRACE("net_stack_open(%s, %s%s) return this cookie: %p\n",
( ((flags & O_RWMASK) == O_RDONLY) ? "O_RDONLY" : name,
((flags & O_RWMASK) == O_WRONLY) ? "O_WRONLY" : "O_RDWR"), (((flags & O_RWMASK) == O_RDONLY) ? "O_RDONLY" :
(flags & O_NONBLOCK) ? " O_NONBLOCK" : "", ((flags & O_RWMASK) == O_WRONLY) ? "O_WRONLY" : "O_RDWR"),
*cookie)); (flags & O_NONBLOCK) ? " O_NONBLOCK" : "",
*cookie);
return B_OK; return B_OK;
} }
static status_t
static status_t net_stack_close(void *cookie) net_stack_close(void *cookie)
{ {
net_stack_cookie *nsc = cookie; net_stack_cookie *nsc = cookie;
int rv; int rv;
TRACE((LOGID "net_stack_close(%p)\n", nsc)); TRACE("net_stack_close(%p)\n", nsc);
rv = B_ERROR; rv = B_ERROR;
if (nsc->socket) { if (nsc->socket) {
// if a socket was opened on this fd, close it now. // if a socket was opened on this fd, close it now.
rv = g_core->socket_close(nsc->socket); rv = sCore->socket_close(nsc->socket);
nsc->socket = NULL; nsc->socket = NULL;
} }
@@ -302,13 +308,13 @@ static status_t net_stack_close(void *cookie)
} }
static status_t
static status_t net_stack_free_cookie(void *cookie) net_stack_free_cookie(void *cookie)
{ {
net_stack_cookie *nsc = cookie; net_stack_cookie *nsc = cookie;
selecter *s; selecter *s;
TRACE((LOGID "net_stack_free_cookie(%p)\n", cookie)); TRACE("net_stack_free_cookie(%p)\n", cookie);
// free the selecters list // free the selecters list
delete_sem(nsc->selecters_lock); delete_sem(nsc->selecters_lock);
@@ -317,7 +323,7 @@ static status_t net_stack_free_cookie(void *cookie)
selecter *tmp = s; selecter *tmp = s;
s = s->next; s = s->next;
free(tmp); free(tmp);
}; }
// free the cookie // free the cookie
free(cookie); free(cookie);
@@ -325,29 +331,30 @@ static status_t net_stack_free_cookie(void *cookie)
} }
static status_t
static status_t net_stack_control(void *cookie, uint32 op, void *data, size_t len) net_stack_control(void *cookie, uint32 op, void *data, size_t len)
{ {
net_stack_cookie *nsc = cookie; net_stack_cookie *nsc = cookie;
struct stack_driver_args *args = data; struct stack_driver_args *args = data;
int err = B_OK; int err = B_BAD_VALUE;
TRACE((LOGID "net_stack_control(%p, %s (0x%lX), %p, %ld)\n", TRACE("net_stack_control(%p, %s (0x%lX), %p, %ld)\n",
cookie, opcode_name(op), op, data, len)); cookie, opcode_name(op), op, data, len);
#if STAY_LOADED if (!nsc->socket) {
keep_driver_loaded();
#endif
if (! nsc->socket) {
switch (op) { switch (op) {
case NET_STACK_SOCKET: { case NET_STACK_SOCKET: {
// okay, now try to open a real socket behind this fd/net_stack_cookie pair // okay, now try to open a real socket behind this fd/net_stack_cookie pair
err = g_core->socket_init(&nsc->socket); err = sCore->socket_init(&nsc->socket);
if (err == 0) if (err == 0)
err = g_core->socket_create(nsc->socket, args->u.socket.family, args->u.socket.type, args->u.socket.proto); err = sCore->socket_create(nsc->socket, args->u.socket.family,
// TODO: This is where the open flags need to be addressed args->u.socket.type, args->u.socket.proto);
// TODO: handle some more open_flags
if(nsc->open_flags & O_NONBLOCK) {
int on = true;
return sCore->socket_ioctl(nsc->socket, FIONBIO, (caddr_t) &on);
}
return err; return err;
} }
case NET_STACK_GET_COOKIE: { case NET_STACK_GET_COOKIE: {
@@ -360,24 +367,30 @@ static status_t net_stack_control(void *cookie, uint32 op, void *data, size_t le
return B_OK; return B_OK;
} }
case NET_STACK_CONTROL_NET_MODULE: { case NET_STACK_CONTROL_NET_MODULE: {
return g_core->control_net_module(args->u.control.name, args->u.control.op, return sCore->control_net_module(args->u.control.name,
args->u.control.data, args->u.control.length); args->u.control.op, args->u.control.data, args->u.control.length);
} }
}; case NET_STACK_SYSCTL:
return sCore->net_sysctl(args->u.sysctl.name, args->u.sysctl.namelen,
args->u.sysctl.oldp, args->u.sysctl.oldlenp,
args->u.sysctl.newp, args->u.sysctl.newlen);
}
} else { } else {
switch (op) { switch (op) {
case NET_STACK_CONNECT: case NET_STACK_CONNECT:
return g_core->socket_connect(nsc->socket, (caddr_t) args->u.sockaddr.addr, args->u.sockaddr.addrlen); return sCore->socket_connect(nsc->socket,
(caddr_t) args->u.sockaddr.addr, args->u.sockaddr.addrlen);
case NET_STACK_SHUTDOWN: case NET_STACK_SHUTDOWN:
return g_core->socket_shutdown(nsc->socket, args->u.integer); return sCore->socket_shutdown(nsc->socket, args->u.integer);
case NET_STACK_BIND: case NET_STACK_BIND:
return g_core->socket_bind(nsc->socket, (caddr_t) args->u.sockaddr.addr, args->u.sockaddr.addrlen); return sCore->socket_bind(nsc->socket, (caddr_t) args->u.sockaddr.addr,
args->u.sockaddr.addrlen);
case NET_STACK_LISTEN: case NET_STACK_LISTEN:
// backlog to set // backlog to set
return g_core->socket_listen(nsc->socket, args->u.integer); return sCore->socket_listen(nsc->socket, args->u.integer);
case NET_STACK_ACCEPT: { case NET_STACK_ACCEPT: {
/* args->u.accept.cookie == net_stack_cookie of the already opened fd /* args->u.accept.cookie == net_stack_cookie of the already opened fd
@@ -385,22 +398,25 @@ static status_t net_stack_control(void *cookie, uint32 op, void *data, size_t le
*/ */
net_stack_cookie *ansc = args->u.accept.cookie; net_stack_cookie *ansc = args->u.accept.cookie;
return g_core->socket_accept(nsc->socket, &ansc->socket, (void *)args->u.accept.addr, &args->u.accept.addrlen); return sCore->socket_accept(nsc->socket, &ansc->socket,
(void *)args->u.accept.addr, &args->u.accept.addrlen);
} }
case NET_STACK_SEND: case NET_STACK_SEND:
// TODO: flags gets ignored here... // TODO: flags gets ignored here...
return net_stack_write(cookie, 0, args->u.transfer.data, &args->u.transfer.datalen); return net_stack_write(cookie, 0, args->u.transfer.data,
&args->u.transfer.datalen);
case NET_STACK_RECV: case NET_STACK_RECV:
// TODO: flags gets ignored here... // TODO: flags gets ignored here...
return net_stack_read(cookie, 0, args->u.transfer.data, &args->u.transfer.datalen); return net_stack_read(cookie, 0, args->u.transfer.data,
&args->u.transfer.datalen);
case NET_STACK_RECVFROM: { case NET_STACK_RECVFROM: {
struct msghdr * mh = (struct msghdr *) data; struct msghdr * mh = (struct msghdr *) data;
int retsize; int retsize;
err = g_core->socket_recv(nsc->socket, mh, (caddr_t)&mh->msg_namelen, err = sCore->socket_recv(nsc->socket, mh, (caddr_t)&mh->msg_namelen,
&retsize); &retsize);
if (err == 0) if (err == 0)
return retsize; return retsize;
return err; return err;
@@ -409,154 +425,116 @@ static status_t net_stack_control(void *cookie, uint32 op, void *data, size_t le
struct msghdr * mh = (struct msghdr *) data; struct msghdr * mh = (struct msghdr *) data;
int retsize; int retsize;
err = g_core->socket_send(nsc->socket, mh, mh->msg_flags, err = sCore->socket_send(nsc->socket, mh, mh->msg_flags, &retsize);
&retsize);
if (err == 0) if (err == 0)
return retsize; return retsize;
return err; return err;
} }
case NET_STACK_SYSCTL:
return g_core->net_sysctl(args->u.sysctl.name, args->u.sysctl.namelen,
args->u.sysctl.oldp, args->u.sysctl.oldlenp,
args->u.sysctl.newp, args->u.sysctl.newlen);
case NET_STACK_GETSOCKOPT: case NET_STACK_GETSOCKOPT:
return g_core->socket_getsockopt(nsc->socket, args->u.sockopt.level, args->u.sockopt.option, return sCore->socket_getsockopt(nsc->socket, args->u.sockopt.level,
args->u.sockopt.optval, (size_t *) &args->u.sockopt.optlen); args->u.sockopt.option, args->u.sockopt.optval,
(size_t *) &args->u.sockopt.optlen);
case NET_STACK_SETSOCKOPT: case NET_STACK_SETSOCKOPT:
return g_core->socket_setsockopt(nsc->socket, args->u.sockopt.level, args->u.sockopt.option, return sCore->socket_setsockopt(nsc->socket, args->u.sockopt.level,
(const void *) args->u.sockopt.optval, args->u.sockopt.optlen); args->u.sockopt.option, (const void *) args->u.sockopt.optval,
args->u.sockopt.optlen);
case NET_STACK_GETSOCKNAME: case NET_STACK_GETSOCKNAME:
return g_core->socket_getsockname(nsc->socket, args->u.sockaddr.addr, &args->u.sockaddr.addrlen); return sCore->socket_getsockname(nsc->socket, args->u.sockaddr.addr,
&args->u.sockaddr.addrlen);
case NET_STACK_GETPEERNAME: case NET_STACK_GETPEERNAME:
return g_core->socket_getpeername(nsc->socket, args->u.sockaddr.addr, &args->u.sockaddr.addrlen); return sCore->socket_getpeername(nsc->socket, args->u.sockaddr.addr,
&args->u.sockaddr.addrlen);
case NET_STACK_SOCKETPAIR: { case NET_STACK_SOCKETPAIR: {
net_stack_cookie *ansc = args->u.socketpair.cookie; net_stack_cookie *ansc = args->u.socketpair.cookie;
return g_core->socket_socketpair(nsc->socket, &ansc->socket); return sCore->socket_socketpair(nsc->socket, &ansc->socket);
} }
case B_SET_BLOCKING_IO: { case B_SET_BLOCKING_IO: {
int off = false; int off = false;
nsc->open_flags &= ~O_NONBLOCK; nsc->open_flags &= ~O_NONBLOCK;
return g_core->socket_ioctl(nsc->socket, FIONBIO, (caddr_t) &off); return sCore->socket_ioctl(nsc->socket, FIONBIO, (caddr_t) &off);
} }
case B_SET_NONBLOCKING_IO: { case B_SET_NONBLOCKING_IO: {
int on = true; int on = true;
nsc->open_flags |= O_NONBLOCK; nsc->open_flags |= O_NONBLOCK;
return g_core->socket_ioctl(nsc->socket, FIONBIO, (caddr_t) &on); return sCore->socket_ioctl(nsc->socket, FIONBIO, (caddr_t) &on);
} }
case NET_STACK_SELECT:
/* if we get this opcode, we are using the r5 kernel select() call,
* so we can't use his notify_select_event(), but our own implementation! */
nsc->notify = r5_notify_select_event;
return net_stack_select(cookie, (args->u.select.ref & 0x0F),
args->u.select.ref, args->u.select.sync);
case NET_STACK_DESELECT:
return net_stack_deselect(cookie, (args->u.select.ref & 0x0F), args->u.select.sync);
default: default:
if (nsc->socket) return sCore->socket_ioctl(nsc->socket, op, data);
// pass any unhandled opcode to the stack }
return g_core->socket_ioctl(nsc->socket, op, data); }
return B_BAD_VALUE;
};
};
return err; return err;
} }
static status_t
static status_t net_stack_read(void *cookie, net_stack_read(void *cookie, off_t position, void *buffer, size_t *readlen)
off_t position,
void *buffer,
size_t *readlen)
{ {
net_stack_cookie * nsc = (net_stack_cookie *) cookie; net_stack_cookie *nsc = (net_stack_cookie *) cookie;
struct iovec iov; struct iovec iov;
int error; int error;
int flags = 0; int flags = 0;
TRACE((LOGID "net_stack_read(%p, %Ld, %p, %ld)\n", cookie, position, buffer, *readlen)); TRACE("net_stack_read(%p, %Ld, %p, %ld)\n", cookie, position, buffer, *readlen);
#if STAY_LOADED if (!nsc->socket)
TRACE((LOGID "Calling keep_driver_loaded()...\n"));
keep_driver_loaded();
#endif
if (! nsc->socket)
return B_BAD_VALUE; return B_BAD_VALUE;
iov.iov_base = buffer; iov.iov_base = buffer;
iov.iov_len = *readlen; iov.iov_len = *readlen;
error = g_core->socket_readv(nsc->socket, &iov, &flags); error = sCore->socket_readv(nsc->socket, &iov, &flags);
*readlen = error; *readlen = error;
return error; return error;
} }
static status_t
static status_t net_stack_write(void *cookie, net_stack_write(void *cookie, off_t position, const void *buffer, size_t *writelen)
off_t position,
const void *buffer,
size_t *writelen)
{ {
net_stack_cookie * nsc = (net_stack_cookie *) cookie; net_stack_cookie *nsc = (net_stack_cookie *) cookie;
struct iovec iov; struct iovec iov;
int error; int error;
int flags = 0; int flags = 0;
TRACE((LOGID "net_stack_write(%p, %Ld, %p, %ld)\n", cookie, position, buffer, *writelen)); TRACE("net_stack_write(%p, %Ld, %p, %ld)\n", cookie, position, buffer, *writelen);
#if STAY_LOADED
keep_driver_loaded();
#endif
if (! nsc->socket) { if (! nsc->socket) {
#if STAY_LOADED if (*writelen >= strlen(kUnloadCommand)
if (*writelen >= strlen(UNLOAD_CMD) && && strncmp(buffer, kUnloadCommand, strlen(kUnloadCommand)) == 0)
strncmp(buffer, UNLOAD_CMD, strlen(UNLOAD_CMD)) == 0)
// someone write/send/tell us to unload this driver, so do it!
return unload_driver(); return unload_driver();
#endif // we are told to unload this driver
if (*writelen >= strlen(STOP_CMD) &&
strncmp(buffer, STOP_CMD, strlen(STOP_CMD)) == 0)
return g_core->stop();
return B_BAD_VALUE; return B_BAD_VALUE;
}; }
iov.iov_base = (void*)buffer; iov.iov_base = (void*) buffer;
iov.iov_len = *writelen; iov.iov_len = *writelen;
error = g_core->socket_writev(nsc->socket, &iov, flags); error = sCore->socket_writev(nsc->socket, &iov, flags);
*writelen = error; *writelen = error;
return error; return error;
} }
static status_t
static status_t net_stack_select(void *cookie, uint8 event, uint32 ref, selectsync *sync) net_stack_select(void *cookie, uint8 event, uint32 ref, selectsync *sync)
{ {
net_stack_cookie * nsc = (net_stack_cookie *) cookie; net_stack_cookie * nsc = (net_stack_cookie *) cookie;
selecter * s; selecter *s;
status_t status; status_t status;
TRACE((LOGID "net_stack_select(%p, %d, %ld, %p)\n", cookie, event, ref, sync)); TRACE("net_stack_select(%p, %d, %ld, %p)\n", cookie, event, ref, sync);
if (! nsc->socket) if (!nsc->socket)
return B_BAD_VALUE; return B_BAD_VALUE;
// set notification function if undefined
if(nsc->notify == NULL)
nsc->notify = notify_select_event;
s = (selecter *) malloc(sizeof(selecter)); s = (selecter *) malloc(sizeof(selecter));
if (! s) if (! s)
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -565,15 +543,13 @@ static status_t net_stack_select(void *cookie, uint8 event, uint32 ref, selectsy
s->event = event; s->event = event;
s->sync = sync; s->sync = sync;
s->ref = ref; s->ref = ref;
s->notify = nsc->notify;
nsc->notify = NULL;
// lock the selecters list // lock the selecters list
status = acquire_sem(nsc->selecters_lock); status = acquire_sem(nsc->selecters_lock);
if (status != B_OK) { if (status != B_OK) {
free(s); free(s);
return status; return status;
}; }
// add it to selecters list // add it to selecters list
s->next = nsc->selecters; s->next = nsc->selecters;
@@ -583,20 +559,20 @@ static status_t net_stack_select(void *cookie, uint8 event, uint32 ref, selectsy
release_sem(nsc->selecters_lock); release_sem(nsc->selecters_lock);
// start (or continue) to monitor for socket event // start (or continue) to monitor for socket event
return g_core->socket_set_event_callback(nsc->socket, on_socket_event, nsc, event); return sCore->socket_set_event_callback(nsc->socket, on_socket_event, nsc, event);
} }
static status_t
static status_t net_stack_deselect(void *cookie, uint8 event, selectsync *sync) net_stack_deselect(void *cookie, uint8 event, selectsync *sync)
{ {
net_stack_cookie *nsc = (net_stack_cookie *) cookie; net_stack_cookie *nsc = (net_stack_cookie *) cookie;
selecter * previous; selecter *previous;
selecter * s; selecter *s;
thread_id current_thread; thread_id current_thread;
status_t status; status_t status;
TRACE((LOGID "net_stack_deselect(%p, %d, %p)\n", cookie, event, sync)); TRACE("net_stack_deselect(%p, %d, %p)\n", cookie, event, sync);
if (!nsc || !nsc->socket) if (!nsc || !nsc->socket)
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -618,7 +594,7 @@ static status_t net_stack_deselect(void *cookie, uint8 event, selectsync *sync)
previous = s; previous = s;
s = s->next; s = s->next;
}; }
if (s != NULL) { if (s != NULL) {
// remove it from selecters list // remove it from selecters list
@@ -627,33 +603,33 @@ static status_t net_stack_deselect(void *cookie, uint8 event, selectsync *sync)
else else
nsc->selecters = s->next; nsc->selecters = s->next;
free(s); free(s);
}; }
if (nsc->selecters == NULL) if (nsc->selecters == NULL)
// selecters list is empty: no need to monitor socket events anymore // selecters list is empty: no need to monitor socket events anymore
g_core->socket_set_event_callback(nsc->socket, NULL, NULL, event); sCore->socket_set_event_callback(nsc->socket, NULL, NULL, event);
// unlock the selecters list // unlock the selecters list
return release_sem(nsc->selecters_lock); return release_sem(nsc->selecters_lock);
} }
// #pragma mark - static void
on_socket_event(void * socket, uint32 event, void *cookie)
static void on_socket_event(void * socket, uint32 event, void * cookie)
{ {
net_stack_cookie * nsc = (net_stack_cookie *) cookie; net_stack_cookie *nsc = (net_stack_cookie *) cookie;
selecter * s; selecter *s;
if (!nsc) if (!nsc)
return; return;
if (nsc->socket != socket) { if (nsc->socket != socket) {
TRACE((LOGID ERR "on_socket_event(%p, %ld, %p): socket is higly suspect! Aborting.\n", socket, event, cookie)); ERROR("on_socket_event(%p, %ld, %p): socket is higly suspect! Aborting.\n",
socket, event, cookie);
return; return;
} }
TRACE((LOGID "on_socket_event(%p, %ld, %p)\n", socket, event, cookie)); TRACE("on_socket_event(%p, %ld, %p)\n", socket, event, cookie);
// lock the selecters list // lock the selecters list
if (acquire_sem(nsc->selecters_lock) != B_OK) if (acquire_sem(nsc->selecters_lock) != B_OK)
@@ -664,115 +640,22 @@ static void on_socket_event(void * socket, uint32 event, void * cookie)
if (s->event == event) if (s->event == event)
// notify this selecter (thread/event pair) // notify this selecter (thread/event pair)
#ifdef COMPILE_FOR_R5 #ifdef COMPILE_FOR_R5
s->notify(s->sync, s->ref); notify_select_event(s->sync, s->ref);
#else #else
s->notify(s->sync, s->ref, event); notify_select_event(s->sync, s->ref, event);
#endif #endif
s = s->next; s = s->next;
}; }
// unlock the selecters list // unlock the selecters list
release_sem(nsc->selecters_lock); release_sem(nsc->selecters_lock);
return; return;
} }
/*
Under vanilla R5, we can't use the kernel notify_select_event(),
as select() kernel implementation is too buggy to be usefull.
So, here is our own notify_select_event() implementation, the driver-side pair
of the our libnet.so select() implementation...
*/
static status_t r5_notify_select_event(selectsync * sync, uint32 ref, uint8 event)
{
area_id area;
struct r5_selectsync * rss;
int fd;
TRACE((LOGID "r5_notify_select_event(%p, %ld, %d)\n", sync, ref, event)); static const char*
opcode_name(int op)
rss = NULL;
area = clone_area("r5_selectsync_area (driver)", (void **) &rss,
B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, (area_id) sync);
if (area < B_OK) {
TRACE((LOGID "r5_notify_select_event: clone_area(%d) failed -> %d!\n", (int) sync, (int) area));
return area;
};
TRACE((LOGID "r5_selectsync at %p (area %ld, clone from %ld):\n"
"lock %ld\n"
"wakeup %ld\n", rss, area, (area_id) sync, rss->lock, rss->wakeup));
if (acquire_sem(rss->lock) != B_OK)
// if we can't (anymore?) lock the shared r5_selectsync, select() party is done
goto error;
fd = ref >> 8;
switch (ref & 0xFF) { // event == ref & 0xFF
case B_SELECT_READ:
FD_SET(fd, &rss->rbits);
break;
case B_SELECT_WRITE:
FD_SET(fd, &rss->wbits);
break;
case B_SELECT_ERROR:
FD_SET(fd, &rss->ebits);
break;
};
// wakeup select()
release_sem(rss->wakeup);
release_sem(rss->lock);
return B_OK;
error:
delete_area(area);
return B_ERROR;
}
// #pragma mark -
#if STAY_LOADED
static status_t keep_driver_loaded()
{
if ( g_stay_loaded_fd != -1 )
return B_OK;
/* force the driver to stay loaded by opening himself */
TRACE((LOGID "keep_driver_loaded: internaly opening " NET_STACK_DRIVER_PATH " to stay loaded in memory...\n"));
g_stay_loaded_fd = open(NET_STACK_DRIVER_PATH, 0);
if (g_stay_loaded_fd < 0)
TRACE((LOGID ERR "keep_driver_loaded: couldn't open(" NET_STACK_DRIVER_PATH ")!\n"));
return B_OK;
}
static status_t unload_driver()
{
if ( g_stay_loaded_fd >= 0 ) {
int tmp_fd;
/* we need to set g_stay_loaded_fd to < 0 if we don't want
* the next close enter again in this case, and so on...
*/
TRACE((LOGID "unload_driver: unload requested.\n"));
tmp_fd = g_stay_loaded_fd;
g_stay_loaded_fd = -1;
close(tmp_fd);
};
return B_OK;
}
#endif /* STAY_LOADED */
static const char * opcode_name(int op)
{ {
#define C2N(op) { op, #op } #define C2N(op) { op, #op }
// op-code to name // op-code to name
@@ -798,7 +681,6 @@ static const char * opcode_name(int op)
C2N(NET_STACK_SELECT), C2N(NET_STACK_SELECT),
C2N(NET_STACK_DESELECT), C2N(NET_STACK_DESELECT),
C2N(NET_STACK_GET_COOKIE), C2N(NET_STACK_GET_COOKIE),
C2N(NET_STACK_STOP),
C2N(NET_STACK_NOTIFY_SOCKET_EVENT), C2N(NET_STACK_NOTIFY_SOCKET_EVENT),
C2N(NET_STACK_CONTROL_NET_MODULE), C2N(NET_STACK_CONTROL_NET_MODULE),
@@ -825,6 +707,3 @@ static const char * opcode_name(int op)
return "???"; return "???";
} }