From 48c3a92f6faf312951909b203c171f088a5731f4 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 1 Jun 2015 23:00:09 +0100 Subject: [PATCH] syscall_net: first pieces Lots left to put together for the non protocol parts of the stack, but this is a starting point. --- Kernel/syscall_net.c | 373 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 373 insertions(+) create mode 100644 Kernel/syscall_net.c diff --git a/Kernel/syscall_net.c b/Kernel/syscall_net.c new file mode 100644 index 00000000..390ca664 --- /dev/null +++ b/Kernel/syscall_net.c @@ -0,0 +1,373 @@ +#include +#include +#include + +#define NSOCKET 8 + + +struct sockaddrs { + uint32_t laddr; + uint16_t lport; + uint32_t daddr; + uint16_t dport; +}; + +struct socket +{ + inoptr s_inode; + uint8_t s_type; + uint8_t s_error; + uint8_t s_state; +#define SS_UNUSED 0 +#define SS_UNCONNECTED 1 +#define SS_BOUND 2 +#define SS_LISTENING 3 +#define SS_CONNECTING 4 +#define SS_CONNECTED 5 + struct sockaddrs s_addr; +}; + +struct socket sockets[NSOCKET]; +uint32_t our_address; + +static int is_socket(inoptr ino) +{ + if ((ino->c_node.i_mode & F_MASK) == F_SOCK) + return 1; + return 0; +} + +static int8_t alloc_socket(void) +{ + struct socket *s = sockets; + while (s < sockets + NSOCKET) { + if (s->s_state == SS_UNUSED) + return s - sockets; + s++; + } + return -1; +} + +static struct socket *sock_get(int fd, uint8_t *flag) +{ + struct oft *oftp; + inoptr ino = getinode(fd); + if (ino == NULLINODE) + return NULL; + if (!is_socket(ino)) { + udata.u_error = EINVAL; + return NULL; + } + if (flag) { + oftp = of_tab + udata.u_files[fd]; + *flag = oftp->o_access; + } + return sockets + ino->c_node.i_nlink; +} + +static int sock_pending(struct socket *s) +{ + /* TODO */ + return 0; +} + +static int sock_autobind(struct socket *s) +{ + /* TODO */ + s->s_state = SS_BOUND; + return 0; +} + +static struct socket *sock_find_local(uint32_t addr, uint16_t port) +{ + /* TODO */ + return NULL; +} + +static int sa_get(struct sockaddr_in *u, struct sockaddr_in *k) +{ + if (uget(u, k, sizeof(struct sockaddr_in))) + return -1; + if (k->sin_family != AF_INET) { + udata.u_error = EINVAL; + return -1; + } + return 0; +} + +static int sa_getlocal(struct sockaddr_in *u, struct sockaddr_in *k) +{ + if (sa_get(u, k)) + return -1; + if (ntohs(k->sin_port) < 1024 && !super()) { + udata.u_error = EACCES; + return -1; + } + if (k->sin_addr.s_addr != INADDR_ANY && + !IN_LOOPBACK(k->sin_addr.s_addr) && + k->sin_addr.s_addr != our_address) { + udata.u_error = EADDRNOTAVAIL; + return -1; + } + return 0; +} + +static int sa_getremote(struct sockaddr_in *u, struct sockaddr_in *k) +{ + if (sa_get(u, k)) + return -1; + if (ntohs(k->sin_port) >= 512 && ntohs(k->sin_port) < 1024 && !super()) { + udata.u_error = EACCES; + return -1; + } + return 0; +} + +int sock_error(struct socket *s) +{ + udata.u_error = s->s_error; + s->s_error = 0; + if (udata.u_error) + return -1; + else + return 0; +} + +struct sockinfo { + uint8_t af; + uint8_t pf; + uint8_t type; + uint8_t priv; +}; + +#define NSOCKTYPE 3 +struct sockinfo socktypes[NSOCKTYPE] = { + { AF_INET, SOCK_STREAM, IPPROTO_TCP, 0 }, +#define SOCKTYPE_TCP 1 + { AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0 }, +#define SOCKTYPE_UDP 2 + { AF_INET, SOCK_RAW, 0, 0 } +#define SOCKTYPE_RAW 3 +}; + +arg_t make_socket(struct sockinfo *s, int8_t *np) +{ + int8_t n; + int8_t uindex; + int8_t oftindex; + inoptr ino; + + /* RAW sockets are superuser */ + if (s->priv && esuper()) + return -1; + + /* Start by getting the file and inode table entries */ + if ((uindex = uf_alloc()) == -1) + return -1; + if ((oftindex = oft_alloc()) == -1) + goto nooft; + + if (np) + n = *np; + else { + n = alloc_socket(); + if (n == -1) + goto noalloc; + } + /* We need an inode : FIXME - do we want a pipedev aka Unix ? */ + if (!(ino = i_open(root_dev, 0))) + goto noalloc; + /* All good - now set it up */ + /* The nlink cheat needs to be taught to fsck! */ + ino->c_node.i_mode = F_SOCK | 0777; + ino->c_node.i_nlink = n; /* Cheat !! */ + + of_tab[oftindex].o_inode = ino; + of_tab[oftindex].o_access = O_RDWR; + + udata.u_files[uindex] = oftindex; + + sockets[n].s_inode = ino; + sockets[n].s_type = s - socktypes; /* Pointer or uint8_t best ? */ + sockets[n].s_state = SS_UNCONNECTED; + + if (np) + *np = n; + return uindex; + +noalloc: + oft_deref(oftindex); /* Will call i_deref! */ +nooft: + udata.u_files[uindex] = NO_FILE; + return -1; +} + +/******************************************* +socket (af, type, pf) Function ?? +uint16_t af; +uint16_t type; +uint16_t pf; +********************************************/ + +#define afv (uint16_t)udata.u_argn +#define typev (uint16_t)udata.u_argn1 +#define pfv (uint16_t)udata.u_argn2 + +arg_t _socket(void) +{ + struct sockinfo *s = socktypes; + + /* Find the socket */ + while (s && s < socktypes + NSOCKTYPE) { + if (s->af == afv && s->type == typev) { + if (s->pf == 0 || s->pf == pfv) + return make_socket(s, NULL); + } + s++; + } + return -EAFNOSUPPORT; +} + +#undef af +#undef type +#undef pf + +/******************************************* +listen(fd, qlen) Function ?? +int fd; +int qlen; +********************************************/ +#define fd (int16_t)udata.u_argn +#define qlen (int16_t)udata.u_argn1 + +arg_t _listen(void) +{ + struct socket *s = sock_get(fd, NULL); + if (s == NULL) + return -1; + if (s->s_state == SS_UNCONNECTED && sock_autobind(s)) + return -1; + if (s->s_type != SOCKTYPE_TCP || s->s_state != SS_BOUND) { + udata.u_error = EINVAL; + return -1; + } + /* Call the protocol services */ + s->s_state = SS_LISTENING; + return 0; +} + +/******************************************* +bind(fd, addr) Function ?? +int fd; +struct sockaddr_*in addr; +********************************************/ +#define fd (int16_t)udata.u_argn +#define addr (struct sockaddr_in *)udata.u_argn1 + +arg_t _bind(void) +{ + struct socket *s = sock_get(fd, NULL); + struct sockaddr_in sin; + if (s == NULL) + return -1; + if (s->s_state != SS_UNCONNECTED) + return -1; + if (sa_getlocal(addr, &sin) == -1) + return -1; + if (sock_find_local(sin.sin_addr.s_addr, sin.sin_port)) { + udata.u_error = EADDRINUSE; + return -1; + } + s->s_state = SS_BOUND; + return 0; +} + +/******************************************* +connect(fd, addr) Function ?? +int fd; +struct sockaddr_*in addr; +********************************************/ +#define fd (int16_t)udata.u_argn +#define addr (struct sockaddr_in *)udata.u_argn1 + +arg_t _connect(void) +{ + uint8_t flag; + struct socket *s = sock_get(fd, &flag); + struct sockaddr_in sin; + if (s == NULL) + return -1; + if (s->s_state == SS_CONNECTING) { + udata.u_error = EALREADY; + return -1; + } + if (s->s_state == SS_UNCONNECTED && sock_autobind(s)) + return -1; + + if (s->s_state == SS_BOUND) { + if (sa_getremote(addr, &sin) == -1) + return -1; + s->s_state = SS_CONNECTING; + /* Protocol op to kick off */ + } + + do { + /* FIXME: return EINPROGRESS not EINTR for SS_CONNECTING */ + if (psleep_flags(s, flag)) + return -1; + /* Protocol state check */ + } while (s->s_state == SS_CONNECTING); + return sock_error(s); +} + +/******************************************* +accept(fd, addr) Function ?? +int fd; +struct sockaddr_*in addr; +********************************************/ +#define fd (int16_t)udata.u_argn + +/* Note: We don't do address return, the library can handle it */ +arg_t _accept(void) +{ + uint8_t flag; + struct socket *s = sock_get(fd, &flag); + int8_t n; + int8_t nfd; + + if (s == NULL) + return -1; + if (s->s_state == SS_LISTENING) { + udata.u_error = EALREADY; + return -1; + } + + while ((n = sock_pending(s)) != -1) { + if (psleep_flags(s, flag)) + return -1; + if (s->s_error) + return sock_error(s); + } + if ((nfd = make_socket(&socktypes[SOCKTYPE_TCP], &n)) == -1) + return -1; + sockets[n].s_state = SS_CONNECTED; + return nfd; +} + +/******************************************* +getsockaddrs(fd, addr) Function ?? +int fd; +struct sockaddr_*in addr; +********************************************/ +#define fd (int16_t)udata.u_argn +#define addrs (uint8_t *)udata.u_argn1 + +arg_t _getsockaddrs(void) +{ + struct socket *s = sock_get(fd, NULL); + + if (s == NULL) + return -1; + return uput(&s->s_addr, addrs, sizeof(struct sockaddrs)); +} + -- 2.34.1