Okay, I'm starting to feel mad to have both *boring* job days AND no CVS access to OpenBeOS code repository, thanks to my company firewall policy :-( So, let's try to write the longest post on this ML ever... :-) > We can now build ourselves as a kernel driver. [...] > This is the start of allowing ourselves to be very cool and do > all sorts of stuff, as well as simplifying our i/o with regard to > running as a process. developing our own IPC so we could be > running the net stack in one team while other teams used the > services was looking like a PITA and would have been a performance > drag in the extreme. So, the solution? > > Basically we'll build the stack in a series of pieces that live > in the kernel. I can't agree more on this shift of stack design :-) > - socket driver - this will be built mainly from code that is already > in place in net-server/net_server.c, albeit it'll be removed from > there and added to a separate file that will build a simple socket > driver. > This is responsible for creating a /dev/net/socket entry and > handling requests to/from that socket. Hum, nobody want to use my submitted (and commited to CVS) driver net_kit/source/kernel/net_stack_driver.c?! It does exactly what we need: a device driver wrapper between clients (via libnet.so) and our future kernel-living network stack. Just modify the NET_STACK_DRIVER_PATH constant in net_kit/source/server/include/stack_driver.h to let him publish the /dev/net/socket entry instead of /dev/net/stack... What's only missing there is glue code to pass the call he receive to the *core* network stack module. More in this "core network kernel module" point below... > When started for the first time it will load the net-server kernel > module. What about calling it the network stack kernel module(s) now, as the concept of "servers" may being miss-interpreted by [Open]BeOS community members with the well-known userland servers concept? > - kernel modules - these will be everything else. > All the existing modules need to be rewritten to allow them to > be kernel modules and then we need to decide where they should be > installed. I suggest we put them here: /boot/home/config/add-ons/kernel/network/* get_module() and open_module_list() always look for a module_name in this order: /boot/home/config/add-ons/kernel/* /boot/beos/system/add-ons/kernel/* For example, get_module("network/core/v1") will look for a file named /boot/home/config/add-ons/kernel/network /boot/home/config/add-ons/kernel/network/core /boot/home/config/add-ons/kernel/network/core/v1 /boot/beos/system/add-ons/kernel/network /boot/beos/system/add-ons/kernel/network/core /boot/beos/system/add-ons/kernel/network/core/v1 with a "modules" data symbol publishing a "network/core/v1" module_info name. On a side note, this would prevent collision with existing /boot/beos/system/add-ons/kernel/network/* in BONE-based BeOS systems, too: as all BONE modules are named bone_xxxx, we should not encounter module name collision problem until we don't prefix our modules "bone_*". We can also create sub-directories for specific network sub-modules type (interface, protocol, framing, whatever). BTW, I doubt we could have the same module interface (public functions) for all of our modules types (protocols, interfaces, core module). > - What functions do we need in the core module? Basically what do we want > to export and how does the socket driver talk to the core module? > We need ioctl for sure as that's how most of the functions work, and > we'll need an init/uninit (or do we want to call it start/stop) but > can anyone think of other things we need? Here come my so-called "core network kernel module" point: The /dev/net/socket device driver don't need to do more than simply load the network/core kernel module at init_driver() time, pass each call he receive on any socket to corresponding functions exported by the core module and unload the core module at uninit_driver() time (which would do nothing, as the core module will ask to be keep loaded via the B_KEEP_LOADED module_info flag. The *link* between the driver and the core module would be a opaque thing, which I've called a net_endpoint pointer in my current net_kit/source/kernel/net_stack_driver.c implementation: ---- network_core_module.h ---- // Definition of the public interface // exported by the network core kernel module #define NETWORK_CORE_MODULE_NAME "network/core" typedef struct network_core_module_info { struct module_info info; // /dev/net/socket driver <-> network core module glue functions status_t (*endpoint)(net_endpoint ** ne, int family, int type, int protocol); status_t (*open)(net_endpoint * ne); status_t (*close)(net_endpoint * ne); status_t (*free)(net_endpoint * ne); status_t (*read)(net_endpoint * ne, off_t pos, void *data, size_t *len); status_t (*write)(net_endpoint * ne, off_t pos, void *data, size_t *len); status_t (*readv)(net_endpoint * ne, off_t pos, iovec *vec, size_t nb, size_t *len); status_t (*writev)(net_endpoint * ne, off_t pos, iovec *vec, size_t nb, size_t *len); status_t (*control)(net_endpoint * ne, uint32 code, void *data, size_t len); // BSD sockets api int (*connect)(net_endpoint * ne, struct sockaddr * addr, int addr_len); int (*shutdown)(net_endpoint * ne, int direction); int (*bind)(net_endpoint * ne, struct sockaddr * addr, int addr_len); int (*listen)(net_endpoint * ne, int backlog); int (*accept)(net_endpoint * ne, net_endpoint ** ne, struct sockaddr * addr, int * addr_len); int (*send)(net_endpoint * ne, void * data, size_t len, int flags); int (*sendto)(net_endpoint * ne, void * data, size_t len, int flags, struct sockaddr * addr, int addr_len); int (*recv)(net_endpoint * ne, void * data, size_t len, int flags); int (*recvfrom)(net_endpoint * ne, void * data, size_t datalen, int flags, struct sockaddr * addr, int *addr_len); int (*getpeername)(net_endpoint * ne, struct sockaddr * addr, int * addr_len); int (*getsockname)(net_endpoint * ne, struct sockaddr *addr, int * addr_len); int (*getsockopt)(net_endpoint * ne, int level, int option, void * optval, int * optlen); int (*setsockopt)(net_endpoint * ne, int level, int option, void * optval, int optlen); } network_core_module_info; ---- network_core_module.c ---- // TODO: :-p // glue each core module public functions to current net_srv implementation status_t endpoint(net_endpoint ** ne, int family, int type, int protocol) { struct sock_fd * sfd; if (*ne == NULL) { sfd = make_sock_fd(); if (! sfd) return B_NO_MEMORY; *ne = sfd; return B_OK; }; sfd = (struct sock_fd *) *ne; // now set to this previously created sock_fd family, type and protocol... ... return B_OK; } status_t free(net_endpoint * ne) { release_sock_fd((struct sock_fd *) ne); return B_OK; } ... ---- net_kit/source/kernel/net_stack_driver.c ---- static network_core_module_info * g_net_core = NULL; _EXPORT status_t init_driver(void) { status_t status; status = get_module(NETWORK_CORE_MODULE_NAME, (module_info **) &g_net_core); if ( status != B_OK ) { dprintf(LOGID ERR "Argh! Can't load network core module: %s\n", strerror(status)); return status; }; return B_OK; } _EXPORT void uninit_driver(void) { put_module(NETWORK_CORE_MODULE_NAME); } static status_t device_open(const char * name, uint32 flags, void ** cookie) { net_endpoint * ep; status_t status; ep = NULL; // ask network core module for a new, untyped endpoint status = g_net_core->endpoint(&ep, 0, 0, 0); if (status != B_OK || ep == NULL) return status; // attach this net_endpoint to file descriptor cookie *cookie = ep; return B_OK; } static status_t device_close(void * cookie) { // notify the network core module that this endpoint is closing... return g_net_core->close((net_endpoint *) cookie); } static status_t device_free(void * cookie) { return g_net_core->free((net_endpoint *) cookie); } static status_t device_control(void * cookie, uint32 op, void * data, size_t len) { net_endpoint * ep = (net_endpoint *) cookie; switch (op) { case NET_STACK_SOCKET: { socket_ioctl * ctl = (socket_ioctl *) data; // thos time, ask network core module to init our endpoint return g_net_core->endpoint(&ep, ctl->family, ctl->type, ctl->proto); }; case NET_STACK_SHUTDOWN: { int_ioctl * ctl = (int_ioctl *) data; return g_net_core->shutdown(ep, ctl->value); }; case NET_STACK_CONNECT: { sockaddr_ioctl * ctl = (sockaddr_ioctl *) data; return g_net_core->connect(ep, ctl->addr, ctl->len); }; case ... default: return g_net_core->control(ep, op, data, len); }; return B_UNSUPPORTED; } static status_t device_read(void * cookie, off_t pos, void * data, size_t * len) { return g_net_core->read((net_endpoint *) cookie, pos, data, len); } [...] Same idea for all device driver hooks: pass them to the corresponding network core module calls... This way, we isolate the device driver code from the network core module one, the net_endpoint * doing the media between the two. For the driver, it's an opaque thing, for the network core module, it could be a struct socket *. In this pseudo-code, I use the struct sock_fd * because I can directly use the struct socket *, as for one to be valid socreate() require that the family/type/protocol are valid, which I haven't in my endpoint() code. Or did I miss a create_uninited_socket_struct() somewhere? But using the sock_fd structure add a useless layer, as the devfs already handle the file descriptor <-> socket pairing for us, with the help of /dev/net/socket driver "cookies"... With this mechanism, no need to work on the driver code ever. ;-) > Todo > > Well, the above really! First things to be done I think are as follows... > 1. create the new socket driver and get it working. > 2. get the core code we have working as a kernel module > 3. start getting the other modules working as kernel modules and > figure out where to install them Absolutly. Points 1 & 2: I can write a network core module skeleton tonigh if you like, but as I'm not yet fluent with the current BSD-based net_kit/source/server/* code, I'm not sure I can, well, glue all together to make the stack really works... not in that short time. :-( For point 3, I guess the ethernet module is first candidate. We'll have to define the network kernel sub-modules interface. As I've previously write, I doubt we can have a generic interface for all kind of network sub-module. For example, interface sub-modules would have some up(), down(), input() and output() but no resolve()/lookup(). For protocol sub-modules, up() and down() don't mean anything... well > get ready for some nasty debugging experience and dig out the old > serial dbeugging cable as this is a truly useful tool to use. Hey, there is a another way: http://www.betips.net/chunga.php?ID=540 Hint: sometimes, tail -f block forever, you don't see any new message, when in fact there is. Just stop it and re-run. -Philippe