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 ;
if $(TARGET_PLATFORM) != haiku {
if ( $(TARGET_PLATFORM) != haiku ) {
UseHeaders [ FStandardOSHeaders ] : true ;
# Needed for <drivers/Select.h> and maybe other stuff.
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
@@ -11,7 +11,6 @@ if $(TARGET_PLATFORM) != haiku {
}
UsePrivateHeaders net ;
UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared libkernelppp headers ] ;
# a) Userland stack version:
@@ -26,7 +26,6 @@
// Private includes
#include <net_stack_driver.h>
// #include <PPPControl.h> // for NET_STACK_CONTROL_NET_MODULE PPP support...
#include <userland_ipc.h>
#include <sys/sockio.h>
@@ -8,124 +8,88 @@
#error "This module MUST be built as a kernel driver!"
#endif
// Public/system includes
// public/system includes
#include <stdlib.h>
#include <string.h>
#include <drivers/Drivers.h>
#include <drivers/KernelExport.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>
// Private includes
// private includes
#include <net_stack_driver.h>
#include <sys/protosw.h>
#include <core_module.h>
// Trace support
#if defined(DEBUG)
#define TRACE(x) dprintf x
// debugging macros
#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
#define TRACE(x) ;
#define TRACE(format, args...)
#endif
// Force the driver to stay loaded in memory
#define STAY_LOADED 0
/*
* 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 */
// Local definitions
// this struct will store one select() event to monitor per thread
typedef struct selecter {
struct selecter * next;
thread_id thread;
uint32 event;
selectsync * sync;
uint32 ref;
notify_select_event_function notify;
struct selecter *next;
thread_id thread;
uint32 event;
selectsync *sync;
uint32 ref;
} selecter;
// the cookie we attach to each file descriptor opened on our driver entry
typedef struct {
struct socket * socket; // NULL before ioctl(fd, NET_STACK_SOCKET/_ACCEPT)
uint32 open_flags; // the open() flags (mostly for storing O_NONBLOCK mode)
sem_id selecters_lock; // protect the selecters linked-list
selecter * selecters; // the select()'ers lists (thread-aware)
notify_select_event_function notify;
typedef struct net_stack_cookie {
struct socket *socket; // NULL before ioctl(fd, NET_STACK_SOCKET/_ACCEPT)
uint32 open_flags; // the open() flags (mostly for storing O_NONBLOCK mode)
sem_id selecters_lock; // protect the selecters linked-list
selecter *selecters; // the select()'ers lists (thread-aware)
} net_stack_cookie;
#if STAY_LOADED
/* to unload the driver, simply write UNLOAD_CMD to him:
* $ echo stop > /dev/net/stack
* 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...
*/
#define UNLOAD_CMD "unload"
#endif
#define STOP_CMD "stop"
/* To unload this driver execute
* $ echo unload > /dev/net/stack
* As soon as the last app stops using sockets the netstack will be unloaded.
*/
static const char *kUnloadCommand = "unload";
// Prototypes of device hooks functions
static status_t net_stack_open(const char * name, uint32 flags, void ** cookie);
static status_t net_stack_close(void * cookie);
static status_t net_stack_free_cookie(void * cookie);
static status_t net_stack_control(void * cookie, uint32 msg,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);
// prototypes of device hooks functions
static status_t net_stack_open(const char *name, uint32 flags, void **cookie);
static status_t net_stack_close(void *cookie);
static status_t net_stack_free_cookie(void *cookie);
static status_t net_stack_control(void *cookie, uint32 msg, 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_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_writev(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);
// Privates prototypes
static void on_socket_event(void * socket, uint32 event, void * cookie);
static status_t r5_notify_select_event(selectsync * sync, uint32 ref, uint8 event);
// privates prototypes
static void on_socket_event(void *socket, uint32 event, void *cookie);
#if STAY_LOADED
static status_t keep_driver_loaded();
static status_t unload_driver();
#endif
static const char * opcode_name(int op);
static const char *opcode_name(int op);
/*
* Global variables
* ----------------
*/
const char * g_device_names_list[] = {
NET_STACK_DRIVER_DEV,
NULL
};
static const char *sDevices[] = { NET_STACK_DRIVER_DEV, NULL };
device_hooks g_net_stack_driver_hooks =
static device_hooks sDeviceHooks =
{
net_stack_open, /* -> open 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_select, /* -> select entry point */
net_stack_deselect, /* -> deselect entry point */
NULL, /* -> readv entry pint */
NULL /* ->writev entry point */
NULL, /* -> readv entry pint */
NULL /* ->writev entry point */
};
struct core_module_info *g_core = NULL;
static struct core_module_info *sCore = NULL;
#if STAY_LOADED
int g_stay_loaded_fd = -1;
#endif
static int sStayLoadedFD = -1;
// 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
* experience.
*/
_EXPORT status_t init_hardware(void)
_EXPORT status_t
init_hardware(void)
{
bool safemode = false;
void *sfmptr;
@@ -172,17 +175,18 @@ _EXPORT status_t init_hardware(void)
// only use the pointer if it's valid
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);
// now get rid of settings
unload_driver_settings(sfmptr);
}
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;
}
TRACE((LOGID "init_hardware done.\n"));
TRACE("init_hardware done.\n");
return B_OK;
}
@@ -191,63 +195,64 @@ _EXPORT status_t init_hardware(void)
/* init_driver()
* 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
if (!g_core) {
if (!sCore) {
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) {
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;
}
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!
g_core->start();
// start the network stack
sCore->start();
}
keep_driver_loaded();
return B_OK;
}
/* uninit_driver()
* 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
g_core->stop();
sCore->stop();
put_module(NET_CORE_MODULE_NAME);
g_core = NULL;
sCore = NULL;
}
}
/* publish_devices()
* 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 * find_device(const char* device_name)
_EXPORT device_hooks*
find_device(const char* device_name)
{
return &g_net_stack_driver_hooks;
return &sDeviceHooks;
}
// #pragma mark -
/*
* Device hooks
@@ -255,7 +260,8 @@ _EXPORT device_hooks * find_device(const char* device_name)
*/
// 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;
@@ -268,33 +274,33 @@ static status_t net_stack_open(const char *name, uint32 flags, void **cookie)
nsc->open_flags = flags;
nsc->selecters_lock = create_sem(1, "socket_selecters_lock");
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;
TRACE((LOGID "net_stack_open(%s, %s%s) return this cookie: %p\n", name,
( ((flags & O_RWMASK) == O_RDONLY) ? "O_RDONLY" :
((flags & O_RWMASK) == O_WRONLY) ? "O_WRONLY" : "O_RDWR"),
(flags & O_NONBLOCK) ? " O_NONBLOCK" : "",
*cookie));
TRACE("net_stack_open(%s, %s%s) return this cookie: %p\n",
name,
(((flags & O_RWMASK) == O_RDONLY) ? "O_RDONLY" :
((flags & O_RWMASK) == O_WRONLY) ? "O_WRONLY" : "O_RDWR"),
(flags & O_NONBLOCK) ? " O_NONBLOCK" : "",
*cookie);
return B_OK;
}
static status_t net_stack_close(void *cookie)
static status_t
net_stack_close(void *cookie)
{
net_stack_cookie *nsc = cookie;
int rv;
TRACE((LOGID "net_stack_close(%p)\n", nsc));
TRACE("net_stack_close(%p)\n", nsc);
rv = B_ERROR;
if (nsc->socket) {
// 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;
}
@@ -302,13 +308,13 @@ static status_t net_stack_close(void *cookie)
}
static status_t net_stack_free_cookie(void *cookie)
static status_t
net_stack_free_cookie(void *cookie)
{
net_stack_cookie *nsc = cookie;
selecter *s;
TRACE((LOGID "net_stack_free_cookie(%p)\n", cookie));
TRACE("net_stack_free_cookie(%p)\n", cookie);
// free the selecters list
delete_sem(nsc->selecters_lock);
@@ -317,7 +323,7 @@ static status_t net_stack_free_cookie(void *cookie)
selecter *tmp = s;
s = s->next;
free(tmp);
};
}
// free the cookie
free(cookie);
@@ -325,29 +331,30 @@ static status_t net_stack_free_cookie(void *cookie)
}
static status_t net_stack_control(void *cookie, uint32 op, void *data, size_t len)
static status_t
net_stack_control(void *cookie, uint32 op, void *data, size_t len)
{
net_stack_cookie *nsc = cookie;
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",
cookie, opcode_name(op), op, data, len));
TRACE("net_stack_control(%p, %s (0x%lX), %p, %ld)\n",
cookie, opcode_name(op), op, data, len);
#if STAY_LOADED
keep_driver_loaded();
#endif
if (! nsc->socket) {
if (!nsc->socket) {
switch (op) {
case NET_STACK_SOCKET: {
// 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)
err = g_core->socket_create(nsc->socket, args->u.socket.family, args->u.socket.type, args->u.socket.proto);
// TODO: This is where the open flags need to be addressed
err = sCore->socket_create(nsc->socket, args->u.socket.family,
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;
}
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;
}
case NET_STACK_CONTROL_NET_MODULE: {
return g_core->control_net_module(args->u.control.name, args->u.control.op,
args->u.control.data, args->u.control.length);
return sCore->control_net_module(args->u.control.name,
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 {
switch (op) {
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:
return g_core->socket_shutdown(nsc->socket, args->u.integer);
return sCore->socket_shutdown(nsc->socket, args->u.integer);
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:
// 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: {
/* 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;
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:
// 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:
// 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: {
struct msghdr * mh = (struct msghdr *) data;
int retsize;
err = g_core->socket_recv(nsc->socket, mh, (caddr_t)&mh->msg_namelen,
&retsize);
err = sCore->socket_recv(nsc->socket, mh, (caddr_t)&mh->msg_namelen,
&retsize);
if (err == 0)
return retsize;
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;
int retsize;
err = g_core->socket_send(nsc->socket, mh, mh->msg_flags,
&retsize);
err = sCore->socket_send(nsc->socket, mh, mh->msg_flags, &retsize);
if (err == 0)
return retsize;
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:
return g_core->socket_getsockopt(nsc->socket, args->u.sockopt.level, args->u.sockopt.option,
args->u.sockopt.optval, (size_t *) &args->u.sockopt.optlen);
return sCore->socket_getsockopt(nsc->socket, args->u.sockopt.level,
args->u.sockopt.option, args->u.sockopt.optval,
(size_t *) &args->u.sockopt.optlen);
case NET_STACK_SETSOCKOPT:
return g_core->socket_setsockopt(nsc->socket, args->u.sockopt.level, args->u.sockopt.option,
(const void *) args->u.sockopt.optval, args->u.sockopt.optlen);
return sCore->socket_setsockopt(nsc->socket, args->u.sockopt.level,
args->u.sockopt.option, (const void *) args->u.sockopt.optval,
args->u.sockopt.optlen);
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:
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: {
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: {
int off = false;
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: {
int on = true;
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:
if (nsc->socket)
// pass any unhandled opcode to the stack
return g_core->socket_ioctl(nsc->socket, op, data);
return B_BAD_VALUE;
};
};
return sCore->socket_ioctl(nsc->socket, op, data);
}
}
return err;
}
static status_t net_stack_read(void *cookie,
off_t position,
void *buffer,
size_t *readlen)
static status_t
net_stack_read(void *cookie, 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;
int error;
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
TRACE((LOGID "Calling keep_driver_loaded()...\n"));
keep_driver_loaded();
#endif
if (! nsc->socket)
if (!nsc->socket)
return B_BAD_VALUE;
iov.iov_base = buffer;
iov.iov_len = *readlen;
error = g_core->socket_readv(nsc->socket, &iov, &flags);
error = sCore->socket_readv(nsc->socket, &iov, &flags);
*readlen = error;
return error;
return error;
}
static status_t net_stack_write(void *cookie,
off_t position,
const void *buffer,
size_t *writelen)
static status_t
net_stack_write(void *cookie, 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;
int error;
int flags = 0;
TRACE((LOGID "net_stack_write(%p, %Ld, %p, %ld)\n", cookie, position, buffer, *writelen));
#if STAY_LOADED
keep_driver_loaded();
#endif
TRACE("net_stack_write(%p, %Ld, %p, %ld)\n", cookie, position, buffer, *writelen);
if (! nsc->socket) {
#if STAY_LOADED
if (*writelen >= strlen(UNLOAD_CMD) &&
strncmp(buffer, UNLOAD_CMD, strlen(UNLOAD_CMD)) == 0)
// someone write/send/tell us to unload this driver, so do it!
if (*writelen >= strlen(kUnloadCommand)
&& strncmp(buffer, kUnloadCommand, strlen(kUnloadCommand)) == 0)
return unload_driver();
#endif
if (*writelen >= strlen(STOP_CMD) &&
strncmp(buffer, STOP_CMD, strlen(STOP_CMD)) == 0)
return g_core->stop();
// we are told to unload this driver
return B_BAD_VALUE;
};
}
iov.iov_base = (void*)buffer;
iov.iov_base = (void*) buffer;
iov.iov_len = *writelen;
error = g_core->socket_writev(nsc->socket, &iov, flags);
error = sCore->socket_writev(nsc->socket, &iov, flags);
*writelen = error;
return error;
}
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)
{
net_stack_cookie * nsc = (net_stack_cookie *) cookie;
selecter * s;
selecter *s;
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;
// set notification function if undefined
if(nsc->notify == NULL)
nsc->notify = notify_select_event;
s = (selecter *) malloc(sizeof(selecter));
if (! s)
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->sync = sync;
s->ref = ref;
s->notify = nsc->notify;
nsc->notify = NULL;
// lock the selecters list
status = acquire_sem(nsc->selecters_lock);
if (status != B_OK) {
free(s);
return status;
};
}
// add it to selecters list
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);
// 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 net_stack_deselect(void *cookie, uint8 event, selectsync *sync)
static status_t
net_stack_deselect(void *cookie, uint8 event, selectsync *sync)
{
net_stack_cookie *nsc = (net_stack_cookie *) cookie;
selecter * previous;
selecter * s;
selecter *previous;
selecter *s;
thread_id current_thread;
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)
return B_BAD_VALUE;
@@ -618,7 +594,7 @@ static status_t net_stack_deselect(void *cookie, uint8 event, selectsync *sync)
previous = s;
s = s->next;
};
}
if (s != NULL) {
// remove it from selecters list
@@ -627,33 +603,33 @@ static status_t net_stack_deselect(void *cookie, uint8 event, selectsync *sync)
else
nsc->selecters = s->next;
free(s);
};
}
if (nsc->selecters == NULL)
// 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
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;
selecter * s;
net_stack_cookie *nsc = (net_stack_cookie *) cookie;
selecter *s;
if (!nsc)
return;
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;
}
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
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)
// notify this selecter (thread/event pair)
#ifdef COMPILE_FOR_R5
s->notify(s->sync, s->ref);
notify_select_event(s->sync, s->ref);
#else
s->notify(s->sync, s->ref, event);
notify_select_event(s->sync, s->ref, event);
#endif
s = s->next;
};
}
// unlock the selecters list
release_sem(nsc->selecters_lock);
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));
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)
static const char*
opcode_name(int op)
{
#define C2N(op) { op, #op }
// op-code to name
@@ -798,7 +681,6 @@ static const char * opcode_name(int op)
C2N(NET_STACK_SELECT),
C2N(NET_STACK_DESELECT),
C2N(NET_STACK_GET_COOKIE),
C2N(NET_STACK_STOP),
C2N(NET_STACK_NOTIFY_SOCKET_EVENT),
C2N(NET_STACK_CONTROL_NET_MODULE),
@@ -825,6 +707,3 @@ static const char * opcode_name(int op)
return "???";
}