* Removed the "new_stack" test approach; it's no longer useful, and you can
still look for it in the SVN history if you like. * Moved tcp_tester.cpp to its own sub-directory tcp_shell - it doesn't yet build, though (due to recent changes to the stack/TCP implementation). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22631 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
3ee83016ed
commit
fe54eece9d
@ -2,22 +2,6 @@ SubDir HAIKU_TOP src tests kits net ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src tests add-ons kernel file_systems fs_shell ] ;
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols tcp ] ;
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src add-ons kernel network stack ] ;
|
||||
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
||||
UsePrivateHeaders net ;
|
||||
|
||||
# bonefish: Tried to get the first test compiling. It complained about not
|
||||
# being able to find some headers, thus I added the respective include dirs
|
||||
# until it was asking for headers we currently don't have
|
||||
# (sys/select.h, sys/sockio.h).
|
||||
|
||||
#SubDirHdrs [ FDirName $(HAIKU_TOP) headers posix sys ] ;
|
||||
#SubDirHdrs [ FDirName $(HAIKU_TOP) headers posix net ] ;
|
||||
#UsePrivateHeaders kernel ;
|
||||
#UseArchHeaders $(TARGET_ARCH) ;
|
||||
|
||||
SimpleTest udp_client : udp_client.c : $(TARGET_NETWORK_LIBS) ;
|
||||
SimpleTest udp_echo : udp_echo.c : $(TARGET_NETWORK_LIBS) ;
|
||||
SimpleTest udp_server : udp_server.c : $(TARGET_NETWORK_LIBS) ;
|
||||
@ -25,45 +9,9 @@ SimpleTest udp_server : udp_server.c : $(TARGET_NETWORK_LIBS) ;
|
||||
SimpleTest tcp_server : tcp_server.c : $(TARGET_NETWORK_LIBS) ;
|
||||
SimpleTest tcp_client : tcp_client.c : $(TARGET_NETWORK_LIBS) ;
|
||||
|
||||
SimpleTest tcp_tester :
|
||||
tcp_tester.cpp
|
||||
|
||||
# stack
|
||||
net_buffer.cpp
|
||||
utility.cpp
|
||||
|
||||
# tcp
|
||||
tcp.cpp
|
||||
TCPEndpoint.cpp
|
||||
BufferQueue.cpp
|
||||
EndpointManager.cpp
|
||||
|
||||
# misc
|
||||
argv.c
|
||||
ipv4_address.cpp
|
||||
|
||||
: be libkernelland_emu.so
|
||||
;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
tcp.cpp TCPEndpoint.cpp BufferQueue.cpp EndpointManager.cpp
|
||||
] = [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols tcp ] ;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
ipv4_address.cpp
|
||||
] = [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols ipv4 ] ;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
net_buffer.cpp utility.cpp
|
||||
] = [ FDirName $(HAIKU_TOP) src add-ons kernel network stack ] ;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
argv.c
|
||||
] = [ FDirName $(HAIKU_TOP) src tests add-ons kernel file_systems fs_shell ] ;
|
||||
|
||||
SubInclude HAIKU_TOP src tests kits net DialUpPreflet ;
|
||||
SubInclude HAIKU_TOP src tests kits net multicast ;
|
||||
SubInclude HAIKU_TOP src tests kits net netperf ;
|
||||
# SubInclude HAIKU_TOP src tests kits net new_stack ;
|
||||
SubInclude HAIKU_TOP src tests kits net preflet ;
|
||||
SubInclude HAIKU_TOP src tests kits net tcp_shell ;
|
||||
SubInclude HAIKU_TOP src tests kits net tcptester ;
|
||||
|
@ -1,52 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net new_stack headers ] ;
|
||||
|
||||
SimpleTest new_stack_tester :
|
||||
net_stack_server.cpp
|
||||
userland_modules.cpp
|
||||
: be
|
||||
;
|
||||
|
||||
{
|
||||
# symlink the userland add-ons dir to the dir where the net_stack_tester
|
||||
# lives
|
||||
local dir = [ on new_stack_tester return $(LOCATE) ] ;
|
||||
# TODO: We don't have a "distro" tree (including the add-on dir) anymore.
|
||||
# MakeLocate <network_v2-add-ons>userland : $(HAIKU_ADDON_DIR) ;
|
||||
# MakeLocate <network_v2-add-ons>add-ons : $(dir) ;
|
||||
# RelSymLink <network_v2-add-ons>add-ons : <network_v2-add-ons>userland : false ;
|
||||
|
||||
# alias for the stack_tester the modules link against
|
||||
LOCATE on <installed>new_stack_tester = $(dir) ;
|
||||
# Depends <installed>new_stack_tester : <network_v2-add-ons>add-ons ;
|
||||
}
|
||||
|
||||
# for convenience: this target builds all userland new_stack modules
|
||||
NotFile userland_network_v2_modules ;
|
||||
Depends userland_network_v2_modules :
|
||||
# the main stack modules
|
||||
<v2>stack
|
||||
<userland>memory_pool
|
||||
<userland>atomizer
|
||||
|
||||
# framing modules
|
||||
<v2>ethernet_frame
|
||||
|
||||
# interfaces modules
|
||||
<v2>loopback
|
||||
<v2>ether_drivers
|
||||
|
||||
# protocols modules
|
||||
<v2>arp
|
||||
<v2>ipv4
|
||||
;
|
||||
|
||||
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack memory_pool ;
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack atomizer ;
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack stack ;
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack interfaces ;
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack protocols ;
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack framings ;
|
||||
# SubInclude HAIKU_TOP src tests kits net new_stack ppp ;
|
@ -1,8 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack atomizer ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons kernel generic atomizer ] ;
|
||||
|
||||
Addon <userland>atomizer :
|
||||
atomizer.c
|
||||
: <installed>new_stack_tester
|
||||
;
|
@ -1,3 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack framings ;
|
||||
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack framings ethernet ;
|
@ -1,8 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack framings ethernet ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net new_stack headers ] ;
|
||||
|
||||
Addon <v2>ethernet_frame :
|
||||
ethernet_frame.c
|
||||
: <installed>new_stack_tester be
|
||||
;
|
@ -1,175 +0,0 @@
|
||||
/* ethernet_framer.c - ethernet framing layer module
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <ByteOrder.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
#define ETHER_ADDR_LEN 6 /* Ethernet address length */
|
||||
#define ETHER_TYPE_LEN 2 /* Ethernet type field length */
|
||||
#define ETHER_CRC_LEN 4 /* Ethernet CRC lenght */
|
||||
#define ETHER_HDR_LEN ((ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN)
|
||||
#define ETHER_MIN_LEN 64 /* Minimum frame length, CRC included */
|
||||
#define ETHER_MAX_LEN 1518 /* Maximum frame length, CRC included */
|
||||
|
||||
#define ETHERMTU (ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
|
||||
#define ETHERMIN (ETHER_MIN_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
|
||||
|
||||
typedef struct ethernet_addr {
|
||||
uint8 byte[ETHER_ADDR_LEN];
|
||||
} ethernet_addr;
|
||||
|
||||
|
||||
typedef struct ethernet2_header {
|
||||
ethernet_addr dst;
|
||||
ethernet_addr src;
|
||||
uint16 type;
|
||||
} ethernet2_header;
|
||||
|
||||
|
||||
|
||||
status_t std_ops(int32 op, ...);
|
||||
|
||||
struct net_layer_module_info nlmi;
|
||||
|
||||
static struct net_stack_module_info *g_stack = NULL;
|
||||
|
||||
string_token ethernet_header_attr;
|
||||
string_token ethernet_from_attr;
|
||||
string_token ethernet_to_attr;
|
||||
string_token ethernet_protocol_attr;
|
||||
|
||||
|
||||
static void dump_ethernet(net_buffer *buffer)
|
||||
{
|
||||
ethernet2_header hdr;
|
||||
const char *pname;
|
||||
|
||||
g_stack->read_buffer(buffer, 0, &hdr, sizeof(hdr));
|
||||
|
||||
switch(ntohs(hdr.type)) {
|
||||
case 0x0800: pname = "IPv4"; break;
|
||||
case 0x0806: pname = "ARP"; break;
|
||||
default: pname = "unknown"; break;
|
||||
};
|
||||
|
||||
dprintf("========== Ethernet Frame ==========\n");
|
||||
dprintf("Station: %02x:%02x:%02x:%02x:%02x:%02x ----> %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
hdr.src.byte[0], hdr.src.byte[1], hdr.src.byte[2], hdr.src.byte[3], hdr.src.byte[4], hdr.src.byte[5],
|
||||
hdr.dst.byte[0], hdr.dst.byte[1], hdr.dst.byte[2], hdr.dst.byte[3], hdr.dst.byte[4], hdr.dst.byte[5]);
|
||||
dprintf("Protocol: 0x%04x (%s)\n", ntohs(hdr.type), pname);
|
||||
}
|
||||
|
||||
|
||||
// -------------------
|
||||
static status_t init(net_layer *me)
|
||||
{
|
||||
dprintf("%s: initing layer\n", me->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t uninit(net_layer *me)
|
||||
{
|
||||
dprintf("%s: uniniting layer\n", me->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t enable(net_layer *me, bool enable)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
static status_t process_input(net_layer *me, net_buffer *buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
return B_ERROR;
|
||||
|
||||
dprintf("%s: process_input:\n", me->name);
|
||||
|
||||
dump_ethernet(buffer);
|
||||
|
||||
g_stack->add_buffer_attribute(buffer, ethernet_header_attr, FROM_BUFFER, 0, 14);
|
||||
g_stack->add_buffer_attribute(buffer, ethernet_to_attr, FROM_BUFFER, 0, 6);
|
||||
g_stack->add_buffer_attribute(buffer, ethernet_from_attr, FROM_BUFFER, 6, 6);
|
||||
g_stack->add_buffer_attribute(buffer, ethernet_protocol_attr, FROM_BUFFER | NETWORK_ORDER, 12, 2);
|
||||
|
||||
// strip ethernet header
|
||||
g_stack->remove_from_buffer(buffer, 0, 14);
|
||||
|
||||
return g_stack->send_layers_up(me, buffer);
|
||||
}
|
||||
|
||||
|
||||
static status_t process_output(net_layer *me, net_buffer *buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
return B_ERROR;
|
||||
|
||||
// TODO!
|
||||
dprintf("%s: process_output:\n", me->name);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
status_t std_ops(int32 op, ...)
|
||||
{
|
||||
switch(op) {
|
||||
case B_MODULE_INIT: {
|
||||
status_t status;
|
||||
|
||||
dprintf("ethernet_frame: B_MODULE_INIT\n");
|
||||
status = get_module(NET_STACK_MODULE_NAME, (module_info **) &g_stack);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
ethernet_header_attr = g_stack->string_to_token("ethernet:header");
|
||||
ethernet_from_attr = g_stack->string_to_token("ethernet:from");
|
||||
ethernet_to_attr = g_stack->string_to_token("ethernet:to");
|
||||
ethernet_protocol_attr = g_stack->string_to_token("ethernet:protocol");
|
||||
|
||||
return g_stack->register_layer("Ethernet framing", "frame/ethernet", 0, &nlmi, NULL, NULL);
|
||||
};
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
dprintf("ethernet_frame: B_MODULE_UNINIT\n");
|
||||
put_module(NET_STACK_MODULE_NAME);
|
||||
break;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
struct net_layer_module_info nlmi = {
|
||||
{
|
||||
NET_MODULES_ROOT "framings/ethernet_frame",
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
|
||||
NET_LAYER_API_VERSION,
|
||||
|
||||
init,
|
||||
uninit,
|
||||
enable,
|
||||
NULL, // no control()
|
||||
process_input,
|
||||
process_output
|
||||
};
|
||||
|
||||
_EXPORT module_info *modules[] = {
|
||||
(module_info*) &nlmi, // net_layer_module_info
|
||||
NULL
|
||||
};
|
@ -1,38 +0,0 @@
|
||||
#ifndef OBOS_MEMORY_POOL_H
|
||||
#define OBOS_MEMORY_POOL_H
|
||||
|
||||
#include <drivers/module.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Pools of *nodes* kernel module
|
||||
// Pools store any node of data, but they should be all the same node_size
|
||||
// size (set at pool creation time).
|
||||
// Very usefull for multiple same-sized structs storage...
|
||||
|
||||
struct memory_pool;
|
||||
typedef struct memory_pool memory_pool;
|
||||
|
||||
// for_each_pool_node() callback prototype:
|
||||
typedef status_t (*pool_iterate_func)(memory_pool * pool, void * node, void * cookie);
|
||||
|
||||
typedef struct {
|
||||
module_info module;
|
||||
|
||||
memory_pool * (*new_pool)(size_t node_size, uint32 node_count);
|
||||
status_t (*delete_pool)(memory_pool * pool);
|
||||
void * (*new_pool_node)(memory_pool * pool);
|
||||
status_t (*delete_pool_node)(memory_pool * pool, void * node);
|
||||
status_t (*for_each_pool_node)(memory_pool * pool, pool_iterate_func iterate, void * cookie);
|
||||
} memory_pool_module_info;
|
||||
|
||||
#define MEMORY_POOL_MODULE_NAME "generic/memory_pool/v1"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OBOS_MEMORY_POOL_H */
|
||||
|
@ -1,190 +0,0 @@
|
||||
/* net_stack.h
|
||||
* definitions needed by all network stack modules
|
||||
*/
|
||||
|
||||
#ifndef OBOS_NET_STACK_H
|
||||
#define OBOS_NET_STACK_H
|
||||
|
||||
#include <drivers/module.h>
|
||||
|
||||
#include "memory_pool.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// String tokens use here and there by stack components
|
||||
typedef const void *string_token;
|
||||
|
||||
// Networking attribute(s) definition
|
||||
typedef struct net_attribute net_attribute;
|
||||
|
||||
#define NET_ATTRIBUTE_TYPE_MASK 0xFF // Up to 256 basic types
|
||||
#define NET_ATTRIBUTE_FLAGS_MASK 0xFFFFFF00
|
||||
enum {
|
||||
NET_ATTRIBUTE_BOOL = 1, // ... = bool value
|
||||
NET_ATTRIBUTE_BYTE, // ... = uint8 value
|
||||
NET_ATTRIBUTE_INT16, // ... = uint16 value
|
||||
NET_ATTRIBUTE_INT32, // ... = uint32 value
|
||||
NET_ATTRIBUTE_INT64, // ... = uint64 value
|
||||
NET_ATTRIBUTE_DATA, // ... = void *data, size_t data_len
|
||||
NET_ATTRIBUTE_STRING, // ... = char *string
|
||||
NET_ATTRIBUTE_POINTER, // ... = void *ptr
|
||||
NET_ATTRIBUTE_IOVEC // ... = int nb, iovec *vec
|
||||
};
|
||||
|
||||
// Networking buffer(s) definition
|
||||
typedef struct net_buffer net_buffer;
|
||||
typedef struct net_buffer_queue net_buffer_queue;
|
||||
typedef void (*buffer_chunk_free_func)(void * arg1, ...); // buffer chunk free callback prototype
|
||||
|
||||
// Networking timers definitions
|
||||
typedef struct net_timer net_timer;
|
||||
typedef void (*net_timer_func)(net_timer *timer, void *cookie); // timer callback prototype
|
||||
|
||||
// Generic lockers support
|
||||
typedef int benaphore;
|
||||
#define create_benaphore(a, b)
|
||||
#define delete_benaphore(a)
|
||||
#define lock_benaphore(a)
|
||||
#define unlock_benaphore(a)
|
||||
|
||||
// Networking layer(s) definitions
|
||||
typedef struct net_layer net_layer;
|
||||
typedef struct net_layer_module_info net_layer_module_info;
|
||||
|
||||
#define NET_MODULES_ROOT "network_v2/"
|
||||
|
||||
struct net_layer_module_info {
|
||||
module_info info;
|
||||
|
||||
uint32 api_version;
|
||||
#define NET_LAYER_API_VERSION (0x1)
|
||||
|
||||
status_t (*init)(net_layer *me);
|
||||
status_t (*uninit)(net_layer *me);
|
||||
status_t (*enable)(net_layer *me, bool enable);
|
||||
status_t (*control)(net_layer *me, int opcode, ...);
|
||||
status_t (*process_input)(net_layer *me, struct net_buffer *buffer);
|
||||
status_t (*process_output)(net_layer *me, struct net_buffer *buffer);
|
||||
};
|
||||
|
||||
struct net_layer {
|
||||
struct net_layer *next;
|
||||
char *name;
|
||||
string_token type; // "frame", "ethernet" "ipv4", "ppp", etc. Joker (*) allowed
|
||||
string_token sub_type; // joker (*) allowed here too.
|
||||
int priority; // negative values reserved for packet sniffing, high value = lesser priority
|
||||
net_layer_module_info *module;
|
||||
void *cookie;
|
||||
uint32 use_count;
|
||||
struct net_layer **layers_above;
|
||||
struct net_layer **layers_below;
|
||||
net_attribute *attributes; // layer attributes
|
||||
};
|
||||
|
||||
// Network stack main module definition
|
||||
|
||||
struct net_stack_module_info {
|
||||
module_info module;
|
||||
|
||||
// Global stack control
|
||||
status_t (*start)(void);
|
||||
status_t (*stop)(void);
|
||||
|
||||
// String IDs atomizer
|
||||
string_token (*string_to_token)(const char *name);
|
||||
const char * (*string_for_token)(string_token token);
|
||||
|
||||
/*
|
||||
* Socket layer
|
||||
*/
|
||||
|
||||
/*
|
||||
* Net layers handling
|
||||
*/
|
||||
|
||||
status_t (*register_layer)(const char *name, const char *packets_type, int priority,
|
||||
net_layer_module_info *module, void *cookie, net_layer **layer);
|
||||
status_t (*unregister_layer)(net_layer *layer);
|
||||
net_layer * (*find_layer)(const char *name);
|
||||
|
||||
status_t (*add_layer_attribute)(net_layer *layer, string_token id, int type, ...);
|
||||
status_t (*remove_layer_attribute)(net_layer *layer, string_token id, int index);
|
||||
status_t (*find_layer_attribute)(net_layer *layer, string_token id, int index,
|
||||
int *type, void **value, size_t *size);
|
||||
|
||||
status_t (*send_layers_up)(net_layer *me, net_buffer *buffer);
|
||||
status_t (*send_layers_down)(net_layer *me, net_buffer *buffer);
|
||||
|
||||
/*
|
||||
* Buffer(s) support
|
||||
*/
|
||||
|
||||
|
||||
net_buffer * (*new_buffer)(void);
|
||||
status_t (*delete_buffer)(net_buffer *buffer, bool interrupt_safe);
|
||||
|
||||
net_buffer * (*duplicate_buffer)(net_buffer *from);
|
||||
net_buffer * (*clone_buffer)(net_buffer *from);
|
||||
net_buffer * (*split_buffer)(net_buffer *from, uint32 offset);
|
||||
|
||||
|
||||
// specials offsets for add_to_buffer()
|
||||
#define BUFFER_BEGIN 0
|
||||
#define BUFFER_END 0xFFFFFFFF
|
||||
status_t (*add_to_buffer)(net_buffer *buffer, uint32 offset, const void *data, size_t bytes, buffer_chunk_free_func freethis);
|
||||
status_t (*remove_from_buffer)(net_buffer *buffer, uint32 offset, size_t bytes);
|
||||
|
||||
status_t (*attach_buffer_free_element)(net_buffer *buffer, void *arg1, void *arg2, buffer_chunk_free_func freethis);
|
||||
|
||||
size_t (*read_buffer)(net_buffer *buffer, uint32 offset, void *data, size_t bytes);
|
||||
size_t (*write_buffer)(net_buffer *buffer, uint32 offset, const void *data, size_t bytes);
|
||||
|
||||
// Flags to combine with
|
||||
#define FROM_BUFFER 0x010000 // ... = int offset, int size
|
||||
#define NETWORK_ORDER 0x020000
|
||||
status_t (*add_buffer_attribute)(net_buffer *buffer, string_token id, int type, ...);
|
||||
status_t (*remove_buffer_attribute)(net_buffer *buffer, string_token id, int index);
|
||||
status_t (*find_buffer_attribute)(net_buffer *buffer, string_token id, int index,
|
||||
int *type, void **value, size_t *size);
|
||||
|
||||
void (*dump_buffer)(net_buffer *buffer);
|
||||
|
||||
// Buffers queues support
|
||||
net_buffer_queue * (*new_buffer_queue)(size_t max_bytes);
|
||||
status_t (*delete_buffer_queue)(net_buffer_queue *queue);
|
||||
|
||||
status_t (*empty_buffer_queue)(net_buffer_queue *queue);
|
||||
status_t (*enqueue_buffer)(net_buffer_queue *queue, net_buffer *buffer);
|
||||
size_t (*dequeue_buffer)(net_buffer_queue *queue, net_buffer **buffer, bigtime_t timeout, bool peek);
|
||||
|
||||
// Timers support
|
||||
|
||||
net_timer * (*new_timer)(void);
|
||||
status_t (*delete_timer)(net_timer *timer);
|
||||
status_t (*start_timer)(net_timer *timer, net_timer_func func, void *cookie, bigtime_t period);
|
||||
status_t (*cancel_timer)(net_timer *timer);
|
||||
status_t (*timer_appointment)(net_timer *timer, bigtime_t *period, bigtime_t *when);
|
||||
|
||||
// Lockers
|
||||
|
||||
// Misc.
|
||||
void (*dump_memory)(const char *prefix, const void *data, size_t len);
|
||||
|
||||
// Memory Pools support
|
||||
memory_pool * (*new_pool)(size_t node_size, uint32 node_count);
|
||||
status_t (*delete_pool)(memory_pool *pool);
|
||||
void * (*new_pool_node)(memory_pool *pool);
|
||||
status_t (*delete_pool_node)(memory_pool *pool, void *node);
|
||||
status_t (*for_each_pool_node)(memory_pool *pool, pool_iterate_func iterate, void *cookie);
|
||||
|
||||
};
|
||||
|
||||
#define NET_STACK_MODULE_NAME NET_MODULES_ROOT "stack/v1"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OBOS_NET_STACK_H */
|
@ -1,5 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack interfaces ;
|
||||
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack interfaces ether_drivers ;
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack interfaces loopback ;
|
||||
# SubInclude HAIKU_TOP src tests kits net new_stack interfaces dialup ;
|
@ -1,8 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack interfaces ether_drivers ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net new_stack headers ] ;
|
||||
|
||||
Addon <v2>ether_drivers :
|
||||
ether_drivers.c
|
||||
: <installed>new_stack_tester be
|
||||
;
|
@ -1,356 +0,0 @@
|
||||
/* legacy_devices.c - generic ethernet legacy devices layer module
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <Drivers.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
enum {
|
||||
ETHER_GETADDR = B_DEVICE_OP_CODES_END,
|
||||
ETHER_INIT,
|
||||
ETHER_NONBLOCK,
|
||||
ETHER_ADDMULTI,
|
||||
ETHER_REMMULTI,
|
||||
ETHER_SETPROMISC,
|
||||
ETHER_GETFRAMESIZE
|
||||
};
|
||||
|
||||
typedef struct ether_drivers_device {
|
||||
int fd;
|
||||
int max_frame_size;
|
||||
volatile thread_id reader_thread;
|
||||
} ether_drivers_device;
|
||||
|
||||
#define ETHER_ADDR_LEN 6 /* Ethernet address length */
|
||||
#define ETHER_TYPE_LEN 2 /* Ethernet type field length */
|
||||
#define ETHER_CRC_LEN 4 /* Ethernet CRC lenght */
|
||||
#define ETHER_HDR_LEN ((ETHER_ADDR_LEN * 2) + ETHER_TYPE_LEN)
|
||||
#define ETHER_MIN_LEN 64 /* Minimum frame length, CRC included */
|
||||
#define ETHER_MAX_LEN 1518 /* Maximum frame length, CRC included */
|
||||
|
||||
#define ETHERMTU (ETHER_MAX_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
|
||||
#define ETHERMIN (ETHER_MIN_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN)
|
||||
|
||||
typedef struct ethernet_addr {
|
||||
uint8 byte[ETHER_ADDR_LEN];
|
||||
} ethernet_addr;
|
||||
|
||||
status_t lookup_devices(char *root, void *cookie);
|
||||
status_t register_device(const char *path, void *cookie);
|
||||
status_t device_reader(void *args);
|
||||
status_t std_ops(int32 op, ...);
|
||||
|
||||
struct net_layer_module_info nlmi;
|
||||
|
||||
static struct net_stack_module_info *g_stack = NULL;
|
||||
|
||||
|
||||
// -------------------
|
||||
static status_t init(net_layer *me)
|
||||
{
|
||||
dprintf("%s: initing layer\n", me->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t uninit(net_layer *me)
|
||||
{
|
||||
ether_drivers_device *edd = me->cookie;
|
||||
|
||||
dprintf("%s: uniniting layer\n", me->name);
|
||||
|
||||
close(edd->fd);
|
||||
free(me->cookie);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t enable(net_layer *me, bool enable)
|
||||
{
|
||||
ether_drivers_device *edd = me->cookie;
|
||||
|
||||
if (enable) {
|
||||
// enable this layer
|
||||
thread_id tid;
|
||||
char name[B_OS_NAME_LENGTH * 2];
|
||||
|
||||
if (edd->reader_thread != -1)
|
||||
// already up
|
||||
return B_OK;
|
||||
|
||||
strncpy(name, me->name, sizeof(name));
|
||||
strncat(name, " reader", sizeof(name));
|
||||
tid = spawn_kernel_thread(device_reader, name, B_NORMAL_PRIORITY, me);
|
||||
if (tid < 0) {
|
||||
dprintf("%s: failed to start device reader thread -> %d [%s]\n",
|
||||
me->name, (int) tid, strerror(tid));
|
||||
return tid;
|
||||
};
|
||||
|
||||
edd->reader_thread = tid;
|
||||
return resume_thread(tid);
|
||||
|
||||
} else {
|
||||
|
||||
status_t dummy;
|
||||
|
||||
// disable this layer
|
||||
if (edd->reader_thread == -1)
|
||||
// already down
|
||||
return B_OK;
|
||||
|
||||
send_signal_etc(edd->reader_thread, SIGTERM, 0);
|
||||
wait_for_thread(edd->reader_thread, &dummy);
|
||||
dprintf("%s: device reader stopped.\n", me->name);
|
||||
edd->reader_thread = -1;
|
||||
return B_OK;
|
||||
};
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t process_output(net_layer *me, net_buffer *buffer)
|
||||
{
|
||||
ether_drivers_device *edd = me->cookie;
|
||||
status_t status;
|
||||
void *frame;
|
||||
ssize_t sz;
|
||||
|
||||
if (!buffer)
|
||||
return B_ERROR;
|
||||
|
||||
dprintf("%s: process_output:\n", me->name);
|
||||
g_stack->dump_buffer(buffer);
|
||||
|
||||
// write buffer content
|
||||
frame = malloc(edd->max_frame_size);
|
||||
if (!frame)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// TODO: remove unwanted copy!!!
|
||||
sz = g_stack->read_buffer(buffer, 0, frame, edd->max_frame_size);
|
||||
if (sz >= 1)
|
||||
sz = write(edd->fd, frame, sz);
|
||||
|
||||
g_stack->delete_buffer(buffer, false);
|
||||
return (sz >= 0);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
status_t lookup_devices(char *root, void *cookie)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
struct stat st;
|
||||
char path[1024];
|
||||
status_t status;
|
||||
|
||||
dir = opendir(root);
|
||||
if (!dir) {
|
||||
dprintf("Couldn't open the directory %s\n", root);
|
||||
return B_ERROR;
|
||||
};
|
||||
|
||||
status = B_OK;
|
||||
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
|
||||
continue; // skip pseudo-directories
|
||||
|
||||
sprintf(path, "%s/%s", root, de->d_name);
|
||||
|
||||
if (stat(path, &st) < 0) {
|
||||
dprintf("ether_drivers: Can't stat(%s) entry! Skipping...\n", path);
|
||||
continue;
|
||||
};
|
||||
|
||||
if (S_ISDIR(st.st_mode))
|
||||
status = lookup_devices(path, cookie);
|
||||
else if (S_ISCHR(st.st_mode)) { // char device = driver!
|
||||
if (strcmp(de->d_name, "socket") == 0 || // Old OBOS stack driver
|
||||
strcmp(de->d_name, "stack") == 0 || // OBOS stack driver
|
||||
strcmp(de->d_name, "server") == 0 || // OBOS server driver
|
||||
strcmp(de->d_name, "api") == 0) // BONE stack driver
|
||||
continue; // skip pseudo-entries
|
||||
|
||||
status = register_device(path, cookie);
|
||||
};
|
||||
};
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t register_device(const char *path, void *cookie)
|
||||
{
|
||||
ether_drivers_device *edd;
|
||||
int frame_size;
|
||||
ethernet_addr mac_address;
|
||||
int fd;
|
||||
status_t status;
|
||||
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd < B_OK) {
|
||||
dprintf("ether_drivers: Unable to open %s device -> %d [%s]. Skipping...\n", path,
|
||||
fd, strerror(fd));
|
||||
return fd;
|
||||
};
|
||||
|
||||
// Init the network card
|
||||
status = ioctl(fd, ETHER_INIT, NULL, 0);
|
||||
if (status < B_OK) {
|
||||
dprintf("ether_drivers: Failed to init %s device -> %ld [%s]. Skipping...\n", path,
|
||||
status, strerror(status));
|
||||
close(fd);
|
||||
return status;
|
||||
};
|
||||
|
||||
// get the MAC address...
|
||||
status = ioctl(fd, ETHER_GETADDR, &mac_address, 6);
|
||||
if (status < B_OK) {
|
||||
dprintf("ether_drivers: Failed to get %s device MAC address -> %ld [%s]. Skipping...\n",
|
||||
path, status, strerror(status));
|
||||
close(fd);
|
||||
return status;
|
||||
};
|
||||
|
||||
// Try to determine the MTU to use
|
||||
status = ioctl(fd, ETHER_GETFRAMESIZE, &frame_size, sizeof(frame_size));
|
||||
if (status < B_OK) {
|
||||
frame_size = ETHERMTU;
|
||||
dprintf("ether_drivers: %s device don't support ETHER_GETFRAMESIZE; defaulting to %d\n",
|
||||
path, frame_size);
|
||||
};
|
||||
|
||||
dprintf("ether_drivers: Found device '%s': MAC address: %02x:%02x:%02x:%02x:%02x:%02x, MTU: %d bytes\n",
|
||||
path,
|
||||
mac_address.byte[0], mac_address.byte[1],
|
||||
mac_address.byte[2], mac_address.byte[3],
|
||||
mac_address.byte[4], mac_address.byte[5], frame_size);
|
||||
|
||||
edd = malloc(sizeof(*edd));
|
||||
if (!edd) {
|
||||
close(fd);
|
||||
return B_NO_MEMORY;
|
||||
};
|
||||
|
||||
edd->fd = fd;
|
||||
edd->max_frame_size = frame_size;
|
||||
edd->reader_thread = -1;
|
||||
|
||||
if (strncmp(path, "/dev/net/", 9) == 0)
|
||||
path += 9; // drop the path root from layer(s) name(s)
|
||||
|
||||
return g_stack->register_layer(path, "interface/ethernet", 0, &nlmi, edd, NULL);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
status_t device_reader(void *args)
|
||||
{
|
||||
net_layer *me = args;
|
||||
ether_drivers_device *edd = me->cookie;
|
||||
net_buffer *buffer;
|
||||
status_t status;
|
||||
void *frame;
|
||||
ssize_t sz;
|
||||
|
||||
dprintf("%s: device reader started.\n", me->name);
|
||||
|
||||
status = B_OK;
|
||||
while(1) {
|
||||
frame = malloc(edd->max_frame_size);
|
||||
if (!frame) {
|
||||
status = B_NO_MEMORY;
|
||||
break;
|
||||
};
|
||||
|
||||
// read on frame at time
|
||||
sz = read(edd->fd, frame, edd->max_frame_size);
|
||||
if (sz >= B_OK) {
|
||||
buffer = g_stack->new_buffer();
|
||||
if (!buffer) {
|
||||
free(frame);
|
||||
status = B_NO_MEMORY;
|
||||
break;
|
||||
};
|
||||
|
||||
g_stack->add_to_buffer(buffer, 0, frame, sz, (buffer_chunk_free_func) free);
|
||||
|
||||
dprintf("%s: input packet %p:\n", me->name, buffer);
|
||||
if (g_stack->send_layers_up(me, buffer) != B_OK) {
|
||||
// nobody above us *eat* this packet, so we drop it ourself :-(
|
||||
dprintf("%s: okay, nobody cares about this input packet %p: deletion!\n", me->name, buffer);
|
||||
g_stack->dump_buffer(buffer);
|
||||
g_stack->delete_buffer(buffer, false);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
edd->reader_thread = -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
status_t std_ops(int32 op, ...)
|
||||
{
|
||||
switch(op) {
|
||||
case B_MODULE_INIT: {
|
||||
status_t status;
|
||||
|
||||
dprintf("ether_drivers: B_MODULE_INIT\n");
|
||||
status = get_module(NET_STACK_MODULE_NAME, (module_info **) &g_stack);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
lookup_devices("/dev/net", NULL);
|
||||
return B_OK;
|
||||
};
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
dprintf("ether_drivers: B_MODULE_UNINIT\n");
|
||||
put_module(NET_STACK_MODULE_NAME);
|
||||
break;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
struct net_layer_module_info nlmi = {
|
||||
{
|
||||
NET_MODULES_ROOT "interfaces/ether_drivers",
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
|
||||
NET_LAYER_API_VERSION,
|
||||
|
||||
init,
|
||||
uninit,
|
||||
enable,
|
||||
NULL, // no control()
|
||||
NULL, // interface layer: processing input buffer doesn't make sense!
|
||||
process_output
|
||||
};
|
||||
|
||||
_EXPORT module_info *modules[] = {
|
||||
(module_info*) &nlmi, // net_layer_module_info
|
||||
NULL
|
||||
};
|
@ -1,8 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack interfaces loopback ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net new_stack headers ] ;
|
||||
|
||||
Addon <v2>loopback :
|
||||
loopback.c
|
||||
: <installed>new_stack_tester be
|
||||
;
|
@ -1,96 +0,0 @@
|
||||
/* loopback.c - loopback interface module
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
status_t std_ops(int32 op, ...);
|
||||
|
||||
struct net_layer_module_info nlmi;
|
||||
|
||||
static struct net_stack_module_info *g_stack = NULL;
|
||||
|
||||
|
||||
// -------------------
|
||||
static status_t init(net_layer *me)
|
||||
{
|
||||
dprintf("%s: initing layer\n", me->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t uninit(net_layer *me)
|
||||
{
|
||||
dprintf("loopback: uniniting layer\n");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t enable(net_layer *me, bool enable)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t process_output(net_layer *me, net_buffer *buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
return B_ERROR;
|
||||
|
||||
// Here the magical loopback effect ;-)
|
||||
return g_stack->send_layers_up(me, buffer);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
status_t std_ops(int32 op, ...)
|
||||
{
|
||||
switch(op) {
|
||||
case B_MODULE_INIT: {
|
||||
status_t status;
|
||||
|
||||
dprintf("loopback: B_MODULE_INIT\n");
|
||||
status = get_module(NET_STACK_MODULE_NAME, (module_info **) &g_stack);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return g_stack->register_layer("loopback", "interface/*", 0, &nlmi, NULL, NULL);
|
||||
}
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
dprintf("loopback: B_MODULE_UNINIT\n");
|
||||
put_module(NET_STACK_MODULE_NAME);
|
||||
break;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
struct net_layer_module_info nlmi = {
|
||||
{
|
||||
NET_MODULES_ROOT "interfaces/loopback",
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
|
||||
NET_LAYER_API_VERSION,
|
||||
|
||||
init,
|
||||
uninit,
|
||||
enable,
|
||||
NULL, // no control()
|
||||
NULL, // interface layer: processing input buffer doesn't make sense!
|
||||
process_output
|
||||
};
|
||||
|
||||
_EXPORT module_info *modules[] = {
|
||||
(module_info*) &nlmi, // net_layer_module_info
|
||||
NULL
|
||||
};
|
@ -1,8 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack memory_pool ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net new_stack headers ] ;
|
||||
|
||||
Addon <userland>memory_pool :
|
||||
memory_pool.c
|
||||
: <installed>new_stack_tester
|
||||
;
|
@ -1,295 +0,0 @@
|
||||
#include <stdio.h> // for the hack using malloc() / free()
|
||||
#include <stdlib.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "memory_pool.h"
|
||||
|
||||
// Keep in mind that pools size are rounded to B_PAGE_SIZE, and
|
||||
// node_size are align to 32 bits boundaries...
|
||||
|
||||
struct memory_pool {
|
||||
struct memory_pool * next; // for dynamic pool expansion/shrinking...
|
||||
size_t node_size; // in byte, rounded to 32 bits boundary
|
||||
uint32 node_count;
|
||||
// struct memory_pool_block blocks[1];
|
||||
};
|
||||
|
||||
typedef struct memory_pool_block {
|
||||
uint32 nb_max; // in this pool only, may vary from pool to another for same pools chain
|
||||
uint32 nb_free; // in this pool only, if 0 try 'next' one...
|
||||
void * first; // address of first node, just next to freemap
|
||||
void * last; // address of last node in this pool
|
||||
// the uint32 freemap[] follow, aligned to 32 bits boundary
|
||||
// then the nodes data follow...
|
||||
} memory_pool_block;
|
||||
|
||||
#define BITMAPSIZE(nb_nodes) (nb_nodes / 8)
|
||||
|
||||
status_t std_ops(int32 op, ...);
|
||||
|
||||
memory_pool * new_pool(size_t node_size, uint32 node_count);
|
||||
status_t delete_pool(memory_pool * pool);
|
||||
void * new_pool_node(memory_pool * pool);
|
||||
status_t delete_pool_node(memory_pool * pool, void * node);
|
||||
status_t for_each_pool_node(memory_pool * pool, pool_iterate_func iterate, void * cookie);
|
||||
|
||||
// Keep in mind that pools size are rounded to B_PAGE_SIZE...
|
||||
|
||||
#define ROUND(x, y) (((x) + (y) - 1) & ~((y) - 1))
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
|
||||
|
||||
#ifdef CODEWARRIOR
|
||||
#pragma mark [Public functions]
|
||||
#endif
|
||||
|
||||
// -------------------------------
|
||||
memory_pool * new_pool(size_t node_size, uint32 node_count)
|
||||
{
|
||||
// TODO!
|
||||
return (memory_pool *) node_size; // quick hack
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------
|
||||
status_t delete_pool(memory_pool * pool)
|
||||
{
|
||||
// TODO!
|
||||
|
||||
return 0; // return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------
|
||||
void * new_pool_node(memory_pool * pool)
|
||||
{
|
||||
// TODO!
|
||||
|
||||
return malloc((size_t) pool); // quick hack
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------
|
||||
status_t delete_pool_node(memory_pool * pool, void * node)
|
||||
{
|
||||
// TODO!
|
||||
|
||||
free(node); // quick hack
|
||||
return 0; // return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------
|
||||
status_t for_each_pool_node(memory_pool * pool, pool_iterate_func iterate, void * cookie)
|
||||
{
|
||||
// TODO!
|
||||
return 0; // return B_OK;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
// -------------------------------
|
||||
memory_pool * new_pool2(size_t node_size, uint32 node_count)
|
||||
{
|
||||
memory_pool * pool;
|
||||
size_t size;
|
||||
size_t freemap_size;
|
||||
uint8 * ptr;
|
||||
|
||||
|
||||
node_size = ROUND(node_size, 4); // aligned to 32 bits
|
||||
|
||||
freemap_size = ROUND(node_count, 32) / 8; // aligned to 32 bits
|
||||
|
||||
size = sizeof(memory_pool);
|
||||
|
||||
size += freemap_size;
|
||||
size += node_size * node_count;
|
||||
|
||||
pool = (memory_pool *) malloc(size);
|
||||
|
||||
pool->next = NULL; // no secondary pool for the moment...
|
||||
|
||||
pool->node_size = node_size; // aligned to 32 bits
|
||||
pool->nb_max = node_count;
|
||||
pool->nb_free = node_count;
|
||||
|
||||
ptr = (uint8 *) (pool + 1);
|
||||
ptr += freemap_size;
|
||||
|
||||
pool->first = ptr;
|
||||
|
||||
ptr += (node_count-1) * node_size;
|
||||
|
||||
pool->last = ptr;
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// -------------------------------
|
||||
status_t delete_pool2(memory_pool * pool)
|
||||
{
|
||||
memory_pool * next;
|
||||
|
||||
while (pool) {
|
||||
next = pool->next;
|
||||
|
||||
my_free2("delete_pool: ", pool);
|
||||
|
||||
pool = next;
|
||||
};
|
||||
|
||||
return 0; // return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------
|
||||
void * new_pool_node2(memory_pool * pool)
|
||||
{
|
||||
memory_pool * p;
|
||||
size_t slot;
|
||||
sizet nb_slots;
|
||||
uint32* freemap;
|
||||
uint8 * ptr;
|
||||
|
||||
// seaching pools list for one with at least one free node
|
||||
p = pool;
|
||||
while (p->nb_free == 0) {
|
||||
p = p->next;
|
||||
};
|
||||
|
||||
if (! p) {
|
||||
// need to add a new pool
|
||||
p = new_pool2(pool->node_size, pool->nb_max);
|
||||
if (!p)
|
||||
return NULL; // argh, no more memory!?!
|
||||
|
||||
p->next = pool->next;
|
||||
pool->next = p;
|
||||
};
|
||||
|
||||
// okay, now find the first free slot of this pool
|
||||
slot = 0;
|
||||
nb_slots = ROUND(p->nb_max, 32); // aligned to 32 bits
|
||||
freemap = (uint32 *) (p + 1);
|
||||
|
||||
// fast lookup over 32 contiguous slots already in use (if any)
|
||||
while (slot < nb_slots) {
|
||||
if (*freemap != 0xFFFFFFFF)
|
||||
break;
|
||||
|
||||
freemap++; // all 32 contiguous slots used
|
||||
slot += 32;
|
||||
};
|
||||
|
||||
// find the first free slot of these next 32 ones
|
||||
while(slot < nb_slots) {
|
||||
if ( *freemap & (1 << (31 - (slot % 32))) == 0)
|
||||
// free slot found :-)
|
||||
break;
|
||||
|
||||
slot++;
|
||||
};
|
||||
|
||||
if (slot >= nb_slots)
|
||||
// oh oh, should never happend! ;-)
|
||||
return NULL;
|
||||
|
||||
*freemap |= (1 << (31 - (slot % 32)));
|
||||
p->nb_free--;
|
||||
|
||||
ptr = (uint8 *) p->first;
|
||||
ptr += slot * p->node_size;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------
|
||||
status_t delete_pool_node2(memory_pool * pool, void * node)
|
||||
{
|
||||
memory_pool * p;
|
||||
size_t slot;
|
||||
size_t nb_slots;
|
||||
uint32* freemap;
|
||||
uint8 * ptr;
|
||||
|
||||
// seaching pools list for the one who host this node
|
||||
p = pool;
|
||||
while (pool) {
|
||||
if (node >= pool->first && node <= pool->last)
|
||||
break; // node's hosting pool found
|
||||
pool = pool->next;
|
||||
};
|
||||
|
||||
if (! pool)
|
||||
return -1; // return B_BAD_VALUE;
|
||||
|
||||
// find node slot number on this pool
|
||||
slot = (node - pool->first);
|
||||
if (slot % pool->node_size)
|
||||
// oh oh, not a valid, starting node address value!
|
||||
return -1; // return B_BAD_VALUE;
|
||||
|
||||
nb_slots = ROUND(p->nb_max, 32); // aligned to 32 bits
|
||||
slot /= pool->node_size;
|
||||
if (slot >= nb_slots)
|
||||
// oh oh, node slot out of range!!!
|
||||
// something go wrong with pool->last value!?!
|
||||
return -1; // return B_BAD_VALUE;
|
||||
|
||||
freemap = (uint32 *) (pool + 1);
|
||||
|
||||
pool->nb_free++;
|
||||
if (pool->nb_free == pool->nb_max)
|
||||
// free this pool_block
|
||||
|
||||
return 0; // return B_OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
memory_pool_module_info mpmi = {
|
||||
{
|
||||
MEMORY_POOL_MODULE_NAME,
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
|
||||
new_pool,
|
||||
delete_pool,
|
||||
new_pool_node,
|
||||
delete_pool_node,
|
||||
for_each_pool_node
|
||||
};
|
||||
|
||||
status_t std_ops(int32 op, ...)
|
||||
{
|
||||
switch(op) {
|
||||
case B_MODULE_INIT:
|
||||
printf("memory_pool: B_MODULE_INIT\n");
|
||||
break;
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
printf("memory_pool: B_MODULE_UNINIT\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
_EXPORT module_info *modules[] = {
|
||||
(module_info *) &mpmi, // memory_pool_module_info
|
||||
NULL
|
||||
};
|
||||
|
@ -1,120 +0,0 @@
|
||||
/* Userland modules emulation support
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <app/Application.h>
|
||||
#include <drivers/module.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
// #include <userland_ipc.h>
|
||||
|
||||
struct net_stack_module_info * g_stack = NULL;
|
||||
|
||||
void my_free(void * ptr, ...)
|
||||
{
|
||||
printf("my_free(%p)\n", ptr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void my_free2(void * prompt, ...) // void * ptr)
|
||||
{
|
||||
va_list args;
|
||||
void * ptr;
|
||||
|
||||
va_start(args, prompt);
|
||||
ptr = va_arg(args, void *);
|
||||
va_end(args);
|
||||
|
||||
printf("%s: my_free2(%p)\n", (char *) prompt, ptr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
int test_buffer()
|
||||
{
|
||||
net_buffer *buffer;
|
||||
char data[128];
|
||||
size_t len;
|
||||
char *tata;
|
||||
char *titi;
|
||||
char *toto;
|
||||
char *tutu;
|
||||
|
||||
puts("test_buffer():");
|
||||
|
||||
tata = (char *) malloc(16);
|
||||
strcpy(tata, "0123456789");
|
||||
|
||||
titi = (char *) malloc(16);
|
||||
strcpy(titi, "ABCDEF");
|
||||
|
||||
toto = (char *) malloc(48);
|
||||
strcpy(toto, "abcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
tutu = (char *) malloc(16);
|
||||
strcpy(tutu, "hello there!");
|
||||
|
||||
buffer = g_stack->new_buffer();
|
||||
|
||||
g_stack->add_to_buffer(buffer, BUFFER_END, titi, 6, my_free);
|
||||
g_stack->add_to_buffer(buffer, 0, tata, 10, my_free);
|
||||
g_stack->attach_buffer_free_element(buffer, tutu, (void *) "hello there", my_free2);
|
||||
g_stack->add_to_buffer(buffer, 5, toto, 26, my_free);
|
||||
g_stack->add_to_buffer(buffer, 0, "this is a net_buffer test: ", 27, NULL);
|
||||
|
||||
g_stack->dump_buffer(buffer);
|
||||
|
||||
printf("Removing 61 bytes at offset 4...\n");
|
||||
g_stack->remove_from_buffer(buffer, 4, 61);
|
||||
|
||||
g_stack->dump_buffer(buffer);
|
||||
|
||||
len = g_stack->read_buffer(buffer, 2, data, sizeof(data));
|
||||
data[len] = 0;
|
||||
|
||||
printf("data = [%s]\n", data);
|
||||
|
||||
g_stack->delete_buffer(buffer, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
new BApplication("application/x-vnd-OBOS-net_server");
|
||||
|
||||
// if (init_userland_ipc() < B_OK)
|
||||
// goto exit0;
|
||||
|
||||
if (get_module(NET_STACK_MODULE_NAME, (module_info **) &g_stack) != B_OK)
|
||||
goto exit1;
|
||||
|
||||
if (g_stack->start() == B_OK) {
|
||||
|
||||
puts("Userland net stack (net_server) is running.");
|
||||
puts("Press any key to quit.");
|
||||
|
||||
fflush(stdin);
|
||||
fgetc(stdin);;
|
||||
|
||||
// test_buffer();
|
||||
|
||||
g_stack->stop();
|
||||
};
|
||||
|
||||
put_module(NET_STACK_MODULE_NAME);;
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit1:;
|
||||
// shutdown_userland_ipc();
|
||||
|
||||
// exit0:;
|
||||
delete be_app;
|
||||
return ret;
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack protocols ;
|
||||
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack protocols arp ;
|
||||
SubInclude HAIKU_TOP src tests kits net new_stack protocols ipv4 ;
|
||||
|
@ -1,8 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack protocols arp ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net new_stack headers ] ;
|
||||
|
||||
Addon <v2>arp :
|
||||
arp.c
|
||||
: <installed>new_stack_tester be
|
||||
;
|
@ -1,219 +0,0 @@
|
||||
/* ethernet.c - ethernet devices interface module
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <ByteOrder.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
status_t std_ops(int32 op, ...);
|
||||
|
||||
struct net_layer_module_info nlmi;
|
||||
|
||||
static struct net_stack_module_info *g_stack = NULL;
|
||||
|
||||
string_token ethernet_protocol_attr;
|
||||
|
||||
typedef struct ethernet_addr {
|
||||
uint8 byte[6];
|
||||
} ethernet_addr;
|
||||
|
||||
typedef struct ipv4_addr {
|
||||
uint8 byte[4];
|
||||
} ipv4_addr;
|
||||
|
||||
struct arp_header {
|
||||
uint16 hardware_type; /* format of hardware address */
|
||||
uint16 protocol_type; /* format of protocol address */
|
||||
uint8 hardware_size; /* length of hardware address */
|
||||
uint8 protocol_size; /* length of protocol address */
|
||||
uint16 op; /* one of: */
|
||||
|
||||
// for ethernet/ipv4 arp packets
|
||||
|
||||
ethernet_addr sender_hardware_address; /* sender hardware address */
|
||||
ipv4_addr sender_protocol_address; /* sender protocol address */
|
||||
ethernet_addr target_hardware_address; /* target hardware address */
|
||||
ipv4_addr target_protocol_address; /* target protocol address */
|
||||
};
|
||||
|
||||
enum {
|
||||
ARP_HARDWARE_TYPE_ETHERNET = 1, /* ethernet hardware format */
|
||||
ARP_HARDWARE_TYPE_IEEE802 = 6, /* IEEE 802 hardware format */
|
||||
ARP_HARDWARE_TYPE_FRAMERELAY = 15
|
||||
};
|
||||
|
||||
enum {
|
||||
ARP_OP_REQUEST = 1, /* request to resolve address */
|
||||
ARP_OP_REPLY,
|
||||
ARP_OP_RARP_REQUEST,
|
||||
ARP_OP_RARP_REPLY
|
||||
};
|
||||
|
||||
static void dump_arp(net_buffer *buffer)
|
||||
{
|
||||
struct arp_header arp;
|
||||
const char *pname;
|
||||
ethernet_addr *ea;
|
||||
ipv4_addr *ia;
|
||||
|
||||
g_stack->read_buffer(buffer, 0, &arp, sizeof(arp));
|
||||
|
||||
switch(ntohs(arp.protocol_type)) {
|
||||
case 0x0800: pname = "IPv4"; break;
|
||||
case 0x0806: pname = "ARP"; break;
|
||||
default: pname = "unknown"; break;
|
||||
};
|
||||
|
||||
dprintf("========== Address Resolution Protocol (ARP) ====\n");
|
||||
dprintf("Hardware : %s\n",
|
||||
ntohs(arp.hardware_type) == ARP_HARDWARE_TYPE_ETHERNET ? "ethernet" : "unknown");
|
||||
dprintf("Protocol : 0x%04x (%s)\n", ntohs(arp.protocol_type), pname);
|
||||
dprintf("Operation : ");
|
||||
switch(ntohs(arp.op)) {
|
||||
case ARP_OP_REPLY:
|
||||
dprintf("ARP Reply\n");
|
||||
break;
|
||||
case ARP_OP_REQUEST:
|
||||
dprintf("ARP Request\n");
|
||||
break;
|
||||
default:
|
||||
dprintf("Who knows? 0x%04x\n", ntohs(arp.op));
|
||||
};
|
||||
dprintf("Hardware address length: %d\n", arp.hardware_size);
|
||||
dprintf("Protocol address length: %d\n", arp.protocol_size);
|
||||
|
||||
ea = &arp.sender_hardware_address;
|
||||
dprintf("Sender Hardware Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
ea->byte[0], ea->byte[1], ea->byte[2], ea->byte[3], ea->byte[4], ea->byte[5]);
|
||||
ia = &arp.sender_protocol_address;
|
||||
dprintf("Sender Protocol Address: %d.%d.%d.%d\n",
|
||||
ia->byte[0], ia->byte[1], ia->byte[2], ia->byte[3]);
|
||||
|
||||
ea = &arp.target_hardware_address;
|
||||
dprintf("Target Hardware Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
ea->byte[0], ea->byte[1], ea->byte[2], ea->byte[3], ea->byte[4], ea->byte[5]);
|
||||
ia = &arp.target_protocol_address;
|
||||
dprintf("Target Protocol Address: %d.%d.%d.%d\n",
|
||||
ia->byte[0], ia->byte[1], ia->byte[2], ia->byte[3]);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
// -------------------
|
||||
static status_t init(net_layer *me)
|
||||
{
|
||||
dprintf("%s: initing layer\n", me->name);
|
||||
return B_OK;
|
||||
|
||||
}
|
||||
|
||||
static status_t uninit(net_layer *me)
|
||||
{
|
||||
dprintf("%s: uniniting layer\n", me->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t enable(net_layer *me, bool enable)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t process_input(net_layer *me, net_buffer *buffer)
|
||||
{
|
||||
uint16 *protocol;
|
||||
|
||||
if (!buffer)
|
||||
return B_ERROR;
|
||||
|
||||
if (g_stack->find_buffer_attribute(buffer, ethernet_protocol_attr, 0, NULL, (void **) &protocol, NULL) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
if (*protocol != htons(0x0806)) // ARP on Ethernet protocol value
|
||||
// Not an ARP packet
|
||||
return B_ERROR;
|
||||
|
||||
// TODO!
|
||||
dump_arp(buffer);
|
||||
g_stack->delete_buffer(buffer, false);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t process_output(net_layer *me, net_buffer *buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
return B_ERROR;
|
||||
|
||||
// TODO!
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
status_t std_ops(int32 op, ...)
|
||||
{
|
||||
switch(op) {
|
||||
case B_MODULE_INIT: {
|
||||
status_t status;
|
||||
net_layer *layer;
|
||||
|
||||
dprintf("arp: B_MODULE_INIT\n");
|
||||
status = get_module(NET_STACK_MODULE_NAME, (module_info **) &g_stack);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
ethernet_protocol_attr = g_stack->string_to_token("ethernet:protocol");
|
||||
|
||||
status = g_stack->register_layer("ARP", "ethernet/arp", 30, &nlmi, NULL, &layer);
|
||||
if (status != B_OK)
|
||||
goto error;
|
||||
|
||||
return B_OK;
|
||||
|
||||
error:
|
||||
g_stack->unregister_layer(layer);
|
||||
put_module(NET_STACK_MODULE_NAME);
|
||||
return status;
|
||||
}
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
dprintf("arp: B_MODULE_UNINIT\n");
|
||||
put_module(NET_STACK_MODULE_NAME);
|
||||
break;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
struct net_layer_module_info nlmi = {
|
||||
{
|
||||
NET_MODULES_ROOT "protocols/arp/v0",
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
|
||||
NET_LAYER_API_VERSION,
|
||||
|
||||
init,
|
||||
uninit,
|
||||
enable,
|
||||
NULL,
|
||||
process_input,
|
||||
process_output
|
||||
};
|
||||
|
||||
_EXPORT module_info *modules[] = {
|
||||
(module_info*) &nlmi, // net_layer_module_info
|
||||
NULL
|
||||
};
|
@ -1,8 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack protocols ipv4 ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net new_stack headers ] ;
|
||||
|
||||
Addon <v2>ipv4 :
|
||||
ipv4.c
|
||||
: <installed>new_stack_tester be
|
||||
;
|
@ -1,203 +0,0 @@
|
||||
/* ipv4.c - ipv4 protocol module
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <ByteOrder.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
typedef uint32 ipv4_addr;
|
||||
|
||||
typedef struct ipv4_header {
|
||||
uint8 version_header_length;
|
||||
uint8 tos;
|
||||
uint16 total_length;
|
||||
uint16 identification;
|
||||
uint16 flags_frag_offset;
|
||||
uint8 ttl;
|
||||
uint8 protocol;
|
||||
uint16 header_checksum;
|
||||
ipv4_addr src;
|
||||
ipv4_addr dst;
|
||||
} _PACKED ipv4_header;
|
||||
|
||||
#define IPV4_FLAG_MORE_FRAGS 0x2000
|
||||
#define IPV4_FLAG_MAY_NOT_FRAG 0x4000
|
||||
#define IPV4_FRAG_OFFSET_MASK 0x1fff
|
||||
|
||||
|
||||
|
||||
status_t std_ops(int32 op, ...);
|
||||
|
||||
struct net_layer_module_info nlmi;
|
||||
|
||||
static struct net_stack_module_info *g_stack = NULL;
|
||||
string_token ethernet_protocol_attr;
|
||||
static uint32 g_next_ipv4_id = 0;
|
||||
|
||||
static void dump_ipv4_addr(ipv4_addr *addr)
|
||||
{
|
||||
uint8 *bytes = (uint8 *) addr;
|
||||
|
||||
// NOTE: addr should point to a Network Byte Order'ed (aka Big Endian) IPv4 address
|
||||
|
||||
dprintf("%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
|
||||
}
|
||||
|
||||
static void dump_ipv4_header(net_buffer *buffer)
|
||||
{
|
||||
ipv4_header ip;
|
||||
const char *pname;
|
||||
|
||||
g_stack->read_buffer(buffer, 0, &ip, sizeof(ip));
|
||||
|
||||
switch(ip.protocol) {
|
||||
case 1: pname = "ICMP"; break;
|
||||
case 6: pname = "TCP"; break;
|
||||
case 17: pname = "UDP"; break;
|
||||
default: pname = "unknown"; break;
|
||||
};
|
||||
|
||||
dprintf("========== Internet Protocol (IPv4) =============\n");
|
||||
|
||||
dprintf("Station: ");
|
||||
dump_ipv4_addr(&ip.src);
|
||||
dprintf(" ----> ");
|
||||
dump_ipv4_addr(&ip.dst);
|
||||
dprintf("\n");
|
||||
dprintf("Protocol: %d (%s)\n", ip.protocol, pname);
|
||||
dprintf("Version: %d\n", ip.version_header_length >> 4);
|
||||
dprintf("Header Length (32 bit words): %d (%d bytes)\n",
|
||||
ip.version_header_length & 0x0f,
|
||||
4 * (ip.version_header_length & 0x0f));
|
||||
// TODO: dprintf("Precedence: \n");
|
||||
dprintf("Total length: %d\n", ntohs(ip.total_length));
|
||||
dprintf("Identification: %d\n", ntohs(ip.identification));
|
||||
// TODO: dprintf("Fragmentation allowed, Last fragment\n");
|
||||
dprintf("Fragment Offset: %d\n", ntohs(ip.flags_frag_offset) & 0x1fff);
|
||||
dprintf("Time to Live: %d second(s)\n", ip.ttl);
|
||||
dprintf("Checksum: 0x%X (%s)\n", ntohs(ip.header_checksum), "Valid"); // TODO: check the checksum!
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
// -------------------
|
||||
static status_t init(net_layer *me)
|
||||
{
|
||||
printf("%s: initing layer\n", me->name);
|
||||
g_next_ipv4_id = system_time();
|
||||
return B_OK;
|
||||
|
||||
}
|
||||
|
||||
static status_t uninit(net_layer *me)
|
||||
{
|
||||
printf("%s: uniniting layer\n", me->name);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t enable(net_layer *me, bool enable)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t process_input(net_layer *me, net_buffer *buffer)
|
||||
{
|
||||
uint16 *protocol;
|
||||
|
||||
if (!buffer)
|
||||
return B_ERROR;
|
||||
|
||||
if (g_stack->find_buffer_attribute(buffer, ethernet_protocol_attr, 0, NULL, (void **) &protocol, NULL) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
if (*protocol != htons(0x0800)) // IPv4 on Ethernet protocol value
|
||||
return B_ERROR;
|
||||
|
||||
// TODO!
|
||||
dump_ipv4_header(buffer);
|
||||
g_stack->delete_buffer(buffer, false);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t process_output(net_layer *me, net_buffer *buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
return B_ERROR;
|
||||
|
||||
// TODO!
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
status_t std_ops(int32 op, ...)
|
||||
{
|
||||
switch(op) {
|
||||
case B_MODULE_INIT: {
|
||||
status_t status;
|
||||
net_layer *layer;
|
||||
|
||||
printf("ipv4: B_MODULE_INIT\n");
|
||||
status = get_module(NET_STACK_MODULE_NAME, (module_info **) &g_stack);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
ethernet_protocol_attr = g_stack->string_to_token("ethernet:protocol");
|
||||
|
||||
status = g_stack->register_layer("IPv4", "ethernet/ipv4", 2, &nlmi, NULL, &layer);
|
||||
if (status != B_OK)
|
||||
goto error;
|
||||
|
||||
return B_OK;
|
||||
|
||||
error:
|
||||
g_stack->unregister_layer(layer);
|
||||
put_module(NET_STACK_MODULE_NAME);
|
||||
return status;
|
||||
}
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
printf("ipv4: B_MODULE_UNINIT\n");
|
||||
put_module(NET_STACK_MODULE_NAME);
|
||||
break;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
struct net_layer_module_info nlmi = {
|
||||
{
|
||||
NET_MODULES_ROOT "protocols/ipv4/v0",
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
|
||||
NET_LAYER_API_VERSION,
|
||||
|
||||
init,
|
||||
uninit,
|
||||
enable,
|
||||
NULL,
|
||||
process_input,
|
||||
process_output
|
||||
};
|
||||
|
||||
_EXPORT module_info *modules[] = {
|
||||
(module_info*) &nlmi, // net_layer_module_info
|
||||
NULL
|
||||
};
|
@ -1,13 +0,0 @@
|
||||
SubDir HAIKU_TOP src tests kits net new_stack stack ;
|
||||
|
||||
UseHeaders [ FDirName $(HAIKU_TOP) src tests kits net new_stack headers ] ;
|
||||
|
||||
Addon <v2>stack :
|
||||
stack.c
|
||||
attribute.c
|
||||
layers_manager.c
|
||||
buffer.c
|
||||
timer.c
|
||||
dump.c
|
||||
: <installed>new_stack_tester be
|
||||
;
|
@ -1,210 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <iovec.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <OS.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
#include "memory_pool.h"
|
||||
#include "attribute.h"
|
||||
|
||||
#define DPRINTF printf
|
||||
|
||||
#define ATTRIBUTES_PER_POOL (64)
|
||||
|
||||
static memory_pool *g_attributes_pool = NULL;
|
||||
extern memory_pool_module_info *g_memory_pool;
|
||||
|
||||
// Privates prototypes
|
||||
// -------------------
|
||||
|
||||
// LET'S GO FOR IMPLEMENTATION
|
||||
// ------------------------------------
|
||||
|
||||
status_t add_attribute(net_attribute **in_list, string_token id, int type, va_list args)
|
||||
{
|
||||
net_attribute *attr;
|
||||
|
||||
attr = new_attribute(in_list, id);
|
||||
if (! attr)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
attr->type = type;
|
||||
switch(type & NET_ATTRIBUTE_TYPE_MASK) {
|
||||
case NET_ATTRIBUTE_BOOL:
|
||||
attr->u.boolean = va_arg(args, bool);
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_BYTE:
|
||||
attr->u.byte = va_arg(args, uint8);
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_INT16:
|
||||
attr->u.word = va_arg(args, uint16);
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_INT32:
|
||||
attr->u.dword = va_arg(args, uint32);
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_INT64:
|
||||
attr->u.ddword = va_arg(args, uint64);
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_DATA:
|
||||
{ // void *data, size_t data_len
|
||||
void *data = va_arg(args, void *);
|
||||
size_t sz = va_arg(args, size_t);
|
||||
|
||||
if (sz > MAX_ATTRIBUTE_DATA_LEN)
|
||||
sz = MAX_ATTRIBUTE_DATA_LEN;
|
||||
|
||||
memcpy(attr->u.data, data, sz);
|
||||
break;
|
||||
}
|
||||
|
||||
case NET_ATTRIBUTE_STRING:
|
||||
strncpy(attr->u.data, va_arg(args, char *), MAX_ATTRIBUTE_DATA_LEN);
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_POINTER:
|
||||
// NB: data behind pointer ARE NOT copied
|
||||
attr->u.ptr = va_arg(args, void *);
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_IOVEC:
|
||||
{ // int nb, iovec *vec
|
||||
int nb = va_arg(args, int);
|
||||
iovec * vec = va_arg(args, iovec *);
|
||||
if (nb > MAX_ATTRIBUTE_IOVECS)
|
||||
nb = MAX_ATTRIBUTE_IOVECS;
|
||||
|
||||
memcpy(&attr->u.vec, vec, nb * sizeof(iovec));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
net_attribute * new_attribute(net_attribute **in_list, string_token id)
|
||||
{
|
||||
net_attribute *attr;
|
||||
|
||||
if (! g_attributes_pool)
|
||||
g_attributes_pool = g_memory_pool->new_pool(sizeof(*attr), ATTRIBUTES_PER_POOL);
|
||||
|
||||
if (! g_attributes_pool)
|
||||
return NULL;
|
||||
|
||||
attr = (net_attribute *) g_memory_pool->new_pool_node(g_attributes_pool);
|
||||
if (! attr)
|
||||
return NULL;
|
||||
|
||||
attr->id = id;
|
||||
attr->type = 0;
|
||||
|
||||
if (in_list) {
|
||||
// prepend this attribut to the list
|
||||
attr->next = *in_list;
|
||||
*in_list = attr;
|
||||
} else
|
||||
attr->next = NULL;
|
||||
|
||||
return attr;
|
||||
|
||||
}
|
||||
|
||||
status_t delete_attribute(net_attribute *attr, net_attribute **from_list)
|
||||
{
|
||||
if (! attr)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (! g_attributes_pool)
|
||||
// Uh? From where come this net_attribute!?!
|
||||
return B_ERROR;
|
||||
|
||||
// dprintf("delete_attribute(%p, %p)\n", attr, from_list);
|
||||
|
||||
// Remove attribut from list, if any
|
||||
if (from_list) {
|
||||
if (*from_list == attr)
|
||||
*from_list = attr->next;
|
||||
else {
|
||||
net_attribute *tmp = *from_list;
|
||||
while (tmp) {
|
||||
if (tmp->next == attr)
|
||||
break;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
if (tmp)
|
||||
tmp->next = attr->next;
|
||||
}
|
||||
}
|
||||
|
||||
// Last, delete the net_buffer itself
|
||||
return g_memory_pool->delete_pool_node(g_attributes_pool, attr);
|
||||
}
|
||||
|
||||
|
||||
net_attribute * find_attribute(net_attribute *list, string_token id, int index,
|
||||
int *type, void **value, size_t *size)
|
||||
{
|
||||
net_attribute *attr;
|
||||
|
||||
if (! list)
|
||||
return NULL;
|
||||
|
||||
// dprintf("find_attribute(%p, %p)\n", list, id);
|
||||
attr = list;
|
||||
while (attr) {
|
||||
if (attr->id == id && index-- == 0) {
|
||||
if (type) *type = attr->type;
|
||||
if (size) *size = attr->size;
|
||||
if (value) {
|
||||
switch (attr->type & NET_ATTRIBUTE_TYPE_MASK) {
|
||||
case NET_ATTRIBUTE_BOOL:
|
||||
*value = &attr->u.boolean;
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_BYTE:
|
||||
*value = &attr->u.byte;
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_INT16:
|
||||
*value = &attr->u.word;
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_INT32:
|
||||
*value = &attr->u.dword;
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_INT64:
|
||||
*value = &attr->u.ddword;
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_DATA:
|
||||
case NET_ATTRIBUTE_STRING:
|
||||
*value = &attr->u.data;
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_POINTER:
|
||||
*value = attr->u.ptr;
|
||||
break;
|
||||
|
||||
case NET_ATTRIBUTE_IOVEC:
|
||||
*value = &attr->u.vec;
|
||||
break;
|
||||
};
|
||||
};
|
||||
return attr;
|
||||
};
|
||||
attr = attr->next;
|
||||
};
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,48 +0,0 @@
|
||||
/* attribute.h
|
||||
* private definitions for network attributes
|
||||
*/
|
||||
|
||||
#ifndef OBOS_NET_STACK_ATTRIBUTE_H
|
||||
#define OBOS_NET_STACK_ATTRIBUTE_H
|
||||
|
||||
#include <iovec.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_ATTRIBUTE_IOVECS (16)
|
||||
#define MAX_ATTRIBUTE_DATA_LEN (256)
|
||||
|
||||
struct net_attribute {
|
||||
struct net_attribute *next;
|
||||
string_token id;
|
||||
uint32 type;
|
||||
size_t size;
|
||||
union {
|
||||
bool boolean;
|
||||
uint8 byte;
|
||||
uint16 word;
|
||||
uint32 dword;
|
||||
uint64 ddword;
|
||||
char data[MAX_ATTRIBUTE_DATA_LEN]; // Beware: data max size is limited :-(
|
||||
void *ptr;
|
||||
iovec vec[MAX_ATTRIBUTE_IOVECS]; // Beware: these are limited too :-(
|
||||
} u;
|
||||
};
|
||||
|
||||
extern status_t add_attribute(net_attribute **in_list, string_token id, int type, va_list args);
|
||||
extern net_attribute * new_attribute(net_attribute **in_list, string_token id);
|
||||
extern status_t delete_attribute(net_attribute *attribut, net_attribute **from_list);
|
||||
extern net_attribute * find_attribute(net_attribute *list, string_token id, int index, int *type, void **value, size_t *size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OBOS_NET_STACK_ATTRIBUTE_H
|
File diff suppressed because it is too large
Load Diff
@ -1,54 +0,0 @@
|
||||
/* buffer.h
|
||||
* private definitions for network buffers support
|
||||
*/
|
||||
|
||||
#ifndef OBOS_NET_STACK_BUFFER_H
|
||||
#define OBOS_NET_STACK_BUFFER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern status_t start_buffers_service(void);
|
||||
extern status_t stop_buffers_service(void);
|
||||
|
||||
// Network buffer(s)
|
||||
extern net_buffer * new_buffer(void);
|
||||
extern status_t delete_buffer(net_buffer *buffer, bool interrupt_safe);
|
||||
|
||||
extern net_buffer * duplicate_buffer(net_buffer *from);
|
||||
extern net_buffer * clone_buffer(net_buffer *from);
|
||||
extern net_buffer * split_buffer(net_buffer *from, uint32 offset);
|
||||
extern status_t merge_buffers(net_buffer *begin, net_buffer *end);
|
||||
|
||||
extern status_t add_to_buffer(net_buffer *buffer, uint32 offset, const void *data, size_t bytes, buffer_chunk_free_func freethis);
|
||||
extern status_t remove_from_buffer(net_buffer *buffer, uint32 offset, size_t bytes);
|
||||
|
||||
extern status_t attach_buffer_free_element(net_buffer *buffer, void *arg1, void *arg2, buffer_chunk_free_func freethis);
|
||||
|
||||
extern size_t read_buffer(net_buffer *buffer, uint32 offset, void *data, size_t bytes);
|
||||
extern size_t write_buffer(net_buffer *buffer, uint32 offset, const void *data, size_t bytes);
|
||||
|
||||
extern status_t add_buffer_attribute(net_buffer *buffer, string_token id, int type, ...);
|
||||
extern status_t remove_buffer_attribute(net_buffer *buffer, string_token id, int index);
|
||||
extern status_t find_buffer_attribute(net_buffer *buffer, string_token id, int index, int *type, void **value, size_t *size);
|
||||
|
||||
extern void dump_buffer(net_buffer *buffer);
|
||||
|
||||
// Network buffer(s) queue(s)
|
||||
extern net_buffer_queue * new_buffer_queue(size_t max_bytes);
|
||||
extern status_t delete_buffer_queue(net_buffer_queue *queue);
|
||||
|
||||
extern status_t empty_buffer_queue(net_buffer_queue *queue);
|
||||
extern status_t enqueue_buffer(net_buffer_queue *queue, net_buffer *buffer);
|
||||
extern size_t dequeue_buffer(net_buffer_queue *queue, net_buffer **buffer, bigtime_t timeout, bool peek);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // OBOS_NET_STACK_BUFFER_H
|
@ -1,51 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <drivers/module.h>
|
||||
#include <drivers/KernelExport.h>
|
||||
|
||||
#include "dump.h"
|
||||
|
||||
// --------------------------------------------------
|
||||
void dump_memory(const char *prefix, const void *data, size_t len)
|
||||
{
|
||||
uint32 i,j;
|
||||
char text[96]; // only 3*16 + 3 + 16 max by line needed
|
||||
uint8 *byte;
|
||||
char *ptr;
|
||||
|
||||
byte = (uint8 *) data;
|
||||
|
||||
for ( i = 0; i < len; i += 16 ) {
|
||||
ptr = text;
|
||||
|
||||
for ( j = i; j < i+16 ; j++ ) {
|
||||
if ( j < len )
|
||||
sprintf(ptr, "%02x ", byte[j]);
|
||||
else
|
||||
sprintf(ptr, " ");
|
||||
ptr += 3;
|
||||
};
|
||||
|
||||
strcat(ptr, "| ");
|
||||
ptr += 2;
|
||||
|
||||
for (j = i; j < len && j < i+16;j++) {
|
||||
if ( byte[j] >= 0x20 && byte[j] < 0x7e )
|
||||
*ptr = byte[j];
|
||||
else
|
||||
*ptr = '.';
|
||||
|
||||
ptr++;
|
||||
};
|
||||
*ptr = '\n';
|
||||
ptr++;
|
||||
*ptr = '\0';
|
||||
|
||||
if (prefix)
|
||||
dprintf(prefix);
|
||||
dprintf(text);
|
||||
|
||||
// next line
|
||||
};
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#ifndef DUMP_H
|
||||
#define DUMP_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
extern void dump_memory(const char *prefix, const void *data, size_t len);
|
||||
|
||||
#endif
|
@ -1,469 +0,0 @@
|
||||
/* layers_manager.c */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <OS.h>
|
||||
#include <module.h>
|
||||
|
||||
#include "memory_pool.h"
|
||||
#include "layers_manager.h"
|
||||
#include "buffer.h"
|
||||
#include "attribute.h"
|
||||
#include "stack.h" // for string_{to|for}_token()
|
||||
|
||||
struct layers_list {
|
||||
struct net_layer *first;
|
||||
sem_id lock;
|
||||
};
|
||||
|
||||
static struct layers_list g_layers;
|
||||
|
||||
static memory_pool * g_layers_pool = NULL;
|
||||
#define LAYERS_PER_POOL (64)
|
||||
|
||||
static net_layer * new_layer(const char *name, const char *type, int priority,
|
||||
net_layer_module_info *module, void *cookie);
|
||||
static status_t delete_layer(net_layer *layer);
|
||||
|
||||
extern memory_pool_module_info *g_memory_pool;
|
||||
|
||||
string_token g_joker_token = 0;
|
||||
string_token g_layers_trace_attr = 0;
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t start_layers_manager(void)
|
||||
{
|
||||
void *module_list;
|
||||
net_layer *layer;
|
||||
|
||||
g_joker_token = string_to_token("*");
|
||||
g_layers_trace_attr = string_to_token("layers_trace");
|
||||
|
||||
g_layers.first = NULL;
|
||||
|
||||
g_layers.lock = create_sem(1, "net_layers list lock");
|
||||
if (g_layers.lock < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
#ifdef _KERNEL_MODE
|
||||
set_sem_owner(g_layers.lock, B_SYSTEM_TEAM);
|
||||
#endif
|
||||
|
||||
// Load all network/* modules and let them
|
||||
// register any layer they may support by calling init()
|
||||
module_list = open_module_list(NET_MODULES_ROOT);
|
||||
if (module_list) {
|
||||
size_t sz;
|
||||
char module_name[256];
|
||||
struct net_layer_module_info *nlmi;
|
||||
|
||||
sz = sizeof(module_name);
|
||||
while (read_next_module_name(module_list, module_name, &sz) == B_OK) {
|
||||
sz = sizeof(module_name);
|
||||
if (!strlen(module_name))
|
||||
continue;
|
||||
|
||||
if (strcmp(module_name, NET_STACK_MODULE_NAME) == 0)
|
||||
continue; // skip ourself! ;-)
|
||||
|
||||
dprintf("layers_manager: loading %s layer(s) module\n", module_name);
|
||||
if (get_module(module_name, (module_info **) &nlmi) != B_OK)
|
||||
continue;
|
||||
|
||||
// this module may have been acquire more time if he called register_layer(),
|
||||
// or have a B_KEEP_LOADED flag, so we don't care...
|
||||
put_module(module_name);
|
||||
};
|
||||
close_module_list(module_list);
|
||||
};
|
||||
|
||||
// auto-start layer(s)
|
||||
acquire_sem(g_layers.lock);
|
||||
layer = g_layers.first;
|
||||
while (layer) {
|
||||
layer->module->init(layer);
|
||||
layer->module->enable(layer, true);
|
||||
layer = layer->next;
|
||||
};
|
||||
release_sem(g_layers.lock);
|
||||
|
||||
puts("net layers manager started.");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t stop_layers_manager(void)
|
||||
{
|
||||
net_layer *layer, *next;
|
||||
const char *module_name;
|
||||
|
||||
delete_sem(g_layers.lock);
|
||||
g_layers.lock = -1;
|
||||
|
||||
// TODO: handle multiple layers registered by same net module
|
||||
|
||||
// disable all layers...
|
||||
layer = g_layers.first;
|
||||
while (layer) {
|
||||
next = layer->next;
|
||||
module_name = layer->module->info.name;
|
||||
dprintf("layers_manager: uniniting '%s' layer\n", layer->name);
|
||||
// down the layer if currently up
|
||||
layer->module->enable(layer, false);
|
||||
layer->module->uninit(layer);
|
||||
|
||||
delete_layer(layer);
|
||||
|
||||
dprintf("layers_manager: unloading %s layer(s) module\n", module_name);
|
||||
put_module(module_name);
|
||||
|
||||
layer = next;
|
||||
};
|
||||
|
||||
puts("net layers manager stopped.");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t register_layer(const char *name, const char *type, int priority,
|
||||
net_layer_module_info *module, void *cookie, net_layer **_layer)
|
||||
{
|
||||
status_t status;
|
||||
module_info *dummy;
|
||||
net_layer *layer;
|
||||
|
||||
if (name == NULL ||
|
||||
strlen(name) <= 0 ||
|
||||
module == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
layer = new_layer(name, type, priority, module, cookie);
|
||||
if (!layer)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// acquire this module, to keep it loaded while this layer is registered
|
||||
status = get_module(module->info.name, &dummy);
|
||||
if (status != B_OK)
|
||||
goto error1;
|
||||
|
||||
status = acquire_sem(g_layers.lock);
|
||||
if (status != B_OK)
|
||||
goto error2;
|
||||
|
||||
layer->next = g_layers.first;
|
||||
g_layers.first = layer;
|
||||
|
||||
release_sem(g_layers.lock);
|
||||
|
||||
dprintf("layers_manager: '%s' layer, registering '%s/%s' type\n", layer->name,
|
||||
string_for_token(layer->type), string_for_token(layer->sub_type));
|
||||
|
||||
if (_layer)
|
||||
*_layer = layer;
|
||||
return B_OK;
|
||||
|
||||
error2:
|
||||
put_module(module->info.name);
|
||||
error1:
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t unregister_layer(net_layer *layer)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
if (!layer)
|
||||
return B_ERROR;
|
||||
|
||||
status = acquire_sem(g_layers.lock);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (g_layers.first == layer)
|
||||
g_layers.first = layer->next;
|
||||
else {
|
||||
net_layer * p = g_layers.first;
|
||||
while (p && p->next != layer)
|
||||
p = p->next;
|
||||
|
||||
if (!p) {
|
||||
// Oh oh... :-(
|
||||
dprintf("layers_manager: unregister_layer(): %p layer not found in list!\n", layer);
|
||||
release_sem(g_layers.lock);
|
||||
return B_ERROR;
|
||||
};
|
||||
|
||||
p->next = layer->next;
|
||||
};
|
||||
release_sem(g_layers.lock);
|
||||
|
||||
layer->module->uninit(layer);
|
||||
|
||||
dprintf("layers_manager: '%s' layer unregistered\n", layer->name);
|
||||
|
||||
put_module(layer->module->info.name);
|
||||
|
||||
return delete_layer(layer);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
net_layer * find_layer(const char *name)
|
||||
{
|
||||
net_layer *layer;
|
||||
status_t status;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
status = acquire_sem(g_layers.lock);
|
||||
if (status != B_OK)
|
||||
return NULL;
|
||||
|
||||
layer = g_layers.first;
|
||||
while (layer) {
|
||||
if (strcmp(layer->name, name) == 0)
|
||||
break;
|
||||
layer = layer->next;
|
||||
}
|
||||
release_sem(g_layers.lock);
|
||||
return layer;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t add_layer_attribute(net_layer *layer, const void *id, int type, ...)
|
||||
{
|
||||
status_t status;
|
||||
va_list args;
|
||||
|
||||
va_start(args, type);
|
||||
status = add_attribute(&layer->attributes, id, type, args);
|
||||
va_end(args);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t remove_layer_attribute(net_layer *layer, const void *id, int index)
|
||||
{
|
||||
net_attribute *attr;
|
||||
|
||||
if (! layer)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
attr = find_attribute(layer->attributes, id, index, NULL, NULL, NULL);
|
||||
if (! attr)
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
return delete_attribute(attr, &layer->attributes);
|
||||
}
|
||||
|
||||
status_t find_layer_attribute(net_layer *layer, const void *id, int index, int *type,
|
||||
void **value, size_t *size)
|
||||
{
|
||||
net_attribute *attr;
|
||||
|
||||
if (! layer)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
attr = find_attribute(layer->attributes, id, index, type, value, size);
|
||||
if (! attr)
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t send_layers_up(net_layer *layer, net_buffer *buffer)
|
||||
{
|
||||
net_layer *above;
|
||||
status_t status;
|
||||
// int i;
|
||||
|
||||
if (!layer)
|
||||
return B_ERROR;
|
||||
|
||||
add_buffer_attribute(buffer, g_layers_trace_attr, NET_ATTRIBUTE_STRING, layer->name),
|
||||
|
||||
status = acquire_sem(g_layers.lock);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status = B_ERROR;
|
||||
// TODO: lookup thru a previoulsy (at each layer [un]registration time) built list of
|
||||
// "above" layers of caller layer.
|
||||
|
||||
// dprintf("layers_manager: send_layers_up(): layer %s (%x/%x), searching a matching upper layer...\n",
|
||||
// layer->name, layer->type, layer->sub_type);
|
||||
|
||||
// HACK: today, we lookup thru ALL :-( registered layers.
|
||||
// In the future, such layers (de)assembly should be done at layer (un)resgistration time, as
|
||||
// it never change until layers list change herself...
|
||||
above = g_layers.first;
|
||||
while (above) {
|
||||
// dprintf("layers_manager: send_layers_up: Matching against layer %s (%x/%x) ?\n",
|
||||
// above->name, above->type, above->sub_type);
|
||||
|
||||
if ( above->module->process_input &&
|
||||
( (above->type == g_joker_token) || (above->type == layer->sub_type) ) ) {
|
||||
/*
|
||||
dprintf("layers_manager: send_layers_up: handing buffer from %x/%x (%s) to %x/%x (%s)...\n",
|
||||
layer->type, layer->sub_type, layer->name,
|
||||
above->type, above->sub_type, above->name);
|
||||
*/
|
||||
release_sem(g_layers.lock);
|
||||
status = above->module->process_input(above, buffer);
|
||||
if (status == B_OK) {
|
||||
atomic_add(&above->use_count, 1);
|
||||
// TODO: resort this layer with previous one, if required.
|
||||
return status;
|
||||
};
|
||||
|
||||
status = acquire_sem(g_layers.lock);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
};
|
||||
above = above->next;
|
||||
}
|
||||
release_sem(g_layers.lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t send_layers_down(net_layer *layer, net_buffer *buffer)
|
||||
{
|
||||
net_layer *below;
|
||||
status_t status;
|
||||
int i;
|
||||
|
||||
if (!layer)
|
||||
return B_ERROR;
|
||||
|
||||
|
||||
// #### TODO: lock the layer(s) above & below hierarchy
|
||||
if (!layer->layers_below)
|
||||
// no layers below this one
|
||||
return B_ERROR;
|
||||
|
||||
add_buffer_attribute(buffer, g_layers_trace_attr, NET_ATTRIBUTE_STRING, layer->name),
|
||||
|
||||
status = B_ERROR;
|
||||
i = 0;
|
||||
while (layer->layers_below[i]) {
|
||||
below = layer->layers_below[i++];
|
||||
if (!below->module->process_output)
|
||||
// this layer don't process output buffer
|
||||
continue;
|
||||
|
||||
status = below->module->process_output(below, buffer);
|
||||
if (status == B_OK) {
|
||||
atomic_add(&below->use_count, 1);
|
||||
// TODO: resort this layer with previous one, if required.
|
||||
return status;
|
||||
};
|
||||
};
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// --------------------------------------------------
|
||||
static net_layer * new_layer(const char *name, const char *type, int priority,
|
||||
net_layer_module_info *module, void *cookie)
|
||||
{
|
||||
net_layer *layer;
|
||||
|
||||
if (! g_layers_pool)
|
||||
g_layers_pool = g_memory_pool->new_pool(sizeof(*layer), LAYERS_PER_POOL);
|
||||
|
||||
if (! g_layers_pool)
|
||||
return NULL;
|
||||
|
||||
layer = (net_layer *) g_memory_pool->new_pool_node(g_layers_pool);
|
||||
if (! layer)
|
||||
return NULL;
|
||||
|
||||
layer->name = strdup(name);
|
||||
|
||||
if (type) {
|
||||
char *tmp, *t, *n;
|
||||
|
||||
tmp = strdup(type);
|
||||
t = strtok_r(tmp, "/", &n);
|
||||
layer->type = (t ? string_to_token(t) : g_joker_token);
|
||||
t = strtok_r(NULL, " ", &n);
|
||||
layer->sub_type = (t ? string_to_token(t) : g_joker_token);
|
||||
free(tmp);
|
||||
} else
|
||||
layer->type = layer->sub_type = 0;
|
||||
|
||||
|
||||
layer->priority = priority;
|
||||
layer->module = module;
|
||||
layer->cookie = cookie;
|
||||
|
||||
layer->layers_above = NULL;
|
||||
layer->layers_below = NULL;
|
||||
|
||||
layer->attributes = NULL;
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
static status_t delete_layer(net_layer *layer)
|
||||
{
|
||||
if (!layer)
|
||||
return B_ERROR;
|
||||
|
||||
if (! g_layers_pool)
|
||||
// Uh? From where come this net_data!?!
|
||||
return B_ERROR;
|
||||
|
||||
if (layer->name)
|
||||
free(layer->name);
|
||||
|
||||
if (layer->layers_above)
|
||||
free(layer->layers_above);
|
||||
if (layer->layers_below)
|
||||
free(layer->layers_below);
|
||||
|
||||
if (layer->attributes) {
|
||||
// Free layer attributes
|
||||
|
||||
net_attribute *attr;
|
||||
net_attribute *next_attr;
|
||||
|
||||
attr = layer->attributes;
|
||||
while (attr) {
|
||||
next_attr = attr->next;
|
||||
delete_attribute(attr, NULL);
|
||||
attr = next_attr;
|
||||
};
|
||||
};
|
||||
|
||||
return g_memory_pool->delete_pool_node(g_layers_pool, layer);
|
||||
}
|
||||
|
||||
|
@ -1,35 +0,0 @@
|
||||
/* layers_manager.h
|
||||
* private definitions for network layers manager
|
||||
*/
|
||||
|
||||
#ifndef OBOS_NET_STACK_LAYERS_MANAGER_H
|
||||
#define OBOS_NET_STACK_LAYERS_MANAGER_H
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern status_t start_layers_manager(void);
|
||||
extern status_t stop_layers_manager(void);
|
||||
|
||||
extern status_t register_layer(const char *name, const char *type, int priority,
|
||||
net_layer_module_info *module, void *cookie, net_layer **layer);
|
||||
extern status_t unregister_layer(net_layer *layer);
|
||||
extern net_layer * find_layer(const char *name);
|
||||
|
||||
extern status_t add_layer_attribute(net_layer *layer, const void *id, int type, ...);
|
||||
extern status_t remove_layer_attribute(net_layer *layer, const void *id, int index);
|
||||
extern status_t find_layer_attribute(net_layer *layer, const void *id, int index,
|
||||
int *type, void **attribute, size_t *size);
|
||||
|
||||
extern status_t send_layers_up(net_layer *me, struct net_buffer *buffer);
|
||||
extern status_t send_layers_down(net_layer *me, struct net_buffer *buffer);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OBOS_NET_STACK_LAYERS_MANAGER_H */
|
@ -1,212 +0,0 @@
|
||||
/* stack.c */
|
||||
|
||||
/* This the heart of network stack
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <drivers/module.h>
|
||||
#include <drivers/KernelExport.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
#include "memory_pool.h"
|
||||
#include "atomizer.h"
|
||||
|
||||
#include "stack.h"
|
||||
#include "attribute.h"
|
||||
#include "layers_manager.h"
|
||||
#include "buffer.h"
|
||||
#include "timer.h"
|
||||
#include "dump.h"
|
||||
|
||||
memory_pool_module_info *g_memory_pool = NULL;
|
||||
atomizer_module_info *g_atomizer = NULL;
|
||||
#define DEFAULT_ATOMIZER (const void *) (-1)
|
||||
|
||||
static bool g_started = false;
|
||||
|
||||
status_t std_ops(int32 op, ...);
|
||||
|
||||
static status_t start(void);
|
||||
static status_t stop(void);
|
||||
|
||||
|
||||
static status_t start(void)
|
||||
{
|
||||
if (g_started)
|
||||
return B_OK;
|
||||
|
||||
dprintf("stack: starting...\n");
|
||||
|
||||
start_buffers_service();
|
||||
start_timers_service();
|
||||
|
||||
start_layers_manager();
|
||||
|
||||
dprintf("stack: started.\n");
|
||||
g_started = true;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
static status_t stop(void)
|
||||
{
|
||||
dprintf("stack: stopping...\n");
|
||||
|
||||
stop_layers_manager();
|
||||
|
||||
stop_timers_service();
|
||||
stop_buffers_service();
|
||||
|
||||
|
||||
dprintf("stack: stopped.\n");
|
||||
g_started = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
string_token string_to_token(const char *name)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
if (g_atomizer == NULL) {
|
||||
status = get_module(B_ATOMIZER_MODULE_NAME, (module_info **) &g_atomizer);
|
||||
if (status != B_OK) {
|
||||
dprintf("string_to_token(%s): Can't load " B_ATOMIZER_MODULE_NAME " module!\n", name);
|
||||
g_atomizer = (atomizer_module_info *) -1;
|
||||
};
|
||||
};
|
||||
|
||||
if (g_atomizer == (atomizer_module_info *) -1)
|
||||
return NULL;
|
||||
|
||||
return g_atomizer->atomize(DEFAULT_ATOMIZER, name, true);
|
||||
}
|
||||
|
||||
|
||||
const char * string_for_token(string_token token)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
if (g_atomizer == NULL) {
|
||||
status = get_module(B_ATOMIZER_MODULE_NAME, (module_info **) &g_atomizer);
|
||||
if (status != B_OK) {
|
||||
dprintf("string_for_token(%x): Can't load " B_ATOMIZER_MODULE_NAME " module!\n", (int) token);
|
||||
g_atomizer = (atomizer_module_info *) -1;
|
||||
};
|
||||
};
|
||||
|
||||
if (g_atomizer == (atomizer_module_info *) -1)
|
||||
return NULL;
|
||||
|
||||
return g_atomizer->string_for_token(DEFAULT_ATOMIZER, token);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
struct net_stack_module_info nsmi = {
|
||||
{
|
||||
NET_STACK_MODULE_NAME,
|
||||
0, // B_KEEP_LOADED,
|
||||
std_ops
|
||||
},
|
||||
|
||||
// Global stack control
|
||||
start,
|
||||
stop,
|
||||
|
||||
// String tokens
|
||||
string_to_token,
|
||||
string_for_token,
|
||||
|
||||
// Layers handling
|
||||
register_layer,
|
||||
unregister_layer,
|
||||
find_layer,
|
||||
add_layer_attribute,
|
||||
remove_layer_attribute,
|
||||
find_layer_attribute,
|
||||
|
||||
send_layers_up,
|
||||
send_layers_down,
|
||||
|
||||
// net_buffer support
|
||||
new_buffer,
|
||||
delete_buffer,
|
||||
duplicate_buffer,
|
||||
clone_buffer,
|
||||
split_buffer,
|
||||
|
||||
add_to_buffer,
|
||||
remove_from_buffer,
|
||||
|
||||
attach_buffer_free_element,
|
||||
|
||||
read_buffer,
|
||||
write_buffer,
|
||||
|
||||
add_buffer_attribute,
|
||||
remove_buffer_attribute,
|
||||
find_buffer_attribute,
|
||||
|
||||
dump_buffer,
|
||||
|
||||
// net_buffer_queue support
|
||||
new_buffer_queue,
|
||||
delete_buffer_queue,
|
||||
empty_buffer_queue,
|
||||
enqueue_buffer,
|
||||
dequeue_buffer,
|
||||
|
||||
// Timers support
|
||||
new_net_timer,
|
||||
delete_net_timer,
|
||||
start_net_timer,
|
||||
cancel_net_timer,
|
||||
net_timer_appointment,
|
||||
|
||||
// Misc.
|
||||
dump_memory
|
||||
};
|
||||
|
||||
status_t std_ops(int32 op, ...)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
switch(op) {
|
||||
case B_MODULE_INIT:
|
||||
dprintf("stack: B_MODULE_INIT\n");
|
||||
load_driver_symbols("stack");
|
||||
status = get_module(MEMORY_POOL_MODULE_NAME, (module_info **) &g_memory_pool);
|
||||
if (status != B_OK) {
|
||||
dprintf("stack: Can't load " MEMORY_POOL_MODULE_NAME " module!\n");
|
||||
return status;
|
||||
};
|
||||
|
||||
// Re-publish memory_pool module api thru our
|
||||
nsmi.new_pool = g_memory_pool->new_pool;
|
||||
nsmi.delete_pool = g_memory_pool->delete_pool;
|
||||
nsmi.new_pool_node = g_memory_pool->new_pool_node;
|
||||
nsmi.delete_pool_node = g_memory_pool->delete_pool_node;
|
||||
nsmi.for_each_pool_node = g_memory_pool->for_each_pool_node;
|
||||
break;
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
dprintf("stack: B_MODULE_UNINIT\n");
|
||||
put_module(MEMORY_POOL_MODULE_NAME);
|
||||
break;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
_EXPORT module_info *modules[] = {
|
||||
(module_info *) &nsmi, // net_stack_module_info
|
||||
NULL
|
||||
};
|
||||
|
@ -1,9 +0,0 @@
|
||||
#ifndef STACK_H
|
||||
#define STACK_H
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
extern string_token string_to_token(const char *name);
|
||||
extern const char * string_for_token(string_token token);
|
||||
|
||||
#endif
|
@ -1,277 +0,0 @@
|
||||
/* timer.c - a small and more or less inaccurate timer for net modules.
|
||||
** The registered hooks will be called in the thread of the timer.
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
**
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <KernelExport.h>
|
||||
#include <OS.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
#include "timer.h"
|
||||
|
||||
struct net_timer {
|
||||
struct net_timer *next;
|
||||
net_timer_func func;
|
||||
void *func_cookie;
|
||||
bigtime_t period;
|
||||
bigtime_t until;
|
||||
bool pending;
|
||||
};
|
||||
|
||||
struct timers_queue {
|
||||
struct net_timer *first;
|
||||
sem_id lock;
|
||||
sem_id wait;
|
||||
int32 counter;
|
||||
volatile int32 in_use;
|
||||
};
|
||||
|
||||
static struct timers_queue g_timers;
|
||||
static thread_id g_timers_thread = -1;
|
||||
|
||||
static int32 timers_thread(void *data);
|
||||
|
||||
// #pragma mark [Start/Stop Service functions]
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t start_timers_service(void)
|
||||
{
|
||||
memset(&g_timers, 0, sizeof(g_timers));
|
||||
|
||||
g_timers.lock = create_sem(1, "net_timers lock");
|
||||
if (g_timers.lock < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
g_timers.wait = create_sem(0,"net_timers wait");
|
||||
if (g_timers.wait < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
#ifdef _KERNEL_MODE
|
||||
set_sem_owner(g_timers.lock, B_SYSTEM_TEAM);
|
||||
set_sem_owner(g_timers.wait, B_SYSTEM_TEAM);
|
||||
#endif
|
||||
|
||||
g_timers_thread = spawn_kernel_thread(timers_thread, "timers lone runner", B_URGENT_DISPLAY_PRIORITY, &g_timers);
|
||||
if (g_timers_thread < B_OK)
|
||||
return g_timers_thread;
|
||||
|
||||
puts("net timers service started.");
|
||||
|
||||
return resume_thread(g_timers_thread);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t stop_timers_service(void)
|
||||
{
|
||||
net_timer *nt, *next;
|
||||
int32 tries = 20;
|
||||
status_t status;
|
||||
|
||||
delete_sem(g_timers.wait);
|
||||
delete_sem(g_timers.lock);
|
||||
g_timers.wait = -1;
|
||||
g_timers.lock = -1;
|
||||
|
||||
wait_for_thread(g_timers_thread, &status);
|
||||
|
||||
// make sure the structure isn't used anymore
|
||||
while (g_timers.in_use != 0 && tries-- > 0)
|
||||
snooze(1000);
|
||||
|
||||
// free the remaining timer entries
|
||||
for (nt = g_timers.first; nt; nt = next) {
|
||||
next = nt->next;
|
||||
free(nt);
|
||||
}
|
||||
|
||||
puts("net timers service stopped.");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark [Public functions]
|
||||
|
||||
// --------------------------------------------------
|
||||
net_timer * new_net_timer(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t delete_net_timer(net_timer *nt)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t start_net_timer(net_timer *nt, net_timer_func func, void *cookie, bigtime_t period)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t cancel_net_timer(net_timer *nt)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------
|
||||
status_t net_timer_appointment(net_timer *nt, bigtime_t *period, bigtime_t *when)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// --------------------------------------------------
|
||||
static int32 timers_thread(void *data)
|
||||
{
|
||||
struct timers_queue *timers = (struct timers_queue *) data;
|
||||
status_t status = B_OK;
|
||||
|
||||
do {
|
||||
bigtime_t timeout = B_INFINITE_TIMEOUT;
|
||||
net_timer *nt;
|
||||
|
||||
// get access to the info structure
|
||||
if (status == B_TIMED_OUT || status == B_OK) {
|
||||
if (acquire_sem(timers->lock) == B_OK) {
|
||||
for (nt = timers->first; nt; nt = nt->next) {
|
||||
// new entry?
|
||||
if (nt->until == -1)
|
||||
nt->until = system_time() + nt->period;
|
||||
|
||||
// execute timer?
|
||||
if (nt->until < system_time()) {
|
||||
nt->until += nt->period;
|
||||
nt->func(nt, nt->func_cookie);
|
||||
}
|
||||
|
||||
// calculate new timeout
|
||||
if (nt->until < timeout)
|
||||
timeout = nt->until;
|
||||
}
|
||||
|
||||
release_sem(timers->lock);
|
||||
}
|
||||
}
|
||||
|
||||
status = acquire_sem_etc(timers->wait, 1, B_ABSOLUTE_TIMEOUT, timeout);
|
||||
// the wait sem normally can't be acquired, so we
|
||||
// have to look at the status value the call returns:
|
||||
//
|
||||
// B_OK - someone wanted to notify us
|
||||
// B_TIMED_OUT - look for timers to be executed
|
||||
// B_BAD_SEM_ID - our sem got deleted
|
||||
|
||||
} while (status != B_BAD_SEM_ID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
|
||||
net_timer_id
|
||||
net_add_timer(net_timer_hook hook,void *data,bigtime_t interval)
|
||||
{
|
||||
struct timer_entry *te;
|
||||
status_t status;
|
||||
|
||||
if (interval < 100)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
atomic_add(&gTimerInfo.ti_inUse,1);
|
||||
|
||||
// get access to the timer info structure
|
||||
status = acquire_sem(gTimerInfo.ti_lock);
|
||||
if (status < B_OK) {
|
||||
atomic_add(&gTimerInfo.ti_inUse,-1);
|
||||
return status;
|
||||
}
|
||||
|
||||
te = (struct timer_entry *)malloc(sizeof(struct timer_entry));
|
||||
if (te == NULL) {
|
||||
atomic_add(&gTimerInfo.ti_inUse,-1);
|
||||
release_sem(gTimerInfo.ti_lock);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
te->te_hook = hook;
|
||||
te->te_data = data;
|
||||
te->te_interval = interval;
|
||||
te->te_until = -1;
|
||||
te->te_id = ++gTimerInfo.ti_counter;
|
||||
|
||||
// add the new entry
|
||||
te->te_next = gTimerInfo.ti_first;
|
||||
gTimerInfo.ti_first = te;
|
||||
|
||||
atomic_add(&gTimerInfo.ti_inUse,-1);
|
||||
release_sem(gTimerInfo.ti_lock);
|
||||
|
||||
// notify timer about the change
|
||||
release_sem(gTimerInfo.ti_wait);
|
||||
|
||||
return te->te_id;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
net_remove_timer(net_timer_id id)
|
||||
{
|
||||
struct timer_entry *te,*last;
|
||||
status_t status;
|
||||
|
||||
if (id <= B_OK)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
atomic_add(&gTimerInfo.ti_inUse,1);
|
||||
|
||||
// get access to the timer info structure
|
||||
status = acquire_sem(gTimerInfo.ti_lock);
|
||||
if (status < B_OK) {
|
||||
atomic_add(&gTimerInfo.ti_inUse,-1);
|
||||
return status;
|
||||
}
|
||||
|
||||
// search the list for the right timer
|
||||
|
||||
// little hack that relies on ti_first being on the same position
|
||||
// in the structure as te_next
|
||||
last = (struct timer_entry *)&gTimerInfo;
|
||||
for (te = gTimerInfo.ti_first;te;te = te->te_next) {
|
||||
if (te->te_id == id) {
|
||||
last->te_next = te->te_next;
|
||||
free(te);
|
||||
break;
|
||||
}
|
||||
last = te;
|
||||
}
|
||||
atomic_add(&gTimerInfo.ti_inUse,-1);
|
||||
release_sem(gTimerInfo.ti_lock);
|
||||
|
||||
if (te == NULL)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
// notify timer about the change
|
||||
release_sem(gTimerInfo.ti_wait);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,37 +0,0 @@
|
||||
/* timer.h
|
||||
* private definitions for network timers support
|
||||
*/
|
||||
|
||||
#ifndef OBOS_NET_STACK_TIMER_H
|
||||
#define OBOS_NET_STACK_TIMER_H
|
||||
|
||||
/* timer.h - a small and more or less inaccurate timer for net modules.
|
||||
** The registered hooks will be called in the thread of the timer.
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
**
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "net_stack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern status_t start_timers_service(void);
|
||||
extern status_t stop_timers_service(void);
|
||||
|
||||
extern net_timer * new_net_timer(void);
|
||||
extern status_t delete_net_timer(net_timer *nt);
|
||||
extern status_t start_net_timer(net_timer *nt, net_timer_func hook, void *cookie, bigtime_t period);
|
||||
extern status_t cancel_net_timer(net_timer *nt);
|
||||
extern status_t net_timer_appointment(net_timer *nt, bigtime_t *period, bigtime_t *when);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OBOS_NET_STACK_TIMER_H */
|
@ -1,554 +0,0 @@
|
||||
/* userland_ipc - Communication between the network driver
|
||||
** and the userland stack.
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include "userland_ipc.h"
|
||||
|
||||
#include "sys/socket.h"
|
||||
#include "net_misc.h"
|
||||
#include "core_module.h"
|
||||
#include "net_module.h"
|
||||
#include "sys/sockio.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
extern struct core_module_info *core;
|
||||
|
||||
// installs a main()
|
||||
//#define COMMUNICATION_TEST
|
||||
|
||||
#define NUM_COMMANDS 32
|
||||
#define CONNECTION_BUFFER_SIZE (65536 + 4096 - CONNECTION_COMMAND_SIZE)
|
||||
|
||||
#define ROUND_TO_PAGE_SIZE(x) (((x) + (B_PAGE_SIZE) - 1) & ~((B_PAGE_SIZE) - 1))
|
||||
|
||||
struct socket; /* forward declaration */
|
||||
|
||||
typedef struct {
|
||||
port_id localPort,port;
|
||||
area_id area;
|
||||
struct socket * socket;
|
||||
|
||||
uint8 *buffer;
|
||||
net_command *commands;
|
||||
sem_id commandSemaphore;
|
||||
|
||||
int32 openFlags;
|
||||
|
||||
thread_id runner;
|
||||
|
||||
// for socket select events support
|
||||
port_id socket_event_port;
|
||||
void * notify_cookie;
|
||||
} connection_cookie;
|
||||
|
||||
|
||||
port_id gStackPort = -1;
|
||||
thread_id gConnectionOpener = -1;
|
||||
|
||||
// prototypes
|
||||
static int32 connection_runner(void *_cookie);
|
||||
static status_t init_connection(net_connection *connection, connection_cookie **_cookie);
|
||||
static void shutdown_connection(connection_cookie *cookie);
|
||||
|
||||
|
||||
static void
|
||||
delete_cloned_areas(net_area_info *area)
|
||||
{
|
||||
int32 i;
|
||||
for (i = 0;i < MAX_NET_AREAS;i++) {
|
||||
if (area[i].id == 0)
|
||||
continue;
|
||||
|
||||
delete_area(area[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
clone_command_areas(net_area_info *localArea,net_command *command)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
memset(localArea,0,sizeof(net_area_info) * MAX_NET_AREAS);
|
||||
|
||||
for (i = 0;i < MAX_NET_AREAS;i++) {
|
||||
if (command->area[i].id <= 0)
|
||||
continue;
|
||||
|
||||
localArea[i].id = clone_area("net connection",(void **)&localArea[i].offset,B_ANY_ADDRESS,
|
||||
B_READ_AREA | B_WRITE_AREA,command->area[i].id);
|
||||
if (localArea[i].id < B_OK)
|
||||
return localArea[i].id;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static uint8 *
|
||||
convert_address(net_area_info *fromArea,net_area_info *toArea,uint8 *data)
|
||||
{
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
if (data < fromArea->offset) {
|
||||
printf("could not translate address: %p\n",data);
|
||||
return data;
|
||||
}
|
||||
|
||||
return data - fromArea->offset + toArea->offset;
|
||||
}
|
||||
|
||||
|
||||
static inline void *
|
||||
convert_to_local(net_area_info *foreignArea,net_area_info *localArea,void *data)
|
||||
{
|
||||
return convert_address(foreignArea,localArea,data);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
convert_to_foreign(net_area_info *foreignArea,net_area_info *localArea,void *data)
|
||||
{
|
||||
return convert_address(localArea,foreignArea,data);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_socket_event(void * socket, uint32 event, void * cookie)
|
||||
{
|
||||
connection_cookie * cc = (connection_cookie *) cookie;
|
||||
struct socket_event_data sed;
|
||||
status_t status;
|
||||
|
||||
if (!cc)
|
||||
return;
|
||||
|
||||
if (cc->socket != socket) {
|
||||
printf("on_socket_event(%p, %ld, %p): socket is higly suspect! Aborting.\n", socket, event, cookie);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("on_socket_event(%p, %ld, %p)\n", socket, event, cookie);
|
||||
|
||||
sed.event = event;
|
||||
sed.cookie = cc->notify_cookie;
|
||||
|
||||
// TODO: don't block here => write_port_etc() ?
|
||||
status = write_port(cc->socket_event_port, NET_STACK_SOCKET_EVENT_NOTIFICATION,
|
||||
&sed, sizeof(sed));
|
||||
if (status != B_OK)
|
||||
printf("write_port(NET_STACK_SOCKET_EVENT_NOTIFICATION) failure: %s\n",
|
||||
strerror(status));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int32
|
||||
connection_runner(void *_cookie)
|
||||
{
|
||||
connection_cookie *cookie = (connection_cookie *)_cookie;
|
||||
bool run = true;
|
||||
|
||||
while (run) {
|
||||
net_area_info area[MAX_NET_AREAS];
|
||||
net_command *command;
|
||||
status_t status = B_OK;
|
||||
uint8 *data;
|
||||
int32 index;
|
||||
ssize_t bytes = read_port(cookie->localPort,&index,NULL,0);
|
||||
if (bytes < B_OK)
|
||||
break;
|
||||
|
||||
if (index >= NUM_COMMANDS || index < 0) {
|
||||
printf("got bad command index: %lx\n",index);
|
||||
continue;
|
||||
}
|
||||
command = cookie->commands + index;
|
||||
if (clone_command_areas(area,command) < B_OK) {
|
||||
printf("could not clone command areas!\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
data = convert_to_local(&command->area[0],&area[0],command->data);
|
||||
printf("command %lx (index = %ld), buffer = %p, length = %ld, result = %ld\n",command->op,index,data,command->length,command->result);
|
||||
|
||||
switch (command->op) {
|
||||
case NET_STACK_OPEN:
|
||||
{
|
||||
struct int_args *args = (struct int_args *)data;
|
||||
cookie->openFlags = args->value;
|
||||
printf("opening socket, mode = %lx!\n",cookie->openFlags);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_CLOSE:
|
||||
printf("closing socket...\n");
|
||||
run = false;
|
||||
break;
|
||||
|
||||
case NET_STACK_SOCKET:
|
||||
{
|
||||
struct socket_args *args = (struct socket_args *)data;
|
||||
|
||||
printf("open a socket... family = %d, type = %d, proto = %d\n",args->family,args->type,args->proto);
|
||||
status = core->socket_init(&cookie->socket);
|
||||
if (status == 0)
|
||||
status = core->socket_create(cookie->socket, args->family, args->type, args->proto);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_GETSOCKOPT:
|
||||
case NET_STACK_SETSOCKOPT:
|
||||
{
|
||||
struct sockopt_args *sockopt = (struct sockopt_args *)data;
|
||||
|
||||
if (command->op == NET_STACK_GETSOCKOPT) {
|
||||
status = core->socket_getsockopt(cookie->socket,sockopt->level,sockopt->option,
|
||||
convert_to_local(&command->area[1],&area[1],sockopt->optval),
|
||||
(size_t *)&sockopt->optlen);
|
||||
} else {
|
||||
status = core->socket_setsockopt(cookie->socket,sockopt->level,sockopt->option,
|
||||
(const void *)convert_to_local(&command->area[1],&area[1],sockopt->optval),
|
||||
sockopt->optlen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NET_STACK_CONNECT:
|
||||
case NET_STACK_BIND:
|
||||
case NET_STACK_GETSOCKNAME:
|
||||
case NET_STACK_GETPEERNAME:
|
||||
{
|
||||
struct sockaddr_args *args = (struct sockaddr_args *)data;
|
||||
caddr_t addr = (caddr_t)convert_to_local(&command->area[1],&area[1],args->addr);
|
||||
|
||||
switch (command->op) {
|
||||
case NET_STACK_CONNECT:
|
||||
status = core->socket_connect(cookie->socket,addr,args->addrlen);
|
||||
break;
|
||||
case NET_STACK_BIND:
|
||||
status = core->socket_bind(cookie->socket,addr,args->addrlen);
|
||||
break;
|
||||
case NET_STACK_GETSOCKNAME:
|
||||
status = core->socket_getsockname(cookie->socket,(struct sockaddr *)addr,&args->addrlen);
|
||||
break;
|
||||
case NET_STACK_GETPEERNAME:
|
||||
status = core->socket_getpeername(cookie->socket,(struct sockaddr *)addr,&args->addrlen);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NET_STACK_LISTEN:
|
||||
status = core->socket_listen(cookie->socket,((struct int_args *)data)->value);
|
||||
break;
|
||||
|
||||
case NET_STACK_GET_COOKIE:
|
||||
/* this is needed by accept() call, to be able to pass back
|
||||
* in NET_STACK_ACCEPT opcode the cookie of the filedescriptor to
|
||||
* use for the new accepted socket
|
||||
*/
|
||||
*((void **)data) = cookie;
|
||||
break;
|
||||
|
||||
case NET_STACK_ACCEPT:
|
||||
{
|
||||
struct accept_args *args = (struct accept_args *)data;
|
||||
connection_cookie *otherCookie = (connection_cookie *)args->cookie;
|
||||
status = core->socket_accept(cookie->socket,&otherCookie->socket,
|
||||
convert_to_local(&command->area[1],&area[1],args->addr),
|
||||
&args->addrlen);
|
||||
}
|
||||
case NET_STACK_SEND:
|
||||
{
|
||||
struct data_xfer_args *args = (struct data_xfer_args *)data;
|
||||
struct iovec iov;
|
||||
int flags = 0;
|
||||
|
||||
iov.iov_base = convert_to_local(&command->area[1],&area[1],args->data);
|
||||
iov.iov_len = args->datalen;
|
||||
|
||||
status = core->socket_writev(cookie->socket,&iov,flags);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_RECV:
|
||||
{
|
||||
struct data_xfer_args *args = (struct data_xfer_args *)data;
|
||||
struct iovec iov;
|
||||
int flags = 0;
|
||||
|
||||
iov.iov_base = convert_to_local(&command->area[1],&area[1],args->data);
|
||||
iov.iov_len = args->datalen;
|
||||
|
||||
/* flags gets ignored here... */
|
||||
status = core->socket_readv(cookie->socket,&iov,&flags);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_RECVFROM:
|
||||
{
|
||||
struct msghdr *msg = (struct msghdr *)data;
|
||||
int received;
|
||||
|
||||
msg->msg_name = convert_to_local(&command->area[1],&area[1],msg->msg_name);
|
||||
msg->msg_iov = convert_to_local(&command->area[2],&area[2],msg->msg_iov);
|
||||
msg->msg_control = convert_to_local(&command->area[3],&area[3],msg->msg_control);
|
||||
|
||||
status = core->socket_recv(cookie->socket, msg, (caddr_t)&msg->msg_namelen,&received);
|
||||
if (status == 0)
|
||||
status = received;
|
||||
|
||||
msg->msg_name = convert_to_foreign(&command->area[1],&area[1],msg->msg_name);
|
||||
msg->msg_iov = convert_to_foreign(&command->area[2],&area[2],msg->msg_iov);
|
||||
msg->msg_control = convert_to_foreign(&command->area[3],&area[3],msg->msg_control);
|
||||
break;
|
||||
}
|
||||
case NET_STACK_SENDTO:
|
||||
{
|
||||
struct msghdr *msg = (struct msghdr *)data;
|
||||
int sent;
|
||||
|
||||
msg->msg_name = convert_to_local(&command->area[1],&area[1],msg->msg_name);
|
||||
msg->msg_iov = convert_to_local(&command->area[2],&area[2],msg->msg_iov);
|
||||
msg->msg_control = convert_to_local(&command->area[3],&area[3],msg->msg_control);
|
||||
|
||||
status = core->socket_send(cookie->socket,msg,msg->msg_flags,&sent);
|
||||
if (status == 0)
|
||||
status = sent;
|
||||
|
||||
msg->msg_name = convert_to_foreign(&command->area[1],&area[1],msg->msg_name);
|
||||
msg->msg_iov = convert_to_foreign(&command->area[2],&area[2],msg->msg_iov);
|
||||
msg->msg_control = convert_to_foreign(&command->area[3],&area[3],msg->msg_control);
|
||||
break;
|
||||
}
|
||||
|
||||
case NET_STACK_NOTIFY_SOCKET_EVENT:
|
||||
{
|
||||
struct notify_socket_event_args *args = (struct notify_socket_event_args *)data;
|
||||
|
||||
cookie->socket_event_port = args->notify_port;
|
||||
cookie->notify_cookie = args->cookie;
|
||||
|
||||
if (cookie->socket_event_port != -1)
|
||||
// start notify socket event
|
||||
status = core->socket_set_event_callback(cookie->socket, on_socket_event, cookie, 0);
|
||||
else
|
||||
// stop notify socket event
|
||||
status = core->socket_set_event_callback(cookie->socket, NULL, NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case NET_STACK_SYSCTL:
|
||||
{
|
||||
struct sysctl_args *args = (struct sysctl_args *)data;
|
||||
|
||||
status = core->net_sysctl(convert_to_local(&command->area[1],&area[1],args->name),
|
||||
args->namelen,convert_to_local(&command->area[2],&area[2],args->oldp),
|
||||
convert_to_local(&command->area[3],&area[3],args->oldlenp),
|
||||
convert_to_local(&command->area[4],&area[4],args->newp),
|
||||
args->newlen);
|
||||
break;
|
||||
}
|
||||
|
||||
case NET_STACK_STOP:
|
||||
core->stop();
|
||||
break;
|
||||
|
||||
case B_SET_BLOCKING_IO:
|
||||
cookie->openFlags &= ~O_NONBLOCK;
|
||||
break;
|
||||
|
||||
case B_SET_NONBLOCKING_IO:
|
||||
cookie->openFlags |= O_NONBLOCK;
|
||||
break;
|
||||
|
||||
case OSIOCGIFCONF:
|
||||
case SIOCGIFCONF:
|
||||
{
|
||||
struct ifconf *ifc = (struct ifconf *)data;
|
||||
ifc->ifc_buf = convert_to_local(&command->area[1],&area[1],ifc->ifc_buf);
|
||||
|
||||
status = core->socket_ioctl(cookie->socket,command->op,(char *)data);
|
||||
|
||||
ifc->ifc_buf = convert_to_foreign(&command->area[1],&area[1],ifc->ifc_buf);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
status = core->socket_ioctl(cookie->socket,command->op,(char *)data);
|
||||
break;
|
||||
}
|
||||
// mark the command as done
|
||||
command->result = status;
|
||||
command->op = 0;
|
||||
delete_cloned_areas(area);
|
||||
|
||||
// notify the command pipeline that we're done with the command
|
||||
release_sem(cookie->commandSemaphore);
|
||||
}
|
||||
|
||||
cookie->runner = -1;
|
||||
shutdown_connection(cookie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
init_connection(net_connection *connection,connection_cookie **_cookie)
|
||||
{
|
||||
connection_cookie *cookie;
|
||||
net_command *commands;
|
||||
|
||||
cookie = (connection_cookie *)malloc(sizeof(connection_cookie));
|
||||
if (cookie == NULL) {
|
||||
fprintf(stderr,"couldn't allocate memory for cookie.\n");
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
connection->area = create_area("net connection",(void *)&commands,B_ANY_ADDRESS,
|
||||
CONNECTION_BUFFER_SIZE + CONNECTION_COMMAND_SIZE,
|
||||
B_NO_LOCK,B_READ_AREA | B_WRITE_AREA);
|
||||
if (connection->area < B_OK) {
|
||||
fprintf(stderr,"couldn't create area: %s.\n",strerror(connection->area));
|
||||
free(cookie);
|
||||
return connection->area;
|
||||
}
|
||||
memset(commands,0,NUM_COMMANDS * sizeof(net_command));
|
||||
|
||||
connection->port = create_port(CONNECTION_QUEUE_LENGTH,"net stack connection");
|
||||
if (connection->port < B_OK) {
|
||||
fprintf(stderr,"couldn't create port: %s.\n",strerror(connection->port));
|
||||
delete_area(connection->area);
|
||||
free(cookie);
|
||||
return connection->port;
|
||||
}
|
||||
|
||||
connection->commandSemaphore = create_sem(0,"net command queue");
|
||||
if (connection->commandSemaphore < B_OK) {
|
||||
fprintf(stderr,"couldn't create semaphore: %s.\n",strerror(connection->commandSemaphore));
|
||||
delete_area(connection->area);
|
||||
delete_port(connection->port);
|
||||
free(cookie);
|
||||
return connection->commandSemaphore;
|
||||
}
|
||||
|
||||
cookie->runner = spawn_thread(connection_runner,"connection runner",B_NORMAL_PRIORITY,cookie);
|
||||
if (cookie->runner < B_OK) {
|
||||
fprintf(stderr,"couldn't create thread: %s.\n",strerror(cookie->runner));
|
||||
delete_sem(connection->commandSemaphore);
|
||||
delete_area(connection->area);
|
||||
delete_port(connection->port);
|
||||
free(cookie);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
connection->numCommands = NUM_COMMANDS;
|
||||
connection->bufferSize = CONNECTION_BUFFER_SIZE;
|
||||
|
||||
// setup connection cookie
|
||||
cookie->area = connection->area;
|
||||
cookie->commands = commands;
|
||||
cookie->buffer = (uint8 *)commands + CONNECTION_COMMAND_SIZE;
|
||||
cookie->commandSemaphore = connection->commandSemaphore;
|
||||
cookie->localPort = connection->port;
|
||||
cookie->openFlags = 0;
|
||||
|
||||
cookie->socket_event_port = -1;
|
||||
cookie->notify_cookie = NULL;
|
||||
|
||||
resume_thread(cookie->runner);
|
||||
|
||||
*_cookie = cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
shutdown_connection(connection_cookie *cookie)
|
||||
{
|
||||
printf("free cookie: %p\n",cookie);
|
||||
kill_thread(cookie->runner);
|
||||
|
||||
delete_port(cookie->localPort);
|
||||
delete_sem(cookie->commandSemaphore);
|
||||
delete_area(cookie->area);
|
||||
|
||||
free(cookie);
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
connection_opener(void *_unused)
|
||||
{
|
||||
while(true) {
|
||||
port_id port;
|
||||
int32 msg;
|
||||
ssize_t bytes = read_port(gStackPort,&msg,&port,sizeof(port_id));
|
||||
if (bytes < B_OK)
|
||||
return bytes;
|
||||
|
||||
if (msg == NET_STACK_NEW_CONNECTION) {
|
||||
net_connection connection;
|
||||
connection_cookie *cookie;
|
||||
|
||||
printf("incoming connection...\n");
|
||||
if (init_connection(&connection,&cookie) == B_OK)
|
||||
write_port(port,NET_STACK_NEW_CONNECTION,&connection,sizeof(net_connection));
|
||||
} else
|
||||
fprintf(stderr,"connection_opener: received unknown command: %lx (expected = %lx)\n",msg,(int32)NET_STACK_NEW_CONNECTION);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
init_userland_ipc(void)
|
||||
{
|
||||
gStackPort = create_port(CONNECTION_QUEUE_LENGTH,NET_STACK_PORTNAME);
|
||||
if (gStackPort < B_OK)
|
||||
return gStackPort;
|
||||
|
||||
gConnectionOpener = spawn_thread(connection_opener,"connection opener",B_NORMAL_PRIORITY,NULL);
|
||||
if (resume_thread(gConnectionOpener) < B_OK) {
|
||||
delete_port(gStackPort);
|
||||
if (gConnectionOpener >= B_OK) {
|
||||
kill_thread(gConnectionOpener);
|
||||
return B_BAD_THREAD_STATE;
|
||||
}
|
||||
return gConnectionOpener;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
shutdown_userland_ipc(void)
|
||||
{
|
||||
delete_port(gStackPort);
|
||||
kill_thread(gConnectionOpener);
|
||||
}
|
||||
|
||||
|
||||
#ifdef COMMUNICATION_TEST
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
char buffer[8];
|
||||
|
||||
if (init_userland_ipc() < B_OK)
|
||||
return -1;
|
||||
|
||||
puts("Userland_ipc - test is running. Press <Return> to quit.");
|
||||
fgets(buffer,sizeof(buffer),stdin);
|
||||
|
||||
shutdown_userland_ipc();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* COMMUNICATION_TEST */
|
@ -1,62 +0,0 @@
|
||||
#ifndef USERLAND_IPC_H
|
||||
#define USERLAND_IPC_H
|
||||
/* userland_ipc - Communication between the network driver
|
||||
** and the userland stack.
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
#include "net_stack_driver.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NET_STACK_PORTNAME "net_server connection"
|
||||
|
||||
enum {
|
||||
NET_STACK_OPEN = NET_STACK_IOCTL_MAX,
|
||||
NET_STACK_CLOSE,
|
||||
NET_STACK_NEW_CONNECTION,
|
||||
};
|
||||
|
||||
#define MAX_NET_AREAS 5
|
||||
|
||||
typedef struct {
|
||||
area_id id;
|
||||
uint8 *offset;
|
||||
} net_area_info;
|
||||
|
||||
typedef struct {
|
||||
int32 op;
|
||||
// int32 buffer;
|
||||
uint8 *data;
|
||||
int32 length;
|
||||
int32 result;
|
||||
net_area_info area[MAX_NET_AREAS];
|
||||
} net_command;
|
||||
|
||||
#define CONNECTION_QUEUE_LENGTH 128
|
||||
#define CONNECTION_COMMAND_SIZE 2048
|
||||
|
||||
typedef struct {
|
||||
port_id port;
|
||||
area_id area;
|
||||
|
||||
sem_id commandSemaphore; // command queue
|
||||
uint32 numCommands,bufferSize;
|
||||
} net_connection;
|
||||
|
||||
|
||||
extern status_t init_userland_ipc(void);
|
||||
extern void shutdown_userland_ipc(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // end of extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* USERLAND_IPC_H */
|
@ -1,869 +0,0 @@
|
||||
/* Userland modules emulation support
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <drivers/KernelExport.h>
|
||||
#include <drivers/module.h>
|
||||
|
||||
#include <app/Application.h>
|
||||
#include <app/Roster.h>
|
||||
#include <kernel/OS.h>
|
||||
#include <kernel/image.h>
|
||||
#include <storage/StorageDefs.h>
|
||||
#include <storage/FindDirectory.h>
|
||||
#include <storage/Path.h>
|
||||
#include <storage/Directory.h>
|
||||
|
||||
#define ASSERT(condition) if (!(condition)) { debugger("Assertion failed!"); }
|
||||
|
||||
typedef enum {
|
||||
MODULE_LOADED = 0,
|
||||
MODULE_INITING,
|
||||
MODULE_READY,
|
||||
MODULE_UNINITING,
|
||||
MODULE_ERROR
|
||||
} module_state;
|
||||
|
||||
typedef struct module {
|
||||
struct module * next;
|
||||
uint32 id;
|
||||
char * name;
|
||||
module_info * info;
|
||||
struct module_addon * addon; // the module addon this module live in
|
||||
// if NULL, builtin module addon
|
||||
int32 ref_count; // reference count of get_module() made on this module
|
||||
bool keep_loaded;
|
||||
module_state state;
|
||||
} module;
|
||||
|
||||
typedef struct module_addon {
|
||||
struct module_addon * next;
|
||||
int32 ref_count; // reference count of get_module() made using this addon
|
||||
bool keep_loaded;
|
||||
char * path;
|
||||
image_id addon_image; // if -1, not loaded in memory currently
|
||||
module_info ** infos; // valid only when addon_image != -1
|
||||
} module_addon;
|
||||
|
||||
typedef struct module_list_cookie {
|
||||
char * prefix;
|
||||
char * search_paths;
|
||||
char * search_path;
|
||||
char * next_path_token;
|
||||
BList * dir_stack;
|
||||
module_addon * ma; // current module addon looked up
|
||||
module_info ** mi; // current module addon module info
|
||||
} module_list_cookie;
|
||||
|
||||
#define LOCK_MODULES acquire_sem(g_modules_lock)
|
||||
#define UNLOCK_MODULES release_sem(g_modules_lock)
|
||||
|
||||
// local prototypes
|
||||
// ------------------
|
||||
|
||||
static module * search_module(const char * name);
|
||||
static status_t init_module(module * m);
|
||||
static status_t uninit_module(module * m);
|
||||
static module * find_loaded_module_by_name(const char * name);
|
||||
static module * find_loaded_module_by_id(uint32 id);
|
||||
|
||||
static module_addon * load_module_addon(const char * path);
|
||||
static status_t unload_module_addon(module_addon * ma);
|
||||
|
||||
// globals
|
||||
// ------------------
|
||||
|
||||
static sem_id g_modules_lock = -1; // One lock for rule them all, etc...
|
||||
static module * g_modules = NULL;
|
||||
static module_addon * g_module_addons = NULL;
|
||||
static int32 g_next_module_id = 1;
|
||||
|
||||
|
||||
// Public routines
|
||||
// ---------------
|
||||
|
||||
extern "C" {
|
||||
|
||||
_EXPORT status_t get_module(const char * name, module_info ** mi)
|
||||
{
|
||||
status_t status;
|
||||
module * m;
|
||||
|
||||
// printf("get_module(%s)\n", name);
|
||||
|
||||
m = find_loaded_module_by_name(name);
|
||||
if (!m)
|
||||
m = search_module(name);
|
||||
|
||||
if (!m)
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
*mi = m->info;
|
||||
|
||||
status = B_OK;
|
||||
|
||||
if (m->addon) // built-in modules don't comes from addon...
|
||||
atomic_add(&m->addon->ref_count, 1);
|
||||
|
||||
if (atomic_add(&m->ref_count, 1) == 0) {
|
||||
// first time we reference this module, so let's init it:
|
||||
status = init_module(m);
|
||||
if (status != B_OK) {
|
||||
printf("Failed to init module %s: %s.\n", m->name, strerror(status));
|
||||
unload_module_addon(m->addon); // unload the module addon...
|
||||
};
|
||||
};
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
_EXPORT status_t put_module(const char * name)
|
||||
{
|
||||
module * m;
|
||||
|
||||
// printf("put_module(%s)\n", name);
|
||||
|
||||
m = find_loaded_module_by_name(name);
|
||||
if (!m)
|
||||
// Hum??? Sorry, this module name was never get_module()'d
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
if (atomic_add(&m->ref_count, -1) <= 1)
|
||||
// this module is no more used...
|
||||
uninit_module(m);
|
||||
|
||||
if (!m->addon)
|
||||
// built-in modules are module addon less...
|
||||
return B_OK;
|
||||
|
||||
if (atomic_add(&m->addon->ref_count, -1) > 1)
|
||||
// Still other module(s) using this module addon
|
||||
return B_OK;
|
||||
|
||||
// okay, this module addon is no more used
|
||||
// let's free up some memory
|
||||
return unload_module_addon(m->addon);
|
||||
}
|
||||
|
||||
|
||||
_EXPORT status_t get_next_loaded_module_name(uint32 *cookie, char *buf, size_t *bufsize)
|
||||
{
|
||||
module * m;
|
||||
status_t status;
|
||||
|
||||
if (buf == NULL && bufsize == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
if (*cookie == 0)
|
||||
// first call expected value
|
||||
m = g_modules;
|
||||
else {
|
||||
// find last loaded module returned, and seek to next one
|
||||
m = (module *) find_loaded_module_by_id((int) *cookie);
|
||||
if (m)
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
// find next loaded module
|
||||
while (m) {
|
||||
if (m->ref_count)
|
||||
break;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
status = B_OK;
|
||||
if (m) {
|
||||
ASSERT(m->info);
|
||||
if (buf != NULL)
|
||||
strncpy(buf, m->info->name, *bufsize);
|
||||
else
|
||||
*bufsize = strlen(m->info->name + 1);
|
||||
*cookie = m->id;
|
||||
} else
|
||||
status = B_BAD_INDEX;
|
||||
|
||||
UNLOCK_MODULES;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
_EXPORT void * open_module_list(const char *prefix)
|
||||
{
|
||||
module_list_cookie * mlc;
|
||||
char * addon_path;
|
||||
|
||||
if (prefix == NULL)
|
||||
return NULL;
|
||||
|
||||
mlc = (module_list_cookie *) malloc(sizeof(*mlc));
|
||||
mlc->prefix = strdup(prefix);
|
||||
|
||||
addon_path = getenv("ADDON_PATH");
|
||||
mlc->search_paths = (addon_path ? strdup(addon_path) : NULL);
|
||||
mlc->search_path = strtok_r(mlc->search_paths, ":", &mlc->next_path_token);
|
||||
mlc->dir_stack = new BList();
|
||||
|
||||
mlc->ma = NULL;
|
||||
mlc->mi = NULL;
|
||||
|
||||
return mlc;
|
||||
}
|
||||
|
||||
|
||||
_EXPORT status_t read_next_module_name(void *cookie, char *buf, size_t *bufsize)
|
||||
{
|
||||
module_list_cookie * mlc = (module_list_cookie *) cookie;
|
||||
|
||||
if (!bufsize)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (!mlc)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
/* Okay, take some time to understand how this function works!
|
||||
Basicly, we iterate thru:
|
||||
- each searchable add-ons path root
|
||||
- each (sub-)directory under the current add-ons path root
|
||||
- each module add-on file in the current (sub-)directory
|
||||
- each module name published by current module add-on
|
||||
|
||||
As the iteration involve sub-directory walks, we use recursive calls.
|
||||
Sorry if this code sounds too complex...
|
||||
*/
|
||||
|
||||
if (mlc->ma && mlc->mi) {
|
||||
// we have a module addon still loaded from a last call
|
||||
// so keep looking at his exported module names list
|
||||
while (*mlc->mi) {
|
||||
module_info * mi = *mlc->mi;
|
||||
mlc->mi++;
|
||||
if(strstr(mi->name, mlc->prefix)) {
|
||||
// We find a matching module name. At least. Yeah!!!
|
||||
if (buf) strncpy(buf, mi->name, *bufsize);
|
||||
*bufsize = strlen(mi->name);
|
||||
return B_OK;
|
||||
};
|
||||
};
|
||||
|
||||
// We've iterate all module names of this module addon. Find another one...
|
||||
atomic_add(&mlc->ma->ref_count, -1);
|
||||
unload_module_addon(mlc->ma);
|
||||
mlc->ma = NULL;
|
||||
mlc->mi = NULL;
|
||||
};
|
||||
|
||||
// Iterate all searchable add-ons paths
|
||||
while (mlc->search_path) {
|
||||
BDirectory * dir;
|
||||
BEntry entry;
|
||||
BPath path;
|
||||
status_t status;
|
||||
|
||||
// Get current directory
|
||||
dir = (BDirectory *) mlc->dir_stack->LastItem();
|
||||
if (!dir) {
|
||||
// find add-ons root directory in this search path
|
||||
if (strncmp(mlc->search_path, "%A/", 3) == 0) {
|
||||
// resolve "%A/..." path
|
||||
app_info ai;
|
||||
|
||||
be_app->GetAppInfo(&ai);
|
||||
entry.SetTo(&ai.ref);
|
||||
entry.GetPath(&path);
|
||||
path.GetParent(&path);
|
||||
path.Append(mlc->search_path + 3);
|
||||
} else {
|
||||
path.SetTo(mlc->search_path);
|
||||
};
|
||||
|
||||
// We look *only* under prefix-matching sub-path
|
||||
path.Append(mlc->prefix);
|
||||
|
||||
// printf("Looking module(s) in %s/%s...\n", mlc->search_path, mlc->prefix);
|
||||
|
||||
dir = new BDirectory(path.Path());
|
||||
if (dir)
|
||||
mlc->dir_stack->AddItem(dir);
|
||||
};
|
||||
|
||||
// Iterate current directory content
|
||||
if (dir) {
|
||||
while (dir->GetNextEntry(&entry) == B_OK) {
|
||||
entry.GetPath(&path);
|
||||
// printf(" %s ?\n", path.Path());
|
||||
|
||||
if (entry.IsDirectory()) {
|
||||
BDirectory * subdir;
|
||||
// push this directory on dir_stack
|
||||
subdir = new BDirectory(path.Path());
|
||||
if (!subdir)
|
||||
continue;
|
||||
|
||||
mlc->dir_stack->AddItem(subdir);
|
||||
// recursivly search this sub-directory
|
||||
return read_next_module_name(cookie, buf, bufsize);
|
||||
};
|
||||
|
||||
if (entry.IsFile() || entry.IsSymLink()) {
|
||||
mlc->ma = load_module_addon(path.Path());
|
||||
if (!mlc->ma)
|
||||
// Oh-oh, not a loadable module addon!?
|
||||
// WTF it's doing there?!?
|
||||
continue;
|
||||
|
||||
atomic_add(&mlc->ma->ref_count, 1);
|
||||
// call ourself to enter the module names list iteration at
|
||||
// function begining code...
|
||||
mlc->mi = mlc->ma->infos;
|
||||
return read_next_module_name(cookie, buf, bufsize);
|
||||
};
|
||||
};
|
||||
|
||||
// We walk thru all this directory content, go back to parent
|
||||
status = mlc->dir_stack->RemoveItem(dir);
|
||||
delete dir;
|
||||
};
|
||||
|
||||
if (!mlc->dir_stack->IsEmpty())
|
||||
continue;
|
||||
|
||||
// We walk thru all this search path content, next now
|
||||
mlc->search_path = strtok_r(NULL, ":", &mlc->next_path_token);
|
||||
};
|
||||
|
||||
// Module(s) list search done, ending...
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
_EXPORT status_t close_module_list(void *cookie)
|
||||
{
|
||||
module_list_cookie * mlc = (module_list_cookie *) cookie;
|
||||
BDirectory * dir;
|
||||
|
||||
ASSERT(mlc);
|
||||
ASSERT(mlc->prefix);
|
||||
|
||||
if (mlc->ma) {
|
||||
atomic_add(&mlc->ma->ref_count, -1);
|
||||
unload_module_addon(mlc->ma);
|
||||
};
|
||||
|
||||
while((dir = (BDirectory *) mlc->dir_stack->FirstItem())) {
|
||||
mlc->dir_stack->RemoveItem(dir);
|
||||
delete dir;
|
||||
};
|
||||
|
||||
delete mlc->dir_stack;
|
||||
|
||||
free(mlc->search_paths);
|
||||
free(mlc->prefix);
|
||||
free(mlc);
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
// Some KernelExport.h support from userland
|
||||
|
||||
_EXPORT void dprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
_EXPORT void kprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
_EXPORT status_t load_driver_symbols(const char *driver_name)
|
||||
{
|
||||
// Userland debugger will extract symbols itself...
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
_EXPORT thread_id spawn_kernel_thread(thread_entry func, const char *name, long priority, void *arg)
|
||||
{
|
||||
return spawn_thread(func, name, priority, arg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
_EXPORT int send_signal_etc(pid_t thid, uint sig, uint32 flags)
|
||||
{
|
||||
return send_signal(thid, sig);
|
||||
}
|
||||
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// Private routines
|
||||
|
||||
static module_addon * load_module_addon(const char * path)
|
||||
{
|
||||
module_addon * ma;
|
||||
image_id addon_id;
|
||||
module_info ** mi;
|
||||
status_t status;
|
||||
|
||||
ASSERT(path);
|
||||
|
||||
addon_id = load_add_on(path);
|
||||
if (addon_id < 0) {
|
||||
printf("Failed to load %s addon: %s.\n", path, strerror(addon_id));
|
||||
return NULL;
|
||||
};
|
||||
|
||||
// printf("Addon %s loaded.\n", path);
|
||||
|
||||
ma = NULL;
|
||||
|
||||
status = get_image_symbol(addon_id, "modules", B_SYMBOL_TYPE_DATA, (void **) &mi);
|
||||
if (status != B_OK) {
|
||||
// No "modules" symbol found in this addon
|
||||
printf("Symbol \"modules\" not found in %s addon: not a module addon!\n", path);
|
||||
goto error;
|
||||
};
|
||||
|
||||
ma = (module_addon *) malloc(sizeof(*ma));
|
||||
if (!ma)
|
||||
// Gasp: not enough memory!
|
||||
goto error;
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
ma->ref_count = 0;
|
||||
ma->keep_loaded = false;
|
||||
ma->path = strdup(path);
|
||||
ma->addon_image = addon_id;
|
||||
ma->infos = mi;
|
||||
|
||||
while(*mi) {
|
||||
module * m;
|
||||
|
||||
m = (module *) malloc(sizeof(*m));
|
||||
if (!m)
|
||||
// Gasp, again: not enough memory!
|
||||
goto error;
|
||||
|
||||
m->ref_count = 0;
|
||||
m->id = atomic_add(&g_next_module_id, 1);
|
||||
m->info = (*mi);
|
||||
m->name = strdup(m->info->name);
|
||||
m->addon = ma;
|
||||
m->keep_loaded = (m->info->flags & B_KEEP_LOADED) ? true : false;
|
||||
|
||||
m->state = MODULE_LOADED;
|
||||
|
||||
m->next = g_modules;
|
||||
g_modules = m;
|
||||
|
||||
mi++;
|
||||
};
|
||||
|
||||
// add this module addon to the list
|
||||
ma->next = g_module_addons;
|
||||
g_module_addons = ma;
|
||||
|
||||
UNLOCK_MODULES;
|
||||
|
||||
return ma;
|
||||
|
||||
error:
|
||||
printf("Error while load_module_addon(%s)\n", path);
|
||||
|
||||
if (ma) {
|
||||
// remove any appended modules by this module addon until we got error...
|
||||
module * prev;
|
||||
module * m;
|
||||
|
||||
prev = NULL;
|
||||
m = g_modules;
|
||||
while (m) {
|
||||
if (m->addon == ma) {
|
||||
module * tmp = m;
|
||||
|
||||
m = tmp->next;
|
||||
|
||||
if (prev)
|
||||
prev->next = tmp->next;
|
||||
else
|
||||
g_modules = tmp->next;
|
||||
|
||||
if (tmp->name)
|
||||
free(tmp->name);
|
||||
free(tmp);
|
||||
continue;
|
||||
};
|
||||
|
||||
prev = m;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
|
||||
UNLOCK_MODULES;
|
||||
|
||||
if (ma->path)
|
||||
free(ma->path);
|
||||
free(ma);
|
||||
};
|
||||
|
||||
unload_add_on(addon_id);
|
||||
// printf("Addon %s unloaded.\n", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static status_t unload_module_addon(module_addon * ma)
|
||||
{
|
||||
module * m;
|
||||
module * prev;
|
||||
status_t status;
|
||||
|
||||
if (!ma)
|
||||
// built-in modules are addon-less, so nothing to do...
|
||||
return B_OK;
|
||||
|
||||
if (ma->keep_loaded) {
|
||||
printf("B_KEEP_LOADED flag set for %s module addon. Will be *never* unloaded!\n",
|
||||
ma->path);
|
||||
return B_OK;
|
||||
};
|
||||
|
||||
if (ma->ref_count)
|
||||
// still someone needing this module addon, it seems?
|
||||
return B_OK;
|
||||
|
||||
if (ma->addon_image < 0)
|
||||
// built-in addon, it seems...
|
||||
return B_OK;
|
||||
|
||||
status = unload_add_on(ma->addon_image);
|
||||
if (status != B_OK) {
|
||||
printf("Failed to unload %s addon: %s.\n", ma->path, strerror(status));
|
||||
return status;
|
||||
};
|
||||
// printf("Addon %s unloaded.\n", ma->path);
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
// remove the modules coming from this module addon from g_modules list
|
||||
prev = NULL;
|
||||
m = g_modules;
|
||||
while (m) {
|
||||
if (m->addon == ma) {
|
||||
module * tmp = m;
|
||||
|
||||
m = tmp->next;
|
||||
|
||||
if (prev)
|
||||
prev->next = tmp->next;
|
||||
else
|
||||
g_modules = tmp->next;
|
||||
|
||||
if (tmp->name)
|
||||
free(tmp->name);
|
||||
free(tmp);
|
||||
continue;
|
||||
};
|
||||
|
||||
prev = m;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
// remove the module addon from g_module_addons list:
|
||||
if (g_module_addons == ma)
|
||||
g_module_addons = ma->next;
|
||||
else {
|
||||
module_addon * tmp;
|
||||
tmp = g_module_addons;
|
||||
while (tmp && tmp->next != ma)
|
||||
tmp = tmp->next;
|
||||
|
||||
ASSERT(tmp);
|
||||
tmp->next = ma->next;
|
||||
};
|
||||
|
||||
if (ma->path)
|
||||
free(ma->path);
|
||||
free(ma);
|
||||
|
||||
UNLOCK_MODULES;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static module * search_module(const char * name)
|
||||
{
|
||||
BPath path;
|
||||
BPath addons_path;
|
||||
BEntry entry;
|
||||
module * found_module;
|
||||
char * search_paths;
|
||||
char * search_path;
|
||||
char * next_path_token;
|
||||
|
||||
// printf("search_module(%s):\n", name);
|
||||
|
||||
search_paths = getenv("ADDON_PATH");
|
||||
if (!search_paths)
|
||||
// Nowhere to search addons!!!
|
||||
return NULL;
|
||||
|
||||
search_paths = strdup(search_paths);
|
||||
search_path = strtok_r(search_paths, ":", &next_path_token);
|
||||
|
||||
found_module = NULL;
|
||||
while (search_path && found_module == NULL) {
|
||||
if (strncmp(search_path, "%A/", 3) == 0) {
|
||||
// compute "%A/..." path
|
||||
app_info ai;
|
||||
|
||||
be_app->GetAppInfo(&ai);
|
||||
entry.SetTo(&ai.ref);
|
||||
entry.GetPath(&addons_path);
|
||||
addons_path.GetParent(&addons_path);
|
||||
addons_path.Append(search_path + 3);
|
||||
} else {
|
||||
addons_path.SetTo(search_path);
|
||||
};
|
||||
|
||||
// printf("Looking into %s\n", search_path);
|
||||
|
||||
path.SetTo(addons_path.Path());
|
||||
path.Append(name);
|
||||
|
||||
while(path != addons_path) {
|
||||
// printf(" %s ?\n", path.Path());
|
||||
entry.SetTo(path.Path());
|
||||
if (entry.IsFile() || entry.IsSymLink()) {
|
||||
module_addon * ma;
|
||||
|
||||
// try to load the module addon
|
||||
ma = load_module_addon(path.Path());
|
||||
if (ma) {
|
||||
found_module = find_loaded_module_by_name(name);
|
||||
if (found_module)
|
||||
break;
|
||||
|
||||
unload_module_addon(ma);
|
||||
}; // if (ma)
|
||||
}; // if (entry.IsFile() || entry.IsSymLink())
|
||||
|
||||
// okay, remove the current path leaf and try again...
|
||||
path.GetParent(&path);
|
||||
};
|
||||
|
||||
search_path = strtok_r(NULL, ":", &next_path_token);
|
||||
};
|
||||
|
||||
free(search_paths);
|
||||
|
||||
/*
|
||||
if (found_module)
|
||||
printf(" Found it in %s addon module!\n",
|
||||
found_module->addon ? found_module->addon->path : "BUILTIN");
|
||||
*/
|
||||
|
||||
return found_module;
|
||||
}
|
||||
|
||||
|
||||
static status_t init_module(module * m)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
ASSERT(m);
|
||||
|
||||
switch (m->state) {
|
||||
case MODULE_LOADED:
|
||||
m->state = MODULE_INITING;
|
||||
ASSERT(m->info);
|
||||
// printf("Initing module %s... ", m->name);
|
||||
status = m->info->std_ops(B_MODULE_INIT);
|
||||
// printf("done (%s).\n", strerror(status));
|
||||
m->state = (status == B_OK) ? MODULE_READY : MODULE_LOADED;
|
||||
|
||||
if (m->state == MODULE_READY && m->keep_loaded && m->addon) {
|
||||
// one module (at least) was inited and request to never being
|
||||
// unload from memory, so keep the corresponding addon loaded
|
||||
// printf("module %s set B_KEEP_LOADED flag:\nmodule addon %s will never be unloaded!\n",
|
||||
// m->name, m->addon->path);
|
||||
m->addon->keep_loaded = true;
|
||||
};
|
||||
break;
|
||||
|
||||
case MODULE_READY:
|
||||
status = B_OK;
|
||||
break;
|
||||
|
||||
case MODULE_INITING: // circular reference!!!
|
||||
case MODULE_UNINITING: // initing a module currently unloading...
|
||||
case MODULE_ERROR: // module failed to unload previously...
|
||||
default: // Unknown module state!!!
|
||||
status = B_ERROR;
|
||||
break;
|
||||
};
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t uninit_module(module * m)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
ASSERT(m);
|
||||
|
||||
switch (m->state) {
|
||||
case MODULE_READY:
|
||||
m->state = MODULE_UNINITING;
|
||||
ASSERT(m->info);
|
||||
// printf("Uniniting module %s... ", m->name);
|
||||
status = m->info->std_ops(B_MODULE_UNINIT);
|
||||
// printf("done (%s).\n", strerror(status));
|
||||
m->state = (status == B_OK) ? MODULE_LOADED : MODULE_ERROR;
|
||||
break;
|
||||
|
||||
case MODULE_LOADED:
|
||||
// No need to uninit it, all is fine so.
|
||||
status = B_OK;
|
||||
break;
|
||||
|
||||
case MODULE_INITING: // uniniting while initializing
|
||||
case MODULE_UNINITING: // uniniting already pending
|
||||
case MODULE_ERROR: // module failed previously...
|
||||
default: // Unknown module state!!!
|
||||
status = B_ERROR;
|
||||
break;
|
||||
};
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static module * find_loaded_module_by_name(const char * name)
|
||||
{
|
||||
module * m;
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
m = g_modules;
|
||||
while (m) {
|
||||
if (strcmp(name, m->name) == 0)
|
||||
break;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
UNLOCK_MODULES;
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
static module * find_loaded_module_by_id(uint32 id)
|
||||
{
|
||||
module * m;
|
||||
|
||||
LOCK_MODULES;
|
||||
|
||||
m = g_modules;
|
||||
while (m) {
|
||||
if (m->id == id)
|
||||
break;
|
||||
m = m->next;
|
||||
};
|
||||
|
||||
UNLOCK_MODULES;
|
||||
return m;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// #pragma mark -
|
||||
|
||||
#define NET_CORE_MODULE_NAME "network/core/v1"
|
||||
#define NET_ETHERNET_MODULE_NAME "network/interfaces/ethernet"
|
||||
#define NET_IPV4_MODULE_NAME "network/protocols/ipv4/v1"
|
||||
|
||||
#define MODULE_LIST_PREFIX "network"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
module_info * core;
|
||||
module_info * ethernet;
|
||||
module_info * ipv4;
|
||||
char module_name[256];
|
||||
uint32 cookie;
|
||||
size_t sz;
|
||||
void * ml_cookie;
|
||||
|
||||
new BApplication("application/x-vnd-OBOS-net_server");
|
||||
|
||||
printf("open_module_list(%s):\n", MODULE_LIST_PREFIX);
|
||||
ml_cookie = open_module_list(MODULE_LIST_PREFIX);
|
||||
sz = sizeof(module_name);
|
||||
while(read_next_module_name(ml_cookie, module_name, &sz) == B_OK) {
|
||||
if (strlen(module_name))
|
||||
printf(" %s\n", module_name);
|
||||
sz = sizeof(module_name);
|
||||
};
|
||||
close_module_list(ml_cookie);
|
||||
printf("close_module_list()\n");
|
||||
// return 0;
|
||||
|
||||
core = NULL;
|
||||
get_module(NET_CORE_MODULE_NAME, (module_info **) &core);
|
||||
|
||||
ethernet = NULL;
|
||||
get_module(NET_ETHERNET_MODULE_NAME, (module_info **) ðernet);
|
||||
|
||||
ipv4 = NULL;
|
||||
get_module(NET_IPV4_MODULE_NAME, (module_info **) &ipv4);
|
||||
|
||||
printf("get_next_loaded_module_name() test:\n");
|
||||
cookie = 0;
|
||||
sz = sizeof(module_name);
|
||||
while (get_next_loaded_module_name(&cookie, module_name, &sz) == B_OK)
|
||||
printf("%ld: %s\n", cookie, module_name);
|
||||
|
||||
if (ipv4)
|
||||
put_module(NET_IPV4_MODULE_NAME);
|
||||
|
||||
if (ethernet)
|
||||
put_module(NET_ETHERNET_MODULE_NAME);
|
||||
|
||||
if (core)
|
||||
put_module(NET_CORE_MODULE_NAME);
|
||||
|
||||
printf("get_next_loaded_module_name() test:\n");
|
||||
cookie = 0;
|
||||
sz = sizeof(module_name);
|
||||
while (get_next_loaded_module_name(&cookie, module_name, &sz) == B_OK)
|
||||
printf("%ld: %s\n", cookie, module_name);
|
||||
|
||||
delete be_app;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
45
src/tests/kits/net/tcp_shell/Jamfile
Normal file
45
src/tests/kits/net/tcp_shell/Jamfile
Normal file
@ -0,0 +1,45 @@
|
||||
SubDir HAIKU_TOP src tests kits net tcp_shell ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src tests add-ons kernel file_systems fs_shell ] ;
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols tcp ] ;
|
||||
SubDirHdrs [ FDirName $(HAIKU_TOP) src add-ons kernel network stack ] ;
|
||||
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
||||
UsePrivateHeaders kernel net shared ;
|
||||
|
||||
SimpleTest tcp_shell :
|
||||
tcp_tester.cpp
|
||||
|
||||
# stack
|
||||
net_buffer.cpp
|
||||
utility.cpp
|
||||
|
||||
# tcp
|
||||
tcp.cpp
|
||||
TCPEndpoint.cpp
|
||||
BufferQueue.cpp
|
||||
EndpointManager.cpp
|
||||
|
||||
# misc
|
||||
argv.c
|
||||
ipv4_address.cpp
|
||||
|
||||
: be libkernelland_emu.so
|
||||
;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
tcp.cpp TCPEndpoint.cpp BufferQueue.cpp EndpointManager.cpp
|
||||
] = [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols tcp ] ;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
ipv4_address.cpp
|
||||
] = [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols ipv4 ] ;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
net_buffer.cpp utility.cpp
|
||||
] = [ FDirName $(HAIKU_TOP) src add-ons kernel network stack ] ;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
argv.c
|
||||
] = [ FDirName $(HAIKU_TOP) src tests add-ons kernel file_systems fs_shell ] ;
|
Loading…
Reference in New Issue
Block a user