From e17ba000e24d4e2742a365a81d5cd6a49dbee51b Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 10 Sep 2026 17:19:35 -0300 Subject: [PATCH] raw sockets: finish implementation --- kernel-src/include/kernel/sock.h | 4 +- kernel-src/io/net/raw.c | 208 +++++++++++++++++++++++++++---- 2 files changed, 187 insertions(+), 25 deletions(-) diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index 2d438ec7..49535220 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -10,6 +10,7 @@ #include #include #include +#include #define SOCKET_STATE_UNBOUND 0 #define SOCKET_STATE_BOUND 1 @@ -20,7 +21,7 @@ #define SOCKET_SHUTDOWN_WRITE 2 #define SOCKET_SHUTDOWN_RW 3 -typedef struct { +typedef struct socket { struct socketops_t *ops; mutex_t mutex; int state; @@ -38,6 +39,7 @@ typedef struct { union { ipv4addr_t ipv4addr; char path[256]; + raw_addr_t raw; }; } sockaddr_t; diff --git a/kernel-src/io/net/raw.c b/kernel-src/io/net/raw.c index 298f2fbe..2918ff8b 100644 --- a/kernel-src/io/net/raw.c +++ b/kernel-src/io/net/raw.c @@ -19,13 +19,17 @@ static list_t socket_list; typedef struct { uint8_t sender[6]; uint16_t size; + uint16_t proto; } packet_header_t; typedef struct { socket_t socket; + spinlock_t ringbuffer_lock; ringbuffer_t ringbuffer; list_node_t list_node; netdev_t *netdev_binding; + uint16_t netdev_index; + uint16_t proto; } raw_socket_t; // expectd to be called at IPL_DPC @@ -34,55 +38,205 @@ void raw_process(netdev_t *netdev, void *buffer, mac_t *sender, uint16_t proto, list_for_each (&socket_list, node) { raw_socket_t *socket = container_of(node, raw_socket_t, list_node); - if (socket->netdev_binding && socket->netdev_binding != netdev) - continue; - if (RINGBUFFER_FREESPACE(&socket->ringbuffer) < size + sizeof(packet_header_t)) + spinlock_acquire(&socket->ringbuffer_lock); + if ((socket->netdev_binding && socket->netdev_binding != netdev) || + (socket->proto && socket->proto != proto) || + (RINGBUFFER_FREESPACE(&socket->ringbuffer) < size + sizeof(packet_header_t))) { + spinlock_release(&socket->ringbuffer_lock); continue; + } packet_header_t header; memcpy(header.sender, sender, 6); header.size = size; + header.proto = proto; ringbuffer_write(&socket->ringbuffer, &header, sizeof(header)); ringbuffer_write(&socket->ringbuffer, buffer, size); + poll_event(&socket->socket.pollheader, POLLIN); + spinlock_release(&socket->ringbuffer_lock); } spinlock_release(&list_lock); } -static int raw_bind(socket_t *socket, sockaddr_t *addr, cred_t *cred) { - -} +static int raw_bind(socket_t *socket_handle, sockaddr_t *addr_handle, cred_t *cred) { + raw_socket_t *socket = (raw_socket_t *)socket_handle; + raw_addr_t *addr = &addr_handle->raw; -static int internalpoll(socket_t *socket, polldata_t *data, int events) { + if (addr->netdev == 0) + return EINVAL; -} + netdev_t *netdev = netdev_from_minor(addr->netdev - 1); + if (netdev == NULL) + return EINVAL; -static int raw_send(socket_t *socket, sockdesc_t *sockdesc) { - -} - -static int raw_recv(socket_t *socket, sockdesc_t *sockdesc) { - -} - -static int raw_getname(socket_t *socket, sockaddr_t *addr) { - raw_socket_t *raw_socket = (raw_socket_t *)socket; + long ipl = spinlock_acquire_raise_ipl(&socket->ringbuffer_lock, IPL_DPC); + socket->netdev_index = addr->netdev; + socket->proto = addr->proto; + socket->netdev_binding = netdev; + spinlock_release_lower_ipl(&socket->ringbuffer_lock, ipl); return 0; } -static int raw_getpeername(socket_t *socket, sockaddr_t *addr) { - return EINVAL; +static int internalpoll(raw_socket_t *socket, polldata_t *data, int events) { + int revents = 0; + + if (events & POLLOUT) + revents |= POLLOUT; + + if ((events & POLLIN) && RINGBUFFER_DATACOUNT(&socket->ringbuffer)) + revents |= POLLIN; + + if (revents == 0 && data) + poll_add(&socket->socket.pollheader, data, events); + + return revents; } -static int raw_poll(socket_t *socket, polldata_t *data, int events) { +static int raw_send(socket_t *socket_handle, sockdesc_t *sockdesc) { + raw_socket_t *socket = (raw_socket_t *)socket_handle; + int error = 0; + netdesc_t desc; + + sockdesc->donecount = 0; + MUTEX_ACQUIRE(&socket->socket.mutex); + + if (socket->socket.shutdown & SOCKET_SHUTDOWN_WRITE) + goto leave; + + if (sockdesc->addr == NULL) { + error = EDESTADDRREQ; + goto leave; + } + + if (socket->netdev_binding == NULL) { + error = ENOTCONN; + goto leave; + } + + if (sockdesc->count > socket->netdev_binding->mtu) { + error = EMSGSIZE; + goto leave; + } + + error = socket->netdev_binding->allocdesc(socket->netdev_binding, sockdesc->count, &desc); + if (error) + goto leave; + + error = iovec_iterator_copy_to_buffer(sockdesc->iovec_iterator, (void *)((uintptr_t)desc.address + desc.curroffset), sockdesc->count); + if (error) { + socket->netdev_binding->freedesc(socket->netdev_binding, &desc); + goto leave; + } + + mac_t target; + memcpy(&target, sockdesc->addr->raw.mac, sizeof(target)); + error = socket->netdev_binding->sendpacket(socket->netdev_binding, desc, target, socket->proto); + if (error == 0) + sockdesc->donecount = sockdesc->count; + + leave: + MUTEX_RELEASE(&socket->socket.mutex); + return error; +} + +static int raw_recv(socket_t *socket_handle, sockdesc_t *sockdesc) { + raw_socket_t *socket = (raw_socket_t *)socket_handle; + uintmax_t flags = sockdesc->flags; + int error = 0; + + sockdesc->donecount = 0; + MUTEX_ACQUIRE(&socket->socket.mutex); + + for (;;) { + polldesc_t desc = {0}; + error = poll_initdesc(&desc, 1); + if (error) + goto leave; + + int revents = internalpoll(socket, &desc.data[0], POLLIN); + if (revents) { + poll_leave(&desc); + poll_destroydesc(&desc); + break; + } + + if (socket_nonblocking(&socket->socket, flags)) { + error = EAGAIN; + poll_leave(&desc); + poll_destroydesc(&desc); + goto leave; + } + + MUTEX_RELEASE(&socket->socket.mutex); + + error = poll_dowait(&desc, 0); + + poll_leave(&desc); + poll_destroydesc(&desc); + if (error) + return error; + + MUTEX_ACQUIRE(&socket->socket.mutex); + } + + long ipl = spinlock_acquire_raise_ipl(&socket->ringbuffer_lock, IPL_DPC); + + packet_header_t header; + size_t header_size = ringbuffer_peek(&socket->ringbuffer, &header, 0, sizeof(header)); + + spinlock_release_lower_ipl(&socket->ringbuffer_lock, ipl); + + __assert(header_size == sizeof(header)); + + size_t copycount = min(header.size, sockdesc->count); + sockdesc->donecount = iovec_iterator_peek_from_ringbuffer(sockdesc->iovec_iterator, &socket->ringbuffer, sizeof(header), copycount); + if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) { + sockdesc->donecount = 0; + error = EFAULT; + goto leave; + } + + if ((flags & SOCKET_RECV_FLAGS_PEEK) == 0) + ringbuffer_truncate(&socket->ringbuffer, sizeof(header) + header.size); + + if (sockdesc->addr) { + memcpy(sockdesc->addr->raw.mac, header.sender, sizeof(sockdesc->addr->raw.mac)); + sockdesc->addr->raw.proto = header.proto; + } + + leave: + MUTEX_RELEASE(&socket->socket.mutex); + return error; +} + +static int raw_getname(socket_t *socket_handle, sockaddr_t *addr) { + raw_socket_t *socket = (raw_socket_t *)socket_handle; + + long ipl = spinlock_acquire_raise_ipl(&socket->ringbuffer_lock, IPL_DPC); + + memset(addr, 0, sizeof(addr->raw)); + + addr->raw.netdev = socket->netdev_index; + addr->raw.proto = socket->proto; + if (socket->netdev_binding) + memcpy(addr->raw.mac, socket->netdev_binding->mac.address, sizeof(addr->raw.mac)); + + spinlock_release_lower_ipl(&socket->ringbuffer_lock, ipl); + + return 0; +} + +static int raw_poll(socket_t *handle, polldata_t *data, int events) { + raw_socket_t *socket = (raw_socket_t *)handle; int revents = 0; - MUTEX_ACQUIRE(&socket->mutex); + MUTEX_ACQUIRE(&socket->socket.mutex); revents = internalpoll(socket, data, events); - MUTEX_RELEASE(&socket->mutex); + MUTEX_RELEASE(&socket->socket.mutex); return revents; } @@ -102,6 +256,10 @@ static int raw_connect(socket_t *socket, sockaddr_t *addr, uintmax_t flags, cred return EINVAL; } +static int raw_getpeername(socket_t *socket, sockaddr_t *addr) { + return EINVAL; +} + static void raw_destroy(socket_t *handle) { raw_socket_t *socket = (raw_socket_t *)handle; long ipl = spinlock_acquire_raise_ipl(&list_lock, IPL_DPC); @@ -122,7 +280,7 @@ static socketops_t socketops = { .connect = raw_connect }; -socket_t *raw_create_socket(void) { +socket_t *raw_create_socket(int protocol) { // XXX possibly move this to a slab? raw_socket_t *socket = alloc(sizeof(raw_socket_t)); if (socket == NULL) @@ -133,6 +291,8 @@ socket_t *raw_create_socket(void) { return NULL; } + SPINLOCK_INIT(socket->ringbuffer_lock); + socket->proto = protocol; socket->socket.ops = &socketops; long ipl = spinlock_acquire_raise_ipl(&list_lock, IPL_DPC);