From 58cdaa07fb8c6d229da71bb175f2d8a395bf9a68 Mon Sep 17 00:00:00 2001 From: Philippe Houdoin Date: Tue, 27 Jan 2004 08:05:13 +0000 Subject: [PATCH] Add new code reorg files. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6341 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/tests/kits/net/new_stack/framings/Jamfile | 3 + .../net/new_stack/framings/ethernet/Jamfile | 9 + .../framings/ethernet/ethernet_frame.c | 175 +++++++++ .../kits/net/new_stack/interfaces/Jamfile | 5 + .../interfaces/ether_drivers/Jamfile | 9 + .../interfaces/ether_drivers/ether_drivers.c | 339 ++++++++++++++++++ .../net/new_stack/interfaces/loopback/Jamfile | 9 + .../new_stack/interfaces/loopback/loopback.c | 96 +++++ .../kits/net/new_stack/protocols/Jamfile | 5 + .../kits/net/new_stack/protocols/arp/Jamfile | 9 + .../kits/net/new_stack/protocols/arp/arp.c | 220 ++++++++++++ .../kits/net/new_stack/protocols/ipv4/Jamfile | 9 + .../kits/net/new_stack/protocols/ipv4/ipv4.c | 134 +++++++ 13 files changed, 1022 insertions(+) create mode 100644 src/tests/kits/net/new_stack/framings/Jamfile create mode 100644 src/tests/kits/net/new_stack/framings/ethernet/Jamfile create mode 100644 src/tests/kits/net/new_stack/framings/ethernet/ethernet_frame.c create mode 100644 src/tests/kits/net/new_stack/interfaces/Jamfile create mode 100644 src/tests/kits/net/new_stack/interfaces/ether_drivers/Jamfile create mode 100644 src/tests/kits/net/new_stack/interfaces/ether_drivers/ether_drivers.c create mode 100644 src/tests/kits/net/new_stack/interfaces/loopback/Jamfile create mode 100644 src/tests/kits/net/new_stack/interfaces/loopback/loopback.c create mode 100644 src/tests/kits/net/new_stack/protocols/Jamfile create mode 100644 src/tests/kits/net/new_stack/protocols/arp/Jamfile create mode 100644 src/tests/kits/net/new_stack/protocols/arp/arp.c create mode 100644 src/tests/kits/net/new_stack/protocols/ipv4/Jamfile create mode 100644 src/tests/kits/net/new_stack/protocols/ipv4/ipv4.c diff --git a/src/tests/kits/net/new_stack/framings/Jamfile b/src/tests/kits/net/new_stack/framings/Jamfile new file mode 100644 index 0000000000..c083841eea --- /dev/null +++ b/src/tests/kits/net/new_stack/framings/Jamfile @@ -0,0 +1,3 @@ +SubDir OBOS_TOP src tests kits net new_stack framings ; + +SubInclude OBOS_TOP src tests kits net new_stack framings ethernet ; diff --git a/src/tests/kits/net/new_stack/framings/ethernet/Jamfile b/src/tests/kits/net/new_stack/framings/ethernet/Jamfile new file mode 100644 index 0000000000..53d2595888 --- /dev/null +++ b/src/tests/kits/net/new_stack/framings/ethernet/Jamfile @@ -0,0 +1,9 @@ +SubDir OBOS_TOP src tests kits net new_stack framings ethernet ; + +UseHeaders [ FDirName $(OBOS_TOP) src tests kits net new_stack headers ] ; + +Addon ethernet_frame : userland network_v2 framings : + ethernet_frame.c +; + +LinkSharedOSLibs ethernet_frame : new_stack_tester be ; diff --git a/src/tests/kits/net/new_stack/framings/ethernet/ethernet_frame.c b/src/tests/kits/net/new_stack/framings/ethernet/ethernet_frame.c new file mode 100644 index 0000000000..2338fe4faf --- /dev/null +++ b/src/tests/kits/net/new_stack/framings/ethernet/ethernet_frame.c @@ -0,0 +1,175 @@ +/* ethernet_framer.c - ethernet framing layer module + */ + +#include +#include +#include +#include + +#include +#include + +#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; + +net_attribute_id ethernet_header_attr; +net_attribute_id ethernet_from_attr; +net_attribute_id ethernet_to_attr; +net_attribute_id 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_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 +}; diff --git a/src/tests/kits/net/new_stack/interfaces/Jamfile b/src/tests/kits/net/new_stack/interfaces/Jamfile new file mode 100644 index 0000000000..8bceaf83d7 --- /dev/null +++ b/src/tests/kits/net/new_stack/interfaces/Jamfile @@ -0,0 +1,5 @@ +SubDir OBOS_TOP src tests kits net new_stack interfaces ; + +SubInclude OBOS_TOP src tests kits net new_stack interfaces ether_drivers ; +SubInclude OBOS_TOP src tests kits net new_stack interfaces loopback ; +# SubInclude OBOS_TOP src tests kits net new_stack interfaces dialup ; diff --git a/src/tests/kits/net/new_stack/interfaces/ether_drivers/Jamfile b/src/tests/kits/net/new_stack/interfaces/ether_drivers/Jamfile new file mode 100644 index 0000000000..c1c490a01d --- /dev/null +++ b/src/tests/kits/net/new_stack/interfaces/ether_drivers/Jamfile @@ -0,0 +1,9 @@ +SubDir OBOS_TOP src tests kits net new_stack interfaces ether_drivers ; + +UseHeaders [ FDirName $(OBOS_TOP) src tests kits net new_stack headers ] ; + +Addon ether_drivers : userland network_v2 interfaces : + ether_drivers.c +; + +LinkSharedOSLibs ether_drivers : new_stack_tester be ; diff --git a/src/tests/kits/net/new_stack/interfaces/ether_drivers/ether_drivers.c b/src/tests/kits/net/new_stack/interfaces/ether_drivers/ether_drivers.c new file mode 100644 index 0000000000..86df2c8509 --- /dev/null +++ b/src/tests/kits/net/new_stack/interfaces/ether_drivers/ether_drivers.c @@ -0,0 +1,339 @@ +/* legacy_devices.c - generic ethernet legacy devices layer module + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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) +{ + if (!buffer) + return B_ERROR; + + // TODO! + dprintf("%s: process_output:\n", me->name); + g_stack->dump_buffer(buffer); + + g_stack->delete_buffer(buffer, false); + return B_OK; +} + + +// #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; + + return g_stack->register_layer(path, "ethernet/frame", 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_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 +}; diff --git a/src/tests/kits/net/new_stack/interfaces/loopback/Jamfile b/src/tests/kits/net/new_stack/interfaces/loopback/Jamfile new file mode 100644 index 0000000000..dde5351dd2 --- /dev/null +++ b/src/tests/kits/net/new_stack/interfaces/loopback/Jamfile @@ -0,0 +1,9 @@ +SubDir OBOS_TOP src tests kits net new_stack interfaces loopback ; + +UseHeaders [ FDirName $(OBOS_TOP) src tests kits net new_stack headers ] ; + +Addon loopback : userland network_v2 interfaces : + loopback.c +; + +LinkSharedOSLibs loopback : new_stack_tester be ; diff --git a/src/tests/kits/net/new_stack/interfaces/loopback/loopback.c b/src/tests/kits/net/new_stack/interfaces/loopback/loopback.c new file mode 100644 index 0000000000..64aa62159e --- /dev/null +++ b/src/tests/kits/net/new_stack/interfaces/loopback/loopback.c @@ -0,0 +1,96 @@ +/* loopback.c - loopback interface module + */ + +#include +#include +#include +#include + +#include + +#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; + + +// ------------------- +status_t init(net_layer *me) +{ + dprintf("%s: initing layer\n", me->name); + return B_OK; +} + +status_t uninit(net_layer *me) +{ + dprintf("loopback: uniniting layer\n"); + return B_OK; +} + + +status_t enable(net_layer *me, bool enable) +{ + return B_OK; +} + + +status_t process_output(net_layer *me, net_buffer *buffer) +{ + if (!buffer) + return B_ERROR; + + // Here the magical loopback effect ;-) + return g_stack->send_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", "loopback/frame", 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 +}; diff --git a/src/tests/kits/net/new_stack/protocols/Jamfile b/src/tests/kits/net/new_stack/protocols/Jamfile new file mode 100644 index 0000000000..824f2f2d93 --- /dev/null +++ b/src/tests/kits/net/new_stack/protocols/Jamfile @@ -0,0 +1,5 @@ +SubDir OBOS_TOP src tests kits net new_stack protocols ; + +SubInclude OBOS_TOP src tests kits net new_stack protocols arp ; +SubInclude OBOS_TOP src tests kits net new_stack protocols ipv4 ; + diff --git a/src/tests/kits/net/new_stack/protocols/arp/Jamfile b/src/tests/kits/net/new_stack/protocols/arp/Jamfile new file mode 100644 index 0000000000..523fa8e0f5 --- /dev/null +++ b/src/tests/kits/net/new_stack/protocols/arp/Jamfile @@ -0,0 +1,9 @@ +SubDir OBOS_TOP src tests kits net new_stack protocols arp ; + +UseHeaders [ FDirName $(OBOS_TOP) src tests kits net new_stack headers ] ; + +Addon arp : userland network_v2 protocols : + arp.c +; + +LinkSharedOSLibs arp : new_stack_tester be ; diff --git a/src/tests/kits/net/new_stack/protocols/arp/arp.c b/src/tests/kits/net/new_stack/protocols/arp/arp.c new file mode 100644 index 0000000000..71f49b401f --- /dev/null +++ b/src/tests/kits/net/new_stack/protocols/arp/arp.c @@ -0,0 +1,220 @@ +/* ethernet.c - ethernet devices interface module + */ + +#include +#include +#include + +#include +#include + +#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; + +net_attribute_id 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_FRAMEREALY = 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 ==========\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, 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! + // dprintf("%s: packet %p is an ARP packet!\n", me->name, buffer); + 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 +}; diff --git a/src/tests/kits/net/new_stack/protocols/ipv4/Jamfile b/src/tests/kits/net/new_stack/protocols/ipv4/Jamfile new file mode 100644 index 0000000000..8f14fa4a94 --- /dev/null +++ b/src/tests/kits/net/new_stack/protocols/ipv4/Jamfile @@ -0,0 +1,9 @@ +SubDir OBOS_TOP src tests kits net new_stack protocols ipv4 ; + +UseHeaders [ FDirName $(OBOS_TOP) src tests kits net new_stack headers ] ; + +Addon ipv4 : userland network_v2 protocols : + ipv4.c +; + +LinkSharedOSLibs ipv4 : new_stack_tester be ; diff --git a/src/tests/kits/net/new_stack/protocols/ipv4/ipv4.c b/src/tests/kits/net/new_stack/protocols/ipv4/ipv4.c new file mode 100644 index 0000000000..5d4fea72cb --- /dev/null +++ b/src/tests/kits/net/new_stack/protocols/ipv4/ipv4.c @@ -0,0 +1,134 @@ +/* ipv4.c - ipv4 protocol module + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#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; + +net_attribute_id ethernet_protocol_attr; + +// ------------------- +static status_t init(net_layer *me) +{ + printf("%s: initing layer\n", me->name); + 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, NULL, (void **) &protocol, NULL) != B_OK) + return B_ERROR; + + if (*protocol != htons(0x0800)) // IPv4 on Ethernet protocol value + return B_ERROR; + + // TODO! + dprintf("%s: packet %p is an IPv4 packet!\n", me->name, 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 +};