* Removed the old net_stack driver code, and the kernel socket interface.

* Also removed the header files that belong to those files.
* Only kept the userland_ipc.h header for now, to remember us about the
  former userland server driver (that I also removed - it can always be
  resurrected from SVN if needed).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25045 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-04-19 12:42:25 +00:00
parent 88321c8cd5
commit 45e95a057f
10 changed files with 1 additions and 2158 deletions
build/jam
headers
src/add-ons/kernel

@ -373,8 +373,7 @@ AddSymlinkToHaikuImage beos system add-ons Tracker
AddFilesToHaikuImage beos system add-ons input_server devices
: <input>keyboard <input>mouse <input>wacom ;
AddFilesToHaikuImage beos system add-ons input_server filters : screen_saver ;
AddFilesToHaikuImage beos system add-ons kernel network
: stack socket ;
AddFilesToHaikuImage beos system add-ons kernel network : stack ;
AddFilesToHaikuImage beos system add-ons kernel network devices
: $(BEOS_NETWORK_DEVICES) ;
AddFilesToHaikuImage beos system add-ons kernel network datalink_protocols

@ -1,43 +0,0 @@
/* Copyright 2007, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _SOCKET_INTERFACE_H
#define _SOCKET_INTERFACE_H
//! Kernel interface to the socket API
#include <module.h>
#include <sys/socket.h>
#define B_SOCKET_MODULE_NAME "network/socket/v1"
struct socket_module_info {
struct module_info info;
int (*accept)(int socket, struct sockaddr *address, socklen_t *_addressLength);
int (*bind)(int socket, const struct sockaddr *address, socklen_t addressLength);
int (*connect)(int socket, const struct sockaddr *address, socklen_t addressLength);
int (*getpeername)(int socket, struct sockaddr *address, socklen_t *_addressLength);
int (*getsockname)(int socket, struct sockaddr *address, socklen_t *_addressLength);
int (*getsockopt)(int socket, int level, int option, void *value, socklen_t *_length);
int (*listen)(int socket, int backlog);
ssize_t (*recv)(int socket, void *buffer, size_t length, int flags);
ssize_t (*recvfrom)(int socket, void *buffer, size_t bufferLength, int flags,
struct sockaddr *address, socklen_t *_addressLength);
ssize_t (*recvmsg)(int socket, struct msghdr *message, int flags);
ssize_t (*send)(int socket, const void *buffer, size_t length, int flags);
ssize_t (*sendmsg)(int socket, const struct msghdr *message, int flags);
ssize_t (*sendto)(int socket, const void *message, size_t length, int flags,
const struct sockaddr *address, socklen_t addressLength);
int (*setsockopt)(int socket, int level, int option, const void *value,
socklen_t length);
int (*shutdown)(int socket, int how);
int (*socket)(int domain, int type, int protocol);
int (*sockatmark)(int socket);
int (*socketpair)(int domain, int type, int protocol, int socketVector[2]);
};
#endif // _SOCKET_INTERFACE_H

@ -1,97 +0,0 @@
/*
* Copyright 2002-2006, Haiku, Inc. All Rights Reserved.
* This file may be used under the terms of the MIT License.
*/
#ifndef NET_STACK_DRIVER_H
#define NET_STACK_DRIVER_H
#include <net_stat.h>
#include <sys/select.h>
// Forward declaration
struct sockaddr;
#define NET_STACK_DRIVER_DEVICE "net/stack"
#define NET_STACK_DRIVER_PATH "/dev/" NET_STACK_DRIVER_DEVICE
enum {
NET_STACK_IOCTL_BASE = 8800,
NET_STACK_IOCTL_END = 8999,
// ops not acting on an existing socket
NET_STACK_SOCKET = NET_STACK_IOCTL_BASE, // socket_args *
NET_STACK_GET_COOKIE, // void **
NET_STACK_CONTROL_NET_MODULE, // control_net_module_args *
NET_STACK_GET_NEXT_STAT, // get_next_stat_args *
// ops acting on an existing socket
NET_STACK_BIND, // sockaddr_args *
NET_STACK_RECEIVE, // message_args *
NET_STACK_SEND, // message_args *
NET_STACK_LISTEN, // int_args * (value = backlog)
NET_STACK_ACCEPT, // sockaddr_args *
NET_STACK_CONNECT, // sockaddr_args *
NET_STACK_SHUTDOWN, // int_args * (value = how)
NET_STACK_GETSOCKOPT, // sockopt_args *
NET_STACK_SETSOCKOPT, // sockopt_args *
NET_STACK_GETSOCKNAME, // sockaddr_args *
NET_STACK_GETPEERNAME, // sockaddr_args *
NET_STACK_SOCKETPAIR, // socketpair_args *
NET_STACK_NOTIFY_SOCKET_EVENT, // notify_socket_event_args * (userland stack only)
NET_STACK_IOCTL_MAX
};
struct sockaddr_args { // used by NET_STACK_CONNECT/_BIND/_GETSOCKNAME/_GETPEERNAME
struct sockaddr *address;
socklen_t address_length;
};
struct sockopt_args { // used by NET_STACK_SETSOCKOPT/_GETSOCKOPT
int level;
int option;
void *value;
int length;
};
struct message_args {
struct msghdr *header;
void *data;
size_t length;
int flags;
};
struct socket_args { // used by NET_STACK_SOCKET
int family;
int type;
int protocol;
};
struct socketpair_args { // used by NET_STACK_SOCKETPAIR
int second_socket;
};
struct accept_args { // used by NET_STACK_ACCEPT
int accept_socket;
struct sockaddr *address;
socklen_t address_length;
};
struct get_next_stat_args { // used by NET_STACK_GET_NEXT_STAT
uint32 cookie;
int family;
struct net_stat stat;
};
struct control_net_module_args { // used by NET_STACK_CONTROL_NET_MODULE
const char *name;
uint32 op;
void *data;
size_t length;
};
#endif /* NET_STACK_DRIVER_H */

@ -7,7 +7,6 @@ SubInclude HAIKU_TOP src add-ons kernel drivers network pegasus ;
SubInclude HAIKU_TOP src add-ons kernel drivers network rtl8139 ;
SubInclude HAIKU_TOP src add-ons kernel drivers network rtl8169 ;
SubInclude HAIKU_TOP src add-ons kernel drivers network sis900 ;
SubInclude HAIKU_TOP src add-ons kernel drivers network stack ;
SubInclude HAIKU_TOP src add-ons kernel drivers network via_rhine ;
SubInclude HAIKU_TOP src add-ons kernel drivers network vlance ;
SubInclude HAIKU_TOP src add-ons kernel drivers network wb840 ;

@ -1,55 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel drivers network stack ;
SetSubDirSupportedPlatformsBeOSCompatible ;
if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) {
UseHeaders [ FStandardOSHeaders ] : true ;
# Needed for <drivers/Select.h> and maybe other stuff.
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
# We need the public network headers also when not compiling for Haiku.
# Unfortunately we get more than we want, namely all POSIX headers.
}
UsePrivateHeaders kernel net ;
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
# a) Userland stack version:
KernelAddon userland_net_server :
userland_server.cpp
;
# b) Kernelland stack version:
KernelAddon net_stack :
kernel_stack.cpp
;
# Installation
HaikuInstall install-networking : /boot/home/config/add-ons/kernel/drivers/bin :
userland_net_server
net_stack
;
HaikuInstallRelSymLink install-networking : /boot/home/config/add-ons/kernel/drivers/dev/net :
<installed>userland_net_server
<installed>net_stack :
installed-symlink
;
HaikuInstall install-userland-networking : /boot/home/config/add-ons/kernel/drivers/bin :
userland_net_server :
installed-userland-networking
;
HaikuInstallRelSymLink install-userland-networking : /boot/home/config/add-ons/kernel/drivers/dev/net :
<installed-userland-networking>userland_net_server :
installed-userland-networking-symlink
;
Package haiku-networkingkit-cvs :
net_stack userland_net_server :
boot home config add-ons kernel drivers bin ;
PackageDriverSymLink haiku-networkingkit-cvs : net net_stack ;
PackageDriverSymLink haiku-networkingkit-cvs : net userland_net_server ;

@ -1,746 +0,0 @@
/*
* Copyright 2002-2008, Haiku, Inc. All Rights Reserved.
* This file may be used under the terms of the MIT License.
*/
/*!
This file implements a very simple socket driver that is intended to
act as an interface to the networking stack.
*/
#include <net_stack_driver.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <driver_settings.h>
#include <Drivers.h>
#include <KernelExport.h>
#include <fs/fd.h>
#include <kernel.h>
#include <syscall_restart.h>
#include <net_socket.h>
#define NET_STARTER_MODULE_NAME "network/stack/starter/v1"
// debugging macros
#define LOGID "net_stack_driver: "
#define ERROR(format, args...) dprintf(LOGID "ERROR: " format, ## args)
#ifdef DEBUG
# define TRACE(format, args...) dprintf(format, ## args)
#else
# define TRACE(format, args...)
#endif
// the cookie we attach to each file descriptor opened on our driver entry
struct net_stack_cookie {
net_socket *socket;
// is set using NET_STACK_SOCKET/_ACCEPT
};
int32 api_version = B_CUR_DRIVER_API_VERSION;
static int32 sOpenCount = 0;
static status_t sInitializationStatus = B_NO_INIT;
static sem_id sInitializationSem;
static struct net_socket_module_info *sSocket = NULL;
// #pragma mark - internal functions
template<typename ArgType> status_t
return_address(ArgType &args, void *data)
{
sockaddr_storage *target;
socklen_t length;
if (user_memcpy(&target, &((ArgType *)data)->address, sizeof(void *))
< B_OK
|| user_memcpy(&length, &((ArgType *)data)->address_length,
sizeof(socklen_t)) < B_OK)
return B_BAD_ADDRESS;
if (target == NULL)
return B_OK;
if (user_memcpy(&((ArgType *)data)->address_length, &args.address_length,
sizeof(socklen_t)) < B_OK
|| user_memcpy(target, args.address, min_c(length, args.address_length))
< B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
template<typename ArgType> status_t
check_args_and_address(ArgType &args, sockaddr_storage &address, void *data,
size_t length, bool copyAddress = true)
{
if (data == NULL || length != sizeof(ArgType))
return B_BAD_VALUE;
if (user_memcpy(&args, data, sizeof(ArgType)) < B_OK)
return B_BAD_ADDRESS;
if (copyAddress && args.address_length > sizeof(sockaddr_storage))
return B_BAD_VALUE;
if (copyAddress
&& user_memcpy(&address, args.address, args.address_length) < B_OK)
return B_BAD_ADDRESS;
args.address = (sockaddr *)&address;
return B_OK;
}
static status_t
check_message_args(message_args &args, msghdr &header,
sockaddr_storage &address, void *data, size_t length,
sockaddr **originalAddress)
{
if (length < sizeof(message_args))
return B_BAD_VALUE;
status_t status = user_memcpy(&args, data, sizeof(message_args));
if (status < B_OK)
return status;
if (args.header != NULL) {
status = user_memcpy(&header, args.header, sizeof(msghdr));
if (status < B_OK)
return status;
if (header.msg_name == NULL)
return B_OK;
if (originalAddress == NULL) {
if (header.msg_namelen > sizeof(address))
return B_BAD_VALUE;
if (header.msg_name != NULL) {
status = user_memcpy(&address, header.msg_name,
header.msg_namelen);
if (status < B_OK)
return B_BAD_ADDRESS;
}
} else {
*originalAddress = (sockaddr *)header.msg_name;
}
header.msg_name = (char *)&address;
}
return B_OK;
}
template<typename ArgType> status_t
check_args(ArgType &args, void *data, size_t length)
{
if (data == NULL || length != sizeof(ArgType))
return B_BAD_VALUE;
if (user_memcpy(&args, data, sizeof(ArgType)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
#ifdef DEBUG
static const char*
opcode_name(int op)
{
#define C2N(op) { op, #op }
// op-code to name
struct commands_info {
int op;
const char *name;
} *ci, commands_info[] = {
C2N(NET_STACK_SOCKET),
C2N(NET_STACK_GET_COOKIE),
C2N(NET_STACK_CONTROL_NET_MODULE),
C2N(NET_STACK_GET_NEXT_STAT),
C2N(NET_STACK_BIND),
C2N(NET_STACK_RECEIVE),
C2N(NET_STACK_SEND),
C2N(NET_STACK_LISTEN),
C2N(NET_STACK_ACCEPT),
C2N(NET_STACK_CONNECT),
C2N(NET_STACK_SHUTDOWN),
C2N(NET_STACK_GETSOCKOPT),
C2N(NET_STACK_SETSOCKOPT),
C2N(NET_STACK_GETSOCKNAME),
C2N(NET_STACK_GETPEERNAME),
C2N(NET_STACK_SOCKETPAIR),
C2N(NET_STACK_NOTIFY_SOCKET_EVENT),
// Userland IPC-specific opcodes
// C2N(NET_STACK_OPEN),
// C2N(NET_STACK_CLOSE),
// C2N(NET_STACK_NEW_CONNECTION),
// Standard BeOS opcodes
C2N(FIONBIO),
C2N(B_SET_BLOCKING_IO),
C2N(B_SET_NONBLOCKING_IO),
{ 0, "Unknown!" }
};
#undef C2N
ci = commands_info;
while(ci && ci->op) {
if (ci->op == op)
return ci->name;
ci++;
}
return "???";
}
#endif // DEBUG
static status_t
resolve_cookie(int kernel, int socket, net_stack_cookie **cookie)
{
if (kernel)
return ioctl(socket, NET_STACK_GET_COOKIE, cookie, sizeof(*cookie));
return user_fd_kernel_ioctl(socket, NET_STACK_GET_COOKIE, cookie,
sizeof(*cookie));
}
// #pragma mark - device
static status_t
net_stack_open(const char *name, uint32 flags, void **_cookie)
{
if (atomic_add(&sOpenCount, 1) == 0) {
// When we're opened for the first time, we'll try to load the
// networking stack
module_info *module;
status_t status = get_module(NET_STARTER_MODULE_NAME, &module);
if (status == B_OK) {
status = get_module(NET_SOCKET_MODULE_NAME,
(module_info **)&sSocket);
if (status != B_OK) {
put_module(NET_STARTER_MODULE_NAME);
ERROR("Can't load " NET_SOCKET_MODULE_NAME " module: %ld\n",
status);
}
} else
ERROR("Can't load network stack module: %ld\n", status);
sInitializationStatus = status;
release_sem_etc(sInitializationSem, 1,
B_RELEASE_ALL | B_DO_NOT_RESCHEDULE);
if (status < B_OK) {
atomic_add(&sOpenCount, -1);
return status;
}
} else {
while (sInitializationStatus == B_NO_INIT) {
acquire_sem(sInitializationSem);
}
if (sInitializationStatus != B_OK) {
atomic_add(&sOpenCount, -1);
return sInitializationStatus;
}
}
net_stack_cookie *cookie = (net_stack_cookie *)malloc(
sizeof(net_stack_cookie));
if (cookie == NULL)
return B_NO_MEMORY;
cookie->socket = NULL;
*_cookie = 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)
{
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
TRACE("net_stack_close(%p)\n", cookie);
if (cookie->socket == NULL)
return B_OK;
return sSocket->close(cookie->socket);
}
static status_t
net_stack_free_cookie(void *_cookie)
{
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
TRACE("net_stack_free_cookie(%p)\n", cookie);
if (cookie->socket != NULL)
sSocket->free(cookie->socket);
free(cookie);
if (atomic_add(&sOpenCount, -1) == 1) {
// the last reference to us has been removed, unload the networking
// stack again (it will only be actually unloaded in case there is
// no interface defined)
put_module(NET_SOCKET_MODULE_NAME);
put_module(NET_STARTER_MODULE_NAME);
sInitializationStatus = B_NO_INIT;
}
return B_OK;
}
static status_t
net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
{
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
status_t status;
TRACE("net_stack_control(%p, %s (0x%lX), %p, %ld)\n",
_cookie, opcode_name(op), op, data, length);
if (cookie->socket == NULL) {
switch (op) {
case NET_STACK_SOCKET:
{
socket_args args;
status = check_args(args, data, length);
if (status < B_OK)
return status;
return sSocket->open_socket(args.family, args.type,
args.protocol, &cookie->socket);
}
case NET_STACK_GET_COOKIE:
if (!IS_KERNEL_ADDRESS(data))
return B_BAD_ADDRESS;
*((net_stack_cookie **)data) = cookie;
return B_OK;
case NET_STACK_GET_NEXT_STAT:
{
get_next_stat_args args;
status = check_args(args, data, length);
if (status < B_OK)
return status;
status = sSocket->get_next_stat(&args.cookie, args.family,
&args.stat);
if (status < B_OK)
return status;
return user_memcpy(data, &args, sizeof(get_next_stat_args));
}
default:
return B_BAD_VALUE;
}
} else {
switch (op) {
case NET_STACK_CONNECT:
{
sockaddr_storage address;
sockaddr_args args;
status = check_args_and_address(args, address, data, length);
if (status < B_OK)
return status;
status = sSocket->connect(cookie->socket, args.address,
args.address_length);
return syscall_restart_ioctl_handle_post(status);
}
case NET_STACK_BIND:
{
sockaddr_storage address;
sockaddr_args args;
status = check_args_and_address(args, address, data, length);
if (status < B_OK)
return status;
return sSocket->bind(cookie->socket, args.address,
args.address_length);
}
case NET_STACK_LISTEN:
// backlog to set
return sSocket->listen(cookie->socket, (int)data);
case NET_STACK_ACCEPT:
{
int kernel = IS_KERNEL_ADDRESS(data);
sockaddr_storage address;
accept_args args;
status = check_args_and_address(args, address, data, length,
false);
if (status < B_OK)
return status;
net_stack_cookie *acceptCookie;
status = resolve_cookie(kernel, args.accept_socket,
&acceptCookie);
if (status < B_OK)
return status;
status = sSocket->accept(cookie->socket, args.address,
&args.address_length, &acceptCookie->socket);
if (status < B_OK)
return syscall_restart_ioctl_handle_post(status);
return return_address(args, data);
}
case NET_STACK_SHUTDOWN:
return sSocket->shutdown(cookie->socket, (int)data);
case NET_STACK_SEND:
{
sockaddr_storage address;
message_args args;
msghdr header;
status = check_message_args(args, header, address, data,
length, NULL);
if (status < B_OK)
return status;
ssize_t bytesSent = sSocket->send(cookie->socket,
args.header ? &header : NULL,
args.data, args.length, args.flags);
return syscall_restart_ioctl_handle_post(bytesSent);
}
case NET_STACK_RECEIVE:
{
sockaddr *originalAddress = NULL;
sockaddr_storage address;
message_args args;
msghdr header;
status = check_message_args(args, header, address, data,
length, &originalAddress);
if (status < B_OK)
return status;
ssize_t bytesRead = sSocket->receive(cookie->socket,
args.header ? &header : NULL, args.data,
args.length, args.flags);
if (bytesRead < B_OK)
return syscall_restart_ioctl_handle_post(bytesRead);
if (args.header != NULL) {
if (header.msg_name != NULL) {
if (user_memcpy(originalAddress, header.msg_name,
header.msg_namelen) < B_OK)
return B_BAD_ADDRESS;
}
if (user_memcpy(&args.header->msg_flags, &header.msg_flags,
sizeof(int)) < B_OK)
return B_BAD_ADDRESS;
}
return bytesRead;
}
case NET_STACK_GETSOCKOPT:
{
sockopt_args args;
status = check_args(args, data, length);
if (status < B_OK)
return status;
char valueBuffer[256];
if (args.length > (int)sizeof(valueBuffer))
return ENOBUFS;
status = sSocket->getsockopt(cookie->socket, args.level,
args.option, valueBuffer, &args.length);
if (status < B_OK)
return status;
if (user_memcpy(args.value, valueBuffer, args.length) < B_OK
|| user_memcpy(&((sockopt_args *)data)->length,
&args.length, sizeof(int)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
case NET_STACK_SETSOCKOPT:
{
sockopt_args args;
status = check_args(args, data, length);
if (status < B_OK)
return status;
char valueBuffer[256];
if (args.length > (int)sizeof(valueBuffer))
return ENOBUFS;
if (user_memcpy(valueBuffer, args.value, args.length) < B_OK)
return B_BAD_ADDRESS;
return sSocket->setsockopt(cookie->socket, args.level,
args.option, valueBuffer, args.length);
}
case NET_STACK_GETSOCKNAME:
{
sockaddr_storage address;
sockaddr_args args;
status = check_args_and_address(args, address, data, length,
false);
if (status < B_OK)
return status;
status = sSocket->getsockname(cookie->socket, args.address,
&args.address_length);
if (status < B_OK)
return status;
return return_address(args, data);
}
case NET_STACK_GETPEERNAME:
{
sockaddr_storage address;
sockaddr_args args;
status = check_args_and_address(args, address, data, length,
false);
if (status < B_OK)
return status;
status = sSocket->getpeername(cookie->socket, args.address,
&args.address_length);
if (status < B_OK)
return status;
return return_address(args, data);
}
case FIONBIO:
{
int value = (int)data;
return sSocket->setsockopt(cookie->socket, SOL_SOCKET,
SO_NONBLOCK, &value, sizeof(int));
}
case B_SET_BLOCKING_IO:
case B_SET_NONBLOCKING_IO:
{
int value = op == B_SET_NONBLOCKING_IO;
return sSocket->setsockopt(cookie->socket, SOL_SOCKET,
SO_NONBLOCK, &value, sizeof(int));
}
default:
if (op < NET_STACK_IOCTL_BASE || op > NET_STACK_IOCTL_END) {
// we only accept networking ioctl()s to get into our stack
return B_BAD_VALUE;
}
return sSocket->control(cookie->socket, op, data, length);
}
}
return B_BAD_VALUE;
}
static status_t
net_stack_read(void *_cookie, off_t /*offset*/, void *buffer, size_t *_length)
{
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
TRACE("net_stack_read(%p, %p, %ld)\n", cookie, buffer, *_length);
if (cookie->socket == NULL)
return B_BAD_VALUE;
ssize_t bytesRead = sSocket->receive(cookie->socket, NULL, buffer, *_length,
0);
if (bytesRead < 0) {
*_length = 0;
return bytesRead;
}
*_length = bytesRead;
return B_OK;
}
static status_t
net_stack_readv(void *_cookie, off_t /*offset*/, const struct iovec *vecs,
size_t count, size_t *_length)
{
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
TRACE("net_stack_readv(%p, (%p, %lu), %ld)\n", cookie, vecs, count, *_length);
if (cookie->socket == NULL)
return B_BAD_VALUE;
return sSocket->readv(cookie->socket, vecs, count, _length);
}
static status_t
net_stack_write(void *_cookie, off_t /*offset*/, const void *buffer,
size_t *_length)
{
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
TRACE("net_stack_write(%p, %p, %ld)\n", cookie, buffer, *_length);
if (cookie->socket == NULL)
return B_BAD_VALUE;
ssize_t bytesWritten = sSocket->send(cookie->socket, NULL, buffer, *_length,
0);
if (bytesWritten < 0) {
*_length = 0;
return bytesWritten;
}
*_length = bytesWritten;
return B_OK;
}
static status_t
net_stack_writev(void *_cookie, off_t /*offset*/, const struct iovec *vecs,
size_t count, size_t *_length)
{
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
TRACE("net_stack_writev(%p, (%p, %lu), %ld)\n", cookie, vecs, count, *_length);
if (cookie->socket == NULL)
return B_BAD_VALUE;
return sSocket->writev(cookie->socket, vecs, count, _length);
}
static status_t
net_stack_select(void *_cookie, uint8 event, uint32 ref, selectsync *sync)
{
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
TRACE("net_stack_select(%p, %d, %ld, %p)\n", cookie, event, ref, sync);
if (cookie->socket == NULL)
return B_BAD_VALUE;
return sSocket->request_notification(cookie->socket, event, ref, sync);
}
static status_t
net_stack_deselect(void *_cookie, uint8 event, selectsync *sync)
{
net_stack_cookie *cookie = (net_stack_cookie *)_cookie;
TRACE("net_stack_deselect(%p, %d, %p)\n", cookie, event, sync);
if (cookie->socket == NULL)
return B_BAD_VALUE;
return sSocket->cancel_notification(cookie->socket, event, sync);
}
// #pragma mark - driver
status_t
init_hardware(void)
{
return B_OK;
}
status_t
init_driver(void)
{
sInitializationSem = create_sem(1, "net stack init");
if (sInitializationSem < B_OK)
return sInitializationSem;
sInitializationStatus = B_NO_INIT;
return B_OK;
}
void
uninit_driver(void)
{
delete_sem(sInitializationSem);
}
const char **
publish_devices(void)
{
static const char *devices[] = {
NET_STACK_DRIVER_DEVICE,
NULL
};
return devices;
}
device_hooks*
find_device(const char* device_name)
{
static device_hooks hooks = {
net_stack_open,
net_stack_close,
net_stack_free_cookie,
net_stack_control,
net_stack_read,
net_stack_write,
net_stack_select,
net_stack_deselect,
net_stack_readv,
net_stack_writev,
};
return &hooks;
}

@ -1,834 +0,0 @@
/*
* Copyright 2002-2006, Haiku, Inc. All Rights Reserved.
* This file may be used under the terms of the MIT License.
*/
/*!
This file implements a very simple socket driver
that is intended to act as an interface to the networking stack when
it is loaded in userland, hosted by a net_server-like app.
The communication is slow, and could probably be much better, but it's
working, and that should be enough for now.
*/
#ifndef _KERNEL_MODE
# error "This module MUST be built as a kernel driver!"
#endif
#include <net_stack_driver.h>
#include <userland_ipc.h>
#include <sys/sockio.h>
#include <Drivers.h>
#include <KernelExport.h>
#include <driver_settings.h>
#include <netinet/in_var.h>
#include <stdlib.h>
#include <string.h>
#define DEBUG_PREFIX "userland_net_server: "
#define __out dprintf
#define DEBUG 1
#ifdef DEBUG
#define PRINT(x) { __out(DEBUG_PREFIX); __out x; }
#define REPORT_ERROR(status) __out(DEBUG_PREFIX "%s:%ld: %s\n",__FUNCTION__,__LINE__,strerror(status));
#define RETURN_ERROR(err) { status_t _status = err; if (_status < B_OK) REPORT_ERROR(_status); return _status;}
#define FATAL(x) { __out(DEBUG_PREFIX); __out x; }
#define INFORM(x) { __out(DEBUG_PREFIX); __out x; }
#define FUNCTION() __out(DEBUG_PREFIX "%s()\n",__FUNCTION__);
#define FUNCTION_START(x) { __out(DEBUG_PREFIX "%s() ",__FUNCTION__); __out x; }
// #define FUNCTION() ;
// #define FUNCTION_START(x) ;
#define D(x) {x;};
#else
#define PRINT(x) ;
#define REPORT_ERROR(status) ;
#define RETURN_ERROR(status) return status;
#define FATAL(x) { __out(DEBUG_PREFIX); __out x; }
#define INFORM(x) { __out(DEBUG_PREFIX); __out x; }
#define FUNCTION() ;
#define FUNCTION_START(x) ;
#define D(x) ;
#endif
#define NET_SERVER_DRIVER_DEV "net/userland_server"
/* wait one second when waiting on the stack */
#define STACK_TIMEOUT 1000000LL
#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
// 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;
} selecter;
// the cookie we attach to each file descriptor opened on our driver entry
typedef struct {
port_id local_port;
port_id remote_port;
area_id area;
thread_id socket_thread;
sem_id command_sem;
net_command *commands;
int32 command_index;
int32 nb_commands;
sem_id selecters_lock; // protect the selecters linked-list
selecter * selecters; // the select()'ers lists (thread-aware)
} net_server_cookie;
/* device hooks */
static status_t net_server_open(const char *name, uint32 flags, void **cookie);
static status_t net_server_close(void *cookie);
static status_t net_server_free_cookie(void *cookie);
static status_t net_server_control(void *cookie, uint32 msg, void *data, size_t datalen);
static status_t net_server_read(void *cookie, off_t pos, void *data, size_t *datalen);
static status_t net_server_write(void *cookie, off_t pos, const void *data, size_t *datalen);
static status_t net_server_select(void *cookie, uint8 event, uint32 ref, selectsync *sync);
static status_t net_server_deselect(void *cookie, uint8 event, selectsync *sync);
/* select() support */
static int32 socket_event_listener(void *data);
static void on_socket_event(void *socket, uint32 event, void *cookie);
static status_t r5_notify_select_event(selectsync *sync, uint32 ref, uint8 event);
/* command queue */
static status_t init_connection(void **cookie);
static void shutdown_connection(net_server_cookie *nsc);
static net_command *get_command(net_server_cookie *nsc, int32 *index);
static status_t execute_command(net_server_cookie *nsc, uint32 op, void *data, uint32 length);
int32 api_version = B_CUR_DRIVER_API_VERSION;
// by default, assert we can use kernel select() support
notify_select_event_function g_nse = notify_select_event;
thread_id sSocketEventThread = -1;
port_id sSocketEventPort = -1;
static port_id sUserlandPort = -1;
// #pragma mark - driver
status_t
init_hardware(void)
{
return B_OK;
}
status_t
init_driver(void)
{
thread_id thread;
port_id port;
FUNCTION();
port = create_port(32, "socket_event_listener");
if (port < B_OK)
return port;
set_port_owner(port, B_SYSTEM_TEAM);
thread = spawn_kernel_thread(socket_event_listener, "socket_event_listener",
B_NORMAL_PRIORITY, NULL);
if (thread < B_OK) {
delete_port(port);
return thread;
}
sSocketEventThread = thread;
sSocketEventPort = port;
return resume_thread(thread);
}
void
uninit_driver(void)
{
FUNCTION();
delete_port(sSocketEventPort);
status_t dummy;
wait_for_thread(sSocketEventThread, &dummy);
}
const char **
publish_devices(void)
{
FUNCTION();
static const char *deviceNames[] = {
"net/userland_server",
NULL
};
return deviceNames;
}
device_hooks *
find_device(const char *deviceName)
{
FUNCTION();
device_hooks hooks = {
net_server_open,
net_server_close,
net_server_free_cookie,
net_server_control,
net_server_read,
net_server_write,
net_server_select,
net_server_deselect,
NULL,
NULL
};
return &hooks;
}
// #pragma mark -
//*****************************************************/
// Device hooks
//*****************************************************/
static status_t
net_server_open(const char *name, uint32 flags, void **cookie)
{
net_server_cookie *nsc;
status_t status = init_connection(cookie);
if (status < B_OK)
return status;
nsc = *cookie;
status = execute_command(nsc, NET_STACK_OPEN, &flags, sizeof(uint32));
if (status < B_OK)
net_server_free_cookie(nsc);
return status;
}
static status_t
net_server_close(void *cookie)
{
net_server_cookie *nsc = cookie;
if (nsc == NULL)
return B_BAD_VALUE;
// we don't care here if the stack isn't alive anymore -
// from the kernel's point of view, the device can always
// be closed
execute_command(nsc, NET_STACK_CLOSE, NULL, 0);
return B_OK;
}
static status_t
net_server_free_cookie(void *cookie)
{
net_server_cookie *nsc = cookie;
if (nsc == NULL)
return B_BAD_VALUE;
shutdown_connection(nsc);
return B_OK;
}
static status_t
net_server_control(void *cookie, uint32 op, void *data, size_t length)
{
net_server_cookie *nsc = cookie;
struct stack_driver_args *args = data;
//FUNCTION_START(("cookie = %p, op = %lx, data = %p, length = %ld\n", cookie, op, data, length));
if (nsc == NULL)
return B_BAD_VALUE;
switch (op) {
case NET_STACK_SELECT:
// if we get this call via ioctl() we are obviously called from an
// R5 compatible libnet: we are using the r5 kernel select() call,
// So, we can't use the kernel notify_select_event(), but our own implementation!
g_nse = r5_notify_select_event;
return net_server_select(cookie, (args->u.select.ref & 0x0F), args->u.select.ref, args->u.select.sync);
case NET_STACK_DESELECT:
return net_server_deselect(cookie, (args->u.select.ref & 0x0F), args->u.select.sync);
default:
return execute_command(nsc, op, data, -1);
};
}
static status_t
net_server_read(void *cookie, off_t pos, void *buffer, size_t *length)
{
net_server_cookie *nsc = cookie;
struct stack_driver_args args;
int status;
memset(&args, 0, sizeof(args));
args.u.transfer.data = buffer;
args.u.transfer.datalen = *length;
status = execute_command(nsc, NET_STACK_RECV, &args, sizeof(args));
if (status > 0) {
*length = status;
return B_OK;
}
return status;
}
static status_t
net_server_write(void *cookie, off_t pos, const void *buffer, size_t *length)
{
net_server_cookie *nsc = cookie;
struct stack_driver_args args;
int status;
memset(&args, 0, sizeof(args));
args.u.transfer.data = (void *) buffer;
args.u.transfer.datalen = *length;
status = execute_command(nsc, NET_STACK_SEND, &args, sizeof(args));
if (status > 0) {
*length = status;
return B_OK;
}
return status;
}
static status_t
net_server_select(void *cookie, uint8 event, uint32 ref, selectsync *sync)
{
net_server_cookie *nsc = cookie;
struct notify_socket_event_args args;
selecter *s;
status_t status;
FUNCTION_START(("cookie = %p, event = %d, ref = %lx, sync =%p\n", cookie, event, ref, sync));
s = (selecter *) malloc(sizeof(selecter));
if (!s)
return B_NO_MEMORY;
// lock the selecters list
status = acquire_sem(nsc->selecters_lock);
if (status != B_OK) {
free(s);
return status;
};
s->thread = find_thread(NULL); // current thread id
s->event = event;
s->sync = sync;
s->ref = ref;
// add it to selecters list
s->next = nsc->selecters;
nsc->selecters = s;
// unlock the selecters list
release_sem(nsc->selecters_lock);
// Tell the net_server to notify event(s) for this socket
memset(&args, 0, sizeof(args));
args.notify_port = sSocketEventPort;
args.cookie = cookie;;
return execute_command(nsc, NET_STACK_NOTIFY_SOCKET_EVENT, &args, sizeof(args));
}
static status_t
net_server_deselect(void *cookie, uint8 event, selectsync *sync)
{
net_server_cookie *nsc = cookie;
selecter *previous;
selecter *s;
thread_id current_thread;
status_t status;
FUNCTION_START(("cookie = %p, event = %d, sync =%p\n", cookie, event, sync));
if (!nsc)
return B_BAD_VALUE;
current_thread = find_thread(NULL);
// lock the selecters list
status = acquire_sem(nsc->selecters_lock);
if (status != B_OK)
return status;
previous = NULL;
s = nsc->selecters;
while (s) {
if (s->thread == current_thread &&
s->event == event && s->sync == sync)
// selecter found!
break;
previous = s;
s = s->next;
};
if (s != NULL) {
// remove it from selecters list
if (previous)
previous->next = s->next;
else
nsc->selecters = s->next;
free(s);
};
status = B_OK;
if (nsc->selecters == NULL) {
struct notify_socket_event_args args;
// Selecters list is empty: no need to monitor socket events anymore
// Tell the net_server to stop notifying event(s) for this socket
memset(&args, 0, sizeof(args));
args.notify_port = -1; // stop notifying
args.cookie = cookie; // for sanity check
status = execute_command(nsc, NET_STACK_NOTIFY_SOCKET_EVENT, &args, sizeof(args));
};
// unlock the selecters list
release_sem(nsc->selecters_lock);
return status;
}
// #pragma mark -
//*****************************************************/
// select() support
//*****************************************************/
/*
This is started as separate thread at init_driver() time to wait for
socket event notification.
One port to listen them all.
One port to find them.
One port to get them and in [r5_]notify_select_event() send them.
Okay, I should stop watch this movie *now*.
*/
static int32 socket_event_listener(void *data)
{
struct socket_event_data sed;
int32 msg;
ssize_t bytes;
while(true) {
bytes = read_port(sSocketEventPort, &msg, &sed, sizeof(sed));
if (bytes < B_OK)
return bytes;
if (msg == NET_STACK_SOCKET_EVENT_NOTIFICATION)
// yep, we pass a NULL "socket" pointer here, but don't worry, we don't use anyway
on_socket_event(NULL, sed.event, sed.cookie);
};
return 0;
}
static void on_socket_event(void *socket, uint32 event, void *cookie)
{
net_server_cookie *nsc = cookie;
selecter *s;
if (!nsc)
return;
FUNCTION_START(("socket = %p, event = %ld, cookie = %p\n", socket, event, cookie));
// lock the selecters list
if (acquire_sem(nsc->selecters_lock) != B_OK)
return;
s = nsc->selecters;
while (s) {
if (s->event == event)
// notify this selecter (thread/event pair)
#ifdef COMPILE_FOR_R5
g_nse(s->sync, s->ref);
#else
g_nse(s->sync, s->ref, (uint8) 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;
FUNCTION_START(("sync = %p, ref = %lx\n", sync, ref));
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) {
#if SHOW_INSANE_DEBUGGING
dprintf(LOGID "r5_notify_select_event: clone_area(%d) failed -> %d!\n", (area_id) sync, area);
#endif
return area;
};
#if SHOW_INSANE_DEBUGGING
dprintf(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);
#endif
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);
error:
delete_area(area);
return B_ERROR;
}
// #pragma mark -
//*****************************************************/
// The Command Queue
//*****************************************************/
static net_command *
get_command(net_server_cookie *nsc, int32 *index)
{
int32 i, count = 0;
net_command *command;
while (count < nsc->nb_commands*2) {
i = atomic_add(&nsc->command_index,1) & (nsc->nb_commands - 1);
command = nsc->commands + i;
if (command->op == 0) {
// command is free to use
*index = i;
return command;
}
count++;
}
return NULL;
}
static status_t
get_area_from_address(net_area_info *info, void *data)
{
area_info areaInfo;
if (data == NULL)
return B_OK;
info->id = area_for(data);
if (info->id < B_OK)
return info->id;
if (get_area_info(info->id,&areaInfo) != B_OK)
return B_BAD_VALUE;
info->offset = areaInfo.address;
return B_OK;
}
static void
set_command_areas(net_command *command)
{
struct stack_driver_args *args = (void *) command->data;
if (args == NULL)
return;
if (get_area_from_address(&command->area[0], args) < B_OK)
return;
switch (command->op) {
case NET_STACK_GETSOCKOPT:
case NET_STACK_SETSOCKOPT:
get_area_from_address(&command->area[1], args->u.sockopt.optval);
break;
case NET_STACK_CONNECT:
case NET_STACK_BIND:
case NET_STACK_GETSOCKNAME:
case NET_STACK_GETPEERNAME:
get_area_from_address(&command->area[1], args->u.sockaddr.addr);
break;
case NET_STACK_RECV:
case NET_STACK_SEND:
get_area_from_address(&command->area[1], args->u.transfer.data);
get_area_from_address(&command->area[2], args->u.transfer.addr);
break;
case NET_STACK_RECVFROM:
case NET_STACK_SENDTO: {
struct msghdr *mh = (void *) args;
get_area_from_address(&command->area[1],mh->msg_name);
get_area_from_address(&command->area[2],mh->msg_iov);
get_area_from_address(&command->area[3],mh->msg_control);
break;
}
case NET_STACK_ACCEPT:
/* accept_args.cookie is always in the address space of the server */
get_area_from_address(&command->area[1], args->u.accept.addr);
break;
case NET_STACK_SYSCTL:
get_area_from_address(&command->area[1], args->u.sysctl.name);
get_area_from_address(&command->area[2], args->u.sysctl.oldp);
get_area_from_address(&command->area[3], args->u.sysctl.oldlenp);
get_area_from_address(&command->area[4], args->u.sysctl.newp);
break;
case NET_STACK_CONTROL_NET_MODULE:
// TODO!
break;
case OSIOCGIFCONF:
case SIOCGIFCONF: {
struct ifconf *ifc = (void *) args;
get_area_from_address(&command->area[1], ifc->ifc_buf);
break;
}
}
}
static status_t
execute_command(net_server_cookie *nsc, uint32 op, void *data, uint32 length)
{
uint32 command_index;
net_command *command = get_command(nsc, (long *) &command_index);
int32 max_tries = 200;
status_t status;
ssize_t bytes;
if (command == NULL) {
FATAL(("execute: command queue is full\n"));
return B_ERROR;
}
memset(command, 0, sizeof(net_command));
command->op = op;
command->data = data;
set_command_areas(command);
bytes = write_port(nsc->remote_port, command_index, NULL, 0);
if (bytes < B_OK) {
FATAL(("execute %ld: couldn't contact stack (id = %ld): %s\n",op, nsc->remote_port, strerror(bytes)));
return bytes;
}
// if we're closing the connection, there is no need to
// wait for a result
if (op == NET_STACK_CLOSE)
return B_OK;
while (true) {
// wait until we get the results back from our command
if ((status = acquire_sem_etc(nsc->command_sem, 1, B_CAN_INTERRUPT, 0)) == B_OK) {
if (command->op != 0) {
if (--max_tries <= 0) {
FATAL(("command is not freed after 200 tries!\n"));
return B_ERROR;
}
release_sem(nsc->command_sem);
continue;
}
return command->result;
}
FATAL(("command couldn't be executed: %s\n", strerror(status)));
if (status == B_INTERRUPTED)
// Signaling our net_server counterpart, so his socket thread awake too...
send_signal_etc(nsc->socket_thread, SIGINT, 0);
return status;
}
}
static status_t
init_connection(void **cookie)
{
net_connection connection;
ssize_t bytes;
uint32 msg;
net_server_cookie *nsc = (net_server_cookie *) malloc(sizeof(net_server_cookie));
if (nsc == NULL)
return B_NO_MEMORY;
// create a new port and get a connection from the stack
nsc->local_port = create_port(CONNECTION_QUEUE_LENGTH, "net_driver connection");
if (nsc->local_port < B_OK) {
FATAL(("open: couldn't create port: %s\n", strerror(nsc->local_port)));
free(cookie);
return B_ERROR;
}
set_port_owner(nsc->local_port, B_SYSTEM_TEAM);
bytes = write_port(sUserlandPort, NET_STACK_NEW_CONNECTION, &nsc->local_port, sizeof(port_id));
if (bytes == B_BAD_PORT_ID) {
sUserlandPort = find_port(NET_STACK_PORTNAME);
PRINT(("try to get net_server's port id: %ld\n", sUserlandPort));
bytes = write_port(sUserlandPort, NET_STACK_NEW_CONNECTION, &nsc->local_port, sizeof(port_id));
}
if (bytes < B_OK) {
FATAL(("open: couldn't contact stack: %s\n",strerror(bytes)));
delete_port(nsc->local_port);
free(nsc);
return bytes;
}
bytes = read_port_etc(nsc->local_port, &msg, &connection, sizeof(net_connection), B_TIMEOUT,STACK_TIMEOUT);
if (bytes < B_OK) {
FATAL(("open: didn't hear back from stack: %s\n",strerror(bytes)));
delete_port(nsc->local_port);
free(nsc);
return bytes;
}
if (msg != NET_STACK_NEW_CONNECTION) {
FATAL(("open: received wrong answer: %ld\n",msg));
delete_port(nsc->local_port);
free(nsc);
return B_ERROR;
}
// set up communication channels
// ToDo: close server connection if anything fails
// -> could also be done by the server, if it doesn't receive NET_STACK_OPEN
nsc->remote_port = connection.port;
nsc->command_sem = connection.commandSemaphore;
nsc->area = clone_area("net connection buffer", (void **) &nsc->commands,
B_CLONE_ADDRESS, B_READ_AREA | B_WRITE_AREA, connection.area);
if (nsc->area < B_OK) {
status_t err;
FATAL(("couldn't clone command queue: %s\n", strerror(nsc->area)));
err = nsc->area;
delete_port(nsc->local_port);
free(nsc);
return err;
}
nsc->socket_thread = connection.socket_thread;
nsc->nb_commands = connection.numCommands;
nsc->command_index = 0;
nsc->selecters = NULL;
nsc->selecters_lock = create_sem(1, "socket_selecters_lock");
if (nsc->selecters_lock < B_OK) {
status_t err;
FATAL(("couldn't create socket_selecters_lock semaphore: %s\n", strerror(nsc->selecters_lock)));
err = nsc->selecters_lock;
delete_port(nsc->local_port);
delete_area(nsc->area);
free(nsc);
return err;
}
*cookie = nsc;
return B_OK;
}
static void
shutdown_connection(net_server_cookie *nsc)
{
selecter *s;
delete_area(nsc->area);
delete_port(nsc->local_port);
// free the selecters list
delete_sem(nsc->selecters_lock);
s = nsc->selecters;
while (s) {
selecter * tmp = s;
s = s->next;
free(tmp);
};
free(nsc);
}

@ -3,5 +3,4 @@ SubDir HAIKU_TOP src add-ons kernel network ;
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ;
SubInclude HAIKU_TOP src add-ons kernel network devices ;
SubInclude HAIKU_TOP src add-ons kernel network protocols ;
SubInclude HAIKU_TOP src add-ons kernel network socket ;
SubInclude HAIKU_TOP src add-ons kernel network stack ;

@ -1,8 +0,0 @@
SubDir HAIKU_TOP src add-ons kernel network socket ;
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
UsePrivateHeaders net ;
KernelAddon socket :
socket.cpp
;

@ -1,371 +0,0 @@
/*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
*/
/*!
The kernel socket API directly forwards all requests into the stack
via the networking stack driver.
*/
#include <socket_interface.h>
#include <net_stack_driver.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
int
socket(int family, int type, int protocol)
{
int socket = open(NET_STACK_DRIVER_PATH, O_RDWR);
if (socket < 0)
return -1;
socket_args args;
args.family = family;
args.type = type;
args.protocol = protocol;
if (ioctl(socket, NET_STACK_SOCKET, &args, sizeof(args)) < 0) {
close(socket);
return -1;
}
return socket;
}
int
bind(int socket, const struct sockaddr *address, socklen_t addressLength)
{
sockaddr_args args;
args.address = const_cast<struct sockaddr *>(address);
args.address_length = addressLength;
return ioctl(socket, NET_STACK_BIND, &args, sizeof(args));
}
int
shutdown(int socket, int how)
{
return ioctl(socket, NET_STACK_SHUTDOWN, (void *)how, 0);
}
int
connect(int socket, const struct sockaddr *address, socklen_t addressLength)
{
sockaddr_args args;
args.address = const_cast<struct sockaddr *>(address);
args.address_length = addressLength;
return ioctl(socket, NET_STACK_CONNECT, &args, sizeof(args));
}
int
listen(int socket, int backlog)
{
return ioctl(socket, NET_STACK_LISTEN, (void *)backlog, 0);
}
int
accept(int socket, struct sockaddr *address, socklen_t *_addressLength)
{
int acceptSocket = open(NET_STACK_DRIVER_PATH, O_RDWR);
if (acceptSocket < 0)
return -1;
accept_args args;
args.accept_socket = acceptSocket;
args.address = address;
args.address_length = _addressLength ? *_addressLength : 0;
if (ioctl(socket, NET_STACK_ACCEPT, &args, sizeof(args)) < 0) {
close(acceptSocket);
return -1;
}
if (_addressLength != NULL)
*_addressLength = args.address_length;
return acceptSocket;
}
ssize_t
recv(int socket, void *data, size_t length, int flags)
{
message_args args;
args.data = data;
args.length = length;
args.flags = flags;
args.header = NULL;
return ioctl(socket, NET_STACK_RECEIVE, &args, sizeof(args));
}
ssize_t
recvfrom(int socket, void *data, size_t length, int flags,
struct sockaddr *address, socklen_t *_addressLength)
{
message_args args;
msghdr header;
memset(&header, 0, sizeof(header));
args.data = data;
args.length = length;
args.flags = flags;
args.header = &header;
header.msg_name = (char *)address;
header.msg_namelen = _addressLength ? *_addressLength : 0;
ssize_t bytesReceived = ioctl(socket, NET_STACK_RECEIVE, &args, sizeof(args));
if (bytesReceived < 0)
return -1;
if (_addressLength != NULL)
*_addressLength = header.msg_namelen;
return bytesReceived;
}
ssize_t
recvmsg(int socket, struct msghdr *message, int flags)
{
message_args args;
if (message == NULL || (message->msg_iovlen > 0 && message->msg_iov == NULL))
return B_BAD_VALUE;
args.header = message;
args.flags = flags;
if (message->msg_iovlen > 0) {
args.data = message->msg_iov[0].iov_base;
args.length = message->msg_iov[0].iov_len;
} else {
args.data = NULL;
args.length = 0;
}
return ioctl(socket, NET_STACK_RECEIVE, &args, sizeof(args));
}
ssize_t
send(int socket, const void *data, size_t length, int flags)
{
message_args args;
args.data = const_cast<void *>(data);
args.length = length;
args.flags = flags;
args.header = NULL;
return ioctl(socket, NET_STACK_SEND, &args, sizeof(args));
}
ssize_t
sendto(int socket, const void *data, size_t length, int flags,
const struct sockaddr *address, socklen_t addressLength)
{
message_args args;
msghdr header;
memset(&header, 0, sizeof(header));
args.data = const_cast<void *>(data);
args.length = length;
args.flags = flags;
args.header = &header;
header.msg_name = (char *)const_cast<sockaddr *>(address);
header.msg_namelen = addressLength;
return ioctl(socket, NET_STACK_SEND, &args, sizeof(args));
}
ssize_t
sendmsg(int socket, const struct msghdr *message, int flags)
{
message_args args;
if (message == NULL || (message->msg_iovlen > 0 && message->msg_iov == NULL))
return B_BAD_VALUE;
args.header = (msghdr *)message;
args.flags = flags;
if (message->msg_iovlen > 0) {
args.data = message->msg_iov[0].iov_base;
args.length = message->msg_iov[0].iov_len;
} else {
args.data = NULL;
args.length = 0;
}
return ioctl(socket, NET_STACK_SEND, &args, sizeof(args));
}
int
getsockopt(int socket, int level, int option, void *value, socklen_t *_length)
{
sockopt_args args;
args.level = level;
args.option = option;
args.value = value;
args.length = _length ? *_length : 0;
if (ioctl(socket, NET_STACK_GETSOCKOPT, &args, sizeof(args)) < 0)
return -1;
if (_length)
*_length = args.length;
return 0;
}
int
setsockopt(int socket, int level, int option, const void *value, socklen_t length)
{
sockopt_args args;
args.level = level;
args.option = option;
args.value = const_cast<void *>(value);
args.length = length;
return ioctl(socket, NET_STACK_SETSOCKOPT, &args, sizeof(args));
}
int
getpeername(int socket, struct sockaddr *address, socklen_t *_addressLength)
{
sockaddr_args args;
args.address = address;
args.address_length = _addressLength ? *_addressLength : 0;
if (ioctl(socket, NET_STACK_GETPEERNAME, &args, sizeof(args)) < 0)
return -1;
if (_addressLength != NULL)
*_addressLength = args.address_length;
return 0;
}
int
getsockname(int socket, struct sockaddr *address, socklen_t *_addressLength)
{
sockaddr_args args;
args.address = address;
args.address_length = _addressLength ? *_addressLength : 0;
if (ioctl(socket, NET_STACK_GETSOCKNAME, &args, sizeof(args)) < 0)
return -1;
if (_addressLength != NULL)
*_addressLength = args.address_length;
return 0;
}
int
sockatmark(int socket)
{
// TODO: implement me!
return -1;
}
int
socketpair(int family, int type, int protocol, int socketVector[2])
{
socketVector[0] = socket(family, type, protocol);
if (socketVector[0] < 0)
return -1;
socketVector[1] = socket(family, type, protocol);
if (socketVector[1] < 0)
goto err1;
socketpair_args args;
args.second_socket = socketVector[1];
if (ioctl(socketVector[0], NET_STACK_SOCKETPAIR, &args, sizeof(args)) < 0)
goto err2;
return 0;
err2:
close(socketVector[1]);
err1:
close(socketVector[0]);
return -1;
}
// #pragma mark -
static status_t
std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
default:
return B_ERROR;
}
}
static socket_module_info sSocketModule = {
{
B_SOCKET_MODULE_NAME,
0,
std_ops
},
accept,
bind,
connect,
getpeername,
getsockname,
getsockopt,
listen,
recv,
recvfrom,
recvmsg,
send,
sendmsg,
sendto,
setsockopt,
shutdown,
socket,
sockatmark,
socketpair,
};
module_info *modules[] = {
(module_info *)&sSocketModule,
NULL
};