diff --git a/src/add-ons/kernel/network/datalink_protocols/Jamfile b/src/add-ons/kernel/network/datalink_protocols/Jamfile index d059982e9c..dd429227ba 100644 --- a/src/add-ons/kernel/network/datalink_protocols/Jamfile +++ b/src/add-ons/kernel/network/datalink_protocols/Jamfile @@ -2,3 +2,4 @@ SubDir HAIKU_TOP src add-ons kernel network datalink_protocols ; SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols arp ; SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ethernet_frame ; +SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols loopback_frame ; diff --git a/src/add-ons/kernel/network/datalink_protocols/loopback_frame/Jamfile b/src/add-ons/kernel/network/datalink_protocols/loopback_frame/Jamfile new file mode 100644 index 0000000000..d528903182 --- /dev/null +++ b/src/add-ons/kernel/network/datalink_protocols/loopback_frame/Jamfile @@ -0,0 +1,25 @@ +SubDir HAIKU_TOP src add-ons kernel network datalink_protocols loopback_frame ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +if $(TARGET_PLATFORM) != haiku { + UseHeaders [ FStandardOSHeaders ] : true ; + # Needed for and maybe other stuff. + UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; + # We need the public network headers also when not compiling for Haiku. + # Unfortunately we get more than we want, namely all POSIX headers. +} + +UsePrivateHeaders kernel net ; + +KernelAddon loopback_frame : + loopback_frame.cpp +; + +# Installation +HaikuInstall install-networking : /boot/home/config/add-ons/kernel/haiku_network/datalink_protocols + : loopback_frame ; + +Package haiku-networkingkit-cvs : + haiku : + boot home config add-ons kernel haiku_network datalink_protocols ; diff --git a/src/add-ons/kernel/network/datalink_protocols/loopback_frame/loopback_frame.cpp b/src/add-ons/kernel/network/datalink_protocols/loopback_frame/loopback_frame.cpp new file mode 100644 index 0000000000..25dc21ccac --- /dev/null +++ b/src/add-ons/kernel/network/datalink_protocols/loopback_frame/loopback_frame.cpp @@ -0,0 +1,166 @@ +/* + * Copyright 2006, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + + +struct loopback_frame_protocol : net_datalink_protocol { +}; + + +struct net_buffer_module_info *sBufferModule; + + +int32 +loopback_deframe(net_device *device, net_buffer *buffer) +{ + // there is not that much to do... + return 0; +} + + +// #pragma mark - + + +status_t +loopback_frame_init(struct net_interface *interface, net_datalink_protocol **_protocol) +{ + // We currently only support a single family and type! + if (interface->device->type != IFT_LOOP) + return B_BAD_TYPE; + + loopback_frame_protocol *protocol; + + net_stack_module_info *stack; + status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&stack); + if (status < B_OK) + return status; + + status = stack->register_device_deframer(interface->device, &loopback_deframe); + if (status < B_OK) + goto err1; + + // We also register the domain as a handler for our packets + status = stack->register_domain_device_handler(interface->device, + 0, interface->domain); + if (status < B_OK) + goto err2; + + put_module(NET_STACK_MODULE_NAME); + + protocol = new (std::nothrow) loopback_frame_protocol; + if (protocol == NULL) + return B_NO_MEMORY; + + *_protocol = protocol; + return B_OK; + +err2: + stack->unregister_device_deframer(interface->device); +err1: + put_module(NET_STACK_MODULE_NAME); + return status; +} + + +status_t +loopback_frame_uninit(net_datalink_protocol *protocol) +{ + net_stack_module_info *stack; + if (get_module(NET_STACK_MODULE_NAME, (module_info **)&stack) == B_OK) { + stack->unregister_device_deframer(protocol->interface->device); + stack->unregister_device_handler(protocol->interface->device, 0); + put_module(NET_STACK_MODULE_NAME); + } + + delete protocol; + return B_OK; +} + + +status_t +loopback_frame_send_data(net_datalink_protocol *protocol, + net_buffer *buffer) +{ + return protocol->next->module->send_data(protocol->next, buffer); +} + + +status_t +loopback_frame_up(net_datalink_protocol *_protocol) +{ + loopback_frame_protocol *protocol = (loopback_frame_protocol *)_protocol; + + return protocol->next->module->interface_up(protocol->next); +} + + +void +loopback_frame_down(net_datalink_protocol *protocol) +{ + return protocol->next->module->interface_down(protocol->next); +} + + +status_t +loopback_frame_control(net_datalink_protocol *protocol, + int32 op, void *argument, size_t length) +{ + return protocol->next->module->control(protocol->next, op, argument, length); +} + + +static status_t +loopback_frame_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + return get_module(NET_BUFFER_MODULE_NAME, (module_info **)&sBufferModule); + case B_MODULE_UNINIT: + put_module(NET_BUFFER_MODULE_NAME); + return B_OK; + + default: + return B_ERROR; + } +} + + +static net_datalink_protocol_module_info sLoopbackFrameModule = { + { + "network/datalink_protocols/loopback_frame/v1", + 0, + loopback_frame_std_ops + }, + loopback_frame_init, + loopback_frame_uninit, + loopback_frame_send_data, + loopback_frame_up, + loopback_frame_down, + loopback_frame_control, +}; + +module_info *modules[] = { + (module_info *)&sLoopbackFrameModule, + NULL +}; diff --git a/src/add-ons/kernel/network/devices/loopback/Jamfile b/src/add-ons/kernel/network/devices/loopback/Jamfile index d11227666b..728868083b 100644 --- a/src/add-ons/kernel/network/devices/loopback/Jamfile +++ b/src/add-ons/kernel/network/devices/loopback/Jamfile @@ -10,7 +10,7 @@ if $(TARGET_PLATFORM) != haiku { # Unfortunately we get more than we want, namely all POSIX headers. } -UsePrivateHeaders net ; +UsePrivateHeaders kernel net ; KernelAddon loopback : loopback.cpp diff --git a/src/add-ons/kernel/network/devices/loopback/loopback.cpp b/src/add-ons/kernel/network/devices/loopback/loopback.cpp index 173b2c4557..d7ba88c951 100644 --- a/src/add-ons/kernel/network/devices/loopback/loopback.cpp +++ b/src/add-ons/kernel/network/devices/loopback/loopback.cpp @@ -7,7 +7,9 @@ */ +#include #include +#include #include @@ -19,18 +21,66 @@ struct loopback_device : net_device { + net_fifo fifo; }; +struct net_buffer_module_info *sBufferModule; +static struct net_stack_module_info *sStackModule; + + +/*! + Swaps \a size bytes of the memory pointed to by \a and \b with each other. +*/ +void +swap_memory(void *a, void *b, size_t size) +{ + uint32 *a4 = (uint32 *)a; + uint32 *b4 = (uint32 *)b; + while (size > 4) { + uint32 temp = *a4; + *(a4++) = *b4; + *(b4++) = temp; + + size -= 4; + } + + uint8 *a1 = (uint8 *)a4; + uint8 *b1 = (uint8 *)b4; + while (size > 0) { + uint8 temp = *a1; + *(a1++) = *b1; + *(b1++) = temp; + + size--; + } +} + + +// #pragma mark - + + status_t loopback_init(const char *name, net_device **_device) { + loopback_device *device; + if (strncmp(name, "loop", 4)) return B_BAD_VALUE; - loopback_device *device = new (std::nothrow) loopback_device; - if (device == NULL) - return B_NO_MEMORY; + status_t status = get_module(NET_STACK_MODULE_NAME, (module_info **)&sStackModule); + if (status < B_OK) + return status; + + status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&sBufferModule); + if (status < B_OK) + goto err1; + + device = new (std::nothrow) loopback_device; + if (device == NULL) { + status = B_NO_MEMORY; + goto err2; + } memset(device, 0, sizeof(loopback_device)); @@ -41,27 +91,41 @@ loopback_init(const char *name, net_device **_device) *_device = device; return B_OK; + +err2: + put_module(NET_BUFFER_MODULE_NAME); +err1: + put_module(NET_STACK_MODULE_NAME); + return status; } status_t -loopback_uninit(net_device *device) +loopback_uninit(net_device *_device) { + loopback_device *device = (loopback_device *)_device; + + put_module(NET_STACK_MODULE_NAME); + put_module(NET_BUFFER_MODULE_NAME); delete device; + return B_OK; } status_t -loopback_up(net_device *device) +loopback_up(net_device *_device) { - return B_OK; + loopback_device *device = (loopback_device *)_device; + return sStackModule->init_fifo(&device->fifo, "loopback fifo", 65536); } void -loopback_down(net_device *device) +loopback_down(net_device *_device) { + loopback_device *device = (loopback_device *)_device; + sStackModule->uninit_fifo(&device->fifo); } @@ -74,37 +138,55 @@ loopback_control(net_device *device, int32 op, void *argument, status_t -loopback_send_data(net_device *device, net_buffer *buffer) +loopback_send_data(net_device *_device, net_buffer *buffer) { - return B_ERROR; + loopback_device *device = (loopback_device *)_device; + return sStackModule->fifo_enqueue_buffer(&device->fifo, buffer); } status_t -loopback_receive_data(net_device *device, net_buffer **_buffer) +loopback_receive_data(net_device *_device, net_buffer **_buffer) { - return B_ERROR; + loopback_device *device = (loopback_device *)_device; + net_buffer *buffer; + + status_t status = sStackModule->fifo_dequeue_buffer(&device->fifo, 0, 0, &buffer); + if (status < B_OK) + return status; + + // switch network addresses before delivering + swap_memory(&buffer->source, &buffer->destination, + max_c(buffer->source.ss_len, buffer->destination.ss_len)); + + *_buffer = buffer; + return B_OK; } status_t loopback_set_mtu(net_device *device, size_t mtu) { - return B_ERROR; + if (mtu > 65536 + || mtu < 16) + return B_BAD_VALUE; + + device->mtu = mtu; + return B_OK; } status_t loopback_set_promiscuous(net_device *device, bool promiscuous) { - return B_ERROR; + return EOPNOTSUPP; } status_t loopback_set_media(net_device *device, uint32 media) { - return B_ERROR; + return EOPNOTSUPP; } diff --git a/src/add-ons/kernel/network/stack/stack.cpp b/src/add-ons/kernel/network/stack/stack.cpp index e3c13c674c..7d4a9296d3 100644 --- a/src/add-ons/kernel/network/stack/stack.cpp +++ b/src/add-ons/kernel/network/stack/stack.cpp @@ -790,7 +790,8 @@ init_stack() scan_modules("network/datalink_protocols"); // TODO: for now! - register_domain_datalink_protocols(AF_INET, IFT_LOOP, NULL); + register_domain_datalink_protocols(AF_INET, IFT_LOOP, + "network/datalink_protocols/loopback_frame/v1", NULL); register_domain_datalink_protocols(AF_INET, IFT_ETHER, "network/datalink_protocols/arp/v1", "network/datalink_protocols/ethernet_frame/v1",