diff --git a/kernel-src/include/kernel/raw.h b/kernel-src/include/kernel/raw.h new file mode 100644 index 00000000..5f504521 --- /dev/null +++ b/kernel-src/include/kernel/raw.h @@ -0,0 +1,7 @@ +#ifndef _RAW_H +#define _RAW_H + +void raw_process(netdev_t *netdev, void *buffer, uint32_t peer); +socket_t *raw_create_socket(void); + +#endif diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index c5c1d291..33bba570 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -92,6 +92,7 @@ typedef struct { #define SOCKET_TYPE_LOCAL 1 #define SOCKET_TYPE_TCP 2 #define SOCKET_TYPE_LOCAL_SEQPACKET 3 +#define SOCKET_TYPE_RAW_STRIPPED 4 #define SOCKFS_SOCKET_FROM_NODE(nodep) (((socketnode_t *)(nodep))->socket) static inline int sockfd_get(int fd, vnode_t **vnodep, int *fileflags) { diff --git a/kernel-src/io/net/raw.c b/kernel-src/io/net/raw.c new file mode 100644 index 00000000..298f2fbe --- /dev/null +++ b/kernel-src/io/net/raw.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SOCKET_BUFFER (16 * 1024) + +// TODO: check user creating socket is root + +SPINLOCK_DEFINE(list_lock); +static list_t socket_list; + +typedef struct { + uint8_t sender[6]; + uint16_t size; +} packet_header_t; + +typedef struct { + socket_t socket; + ringbuffer_t ringbuffer; + list_node_t list_node; + netdev_t *netdev_binding; +} raw_socket_t; + +// expectd to be called at IPL_DPC +void raw_process(netdev_t *netdev, void *buffer, mac_t *sender, uint16_t proto, size_t size) { + spinlock_acquire(&list_lock); + + 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)) + continue; + + packet_header_t header; + memcpy(header.sender, sender, 6); + header.size = size; + + ringbuffer_write(&socket->ringbuffer, &header, sizeof(header)); + ringbuffer_write(&socket->ringbuffer, buffer, size); + } + + spinlock_release(&list_lock); +} + +static int raw_bind(socket_t *socket, sockaddr_t *addr, cred_t *cred) { + +} + +static int internalpoll(socket_t *socket, polldata_t *data, int events) { + +} + +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; + return 0; +} + +static int raw_getpeername(socket_t *socket, sockaddr_t *addr) { + return EINVAL; +} + +static int raw_poll(socket_t *socket, polldata_t *data, int events) { + int revents = 0; + MUTEX_ACQUIRE(&socket->mutex); + + revents = internalpoll(socket, data, events); + + MUTEX_RELEASE(&socket->mutex); + return revents; +} + +static int raw_shutdown(socket_t *socket, int how) { + if (how > SOCKET_SHUTDOWN_RW) + return EINVAL; + + MUTEX_ACQUIRE(&socket->mutex); + + socket->shutdown |= how; + + MUTEX_RELEASE(&socket->mutex); + return 0; +} + +static int raw_connect(socket_t *socket, sockaddr_t *addr, uintmax_t flags, cred_t *cred) { + 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); + list_remove(&socket_list, &socket->list_node); + spinlock_release_lower_ipl(&list_lock, ipl); + free(socket); +} + +static socketops_t socketops = { + .bind = raw_bind, + .send = raw_send, + .recv = raw_recv, + .destroy = raw_destroy, + .poll = raw_poll, + .getname = raw_getname, + .getpeername = raw_getpeername, + .shutdown = raw_shutdown, + .connect = raw_connect +}; + +socket_t *raw_create_socket(void) { + // XXX possibly move this to a slab? + raw_socket_t *socket = alloc(sizeof(raw_socket_t)); + if (socket == NULL) + return NULL; + + if (ringbuffer_init(&socket->ringbuffer, SOCKET_BUFFER)) { + free(socket); + return NULL; + } + + socket->socket.ops = &socketops; + + long ipl = spinlock_acquire_raise_ipl(&list_lock, IPL_DPC); + list_push_front(&socket_list, &socket->list_node); + spinlock_release_lower_ipl(&list_lock, ipl); + + return (socket_t *)socket; +} diff --git a/kernel-src/io/net/socket.c b/kernel-src/io/net/socket.c index a67b8c3d..13fca2e3 100644 --- a/kernel-src/io/net/socket.c +++ b/kernel-src/io/net/socket.c @@ -1,11 +1,13 @@ #include +#include #include static socket_t *(*createsocket[])() = { udp_createsocket, localsock_createsocket, tcp_createsocket, - localsock_create_seqpacket_socket + localsock_create_seqpacket_socket, + raw_create_socket }; socket_t *socket_create(int type) {