--- /dev/null
+#include <config.h>
+#include <corax/types.h>
+#include <corax/heap.h>
+#include <corax/errno.h>
+#include <sys/socket.h>
+#include <arch.h>
+#include "socket.h"
+#include "process.h"
+
+static struct socket *_sockets[CONFIG_SOCKET_MAX];
+static int _nsockets;
+
+#define SOCKET_PREALLOC ((void*)0xffffffff)
+
+static inline int allocsockfd(void)
+{
+ int ret_val;
+ int i;
+
+ ret_val = -ENFILE;
+
+ if(_nsockets < CONFIG_SOCKET_MAX) {
+ _nsockets++;
+
+ for(i = 0; i < CONFIG_SOCKET_MAX; i++) {
+ if(!_sockets[i]) {
+ _sockets[i] = SOCKET_PREALLOC;
+ ret_val = i;
+ break;
+ }
+ }
+ }
+
+ return(ret_val);
+}
+
+static inline int freesockfd(int fd)
+{
+ int ret_val;
+
+ ret_val = -EINVAL;
+
+ if(fd >= 0 && fd < CONFIG_SOCKET_MAX) {
+ ret_val = -EBADF;
+
+ if(_sockets[fd]) {
+ _sockets[fd] = NULL;
+ _nsockets--;
+ ret_val = 0;
+ }
+ }
+
+ return(ret_val);
+}
+
+int socreate(int dom, int type, int proto)
+{
+ struct task *cur_task;
+ struct process *cur_proc;
+#if 0
+ struct protosw *psw;
+#endif
+ struct socket *so;
+ int ret_val;
+ int sfd;
+ int pfd;
+
+ sfd = -1;
+ pfd = -1;
+ ret_val = -EINVAL;
+
+ /* first of all, make sure all input makes sense */
+ if(!PF_VALID(dom) || !SOCK_VALID(type)) {
+ goto gtfo;
+ }
+
+ ret_val = -ENFILE;
+
+ /* check if the system-wide socket limit has been hit */
+ if(_nsockets >= CONFIG_SOCKET_MAX) {
+ goto gtfo;
+ }
+
+ /*
+ * This function is only executed as a result of a syscall,
+ * so it's safe to assume that task_get_current() will never
+ * return NULL.
+ */
+ cur_task = task_get_current();
+ cur_proc = cur_task->t_proc;
+
+ sfd = allocsockfd();
+
+ if(sfd < 0) {
+ ret_val = sfd;
+ goto gtfo;
+ }
+
+ pfd = process_falloc(cur_proc, sfd);
+
+ if(pfd < 0) {
+ ret_val = pfd;
+ goto gtfo;
+ }
+
+#if 0
+ /* FIXME: Look up the domain/protocol */
+ if(proto) {
+ psw = pffindproto(dom, proto, type);
+ } else {
+ psw = pffindtype(dom, type);
+ }
+
+ if(!psw) {
+ ret_val = -EPROTONOSUPPORT;
+ goto gtfo;
+ }
+
+ if(psw->pr_type != type) {
+ ret_val = -EPROTOTYPE;
+ goto gtfo;
+ }
+#endif
+
+ so = kmalloc(sizeof(*so));
+
+ if(!so) {
+ ret_val = -ENOMEM;
+ goto gtfo;
+ }
+
+ so->so_type = type;
+#if 0
+ so->so_proto = psw;
+#endif
+
+ /*
+ * FIXME: set SS_PRIV on so->so_state if the calling process is
+ * executing as root; initialize remaining members, attach the
+ * socket by meansof psw->pr_usrreq(so, PRU_ATTACH, ...).
+ * ref: TCP/IP Illustrated Vol. 2, p. 426
+ */
+
+ _sockets[sfd] = so;
+ ret_val = pfd;
+
+gtfo:
+ if(ret_val < 0) {
+ if(sfd > 0) {
+ freesockfd(sfd);
+ sfd = -1;
+ }
+
+ if(cur_proc && pfd > 0) {
+ process_ffree(cur_proc, pfd);
+ pfd = -1;
+ }
+
+ if(so) {
+ kfree(so);
+ so = NULL;
+ }
+ }
+
+ return(ret_val);
+}