diff --git a/kernel-src/fs/sockfs.c b/kernel-src/fs/sockfs.c new file mode 100644 index 00000000..a6189db0 --- /dev/null +++ b/kernel-src/fs/sockfs.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static scache_t *nodecache; +static uintmax_t currentinode; + +int sockfs_open(vnode_t **node, int flags, cred_t *cred) { + return ENOSYS; // not needed +} + +int sockfs_close(vnode_t *node, int flags, cred_t *cred) { + return ENOSYS; // not needed +} + +int sockfs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc, cred_t *cred) { + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); + return socket->ops->recv(socket, NULL, buffer, size, flags, readc); +} + +int sockfs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec, cred_t *cred) { + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); + return socket->ops->send(socket, NULL, buffer, size, flags, writec); +} + +int sockfs_poll(vnode_t *node, polldata_t *data, int events) { + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); + return socket->ops->poll(socket, data, events); +} + +int sockfs_getattr(vnode_t *node, vattr_t *attr, cred_t *cred) { + socketnode_t *socketnode = (socketnode_t *)node; + + VOP_LOCK(node); + *attr = socketnode->attr; + attr->type = node->type; + VOP_UNLOCK(node); + + return 0; +} + +int sockfs_setattr(vnode_t *node, vattr_t *attr, cred_t *cred) { + socketnode_t *socketnode = (socketnode_t *)node; + VOP_LOCK(node); + + socketnode->attr.gid = attr->gid; + socketnode->attr.uid = attr->uid; + socketnode->attr.mode = attr->mode; + socketnode->attr.atime = attr->atime; + socketnode->attr.mtime = attr->mtime; + socketnode->attr.ctime = attr->ctime; + + VOP_UNLOCK(node); + return 0; +} + +// arg can be in userspace +int sockfs_ioctl(vnode_t *node, unsigned long request, void *arg, int *result) { + switch (request) { + case SIOCGIFHWADDR: + ifreq_t *ifreq = arg; + netdev_t *netdev = netdev_getdev(ifreq->name); + if (netdev) { + memcpy(ifreq->addr.addr, netdev->mac.address, sizeof(mac_t)); + return 0; + } else { + return ENODEV; + } + default: + return EINVAL; + } +} + +int sockfs_inactive(vnode_t *node) { + socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); + VOP_LOCK(node); + socket->ops->destroy(socket); + slab_free(nodecache, node); + return 0; +} + +static int sockfs_enodev() { + return ENODEV; +} + +static vops_t vnops = { + .create = sockfs_enodev, + .open = sockfs_open, + .close = sockfs_close, + .getattr = sockfs_getattr, + .setattr = sockfs_setattr, + .lookup = sockfs_enodev, + .poll = sockfs_poll, + .read = sockfs_read, + .write = sockfs_write, + .access = sockfs_enodev, + .unlink = sockfs_enodev, + .link = sockfs_enodev, + .symlink = sockfs_enodev, + .readlink = sockfs_enodev, + .inactive = sockfs_inactive, + .mmap = sockfs_enodev, + .munmap = sockfs_enodev, + .getdents = sockfs_enodev, + .resize = sockfs_enodev, + .rename = sockfs_enodev, + .ioctl = sockfs_ioctl +}; + +static void ctor(scache_t *cache, void *obj) { + socketnode_t *node = obj; + memset(node, 0, sizeof(socketnode_t)); + VOP_INIT(&node->vnode, &vnops, 0, V_TYPE_SOCKET, NULL); + node->attr.inode = ++currentinode; +} + +void sockfs_init() { + nodecache = slab_newcache(sizeof(socketnode_t), 0, ctor, ctor); + __assert(nodecache); +} + +int sockfs_newsocket(vnode_t **nodep, socket_t *socket) { + __assert(_cpu()->intstatus); + vnode_t *vnode = slab_allocate(nodecache); + socketnode_t *node = (socketnode_t *)vnode; + if (node == NULL) + return ENOMEM; + + node->socket = socket; + *nodep = vnode; + POLL_INITHEADER(&socket->pollheader); + + return 0; +} diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h new file mode 100644 index 00000000..5817bfe0 --- /dev/null +++ b/kernel-src/include/kernel/sock.h @@ -0,0 +1,100 @@ +#ifndef _SOCK_H +#define _SOCK_H + +#include +#include +#include +#include + +#define SOCKET_STATE_UNBOUND 0 +#define SOCKET_STATE_BOUND 1 +#define SOCKET_STATE_CONNECTED 2 +#define SOCKET_STATE_LISTENING 3 + +typedef struct { + struct socketops_t *ops; + mutex_t mutex; + int state; + int broadcast; + netdev_t *netdev; + pollheader_t pollheader; + int type; +} socket_t; + +typedef struct socketops_t { + int (*bind)(socket_t *socket, sockaddr_t *addr); + int (*send)(socket_t *socket, sockaddr_t *addr, void *buffer, size_t count, uintmax_t flags, size_t *sendcount); + int (*recv)(socket_t *socket, sockaddr_t *addr, void *buffer, size_t count, uintmax_t flags, size_t *recvcount); + int (*poll)(socket_t *socket, polldata_t *data, int events); + void (*destroy)(socket_t *socket); +} socketops_t; + +typedef struct { + vnode_t vnode; + vattr_t attr; + socket_t *socket; +} socketnode_t; + +#define SOCKET_TYPE_UDP 0 +#define SOCKFS_SOCKET_FROM_NODE(nodep) (((socketnode_t *)(nodep))->socket) + +static inline int sock_convertaddress(sockaddr_t *sockaddr, abisockaddr_t *abisockaddr) { + switch (abisockaddr->type) { + case AF_INET: + inaddr_t *inaddr = (inaddr_t *)abisockaddr; + sockaddr->ipv4addr.addr = be_to_cpu_d(inaddr->sin_addr); + sockaddr->ipv4addr.port = be_to_cpu_w(inaddr->sin_port); + break; + default: + return EINVAL; + } + + return 0; +} + +static inline int sock_addrtoabiaddr(int socktype, sockaddr_t *sockaddr, abisockaddr_t *abisockaddr) { + switch (socktype) { + case SOCKET_TYPE_UDP: + inaddr_t *inaddr = (inaddr_t *)abisockaddr; + inaddr->sin_addr = cpu_to_be_d(sockaddr->ipv4addr.addr); + inaddr->sin_port = cpu_to_be_w(sockaddr->ipv4addr.port); + break; + default: + return EINVAL; + } + + return 0; +} + +static inline int sock_copymsghdr(msghdr_t *khdr, msghdr_t *uhdr) { + memcpy(khdr, uhdr, sizeof(msghdr_t)); + iovec_t *iovectmp = alloc(sizeof(iovec_t) * khdr->iovcount); + if (iovectmp == NULL) + return ENOMEM; + memcpy(iovectmp, khdr->iov, sizeof(iovec_t) * khdr->iovcount); + khdr->iov = iovectmp; + + if (khdr->addr) { + abisockaddr_t *addrtmp = alloc(khdr->addrlen); + if (addrtmp == NULL) { + free(iovectmp); + return ENOMEM; + } + memcpy(addrtmp, khdr->addr, khdr->addrlen); + khdr->addr = addrtmp; + } + + return 0; +} + +static inline void sock_freemsghdr(msghdr_t *hdr) { + free(hdr->iov); + free(hdr->addr); +} + +socket_t *udp_createsocket(); +socket_t *socket_create(int type); +int sockfs_newsocket(vnode_t **vnodep, socket_t *socket); +void sockfs_init(); + +#endif diff --git a/kernel-src/io/net/socket.c b/kernel-src/io/net/socket.c new file mode 100644 index 00000000..6ffb99ca --- /dev/null +++ b/kernel-src/io/net/socket.c @@ -0,0 +1,12 @@ +#include +#include + +static socket_t *(*createsocket[])() = { + udp_createsocket +}; + + +socket_t *socket_create(int type) { + __assert(type < sizeof(createsocket) / sizeof(createsocket[0])); + return createsocket[type](); +}