Merge origin/netpush (networking code) (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 22 Mar 2013 00:04:19 +0000 (17:04 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 22 Mar 2013 04:12:23 +0000 (21:12 -0700)
Had some compilation issues (missing mbuf.h, etc), but compiles now.

Other than basic conflicts, this also was using the old semaphore style,
as well as having a few other issues in semaphore usage, so please check
that out.

Rebuild your cross compiler.  There are a bunch of new files in the -ros
folder, so either copy them over, or just make clean.  Here are the new
glibc files:

glibc-2.14.1-ros/sysdeps/ros/accept.c
glibc-2.14.1-ros/sysdeps/ros/bind.c
glibc-2.14.1-ros/sysdeps/ros/connect.c
glibc-2.14.1-ros/sysdeps/ros/listen.c
glibc-2.14.1-ros/sysdeps/ros/recv.c
glibc-2.14.1-ros/sysdeps/ros/recvfrom.c
glibc-2.14.1-ros/sysdeps/ros/select.c
glibc-2.14.1-ros/sysdeps/ros/send.c
glibc-2.14.1-ros/sysdeps/ros/sendto.c
glibc-2.14.1-ros/sysdeps/ros/socket.c

Conflicts:
Makeconfig
kern/include/kthread.h
kern/include/time.h
kern/include/vfs.h
kern/src/Makefrag
kern/src/kthread.c
kern/src/syscall.c

17 files changed:
1  2 
Makeconfig
kern/arch/i686/nic_common.c
kern/arch/i686/x86.h
kern/include/alarm.h
kern/include/kthread.h
kern/include/ros/bits/syscall.h
kern/include/ros/common.h
kern/include/time.h
kern/include/vfs.h
kern/src/Makefrag
kern/src/eth_audio.c
kern/src/init.c
kern/src/net/tcp.c
kern/src/net/udp.c
kern/src/socket.c
kern/src/syscall.c
kern/src/vfs.c

diff --combined Makeconfig
@@@ -3,7 -3,6 +3,7 @@@
  # To enable any of these options, add a line like the following to your Makelocal
  # CFLAGS += $(CONFIG_APPSERVER)
  CONFIG_APPSERVER:=                 -D__CONFIG_APPSERVER__
 +CONFIG_DEMO_SLAVE:=                -D__CONFIG_DEMO_SLAVE__
  CONFIG_ARSC_SERVER:=               -D__CONFIG_ARSC_SERVER__
  
  # Kernel configuration parameters
  # KERN_CFLAGS += $(CONFIG_KFS) $(CONFIG_BSD_ON_CORE0)
  CONFIG_KFS:=                       -D__CONFIG_KFS__
  CONFIG_EXT2FS:=                    -D__CONFIG_EXT2FS__
 -CONFIG_DEDICATED_MONITOR:=         -D__CONFIG_DEDICATED_MONITOR__
  CONFIG_SINGLE_CORE:=               -D__CONFIG_SINGLE_CORE__
  CONFIG_NETWORKING:=                -D__CONFIG_NETWORKING__
  CONFIG_SERIAL_IO:=                 -D__CONFIG_SERIAL_IO__
  CONFIG_BSD_ON_CORE0:=              -D__CONFIG_BSD_ON_CORE0__
  CONFIG_SEQLOCK_DEBUG:=             -D__CONFIG_SEQLOCK_DEBUG__
  CONFIG_SPINLOCK_DEBUG:=            -D__CONFIG_SPINLOCK_DEBUG__
 +CONFIG_SPINPDR_NO_CAS:=            -D__CONFIG_SPINPDR_NO_CAS__
  CONFIG_PAGE_COLORING:=             -D__CONFIG_PAGE_COLORING__
  CONFIG_DEMAND_PAGING:=             -D__CONFIG_DEMAND_PAGING__
  CONFIG_NOMTRRS:=                   -D__CONFIG_NOMTRRS__
@@@ -34,7 -33,7 +34,8 @@@ CONFIG_PCI_VERBOSE:=               -D__
  CONFIG_ETH_AUDIO:=                 -D__CONFIG_ETH_AUDIO__
  CONFIG_KB_CORE0_ONLY:=             -D__CONFIG_KB_CORE0_ONLY__
  CONFIG_KTHREAD_POISON:=            -D__CONFIG_KTHREAD_POISON__
 -CONFIG_SOCKET:=                    -D__CONFIG_SOCKET__                                                                                
 +CONFIG_PRINTK_NO_BACKSPACE:=       -D__CONFIG_PRINTK_NO_BACKSPACE__
++CONFIG_SOCKET:=                    -D__CONFIG_SOCKET__
  
  # Userspace configuration parameters
  # By default, each of these options will be turned off
@@@ -18,6 -18,9 +18,9 @@@
  // Global send_frame function pointer
  // Means we can only have one network card per system right now...
  int (*send_frame)(const char *data, size_t len);
+ int (*send_pbuf)(struct pbuf *p);
+ struct pbuf*  (*recv_pbuf)(void);
  
  // Global variables for managing ethernet packets over a nic
  // Again, since these are global for all network cards we are 
@@@ -29,5 -32,5 +32,5 @@@ char* packet_buffers[MAX_PACKET_BUFFERS
  uint32_t packet_buffers_sizes[MAX_PACKET_BUFFERS];
  uint32_t packet_buffers_head = 0;
  uint32_t packet_buffers_tail = 0;
 -spinlock_t packet_buffers_lock = SPINLOCK_INITIALIZER;
 +spinlock_t packet_buffers_lock = SPINLOCK_INITIALIZER_IRQSAVE;
  
diff --combined kern/arch/i686/x86.h
@@@ -7,8 -7,6 +7,8 @@@
  /* Model Specific Registers */
  #define IA32_APIC_BASE                                0x1b
  #define IA32_FEATURE_CONTROL          0x3a
 +#define IA32_MISC_ENABLE                      0x1a0
 +
  #define IA32_MTRR_DEF_TYPE                    0x2ff
  #define IA32_MTRR_PHYSBASE0                   0x200
  #define IA32_MTRR_PHYSMASK0                   0x201
@@@ -340,4 -338,8 +340,8 @@@ __cpu_relax(void
        asm volatile("pause" : : : "memory");
  }
  
+ #ifndef UNUSED_ARG
+ #define UNUSED_ARG(x) (void)x
+ #endif /* This prevents compiler warnings for UNUSED_ARG */ 
  #endif /* !ROS_INC_X86_H */
diff --combined kern/include/alarm.h
@@@ -44,6 -44,8 +44,6 @@@
  #include <ros/common.h>
  #include <sys/queue.h>
  #include <kthread.h>
 -#include <alarm.h>
 -
  
  /* These structures allow code to block or defer work for a certain amount of
   * time.  Timer chains (like off a per-core timer) are made of lists/trees of
@@@ -62,6 -64,8 +62,8 @@@ struct alarm_waiter 
  };
  TAILQ_HEAD(awaiters_tailq, alarm_waiter);             /* ideally not a LL */
  
 -typedef void (* alarm_handler)(struct alarm_waiter *waiter);
++typedef void (*alarm_handler)(struct alarm_waiter *waiter);
  /* One of these per alarm source, such as a per-core timer.  Based on the
   * source, you may need a lock (such as for a global timer).  set_interrupt() is
   * a method for setting the interrupt source. */
diff --combined kern/include/kthread.h
  
  struct proc;
  struct kthread;
+ struct semaphore;
+ struct semaphore_entry;
  TAILQ_HEAD(kthread_tailq, kthread);
+ LIST_HEAD(semaphore_list, semaphore_entry);
  
  /* This captures the essence of a kernel context that we want to suspend.  When
   * a kthread is running, we make sure its stacktop is the default kernel stack,
@@@ -30,46 -34,75 +34,53 @@@ struct kthread 
        /* ID, other shit, etc */
  };
  
 -
  /* Semaphore for kthreads to sleep on.  0 or less means you need to sleep */
  struct semaphore {
        struct kthread_tailq            waiters;
        int                                             nr_signals;
        spinlock_t                                      lock;
 +      bool                                            irq_okay;
  };
  
 -/* This doesn't have to be inline, but it doesn't matter for now */
 -static inline void init_sem(struct semaphore *sem, int signals)
 -{
 -      TAILQ_INIT(&sem->waiters);
 -      sem->nr_signals = signals;
 -      spinlock_init(&sem->lock);
 -}
 -
 -/* Down and up for the semaphore are a little more low-level than usual, since
 - * they are meant to be called by functions that manage the sleeping of a
 - * kthread.  For instance, __down_sem() always returns right away.  For now,
 - * these are just examples, since the actual usage will probably need lower
 - * access. */
 -
 -/* Down : decrement, if it was 0 or less, we need to sleep.  Returns false if
 - * the kthread did not need to sleep (the signal was already there). */
 -static inline bool __down_sem(struct semaphore *sem, struct kthread *kthread)
 -{
 -      bool retval = FALSE;
 -      spin_lock(&sem->lock);
 -      if (sem->nr_signals-- <= 0 && kthread != NULL) {
 -              /* Need to sleep */
 -              retval = TRUE;
 -              TAILQ_INSERT_TAIL(&sem->waiters, kthread, link);
 -      }
 -      spin_unlock(&sem->lock);
 -      return retval;
 -}
 -
 -/* Ups the semaphore.  If it was < 0, we need to wake up someone, which is the
 - * return value.  If you think there should be at most one, set exactly_one. */
 -static inline struct kthread *__up_sem(struct semaphore *sem, bool exactly_one)
 -{
 -      struct kthread *kthread = 0;
 -      spin_lock(&sem->lock);
 -      if (sem->nr_signals++ < 0) {
 -              /* could do something with 'priority' here */
 -              kthread = TAILQ_FIRST(&sem->waiters);
 -              if (kthread == NULL) warn ("kthread is null\n");
 -              TAILQ_REMOVE(&sem->waiters, kthread, link);
 -              if (exactly_one)
 -                      assert(TAILQ_EMPTY(&sem->waiters));
 -      } else {
 -              assert(TAILQ_EMPTY(&sem->waiters));
 -      }
 -      spin_unlock(&sem->lock);
 -      return kthread;
 -}
 +struct cond_var {
 +      struct semaphore                        sem;
 +      spinlock_t                                      lock;
 +      unsigned long                           nr_waiters;
 +      bool                                            irq_okay;
 +};
 +
++/* TODO: consider building this into struct semaphore */
+ struct semaphore_entry {
+       struct semaphore sem;
+       int fd;
+       LIST_ENTRY(semaphore_entry) link;
+ };
  void kthread_init(void);
 -void sleep_on(struct semaphore *sem);
  void restart_kthread(struct kthread *kthread);
  void kthread_runnable(struct kthread *kthread);
 -/* Kmsg handler to launch/run a kthread.  This must be a routine message, since
 - * it does not return. */
 -void __launch_kthread(struct trapframe *tf, uint32_t srcid, long a0, long a1,
 -                        long a2);
 +void kthread_yield(void);
 +
 +void sem_init(struct semaphore *sem, int signals);
 +void sem_init_irqsave(struct semaphore *sem, int signals);
 +void sem_down(struct semaphore *sem);
 +bool sem_up(struct semaphore *sem);
 +void sem_down_irqsave(struct semaphore *sem, int8_t *irq_state);
 +bool sem_up_irqsave(struct semaphore *sem, int8_t *irq_state);
 +
 +void cv_init(struct cond_var *cv);
 +void cv_init_irqsave(struct cond_var *cv);
 +void cv_lock(struct cond_var *cv);
 +void cv_unlock(struct cond_var *cv);
 +void cv_lock_irqsave(struct cond_var *cv, int8_t *irq_state);
 +void cv_unlock_irqsave(struct cond_var *cv, int8_t *irq_state);
 +void cv_wait_and_unlock(struct cond_var *cv); /* does not mess with irqs */
 +void cv_wait(struct cond_var *cv);
 +void __cv_signal(struct cond_var *cv);
 +void __cv_broadcast(struct cond_var *cv);
 +void cv_signal(struct cond_var *cv);
 +void cv_broadcast(struct cond_var *cv);
 +void cv_signal_irqsave(struct cond_var *cv, int8_t *irq_state);
 +void cv_broadcast_irqsave(struct cond_var *cv, int8_t *irq_state);
  
  #endif /* ROS_KERN_KTHREAD_H */
@@@ -20,7 -20,7 +20,7 @@@
  #define SYS_change_vcore                      14
  #define SYS_fork                                      15
  #define SYS_exec                                      16
 -#define SYS_trywait                                   17
 +#define SYS_waitpid                                   17
  #define SYS_mmap                                      18
  #define SYS_munmap                                    19
  #define SYS_mprotect                          20
@@@ -33,7 -33,7 +33,7 @@@
  /* sys_brk removed */
  #define SYS_shared_page_alloc         22
  #define SYS_shared_page_free          23
 -/* sys_resource_req removed */
 +#define SYS_provision                         24
  #define SYS_notify                                    25
  #define SYS_self_notify                               26
  #define SYS_halt_core                         27
  #define SYS_change_to_m                               29
  #define SYS_poke_ksched                               30
  
+ /* Socket Syscalls */
+ #define SYS_socket                                    40
+ #define SYS_sendto                                    41
+ #define SYS_recvfrom                          42
+ #define SYS_select          43
+ #define SYS_connect                             44
+ #define SYS_send                                              45
+ #define SYS_recv                                              46
+ #define SYS_bind                                              47
+ #define SYS_accept                                    48
+ #define SYS_listen                              49
  /* Platform specific syscalls */
  #define SYS_serial_read                               75
  #define SYS_serial_write                      76
@@@ -61,7 -73,7 +73,7 @@@
  #define SYS_access                            108
  #define SYS_umask                             109
  #define SYS_chmod                             110
 -#define SYS_lseek                             111
 +#define SYS_llseek                            111
  #define SYS_link                              112
  #define SYS_unlink                            113
  #define SYS_symlink                           114
@@@ -47,6 -47,7 +47,7 @@@ typedef size_t uintreg_t
  })
  #endif
  
+ #define ROS_MEM_ALIGN 4
  // Rounding operations (efficient when n is a power of 2)
  // Round down to the nearest multiple of n
  #define ROUNDDOWN(a, n)                                               \
@@@ -61,6 -62,8 +62,8 @@@
        (typeof(a)) (ROUNDDOWN((uintptr_t) (a) + __n - 1, __n));        \
  })
  
+ #define MEM_ALIGN_SIZE(size) ROUNDUP(size, ROS_MEM_ALIGN)
  // Round down to the nearest multiple of n
  #define PTRROUNDDOWN(a, n)                                            \
  ({                                                            \
@@@ -119,47 -122,4 +122,47 @@@ static inline bool mult_will_overflow_u
  // a uint64_t programatically
  #define UINT64(upper, lower) ( (((uint64_t)(upper)) << 32) | (lower) )
  
 +/* Makes sure func is run exactly once.  Can handle concurrent callers, and
 + * other callers spin til the func is complete. */
 +#define run_once(func)                                                         \
 +{                                                                              \
 +      static bool ran_once = FALSE;                                              \
 +      static atomic_t is_running = FALSE;                                        \
 +      if (!ran_once) {                                                           \
 +              if (!atomic_swap(&is_running, TRUE)) {                                 \
 +                      /* we won the race and get to run the func */                      \
 +                      func;                                                              \
 +                      wmb();  /* don't let the ran_once write pass previous writes */    \
 +                      ran_once = TRUE;                                                   \
 +              } else {                                                               \
 +                      /* someone else won, wait til they are done to break out */        \
 +                      while (!ran_once)                                                  \
 +                              cpu_relax();                                                   \
 +                                                                               \
 +              }                                                                      \
 +      }                                                                          \
 +}
 +
 +/* Unprotected, single-threaded version, makes sure func is run exactly once */
 +#define run_once_racy(func)                                                    \
 +{                                                                              \
 +      static bool ran_once = FALSE;                                              \
 +      if (!ran_once) {                                                           \
 +              func;                                                                  \
 +              ran_once = TRUE;                                                       \
 +      }                                                                          \
 +}
 +
 +/* Aborts with 'retcmd' if this function has already been called.  Compared to
 + * run_once, this is put at the top of a function that can be called from
 + * multiple sources but should only execute once. */
 +#define init_once_racy(retcmd)                                                 \
 +{                                                                              \
 +      static bool initialized = FALSE;                                           \
 +      if (initialized) {                                                         \
 +              retcmd;                                                                \
 +      }                                                                          \
 +      initialized = TRUE;                                                        \
 +}
 +
  #endif /* ROS_COMMON_H */
diff --combined kern/include/time.h
@@@ -17,7 -17,11 +17,12 @@@ struct itimerspec 
    struct timespec  it_value;     /* Timer expiration */
  };
  
 -      time_t tv_sec;          /* seconds */
+ struct timeval {
++      time_t tv_sec;  /* seconds */
+       time_t tv_usec; /* microseconds */
+ };
 +void train_timing();
  void udelay(uint64_t usec);
  uint64_t tsc2sec(uint64_t tsc_time);
  uint64_t tsc2msec(uint64_t tsc_time);
@@@ -28,61 -32,4 +33,61 @@@ uint64_t msec2tsc(uint64_t msec)
  uint64_t usec2tsc(uint64_t usec);
  uint64_t nsec2tsc(uint64_t nsec);
  
 +/* Just takes a time measurement.  Meant to be paired with stop_timing.  Use
 + * this if you don't want to muck with overheads or subtraction. */
 +static inline __attribute__((always_inline))
 +uint64_t start_timing(void)
 +{
 +    return read_tsc_serialized();
 +}
 +
 +/* Takes a time measurement and subtracts the start time and timing overhead,
 + * to return the detected elapsed time.  Use this if you don't want to muck
 + * with overheads or subtraction. */
 +static inline __attribute__((always_inline))
 +uint64_t stop_timing(uint64_t start_time)
 +{
 +    uint64_t diff = read_tsc_serialized();
 +    diff -= start_time;
 +    diff -= system_timing.timing_overhead;
 +      if ((int64_t) diff < 0) {
 +              return 1;
 +      }
 +      return diff;
 +}
 +
 +/* Ancient measurement crap below.  TODO: use or lose it */
 +
 +#if 0
 +#include <pool.h>
 +#include <string.h>
 +
 +#define TIMER_TAG_SIZE 20
 +#define MAX_TIMERS 20
 +/* timer_t
 + * This struct is used to keep track of counter values as they are spread
 + * throughput code and timing measurements are made calling TAGGED_TIMING_BEGIN
 + * and TAGGED_TIMING_END
 + */
 +typedef struct Timer{
 +      uint64_t curr_run;
 +      uint64_t aggr_run;
 +      char label[TIMER_TAG_SIZE];
 +} timer_t;
 +
 +#define TAGGED_TIMING_BEGIN(tag)                    \
 +      static timer_t* _timer_##tag = NULL;            \
 +      if (_timer_##tag == NULL) {                     \
 +              _timer_##tag = POOL_GET(&timer_pool);       \
 +              strcpy((_timer_##tag->label), #tag);        \
 +              _timer_##tag->aggr_run = 0;                 \
 +      }                                               \
 +      _timer_##tag->curr_run = start_timing();
 +#define TAGGED_TIMING_END(tag)                                              \
 +({                                                                          \
 +      _timer_##tag->curr_run = stop_timing(_timer_##tag->curr_run);           \
 +      _timer_##tag->aggr_run += _timer_##tag->curr_run;                       \
 +})
 +
 +#endif
  #endif /* ROS_KERN_TIME_H */
diff --combined kern/include/vfs.h
@@@ -15,6 -15,7 +15,7 @@@
  
  #include <ros/common.h>
  #include <sys/queue.h>
+ #include <sys/uio.h>
  #include <bitmask.h>
  #include <kref.h>
  #include <time.h>
@@@ -31,7 -32,6 +32,6 @@@ struct vm_region
  typedef int dev_t;
  typedef int kdev_t;
  typedef int ino_t;
- typedef long off_t; // out there in other .h's, but not in the kernel yet
  struct io_writeback   {int x;};
  struct event_poll {int x;};
  struct poll_table_struct {int x;};
@@@ -50,11 -50,6 +50,6 @@@ struct file_operations
  struct fs_type;
  struct vfsmount;
  
- struct iovec {
-     void *iov_base;
-     size_t iov_len;
- };
  /* List def's we need */
  TAILQ_HEAD(sb_tailq, super_block);
  TAILQ_HEAD(dentry_tailq, dentry);
@@@ -276,13 -271,13 +271,13 @@@ struct file 
        struct kref                                     f_kref;
        unsigned int                            f_flags;                /* O_APPEND, etc */
        int                                                     f_mode;                 /* O_RDONLY, etc */
 -      off_t                                           f_pos;                  /* offset / file pointer */
 +      off64_t                                         f_pos;                  /* offset / file pointer */
        unsigned int                            f_uid;
        unsigned int                            f_gid;
        int                                                     f_error;
        struct event_poll_tailq         f_ep_links;
        spinlock_t                                      f_ep_lock;
-       void                                            *f_fs_info;             /* tty driver hook */
+       void                                            *f_privdata;    /* tty/socket driver hook */
        struct page_map                         *f_mapping;             /* page cache mapping */
  
        /* Ghetto appserver support */
  };
  
  struct file_operations {
 -      off_t (*llseek) (struct file *, off_t, int);
 -      ssize_t (*read) (struct file *, char *, size_t, off_t *);
 -      ssize_t (*write) (struct file *, const char *, size_t, off_t *);
 +      int (*llseek) (struct file *, off64_t, off64_t *, int);
 +      ssize_t (*read) (struct file *, char *, size_t, off64_t *);
 +      ssize_t (*write) (struct file *, const char *, size_t, off64_t *);
        int (*readdir) (struct file *, struct dirent *);
        int (*mmap) (struct file *, struct vm_region *);
        int (*open) (struct inode *, struct file *);
        int (*fsync) (struct file *, struct dentry *, int);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        ssize_t (*readv) (struct file *, const struct iovec *, unsigned long,
 -                        off_t *);
 +                        off64_t *);
        ssize_t (*writev) (struct file *, const struct iovec *, unsigned long,
 -                        off_t *);
 -      ssize_t (*sendpage) (struct file *, struct page *, int, size_t, off_t, int);
 +                        off64_t *);
 +      ssize_t (*sendpage) (struct file *, struct page *, int, size_t, off64_t,
 +                           int);
        int (*check_flags) (int flags);                         /* most FS's ignore this */
  };
  
@@@ -348,13 -342,22 +343,22 @@@ struct vfsmount 
   * could just use the fd_array to check for openness instead of the bitmask,
   * but eventually we might want to use the bitmasks for other things (like
   * which files are close_on_exec. */
- struct fd_set {
+ typedef struct fd_set {
      uint8_t fds_bits[BYTES_FOR_BITMASK(NR_FILE_DESC_MAX)];
- };
+ } fd_set;
  struct small_fd_set {
      uint8_t fds_bits[BYTES_FOR_BITMASK(NR_FILE_DESC_DEFAULT)];
  };
  
+ /* Helper macros to manage fd_sets */
+ #define FD_SET(n, p)  ((p)->fds_bits[(n)/8] |=  (1 << ((n) & 7)))
+ #define FD_CLR(n, p)  ((p)->fds_bits[(n)/8] &= ~(1 << ((n) & 7)))
+ #define FD_ISSET(n,p) ((p)->fds_bits[(n)/8] &   (1 << ((n) & 7)))
+ #define FD_ZERO(p)    memset((void*)(p),0,sizeof(*(p)))
  /* Describes an open file.  We need this, since the FD flags are supposed to be
   * per file descriptor, not per file (like the file status flags). */
  struct file_desc {
@@@ -374,7 -377,7 +378,7 @@@ struct files_struct 
        struct file_desc                        fd_array[NR_OPEN_FILES_DEFAULT];
  };
  
- /* Process specific filesysten info */
+ /* Process specific filesystem info */
  struct fs_struct {
        spinlock_t                                      lock;
        int                                                     umask;
@@@ -442,11 -445,12 +446,12 @@@ struct inode *icache_remove(struct supe
  
  /* File-ish functions */
  ssize_t generic_file_read(struct file *file, char *buf, size_t count,
 -                          off_t *offset);
 +                          off64_t *offset);
  ssize_t generic_file_write(struct file *file, const char *buf, size_t count,
 -                           off_t *offset);
 +                           off64_t *offset);
  ssize_t generic_dir_read(struct file *file, char *u_buf, size_t count,
 -                         off_t *offset);
 -struct file* alloc_file();
 +                         off64_t *offset);
++struct file *alloc_file(void);
  struct file *do_file_open(char *path, int flags, int mode);
  int do_symlink(char *path, const char *symname, int mode);
  int do_link(char *old_path, char *new_path);
diff --combined kern/src/Makefrag
@@@ -59,8 -59,16 +59,16 @@@ KERN_SRCFILES := $(KERN_ARCH_SRCFILES) 
                   $(KERN_SRC_DIR)/kdebug.c \
                   $(KERN_SRC_DIR)/ucq.c \
                   $(KERN_SRC_DIR)/console.c \
 -                 $(KERN_SRC_DIR)/arsc.c \
 +                 $(KERN_SRC_DIR)/trap.c \
+                  $(KERN_SRC_DIR)/socket.c \
 -                 $(KERN_SRC_DIR)/net/timers.c
 -
+                  $(KERN_SRC_DIR)/net/udp.c \
+                  $(KERN_SRC_DIR)/net/tcp.c \
+                  $(KERN_SRC_DIR)/net/ip.c \
+                  $(KERN_SRC_DIR)/net/pbuf.c \
+                  $(KERN_SRC_DIR)/net/tcp_out.c \
+                  $(KERN_SRC_DIR)/net/tcp_in.c \
++                 $(KERN_SRC_DIR)/net/timers.c \
 +                 $(KERN_SRC_DIR)/arsc.c
  
  # Only build files if they exist.
  KERN_SRCFILES := $(wildcard $(KERN_SRCFILES))
diff --combined kern/src/eth_audio.c
@@@ -71,8 -71,9 +71,9 @@@ static void eth_audio_sendpacket(void *
         * Eth-audio device shouldn't care (and Linux seems to be okay with packets
         * that have no checksum (but not a wrong checksum)).  Technically, this
         * hurts our performance a bit (and some NICs can offload this). */
-       eth_udp_out.udp_hdr.checksum = htons(udp_checksum(&eth_udp_out.ip_hdr,
-                                                         &eth_udp_out.udp_hdr));
+       eth_udp_out.udp_hdr.checksum = 0;
+       eth_udp_out.udp_hdr.checksum = udp_checksum(&eth_udp_out.ip_hdr,
+                                                         &eth_udp_out.udp_hdr);
        /* Send it out */
        retval = send_frame((const char*)&eth_udp_out, ETH_AUDIO_FRAME_SZ);
        assert(retval >= 0);
@@@ -100,7 -101,8 +101,8 @@@ static void eth_audio_prep_response(str
        outgoing->ip_hdr.src_addr = htonl(ntohl(incoming->ip_hdr.src_addr) + 1);
        outgoing->ip_hdr.dst_addr = incoming->ip_hdr.src_addr;
        /* Since the IP header is set already, we can compute the checksum. */
-       outgoing->ip_hdr.checksum = htons(ip_checksum(&outgoing->ip_hdr));
+       outgoing->ip_hdr.checksum = 0;
 -      outgoing->ip_hdr.checksum = (ip_checksum(&outgoing->ip_hdr);
++      outgoing->ip_hdr.checksum = ip_checksum(&outgoing->ip_hdr);
        outgoing->udp_hdr.src_port = htons(ETH_AUDIO_SRC_PORT);
        outgoing->udp_hdr.dst_port = htons(ETH_AUDIO_DST_PORT);
        outgoing->udp_hdr.length = htons(ETH_AUDIO_PAYLOAD_SZ + UDP_HDR_SZ);
diff --combined kern/src/init.c
@@@ -8,13 -8,13 +8,13 @@@
  #error "Yeah, it's not possible to build ROS with BSD on Core 0, sorry......"
  #else
  
 -#include <ros/time.h>
  #include <arch/arch.h>
  #include <arch/console.h>
  #include <multiboot.h>
  #include <stab.h>
  #include <smp.h>
  
 +#include <time.h>
  #include <atomic.h>
  #include <stdio.h>
  #include <string.h>
@@@ -43,6 -43,7 +43,7 @@@
  #include <ext2fs.h>
  #include <kthread.h>
  #include <net.h>
+ #include <socket.h>
  #include <eth_audio.h>
  #include <console.h>
  
@@@ -100,6 -101,7 +101,7 @@@ void kernel_init(multiboot_info_t *mboo
        arch_init();
        block_init();
        enable_irq();
+       socket_init();
  #ifdef __CONFIG_EXT2FS__
        mount_fs(&ext2_fs_type, "/dev/ramdisk", "/mnt", 0);
  #endif /* __CONFIG_EXT2FS__ */
  void _panic(const char *file, int line, const char *fmt,...)
  {
        va_list ap;
 +      struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
  
 +      /* We're panicing, possibly in a place that can't handle the lock checker */
 +      pcpui->__lock_depth_disabled++;
        va_start(ap, fmt);
        cprintf("kernel panic at %s:%d, from core %d: ", file, line, core_id());
        vcprintf(fmt, ap);
  
  dead:
        monitor(NULL);
 +      /* We could consider turning the lock checker back on here, but things are
 +       * probably a mess anyways, and with it on we would probably lock up right
 +       * away when we idle. */
 +      //pcpui->__lock_depth_disabled--;
        smp_idle();
  }
  
diff --combined kern/src/net/tcp.c
index 0000000,6035661..bc3ce94
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1628 +1,1616 @@@
 -static void wrap_restart_kthread(struct trapframe *tf, uint32_t srcid,
 -                                      long a0, long a1, long a2){
 -      restart_kthread((struct kthread*) a0);
 -}
 -
+ /**
+  * @file
+  * Transmission Control Protocol for IP
+  *
+  * This file contains common functions for the TCP implementation, such as functinos
+  * for manipulating the data structures and the TCP timer functions. TCP functions
+  * related to input and output is found in tcp_in.c and tcp_out.c respectively.
+  *
+  */
+ /*
+  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
+  * All rights reserved. 
+  * 
+  * Redistribution and use in source and binary forms, with or without modification, 
+  * are permitted provided that the following conditions are met:
+  *
+  * 1. Redistributions of source code must retain the above copyright notice,
+  *    this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright notice,
+  *    this list of conditions and the following disclaimer in the documentation
+  *    and/or other materials provided with the distribution.
+  * 3. The name of the author may not be used to endorse or promote products
+  *    derived from this software without specific prior written permission. 
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
+  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
+  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
+  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
+  * OF SUCH DAMAGE.
+  *
+  * This file is part of the lwIP TCP/IP stack.
+  * 
+  * Author: Adam Dunkels <adam@sics.se>
+  * Modified by David Zhu <yuzhu@cs.berkeley.edu> to be used for Akaros
+  *
+  */
+ #include <ros/common.h>
+ #include <string.h>
+ #include <kmalloc.h>
+ #include <net.h>
+ #include <sys/queue.h>
+ #include <atomic.h>
+ #include <bits/netinet.h>
+ #include <net/ip.h>
+ #include <net/tcp.h>
+ #include <net/tcp_impl.h>
+ #include <slab.h>
+ #include <socket.h>
+ #include <string.h>
+ #include <debug.h>
+ /* String array used to display different TCP states */
+ const char * const tcp_state_str[] = {
+   "CLOSED",      
+   "LISTEN",      
+   "SYN_SENT",    
+   "SYN_RCVD",    
+   "ESTABLISHED", 
+   "FIN_WAIT_1",  
+   "FIN_WAIT_2",  
+   "CLOSE_WAIT",  
+   "CLOSING",     
+   "LAST_ACK",    
+   "TIME_WAIT"   
+ };
+ const uint8_t tcp_backoff[13] =
+     { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
+  /* Times per slowtmr hits */
+ const uint8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };
+ struct tcp_pcb *tcp_pcbs;
+ /** List of all TCP PCBs bound but not yet (connected || listening) */
+ struct tcp_pcb *tcp_bound_pcbs;
+ /** List of all TCP PCBs in LISTEN state */
+ union tcp_listen_pcbs_t tcp_listen_pcbs;
+ /** List of all TCP PCBs that are in a state in which
+  * they accept or send data. */
+ struct tcp_pcb *tcp_active_pcbs;
+ /** List of all TCP PCBs in TIME-WAIT state */
+ struct tcp_pcb *tcp_tw_pcbs;
+ #define NUM_TCP_PCB_LISTS               4
+ #define NUM_TCP_PCB_LISTS_NO_TIME_WAIT  3
+ /** An array with all (non-temporary) PCB lists, mainly used for smaller code size */
+ struct tcp_pcb **tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs,
+   &tcp_active_pcbs, &tcp_tw_pcbs};
+ /** Timer counter to handle calling slow-timer from tcp_tmr() */ 
+ static uint8_t tcp_timer;
+ static uint16_t tcp_new_port(void);
+ /** Only used for temporary storage. */
+ struct tcp_pcb *tcp_tmp_pcb;
+ /* Incremented every coarse grained timer shot (typically every 500 ms). */
+ uint32_t tcp_ticks;
+ uint16_t tcp_port_num = SOCKET_PORT_START;
+ static uint16_t tcp_new_port(void);
+ /**
+  * Abandons a connection and optionally sends a RST to the remote
+  * host.  Deletes the local protocol control block. This is done when
+  * a connection is killed because of shortage of memory.
+  *
+  * @param pcb the tcp_pcb to abort
+  * @param reset boolean to indicate whether a reset should be sent
+  */
+ void
+ tcp_abandon(struct tcp_pcb *pcb, int reset)
+ {
+   uint32_t seqno, ackno;
+   uint16_t remote_port, local_port;
+   ip_addr_t remote_ip, local_ip;
+ #if LWIP_CALLBACK_API  
+   tcp_err_fn errf;
+ #endif /* LWIP_CALLBACK_API */
+   void *errf_arg;
+   /* pcb->state LISTEN not allowed here */
+   LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs",
+     pcb->state != LISTEN);
+   /* Figure out on which TCP PCB list we are, and remove us. If we
+      are in an active state, call the receive function associated with
+      the PCB with a NULL argument, and send an RST to the remote end. */
+   if (pcb->state == TIME_WAIT) {
+     tcp_pcb_remove(&tcp_tw_pcbs, pcb);
+               kmem_cache_free(tcp_pcb_kcache, (void*)pcb);
+   } else {
+     seqno = pcb->snd_nxt;
+     ackno = pcb->rcv_nxt;
+     ip_addr_copy(local_ip, pcb->local_ip);
+     ip_addr_copy(remote_ip, pcb->remote_ip);
+     local_port = pcb->local_port;
+     remote_port = pcb->remote_port;
+ #if LWIP_CALLBACK_API
+     errf = pcb->errf;
+ #endif /* LWIP_CALLBACK_API */
+     errf_arg = pcb->callback_arg;
+     tcp_pcb_remove(&tcp_active_pcbs, pcb);
+     if (pcb->unacked != NULL) {
+       tcp_segs_free(pcb->unacked);
+     }
+     if (pcb->unsent != NULL) {
+       tcp_segs_free(pcb->unsent);
+     }
+ #if TCP_QUEUE_OOSEQ    
+     if (pcb->ooseq != NULL) {
+       tcp_segs_free(pcb->ooseq);
+     }
+ #endif /* TCP_QUEUE_OOSEQ */
+               kmem_cache_free(tcp_pcb_kcache, (void*)pcb);
+     TCP_EVENT_ERR(errf, errf_arg, ECONNABORTED);
+     if (reset) {
+       LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n"));
+       tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);
+     }
+   }
+ }
+ /**
+  * Aborts the connection by sending a RST (reset) segment to the remote
+  * host. The pcb is deallocated. This function never fails.
+  *
+  * ATTENTION: When calling this from one of the TCP callbacks, make
+  * sure you always return ECONNABORTED (and never return ECONNABORTED otherwise
+  * or you will risk accessing deallocated memory or memory leaks!
+  *
+  * @param pcb the tcp pcb to abort
+  */
+ void
+ tcp_abort(struct tcp_pcb *pcb)
+ {
+   tcp_abandon(pcb, 1);
+ }
+ /** 
+  * Update the state that tracks the available window space to advertise.
+  *
+  * Returns how much extra window would be advertised if we sent an
+  * update now.
+  */
+ uint32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)
+ {
+   uint32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd;
+   if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + MIN((TCP_WND / 2), pcb->mss))) {
+     /* we can advertise more window */
+     pcb->rcv_ann_wnd = pcb->rcv_wnd;
+     return new_right_edge - pcb->rcv_ann_right_edge;
+   } else {
+     if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) {
+       /* Can happen due to other end sending out of advertised window,
+        * but within actual available (but not yet advertised) window */
+       pcb->rcv_ann_wnd = 0;
+     } else {
+       /* keep the right edge of window constant */
+       uint32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
+       pcb->rcv_ann_wnd = (uint16_t)new_rcv_ann_wnd;
+     }
+     return 0;
+   }
+ }
+ /**
+  * Kills the oldest connection that is in TIME_WAIT state.
+  * Called from tcp_alloc() if no more connections are available.
+  */
+ static void
+ tcp_kill_timewait(void)
+ {
+   struct tcp_pcb *pcb, *inactive;
+   uint32_t inactivity;
+   inactivity = 0;
+   inactive = NULL;
+   /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */
+   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
+     if ((uint32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
+       inactivity = tcp_ticks - pcb->tmr;
+       inactive = pcb;
+     }
+   }
+   if (inactive != NULL) {
+     LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",
+            (void *)inactive, inactivity));
+     tcp_abort(inactive);
+   }
+ }
+ /**
+  * Kills the oldest active connection that has lower priority than prio.
+  *
+  * @param prio minimum priority
+  */
+ static void
+ tcp_kill_prio(uint8_t prio)
+ {
+   struct tcp_pcb *pcb, *inactive;
+   uint32_t inactivity;
+   uint8_t mprio;
+   mprio = TCP_PRIO_MAX;
+   
+   /* We kill the oldest active connection that has lower priority than prio. */
+   inactivity = 0;
+   inactive = NULL;
+   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
+     if (pcb->prio <= prio &&
+        pcb->prio <= mprio &&
+        (uint32_t)(tcp_ticks - pcb->tmr) >= inactivity) {
+       inactivity = tcp_ticks - pcb->tmr;
+       inactive = pcb;
+       mprio = pcb->prio;
+     }
+   }
+   if (inactive != NULL) {
+     LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",
+            (void *)inactive, inactivity));
+     tcp_abort(inactive);
+   }
+ }
+ /**
+  * This function should be called by the application when it has
+  * processed the data. The purpose is to advertise a larger window
+  * when the data has been processed.
+  *
+  * @param pcb the tcp_pcb for which data is read
+  * @param len the amount of bytes that have been read by the application
+  */
+ void
+ tcp_recved(struct tcp_pcb *pcb, uint16_t len)
+ {
+   int wnd_inflation;
+   check(len <= 0xffff - pcb->rcv_wnd);
+   pcb->rcv_wnd += len;
+   if (pcb->rcv_wnd > TCP_WND) {
+     pcb->rcv_wnd = TCP_WND;
+   }
+   wnd_inflation = tcp_update_rcv_ann_wnd(pcb);
+   /* If the change in the right edge of window is significant (default
+    * watermark is TCP_WND/4), then send an explicit update now.
+    * Otherwise wait for a packet to be sent in the normal course of
+    * events (or more window to be available later) */
+   if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) {
+     tcp_ack_now(pcb);
+     //XXX: tcp_output(pcb);
+   }
+   printk("tcp_recved: received %d  bytes, wnd %d (%d).\n",
+          len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd);
+ }
 -              kthread = __up_sem(&(sock->sem), FALSE);
 -              if (kthread) {
 -                       send_kernel_message(core_id(), (amr_t)wrap_restart_kthread, (long)kthread, 0, 0,
 -                                                                                                KMSG_ROUTINE);
 -              } else {
+ /**
+  * Default receive callback that is called if the user didn't register
+  * a recv callback for the pcb.
+  */
+ error_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, error_t err) {
++      int8_t irq_state = 0;
+       if (pcb == NULL || pcb->pcbsock == NULL) {
+               pbuf_free(p);
+               return -1;
+       }
+   if (p != NULL && pcb != NULL) {
+               // notify that we have recved and increase the recv window
+               // attach it to socket
+               struct socket *sock = pcb->pcbsock;
+               // TODO: attach_pbuf needs to return stuff that can not fit in the buffer right now
+               attach_pbuf(p, &sock->recv_buff);
+               struct kthread *kthread;
+               /* First notify any blocking recv calls,
+                * then notify anyone who might be waiting in a select
+                */ 
+               // multiple people might be waiting on the socket here..
 -                LIST_FOREACH_SAFE(sentry, &(sock->waiters), link, sentry_tmp){
 -                              //should only wake up one waiter
 -                              kthread = __up_sem(&sentry->sem, true);
 -                              if (kthread){
 -                              send_kernel_message(core_id(), (amr_t)wrap_restart_kthread, (long)kthread, 0, 0,
 -                                                                                                KMSG_ROUTINE);
 -                              }
++              if (!sem_up_irqsave(&sock->sem, &irq_state)) {
+                       // wake up all waiters
+                       struct semaphore_entry *sentry, *sentry_tmp;
+                       spin_lock(&sock->waiter_lock);
 -                              /* do not need to free since all the sentry are stack-based vars */
++                      LIST_FOREACH_SAFE(sentry, &sock->waiters, link, sentry_tmp) {
++                              sem_up_irqsave(&sentry->sem, &irq_state);
+                               LIST_REMOVE(sentry, link);
++                              /* do not need to free since all the sentry are stack-based vars
++                               * */
+                       }
+                       spin_unlock(&sock->waiter_lock);
+               }
+       }
+       printk ("received total length tcp %d\n", p->tot_len);
+       tcp_recved(pcb, p->tot_len);
+       // decref
+       pbuf_free(p);
+   return ESUCCESS;
+ }
+ /**
+  * Creates a new TCP protocol control block but doesn't place it on
+  * any of the TCP PCB lists.
+  * The pcb is not put on any list until binding using tcp_bind().
+  *
+  * @internal: Maybe there should be a idle TCP PCB list where these
+  * PCBs are put on. Port reservation using tcp_bind() is implemented but
+  * allocated pcbs that are not bound can't be killed automatically if wanting
+  * to allocate a pcb with higher prio (@see tcp_kill_prio())
+  *
+  * @return a new tcp_pcb that initially is in state CLOSED
+  */
+ struct tcp_pcb* tcp_new(void) {
+   return tcp_alloc(TCP_PRIO_NORMAL);
+ }
+ /**
+  * Calculates a new initial sequence number for new connections.
+  * TODO: Consider use a secure pseduo ISN
+  *
+  * @return uint32_t pseudo random sequence number
+  */
+ uint32_t tcp_next_iss(void)
+ {
+   static uint32_t iss = 6510;
+   
+   iss += tcp_ticks;       /* XXX */
+   return iss;
+ }
+ /**
+  * Allocate a new tcp_pcb structure.
+  *
+  * @param prio priority for the new pcb
+  * @return a new tcp_pcb that initially is in state CLOSED
+  */
+ struct tcp_pcb* tcp_alloc(uint8_t prio) {
+   struct tcp_pcb *pcb;
+   uint32_t iss;
+   pcb = kmem_cache_alloc(tcp_pcb_kcache, 0);
+   if (pcb == NULL) {
+               /* Try killing oldest connection in TIME-WAIT. */
+               printd("tcp_alloc: killing off oldest TIME-WAIT connection\n");
+               tcp_kill_timewait();
+               /* Try to allocate a tcp_pcb again. */
+               pcb = (struct tcp_pcb *)kmem_cache_alloc(tcp_pcb_kcache, 0);
+               if (pcb == NULL) {
+                       /* Try killing active connections with lower priority than the new one. */
+                       printd("tcp_alloc: killing connection with prio lower than %d\n", prio);
+                       tcp_kill_prio(prio);
+                       /* Try to allocate a tcp_pcb again. */
+                       pcb = (struct tcp_pcb *)kmem_cache_alloc(tcp_pcb_kcache, 0);
+               }
+       }
+   if (pcb != NULL) {
+     memset(pcb, 0, sizeof(struct tcp_pcb));
+     pcb->prio = prio;
+     pcb->snd_buf = TCP_SND_BUF;
+     pcb->snd_queuelen = 0;
+     pcb->rcv_wnd = TCP_WND;
+     pcb->rcv_ann_wnd = TCP_WND;
+     pcb->tos = 0;
+     pcb->ttl = TCP_TTL;
+     /* As initial send MSS, we use TCP_MSS but limit it to 536.
+        The send MSS is updated when an MSS option is received. */
+     pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
+     pcb->rto = 3000 / TCP_SLOW_INTERVAL;
+     pcb->sa = 0;
+     pcb->sv = 3000 / TCP_SLOW_INTERVAL;
+     pcb->rtime = -1;
+     pcb->cwnd = 1;
+     iss = tcp_next_iss();
+     pcb->snd_wl2 = iss;
+     pcb->snd_nxt = iss;
+     pcb->lastack = iss;
+     pcb->snd_lbb = iss;   
+     pcb->tmr = tcp_ticks;
+     pcb->polltmr = 0;
+ /* Basically we need to use the callback api because then we can switch
+  * handlers based on the state that the pcb is in. 
+  */
+     pcb->recv = tcp_recv_null;
+     
+     /* Init KEEPALIVE timer */
+     pcb->keep_idle  = TCP_KEEPIDLE_DEFAULT;
+     
+ #if LWIP_TCP_KEEPALIVE
+     pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;
+     pcb->keep_cnt   = TCP_KEEPCNT_DEFAULT;
+ #endif /* LWIP_TCP_KEEPALIVE */
+     pcb->keep_cnt_sent = 0;
+   }
+   return pcb;
+ }
+ /**
+  * A nastly hack featuring 'goto' statements that allocates a
+  * new TCP local port.
+  *
+  * @return a new (free) local TCP port number
+  */
+ static uint16_t tcp_new_port(void) {
+   int i;
+   struct tcp_pcb *pcb;
+   static uint16_t port = TCP_LOCAL_PORT_RANGE_START;
+   
+  again:
+   if (++port > TCP_LOCAL_PORT_RANGE_END) {
+     port = TCP_LOCAL_PORT_RANGE_START;
+   }
+   /* Check all PCB lists. */
+   for (i = 0; i < NUM_TCP_PCB_LISTS; i++) {  
+     for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) {
+       if (pcb->local_port == port) {
+         goto again;
+       }
+     }
+   }
+   return port;
+ }
+ /**
+  * Binds the connection to a local portnumber and IP address. If the
+  * IP address is not given (i.e., ipaddr == NULL), the IP address of
+  * the outgoing network interface is used instead.
+  *
+  * @param pcb the tcp_pcb to bind (no check is done whether this pcb is
+  *        already bound!)
+  * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind
+  *        to any local address
+  * @param port the local port to bind to
+  * @return ERR_USE if the port is already in use
+  *         ESUCCESS if bound
+  */
+ error_t tcp_bind(struct tcp_pcb *pcb, const struct in_addr *ipaddr, uint16_t port) {
+   int i;
+   int max_pcb_list = NUM_TCP_PCB_LISTS;
+   struct tcp_pcb *cpcb;
+   LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return -EISCONN);
+ #if SO_REUSE
+   /* Unless the REUSEADDR flag is set,
+      we have to check the pcbs in TIME-WAIT state, also.
+      We do not dump TIME_WAIT pcb's; they can still be matched by incoming
+      packets using both local and remote IP addresses and ports to distinguish.
+    */
+   if ((pcb->so_options & SO_REUSEADDR) != 0) {
+     max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT;
+   }
+ #endif /* SO_REUSE */
+   if (port == 0) {
+     port = tcp_new_port();
+   }
+   /* Check if the address already is in use (on all lists) */
+   for (i = 0; i < max_pcb_list; i++) {
+     for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
+       if (cpcb->local_port == port) {
+ #if SO_REUSE
+         /* Omit checking for the same port if both pcbs have REUSEADDR set.
+            For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in
+            tcp_connect. */
+         if (((pcb->so_options & SO_REUSEADDR) == 0) ||
+           ((cpcb->so_options & SO_REUSEADDR) == 0))
+ #endif /* SO_REUSE */
+         {
+           if (ip_addr_isany(&(cpcb->local_ip)) ||
+               ip_addr_isany(ipaddr) ||
+               ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {
+             return EADDRINUSE;
+           }
+         }
+       }
+     }
+   }
+   if (!ip_addr_isany(ipaddr)) {
+     pcb->local_ip = *ipaddr;
+   }
+   pcb->local_port = port;
+   TCP_REG(&tcp_bound_pcbs, pcb);
+   LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));
+   return 0;
+ }
+ /**
+  * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously
+  * "refused" by upper layer (application) and sends delayed ACKs.
+  *
+  * Automatically called from tcp_tmr().
+  */
+ void tcp_fasttmr(void) {
+   struct tcp_pcb *pcb = tcp_active_pcbs;
+   while(pcb != NULL) {
+     struct tcp_pcb *next = pcb->next;
+     /* If there is data which was previously "refused" by upper layer */
+     if (pcb->refused_data != NULL) {
+       /* Notify again application with data previously received. */
+       error_t err;
+       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));
+       TCP_EVENT_RECV(pcb, pcb->refused_data, ESUCCESS, err);
+       if (err == ESUCCESS) {
+         pcb->refused_data = NULL;
+       } else if (err == ECONNABORTED) {
+         /* if err == ECONNABORTED, 'pcb' is already deallocated */
+         pcb = NULL;
+       }
+     }
+     /* send delayed ACKs */
+     if (pcb && (pcb->flags & TF_ACK_DELAY)) {
+       printd("tcp_fasttmr: delayed ACK\n");
+       tcp_ack_now(pcb);
+       // XXX: tcp_output(pcb);
+       pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
+     }
+     pcb = next;
+   }
+ }
+ /**
+  * Called periodically to dispatch TCP timers.
+  *
+  */
+ void tcp_tmr(void) {
+       /* Call tcp_fasttmr() every 250 ms */
+   tcp_fasttmr();
+   if (++tcp_timer & 1) {
+     /* Call tcp_tmr() every 500 ms, i.e., every other timer
+        tcp_tmr() is called. */
+     tcp_slowtmr();
+   }
+ }
+ /**
+  * Closes the TX side of a connection held by the PCB.
+  * For tcp_close(), a RST is sent if the application didn't receive all data
+  * (tcp_recved() not called for all data passed to recv callback).
+  *
+  * Listening pcbs are freed and may not be referenced any more.
+  * Connection pcbs are freed if not yet connected and may not be referenced
+  * any more. If a connection is established (at least SYN received or in
+  * a closing state), the connection is closed, and put in a closing state.
+  * The pcb is then automatically freed in tcp_slowtmr(). It is therefore
+  * unsafe to reference it.
+  *
+  * @param pcb the tcp_pcb to close
+  * @return ESUCCESS if connection has been closed
+  *         another error_t if closing failed and pcb is not freed
+  */
+ static error_t
+ tcp_close_shutdown(struct tcp_pcb *pcb, uint8_t rst_on_unacked_data)
+ {
+   error_t err;
+   if (rst_on_unacked_data && (pcb->state != LISTEN)) {
+     if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) {
+       /* Not all data received by application, send RST to tell the remote
+          side about this. */
+       LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED);
+       /* don't call tcp_abort here: we must not deallocate the pcb since
+          that might not be expected when calling tcp_close */
+       tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
+         pcb->local_port, pcb->remote_port);
+       tcp_pcb_purge(pcb);
+       /* TODO: to which state do we move now? */
+       /* move to TIME_WAIT since we close actively */
+       TCP_RMV(&tcp_active_pcbs, pcb);
+       pcb->state = TIME_WAIT;
+       TCP_REG(&tcp_tw_pcbs, pcb);
+       return ESUCCESS;
+     }
+   }
+   switch (pcb->state) {
+   case CLOSED:
+     /* Closing a pcb in the CLOSED state might seem erroneous,
+      * however, it is in this state once allocated and as yet unused
+      * and the user needs some way to free it should the need arise.
+      * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)
+      * or for a pcb that has been used and then entered the CLOSED state 
+      * is erroneous, but this should never happen as the pcb has in those cases
+      * been freed, and so any remaining handles are bogus. */
+     err = ESUCCESS;
+     TCP_RMV(&tcp_bound_pcbs, pcb);
+               kmem_cache_free(tcp_pcb_kcache, (void*)pcb);
+     pcb = NULL;
+     break;
+   case LISTEN:
+     err = ESUCCESS;
+     tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb);
+               kmem_cache_free(tcp_pcb_kcache, (void*)pcb);
+     pcb = NULL;
+     break;
+   case SYN_SENT:
+     err = ESUCCESS;
+     tcp_pcb_remove(&tcp_active_pcbs, pcb);
+               kmem_cache_free(tcp_pcb_kcache, (void*)pcb);
+     pcb = NULL;
+     break;
+   case SYN_RCVD:
+     err = tcp_send_fin(pcb);
+     if (err == ESUCCESS) {
+       pcb->state = FIN_WAIT_1;
+     }
+     break;
+   case ESTABLISHED:
+     err = tcp_send_fin(pcb);
+     if (err == ESUCCESS) {
+       pcb->state = FIN_WAIT_1;
+     }
+     break;
+   case CLOSE_WAIT:
+     err = tcp_send_fin(pcb);
+     if (err == ESUCCESS) {
+       pcb->state = LAST_ACK;
+     }
+     break;
+   default:
+     /* Has already been closed, do nothing. */
+     err = ESUCCESS;
+     pcb = NULL;
+     break;
+   }
+   if (pcb != NULL && err == ESUCCESS) {
+     /* To ensure all data has been sent when tcp_close returns, we have
+        to make sure tcp_output doesn't fail.
+        Since we don't really have to ensure all data has been sent when tcp_close
+        returns (unsent data is sent from tcp timer functions, also), we don't care
+        for the return value of tcp_output for now. */
+     /* @todo: When implementing SO_LINGER, this must be changed somehow:
+        If SOF_LINGER is set, the data should be sent and acked before close returns.
+        This can only be valid for sequential APIs, not for the raw API. */
+     tcp_output(pcb);
+   }
+   return err;
+ }
+ /**
+  * Closes the connection held by the PCB.
+  *
+  * Listening pcbs are freed and may not be referenced any more.
+  * Connection pcbs are freed if not yet connected and may not be referenced
+  * any more. If a connection is established (at least SYN received or in
+  * a closing state), the connection is closed, and put in a closing state.
+  * The pcb is then automatically freed in tcp_slowtmr(). It is therefore
+  * unsafe to reference it (unless an error is returned).
+  *
+  * @param pcb the tcp_pcb to close
+  * @return ESUCCESS if connection has been closed
+  *         another error_t if closing failed and pcb is not freed
+  */
+ error_t
+ tcp_close(struct tcp_pcb *pcb)
+ {
+ #if TCP_DEBUG
+   LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));
+   tcp_debug_print_state(pcb->state);
+ #endif /* TCP_DEBUG */
+   if (pcb->state != LISTEN) {
+     /* Set a flag not to receive any more data... */
+     pcb->flags |= TF_RXCLOSED;
+   }
+   /* ... and close */
+   return tcp_close_shutdown(pcb, 1);
+ }
+ /**
+  * Causes all or part of a full-duplex connection of this PCB to be shut down.
+  * This doesn't deallocate the PCB!
+  *
+  * @param pcb PCB to shutdown
+  * @param shut_rx shut down receive side if this is != 0
+  * @param shut_tx shut down send side if this is != 0
+  * @return ESUCCESS if shutdown succeeded (or the PCB has already been shut down)
+  *         another error_t on error.
+  */
+ error_t
+ tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx)
+ {
+   if (pcb->state == LISTEN) {
+     return ENOTCONN;
+   }
+   if (shut_rx) {
+     /* shut down the receive side: free buffered data... */
+     if (pcb->refused_data != NULL) {
+       pbuf_free(pcb->refused_data);
+       pcb->refused_data = NULL;
+     }
+     /* ... and set a flag not to receive any more data */
+     pcb->flags |= TF_RXCLOSED;
+   }
+   if (shut_tx) {
+     /* This can't happen twice since if it succeeds, the pcb's state is changed.
+        Only close in these states as the others directly deallocate the PCB */
+     switch (pcb->state) {
+   case SYN_RCVD:
+   case ESTABLISHED:
+   case CLOSE_WAIT:
+     return tcp_close_shutdown(pcb, 0);
+   default:
+     /* don't shut down other states */
+     break;
+     }
+   }
+   /* @todo: return another error_t if not in correct state or already shut? */
+   return ESUCCESS;
+ }
+ /**
+  * Default accept callback if no accept callback is specified by the user.
+  */
+ static error_t
+ tcp_accept_null(void *arg, struct tcp_pcb *pcb, error_t err)
+ {
+       //XXX: IMPLEMENT ACCEPT
+   return ECONNABORTED;
+ }
+ /**
+  * Set the state of the connection to be LISTEN, which means that it
+  * is able to accept incoming connections. The protocol control block
+  * is reallocated in order to consume less memory. Setting the
+  * connection to LISTEN is an irreversible process.
+  *
+  * @param pcb the original tcp_pcb
+  * @param backlog the incoming connections queue limit
+  * @return tcp_pcb used for listening, consumes less memory.
+  *
+  * @note The original tcp_pcb is freed. This function therefore has to be
+  *       called like this:
+  *             tpcb = tcp_listen(tpcb);
+  */
+ struct tcp_pcb *
+ tcp_listen_with_backlog(struct tcp_pcb *pcb, uint8_t backlog)
+ {
+   struct tcp_pcb_listen *lpcb;
+   LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);
+   /* already listening? */
+   if (pcb->state == LISTEN) {
+     return pcb;
+   }
+ #if SO_REUSE
+   if ((pcb->so_options & SO_REUSEADDR) != 0) {
+     /* Since SO_REUSEADDR allows reusing a local address before the pcb's usage
+        is declared (listen-/connection-pcb), we have to make sure now that
+        this port is only used once for every local IP. */
+     for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
+       if (lpcb->local_port == pcb->local_port) {
+         if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
+           /* this address/port is already used */
+           return NULL;
+         }
+       }
+     }
+   }
+ #endif /* SO_REUSE */
+       lpcb = kmem_cache_alloc(tcp_pcb_listen_kcache, 0);
+   if (lpcb == NULL) {
+     return NULL;
+   }
+   lpcb->callback_arg = pcb->callback_arg;
+   lpcb->local_port = pcb->local_port;
+   lpcb->state = LISTEN;
+   lpcb->prio = pcb->prio;
+   lpcb->so_options = pcb->so_options;
+   lpcb->so_options |= SO_ACCEPTCONN;
+   lpcb->ttl = pcb->ttl;
+   lpcb->tos = pcb->tos;
+   ip_addr_copy(lpcb->local_ip, pcb->local_ip);
+   TCP_RMV(&tcp_bound_pcbs, pcb);
+       kmem_cache_free(tcp_pcb_kcache, (void*)pcb);
+ #if LWIP_CALLBACK_API
+   lpcb->accept = tcp_accept_null;
+ #endif /* LWIP_CALLBACK_API */
+ #if TCP_LISTEN_BACKLOG
+   lpcb->accepts_pending = 0;
+   lpcb->backlog = (backlog ? backlog : 1);
+ #endif /* TCP_LISTEN_BACKLOG */
+   TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);
+   return (struct tcp_pcb *)lpcb;
+ }
+ /**
+  * Connects to another host. The function given as the "connected"
+  * argument will be called when the connection has been established.
+  *
+  * @param pcb the tcp_pcb used to establish the connection
+  * @param ipaddr the remote ip address to connect to
+  * @param port the remote tcp port to connect to
+  * @param connected callback function to call when connected (or on error)
+  * @return ERR_VAL if invalid arguments are given
+  *         ESUCCESS if connect request has been sent
+  *         other error_t values if connect request couldn't be sent
+  */
+ error_t
+ tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, uint16_t port,
+       tcp_connected_fn connected)
+ {
+   error_t ret;
+   uint32_t iss;
+   LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return EISCONN);
+   LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));
+   if (ipaddr != NULL) {
+     pcb->remote_ip = *ipaddr;
+   } else {
+     return ENETUNREACH;
+   }
+   pcb->remote_port = port;
+   /* check if we have a route to the remote host */
+   if (ip_addr_isany(&(pcb->local_ip))) {
+               // assume we have a route anywhere..
+     /* no local IP address set, yet. */
+     // struct netif *netif = ip_route(&(pcb->remote_ip));
+     /* Use the netif's IP address as local address. */
+               pcb->local_ip = LOCAL_IP_ADDR;
+   }
+   if (pcb->local_port == 0) {
+     pcb->local_port = tcp_new_port();
+   }
+ #if SO_REUSE
+   if ((pcb->so_options & SO_REUSEADDR) != 0) {
+     /* Since SO_REUSEADDR allows reusing a local address, we have to make sure
+        now that the 5-tuple is unique. */
+     struct tcp_pcb *cpcb;
+     int i;
+     /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */
+     for (i = 2; i < NUM_TCP_PCB_LISTS; i++) {
+       for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) {
+         if ((cpcb->local_port == pcb->local_port) &&
+             (cpcb->remote_port == port) &&
+             ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) &&
+             ip_addr_cmp(&cpcb->remote_ip, ipaddr)) {
+           /* linux returns EISCONN here, but ERR_USE should be OK for us */
+           return ERR_USE;
+         }
+       }
+     }
+   }
+ #endif /* SO_REUSE */
+   iss = tcp_next_iss();
+   pcb->rcv_nxt = 0;
+   pcb->snd_nxt = iss;
+   pcb->lastack = iss - 1;
+   pcb->snd_lbb = iss - 1;
+   pcb->rcv_wnd = TCP_WND;
+   pcb->rcv_ann_wnd = TCP_WND;
+   pcb->rcv_ann_right_edge = pcb->rcv_nxt;
+   pcb->snd_wnd = TCP_WND;
+   /* As initial send MSS, we use TCP_MSS but limit it to 536.
+      The send MSS is updated when an MSS option is received. */
+   pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;
+ #if TCP_CALCULATE_EFF_SEND_MSS 
+   pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);
+ #endif /* TCP_CALCULATE_EFF_SEND_MSS */
+   pcb->cwnd = 1;
+   pcb->ssthresh = pcb->mss * 10;
+ #if LWIP_CALLBACK_API
+   pcb->connected = connected;
+ #else /* LWIP_CALLBACK_API */  
+ #endif /* LWIP_CALLBACK_API */
+   /* Send a SYN together with the MSS option. */
+   ret = tcp_enqueue_flags(pcb, TCP_SYN);
+   if (ret == ESUCCESS) {
+     /* SYN segment was enqueued, changed the pcbs state now */
+     pcb->state = SYN_SENT;
+     TCP_RMV(&tcp_bound_pcbs, pcb);
+     TCP_REG(&tcp_active_pcbs, pcb);
+     //snmp_inc_tcpactiveopens();
+     tcp_output(pcb);
+   }
+   return ret;
+ }
+ /**
+  * Called every 500 ms and implements the retransmission timer and the timer that
+  * removes PCBs that have been in TIME-WAIT for enough time. It also increments
+  * various timers such as the inactivity timer in each PCB.
+  *
+  * Automatically called from tcp_tmr().
+  */
+ void
+ tcp_slowtmr(void)
+ {
+   struct tcp_pcb *pcb, *prev;
+   uint16_t eff_wnd;
+   uint8_t pcb_remove;      /* flag if a PCB should be removed */
+   uint8_t pcb_reset;       /* flag if a RST should be sent when removing */
+   error_t err;
+   err = ESUCCESS;
+   ++tcp_ticks;
+   /* Steps through all of the active PCBs. */
+   prev = NULL;
+   pcb = tcp_active_pcbs;
+   if (pcb == NULL) {
+     LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));
+   }
+   while (pcb != NULL) {
+     LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));
+     LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);
+     LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);
+     LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);
+     pcb_remove = 0;
+     pcb_reset = 0;
+     if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {
+       ++pcb_remove;
+       LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));
+     }
+     else if (pcb->nrtx == TCP_MAXRTX) {
+       ++pcb_remove;
+       LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
+     } else {
+       if (pcb->persist_backoff > 0) {
+         /* If snd_wnd is zero, use persist timer to send 1 byte probes
+          * instead of using the standard retransmission mechanism. */
+         pcb->persist_cnt++;
+         if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {
+           pcb->persist_cnt = 0;
+           if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {
+             pcb->persist_backoff++;
+           }
+           tcp_zero_window_probe(pcb);
+         }
+       } else {
+         /* Increase the retransmission timer if it is running */
+         if(pcb->rtime >= 0)
+           ++pcb->rtime;
+         if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
+           /* Time for a retransmission. */
+           LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F
+                                       " pcb->rto %"S16_F"\n",
+                                       pcb->rtime, pcb->rto));
+           /* Double retransmission time-out unless we are trying to
+            * connect to somebody (i.e., we are in SYN_SENT). */
+           if (pcb->state != SYN_SENT) {
+             pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];
+           }
+           /* Reset the retransmission timer. */
+           pcb->rtime = 0;
+           /* Reduce congestion window and ssthresh. */
+           eff_wnd = MIN(pcb->cwnd, pcb->snd_wnd);
+           pcb->ssthresh = eff_wnd >> 1;
+           if (pcb->ssthresh < (pcb->mss << 1)) {
+             pcb->ssthresh = (pcb->mss << 1);
+           }
+           pcb->cwnd = pcb->mss;
+           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F
+                                        " ssthresh %"U16_F"\n",
+                                        pcb->cwnd, pcb->ssthresh));
+  
+           /* The following needs to be called AFTER cwnd is set to one
+              mss - STJ */
+           tcp_rexmit_rto(pcb);
+         }
+       }
+     }
+     /* Check if this PCB has stayed too long in FIN-WAIT-2 */
+     if (pcb->state == FIN_WAIT_2) {
+       if ((uint32_t)(tcp_ticks - pcb->tmr) >
+           TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {
+         ++pcb_remove;
+         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));
+       }
+     }
+     /* Check if KEEPALIVE should be sent */
+     if((pcb->so_options & SO_KEEPALIVE) &&
+        ((pcb->state == ESTABLISHED) ||
+         (pcb->state == CLOSE_WAIT))) {
+ #if LWIP_TCP_KEEPALIVE
+       if((uint32_t)(tcp_ticks - pcb->tmr) >
+          (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))
+          / TCP_SLOW_INTERVAL)
+ #else      
+       if((uint32_t)(tcp_ticks - pcb->tmr) >
+          (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)
+ #endif /* LWIP_TCP_KEEPALIVE */
+       {
+         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",
+                                 ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip),
+                                 ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip)));
+         
+         ++pcb_remove;
+         ++pcb_reset;
+       }
+ #if LWIP_TCP_KEEPALIVE
+       else if((uint32_t)(tcp_ticks - pcb->tmr) > 
+               (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)
+               / TCP_SLOW_INTERVAL)
+ #else
+       else if((uint32_t)(tcp_ticks - pcb->tmr) > 
+               (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT) 
+               / TCP_SLOW_INTERVAL)
+ #endif /* LWIP_TCP_KEEPALIVE */
+       {
+         tcp_keepalive(pcb);
+         pcb->keep_cnt_sent++;
+       }
+     }
+     /* If this PCB has queued out of sequence data, but has been
+        inactive for too long, will drop the data (it will eventually
+        be retransmitted). */
+ #if TCP_QUEUE_OOSEQ
+     if (pcb->ooseq != NULL &&
+         (uint32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {
+       tcp_segs_free(pcb->ooseq);
+       pcb->ooseq = NULL;
+       LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));
+     }
+ #endif /* TCP_QUEUE_OOSEQ */
+     /* Check if this PCB has stayed too long in SYN-RCVD */
+     if (pcb->state == SYN_RCVD) {
+       if ((uint32_t)(tcp_ticks - pcb->tmr) >
+           TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {
+         ++pcb_remove;
+         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));
+       }
+     }
+     /* Check if this PCB has stayed too long in LAST-ACK */
+     if (pcb->state == LAST_ACK) {
+       if ((uint32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
+         ++pcb_remove;
+         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));
+       }
+     }
+     /* If the PCB should be removed, do it. */
+     if (pcb_remove) {
+       struct tcp_pcb *pcb2;
+       tcp_pcb_purge(pcb);
+       /* Remove PCB from tcp_active_pcbs list. */
+       if (prev != NULL) {
+         LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);
+         prev->next = pcb->next;
+       } else {
+         /* This PCB was the first. */
+         LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);
+         tcp_active_pcbs = pcb->next;
+       }
+       TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ECONNABORTED);
+       if (pcb_reset) {
+         tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip,
+           pcb->local_port, pcb->remote_port);
+       }
+       pcb2 = pcb;
+       pcb = pcb->next;
+                       kmem_cache_free(tcp_pcb_kcache, (void*)pcb2);
+     } else {
+       /* get the 'next' element now and work with 'prev' below (in case of abort) */
+       prev = pcb;
+       pcb = pcb->next;
+       /* We check if we should poll the connection. */
+       ++prev->polltmr;
+       if (prev->polltmr >= prev->pollinterval) {
+         prev->polltmr = 0;
+         LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));
+         TCP_EVENT_POLL(prev, err);
+         /* if err == ECONNABORTED, 'prev' is already deallocated */
+         if (err == ESUCCESS) {
+           tcp_output(prev);
+         }
+       }
+     }
+   }
+   
+   /* Steps through all of the TIME-WAIT PCBs. */
+   prev = NULL;
+   pcb = tcp_tw_pcbs;
+   while (pcb != NULL) {
+     LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
+     pcb_remove = 0;
+     /* Check if this PCB has stayed long enough in TIME-WAIT */
+     if ((uint32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {
+       ++pcb_remove;
+     }
+     
+     /* If the PCB should be removed, do it. */
+     if (pcb_remove) {
+       struct tcp_pcb *pcb2;
+       tcp_pcb_purge(pcb);
+       /* Remove PCB from tcp_tw_pcbs list. */
+       if (prev != NULL) {
+         LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);
+         prev->next = pcb->next;
+       } else {
+         /* This PCB was the first. */
+         LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);
+         tcp_tw_pcbs = pcb->next;
+       }
+       pcb2 = pcb;
+       pcb = pcb->next;
+                       kmem_cache_free(tcp_pcb_kcache, (void*)pcb2);
+     } else {
+       prev = pcb;
+       pcb = pcb->next;
+     }
+   }
+ }
+ /**
+  * Deallocates a list of TCP segments (tcp_seg structures).
+  *
+  * @param seg tcp_seg list of TCP segments to free
+  */
+ void
+ tcp_segs_free(struct tcp_seg *seg)
+ {
+   while (seg != NULL) {
+     struct tcp_seg *next = seg->next;
+     tcp_seg_free(seg);
+     seg = next;
+   }
+ }
+ /**
+  * Frees a TCP segment (tcp_seg structure).
+  *
+  * @param seg single tcp_seg to free
+  */
+ void
+ tcp_seg_free(struct tcp_seg *seg)
+ {
+   if (seg != NULL) {
+     if (seg->p != NULL) {
+       pbuf_free(seg->p);
+ #if TCP_DEBUG
+       seg->p = NULL;
+ #endif /* TCP_DEBUG */
+     }
+               kmem_cache_free(tcp_segment_kcache, seg);
+   }
+ }
+ /**
+  * Sets the priority of a connection.
+  *
+  * @param pcb the tcp_pcb to manipulate
+  * @param prio new priority
+  */
+ void
+ tcp_setprio(struct tcp_pcb *pcb, uint8_t prio)
+ {
+   pcb->prio = prio;
+ }
+ #if TCP_QUEUE_OOSEQ
+ /**
+  * Returns a copy of the given TCP segment.
+  * The pbuf and data are not copied, only the pointers
+  *
+  * @param seg the old tcp_seg
+  * @return a copy of seg
+  */ 
+ struct tcp_seg *
+ tcp_seg_copy(struct tcp_seg *seg)
+ {
+   struct tcp_seg *cseg;
+   cseg = (struct tcp_seg *)kmem_cache_alloc(tcp_segment_kcache, 0);
+   if (cseg == NULL) {
+     return NULL;
+   }
+   memcpy((uint8_t *)cseg, (const uint8_t *)seg, sizeof(struct tcp_seg)); 
+   pbuf_ref(cseg->p);
+   return cseg;
+ }
+ #endif /* TCP_QUEUE_OOSEQ */
+ /**
+  * Used to specify the argument that should be passed callback
+  * functions.
+  *
+  * @param pcb tcp_pcb to set the callback argument
+  * @param arg void pointer argument to pass to callback functions
+  */ 
+ void
+ tcp_arg(struct tcp_pcb *pcb, void *arg)
+ {  
+   pcb->callback_arg = arg;
+ }
+ #if LWIP_CALLBACK_API
+ /**
+  * Used to specify the function that should be called when a TCP
+  * connection receives data.
+  *
+  * @param pcb tcp_pcb to set the recv callback
+  * @param recv callback function to call for this pcb when data is received
+  */ 
+ void
+ tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv)
+ {
+   pcb->recv = recv;
+ }
+ /**
+  * Used to specify the function that should be called when TCP data
+  * has been successfully delivered to the remote host.
+  *
+  * @param pcb tcp_pcb to set the sent callback
+  * @param sent callback function to call for this pcb when data is successfully sent
+  */ 
+ void
+ tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent)
+ {
+   pcb->sent = sent;
+ }
+ /**
+  * Used to specify the function that should be called when a fatal error
+  * has occured on the connection.
+  *
+  * @param pcb tcp_pcb to set the err callback
+  * @param err callback function to call for this pcb when a fatal error
+  *        has occured on the connection
+  */ 
+ void
+ tcp_err(struct tcp_pcb *pcb, tcp_err_fn err)
+ {
+   pcb->errf = err;
+ }
+ /**
+  * Used for specifying the function that should be called when a
+  * LISTENing connection has been connected to another host.
+  *
+  * @param pcb tcp_pcb to set the accept callback
+  * @param accept callback function to call for this pcb when LISTENing
+  *        connection has been connected to another host
+  */ 
+ void
+ tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept)
+ {
+   pcb->accept = accept;
+ }
+ #endif /* LWIP_CALLBACK_API */
+ /**
+  * Used to specify the function that should be called periodically
+  * from TCP. The interval is specified in terms of the TCP coarse
+  * timer interval, which is called twice a second.
+  *
+  */ 
+ void
+ tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, uint8_t interval)
+ {
+ #if LWIP_CALLBACK_API
+   pcb->poll = poll;
+ #else /* LWIP_CALLBACK_API */  
+   LWIP_UNUSED_ARG(poll);
+ #endif /* LWIP_CALLBACK_API */  
+   pcb->pollinterval = interval;
+ }
+ /**
+  * Purges a TCP PCB. Removes any buffered data and frees the buffer memory
+  * (pcb->ooseq, pcb->unsent and pcb->unacked are freed).
+  *
+  * @param pcb tcp_pcb to purge. The pcb itself is not deallocated!
+  */
+ void
+ tcp_pcb_purge(struct tcp_pcb *pcb)
+ {
+   if (pcb->state != CLOSED &&
+      pcb->state != TIME_WAIT &&
+      pcb->state != LISTEN) {
+     printd("tcp_pcb_purge\n");
+ #if TCP_LISTEN_BACKLOG
+     if (pcb->state == SYN_RCVD) {
+       /* Need to find the corresponding listen_pcb and decrease its accepts_pending */
+       struct tcp_pcb_listen *lpcb;
+       LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL",
+         tcp_listen_pcbs.listen_pcbs != NULL);
+       for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
+         if ((lpcb->local_port == pcb->local_port) &&
+             (ip_addr_isany(&lpcb->local_ip) ||
+              ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) {
+             /* port and address of the listen pcb match the timed-out pcb */
+             LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending",
+               lpcb->accepts_pending > 0);
+             lpcb->accepts_pending--;
+             break;
+           }
+       }
+     }
+ #endif /* TCP_LISTEN_BACKLOG */
+     if (pcb->refused_data != NULL) {
+       LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));
+       pbuf_free(pcb->refused_data);
+       pcb->refused_data = NULL;
+     }
+     if (pcb->unsent != NULL) {
+       LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));
+     }
+     if (pcb->unacked != NULL) {
+       LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));
+     }
+ #if TCP_QUEUE_OOSEQ
+     if (pcb->ooseq != NULL) {
+       LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));
+     }
+     tcp_segs_free(pcb->ooseq);
+     pcb->ooseq = NULL;
+ #endif /* TCP_QUEUE_OOSEQ */
+     /* Stop the retransmission timer as it will expect data on unacked
+        queue if it fires */
+     pcb->rtime = -1;
+     tcp_segs_free(pcb->unsent);
+     tcp_segs_free(pcb->unacked);
+     pcb->unacked = pcb->unsent = NULL;
+ #if TCP_OVERSIZE
+     pcb->unsent_oversize = 0;
+ #endif /* TCP_OVERSIZE */
+   }
+ }
+ /**
+  * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.
+  *
+  * @param pcblist PCB list to purge.
+  * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated!
+  */
+ void
+ tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)
+ {
+   TCP_RMV(pcblist, pcb);
+   tcp_pcb_purge(pcb);
+   
+   /* if there is an outstanding delayed ACKs, send it */
+   if (pcb->state != TIME_WAIT &&
+      pcb->state != LISTEN &&
+      pcb->flags & TF_ACK_DELAY) {
+     pcb->flags |= TF_ACK_NOW;
+     tcp_output(pcb);
+   }
+   if (pcb->state != LISTEN) {
+     LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL);
+     LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL);
+ #if TCP_QUEUE_OOSEQ
+     LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL);
+ #endif /* TCP_QUEUE_OOSEQ */
+   }
+   pcb->state = CLOSED;
+   LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());
+ }
+ #if TCP_CALCULATE_EFF_SEND_MSS
+ /**
+  * Calcluates the effective send mss that can be used for a specific IP address
+  * by using ip_route to determin the netif used to send to the address and
+  * calculating the minimum of TCP_MSS and that netif's mtu (if set).
+  */
+ uint16_t
+ tcp_eff_send_mss(uint16_t sendmss, ip_addr_t *addr)
+ {
+   uint16_t mss_s;
+   struct netif *outif;
+   //outif = ip_route(addr);
+     mss_s = DEFAULT_MTU - IP_HDR_SZ - TCP_HLEN;
+     /* RFC 1122, chap 4.2.2.6:
+      * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize
+      * We correct for TCP options in tcp_write(), and don't support IP options.
+      */
+     sendmss = MIN(sendmss, mss_s);
+   return sendmss;
+ }
+ #endif /* TCP_CALCULATE_EFF_SEND_MSS */
+ const char*
+ tcp_debug_state_str(enum tcp_state s)
+ {
+   return tcp_state_str[s];
+ }
+ #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG
+ /**
+  * Print a tcp header for debugging purposes.
+  *
+  * @param tcphdr pointer to a struct tcp_hdr
+  */
+ void
+ tcp_debug_print(struct tcp_hdr *tcphdr)
+ {
+   LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));
+   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+   LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n",
+          ntohs(tcphdr->src), ntohs(tcphdr->dest)));
+   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+   LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n",
+           ntohl(tcphdr->seqno)));
+   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+   LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n",
+          ntohl(tcphdr->ackno)));
+   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+   LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (",
+        TCPH_HDRLEN(tcphdr),
+          TCPH_FLAGS(tcphdr) >> 5 & 1,
+          TCPH_FLAGS(tcphdr) >> 4 & 1,
+          TCPH_FLAGS(tcphdr) >> 3 & 1,
+          TCPH_FLAGS(tcphdr) >> 2 & 1,
+          TCPH_FLAGS(tcphdr) >> 1 & 1,
+          TCPH_FLAGS(tcphdr) & 1,
+          ntohs(tcphdr->wnd)));
+   tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
+   LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));
+   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+   LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n",
+          ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));
+   LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));
+ }
+ /**
+  * Print a tcp state for debugging purposes.
+  *
+  * @param s enum tcp_state to print
+  */
+ void
+ tcp_debug_print_state(enum tcp_state s)
+ {
+   LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s]));
+ }
+ /**
+  * Print tcp flags for debugging purposes.
+  *
+  * @param flags tcp flags, all active flags are printed
+  */
+ void
+ tcp_debug_print_flags(uint8_t flags)
+ {
+   if (flags & TCP_FIN) {
+     LWIP_DEBUGF(TCP_DEBUG, ("FIN "));
+   }
+   if (flags & TCP_SYN) {
+     LWIP_DEBUGF(TCP_DEBUG, ("SYN "));
+   }
+   if (flags & TCP_RST) {
+     LWIP_DEBUGF(TCP_DEBUG, ("RST "));
+   }
+   if (flags & TCP_PSH) {
+     LWIP_DEBUGF(TCP_DEBUG, ("PSH "));
+   }
+   if (flags & TCP_ACK) {
+     LWIP_DEBUGF(TCP_DEBUG, ("ACK "));
+   }
+   if (flags & TCP_URG) {
+     LWIP_DEBUGF(TCP_DEBUG, ("URG "));
+   }
+   if (flags & TCP_ECE) {
+     LWIP_DEBUGF(TCP_DEBUG, ("ECE "));
+   }
+   if (flags & TCP_CWR) {
+     LWIP_DEBUGF(TCP_DEBUG, ("CWR "));
+   }
+   LWIP_DEBUGF(TCP_DEBUG, ("\n"));
+ }
+ /**
+  * Print all tcp_pcbs in every list for debugging purposes.
+  */
+ void
+ tcp_debug_print_pcbs(void)
+ {
+   struct tcp_pcb *pcb;
+   LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));
+   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
+     LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
+                        pcb->local_port, pcb->remote_port,
+                        pcb->snd_nxt, pcb->rcv_nxt));
+     tcp_debug_print_state(pcb->state);
+   }    
+   LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));
+   for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {
+     LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
+                        pcb->local_port, pcb->remote_port,
+                        pcb->snd_nxt, pcb->rcv_nxt));
+     tcp_debug_print_state(pcb->state);
+   }    
+   LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));
+   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
+     LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",
+                        pcb->local_port, pcb->remote_port,
+                        pcb->snd_nxt, pcb->rcv_nxt));
+     tcp_debug_print_state(pcb->state);
+   }    
+ }
+ /**
+  * Check state consistency of the tcp_pcb lists.
+  */
+ s16_t tcp_pcbs_sane(void)
+ {
+   struct tcp_pcb *pcb;
+   for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
+     LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);
+     LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);
+     LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
+   }
+   for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
+     LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
+   }
+   return 1;
+ }
+ #endif /* TCP_DEBUG */
diff --combined kern/src/net/udp.c
index 0000000,1b9e535..6f1e7ad
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,324 +1,314 @@@
 -static void wrap_restart_kthread(struct trapframe *tf, uint32_t srcid,
 -                                      long a0, long a1, long a2){
 -      restart_kthread((struct kthread*) a0);
 -}
 -
+ /**
+  * Contains shamelessly stolen code from BSD & lwip, both have
+  * BSD-style licenses
+  *
+  */
+ #include <ros/common.h>
+ #include <string.h>
+ #include <kmalloc.h>
+ #include <socket.h>
+ #include <net.h>
+ #include <sys/queue.h>
+ #include <atomic.h>
+ #include <bits/netinet.h>
+ #include <net/ip.h>
+ #include <net/udp.h>
+ #include <slab.h>
+ #include <socket.h>
+ #include <debug.h>
+ struct udp_pcb *udp_pcbs;
+ uint16_t udp_port_num = SOCKET_PORT_START;
+ struct udp_pcb* udp_new(void){
+       struct udp_pcb *pcb = kmem_cache_alloc(udp_pcb_kcache, 0);
+     // if pcb is only tracking ttl, then no need!
+       if (pcb!= NULL){
+               pcb->ttl = UDP_TTL;
+       memset(pcb, 0, sizeof(struct udp_pcb));
+       }
+       return pcb;
+ }
+ int udp_send(struct udp_pcb *pcb, struct pbuf *p)
+ {
+   /* send to the packet using remote ip and port stored in the pcb */
+   // rip and rport should be in socket not pcb?
+   return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
+ }
+ typedef unsigned char u16;
+ typedef unsigned long u32;
+ u16 udp_sum_calc(u16 len_udp, u16 src_addr[],u16 dest_addr[],  int padding, u16 buff[])
+ {
+ u16 prot_udp=17;
+ u16 padd=0;
+ u16 word16;
+ u32 sum;
+ int i;
+       
+       // Find out if the length of data is even or odd number. If odd,
+       // add a padding byte = 0 at the end of packet
+       if ((padding&1)==1){
+               padd=1;
+               buff[len_udp]=0;
+       }
+       
+       //initialize sum to zero
+       sum=0;
+       
+       // make 16 bit words out of every two adjacent 8 bit words and 
+       // calculate the sum of all 16 vit words
+       for (i=0;i<len_udp+padd;i=i+2){
+               word16 =((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF);
+               sum = sum + (unsigned long)word16;
+       }       
+       // add the UDP pseudo header which contains the IP source and destinationn addresses
+       for (i=0;i<4;i=i+2){
+               word16 =((src_addr[i]<<8)&0xFF00)+(src_addr[i+1]&0xFF);
+               sum=sum+word16; 
+       }
+       for (i=0;i<4;i=i+2){
+               word16 =((dest_addr[i]<<8)&0xFF00)+(dest_addr[i+1]&0xFF);
+               sum=sum+word16;         
+       }
+       // the protocol number and the length of the UDP packet
+       sum = sum + prot_udp + len_udp;
+       // keep only the last 16 bits of the 32 bit calculated sum and add the carries
+       while (sum>>16)
+               sum = (sum & 0xFFFF)+(sum >> 16);
+               
+       // Take the one's complement of sum
+       sum = ~sum;
+ return ((u16) sum);
+ }
+ int udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
+                     struct in_addr *dst_ip, uint16_t dst_port){
+     // we now have one netif to send to, otherwise we need to route
+     // ip_route();
+     struct udp_hdr *udphdr;
+     struct pbuf *q;
+               printd("udp_sendto ip %x, port %d\n", dst_ip->s_addr, dst_port); 
+     // broadcast?
+     if (pcb->local_port == 0) {
+                               /* if the PCB not bound to a port, bind it and give local ip */
+         if (udp_bind(pcb, &pcb->local_ip, pcb->local_port)!=0)
+                                       warn("udp binding failed \n");
+     }
+     if (pbuf_header(p, UDP_HLEN)){ // we could probably save this check for block.
+         // CHECK: should allocate enough for the other headers too
+         q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
+         if (q == NULL)
+            panic("out of memory");
+         // if the original packet is not empty
+         if (p->tot_len !=0) {
+             pbuf_chain(q,p);
+             // check if it is chained properly ..
+         }
+     } else {
+                               /* Successfully padded the header*/
+                               q = p;
+     }
+     udphdr = (struct udp_hdr *) q->payload;
+               printd("src port %d, dst port %d \n, length %d ", pcb->local_port, ntohs(dst_port), q->tot_len);
+     udphdr->src_port = htons(pcb->local_port);
+     udphdr->dst_port = (dst_port);
+     udphdr->length = htons(q->tot_len); 
+               udphdr->checksum = 0; // just to be sure.
+               // printd("checksum inet_chksum %x \n", udphdr->checksum);
+               printd("params src addr %x, dst addr %x, length %x \n", LOCAL_IP_ADDR.s_addr, (dst_ip->s_addr), 
+                                         q->tot_len);
+     udphdr->checksum = inet_chksum_pseudo(q, htonl(LOCAL_IP_ADDR.s_addr), dst_ip->s_addr,
+                                                                                        IPPROTO_UDP, q->tot_len);
+               printd ("method ours %x\n", udphdr->checksum);
+               // 0x0000; //either use brho's checksum or use cards' capabilities
+               ip_output(q, &LOCAL_IP_ADDR, dst_ip, pcb->ttl, pcb->tos, IPPROTO_UDP);
+               // ip_output(q, &global_ip, dst_ip, IPPROTO_UDP);
+     return 0;
+ }
+ /* TODO: use the real queues we have implemented... */
+ int udp_bind(struct udp_pcb *pcb, const struct in_addr *ip, uint16_t port){ 
+     int rebind = pcb->local_port;
+     struct udp_pcb *ipcb;
+               assert(pcb);
+               /* trying to assign port */
+     if (port != 0)
+         pcb->local_port = port;
+     /* no lock needed since we are just traversing/reading */
+     /* Check for double bind and rebind of the same pcb */
+     for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
+         /* is this UDP PCB already on active list? */
+         if (pcb == ipcb) {
+             rebind = 1; //already on the list
+         } else if (ipcb->local_port == port){
+             warn("someone else is using the port %d\n" , port); 
+             return -1;
+         }
+     }
+     /* accept data for all interfaces */
+     if (ip == NULL || (ip->s_addr == INADDR_ANY.s_addr))
+               /* true right now */
+         pcb->local_ip = INADDR_ANY;
+     /* assign a port */
+     if (port == 0) {
+         port = SOCKET_PORT_START; 
+         ipcb = udp_pcbs;
+         while ((ipcb != NULL) && (port != SOCKET_PORT_END)) {
+             if (ipcb->local_port == port) {
+                 /* port is already used by another udp_pcb */
+                 port++;
+                 /* restart scanning all udp pcbs */
+                 ipcb = udp_pcbs;
+             } else {
+                 /* go on with next udp pcb */
+                 ipcb = ipcb->next;
+             }
+         }
+         if (ipcb != NULL){
+             warn("No more udp ports available!");
+         }
+     }
+     if (rebind == 0) {
+         /* place the PCB on the active list if not already there */
+                               pcb->next = udp_pcbs;
+                               udp_pcbs = pcb;
+     }
+               printk("local port bound to 0x%x \n", port);
+     pcb->local_port = port;
+     return 0;
+ }
+ /* port are in host order, ips are in network order */
+ /* Think: a pcb is here, if someone is waiting for a connection or the udp conn
+  * has been established */
+ static struct udp_pcb* find_pcb(struct udp_pcb* list, uint16_t src_port, uint16_t dst_port,
+                                                               uint16_t srcip, uint16_t dstip) {
+       struct udp_pcb* uncon_pcb = NULL;
+       struct udp_pcb* pcb = NULL;
+       uint8_t local_match = 0;
+       for (pcb = list; pcb != NULL; pcb = pcb->next) {
+               local_match = 0;
+               if ((pcb->local_port == dst_port) 
+                       && (pcb->local_ip.s_addr == dstip 
+                       || ip_addr_isany(&pcb->local_ip))){
+                               local_match = 1;
+         if ((uncon_pcb == NULL) && 
+             ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
+           /* the first unconnected matching PCB */
+           uncon_pcb = pcb;
+         }
+               }
+               if (local_match && (pcb->remote_port == src_port) &&
+                               (ip_addr_isany(&pcb->remote_ip) ||
+                                pcb->remote_ip.s_addr == srcip))
+                       /* perfect match */
+                       return pcb;
+       }
+       return uncon_pcb;
+ }
+ #if 0 // not working yet
+ // need to have pbuf queue support
+ int udp_attach(struct pbuf *p, struct sock *socket) {
+       // pretend the attaching of packet is succesful
+       /*
+       recv_q->last->next = p;
+       recv_q->last=p->last
+       */ 
+ }
+ #endif 
+ /** Process an incoming UDP datagram. 
+  * Given an incoming UDP datagram, this function finds the right PCB
+  * which links to the right socket buffer, and attaches the datagram
+  * to the right socket. 
+  * If no appropriate PCB is found, the pbuf is freed.
+  */ 
+ /** TODO: think about combining udp_input and ip_input together */
+ // TODO: figure out if we even need a PCB? or just socket buff. 
+ // TODO: test out looking up pcbs.. since matching function may fail
 -              kthread = __up_sem(&(sock->sem), FALSE);
 -              if (kthread) {
 -                       send_kernel_message(core_id(), (amr_t)wrap_restart_kthread, (long)kthread, 0, 0,
 -                                                                                                KMSG_ROUTINE);
 -              } else {
+ int udp_input(struct pbuf *p){
+       struct udp_hdr *udphdr;
+       struct udp_pcb *pcb, uncon_pcb;
+       struct ip_hdr *iphdr;
+       uint16_t src, dst;
+       bool local_match = 0;
+       iphdr = (struct ip_hdr *)p->payload;
+       /* Move the header to where the udp header is */
+       if (pbuf_header(p, -((int16_t)((iphdr->hdr_len) * 4)))) {
+               warn("udp_input: Did not find a matching PCB for a udp packet\n");
+               pbuf_free(p);
+               return -1;
+       }
+       printk("start of udp %p\n", p->payload);
+       udphdr = (struct udp_hdr *)p->payload;
+       /* convert the src port and dst port to host order */
+       src = ntohs(udphdr->src_port);
+       dst = ntohs(udphdr->dst_port);
+       pcb = find_pcb(udp_pcbs, src, dst, iphdr->src_addr, iphdr->dst_addr);
+       /* TODO: Possibly adjust the pcb to the head of the queue? */
+       /* TODO: Linux uses a set of hashtables to lookup PCBs 
+        * Look at __udp4_lib_lookup function in Linux kernel 2.6.21.1
+        */
+       /* Anything that is not directed at this pcb should have been dropped */
+       if (pcb == NULL){
+               warn("udp_input: Did not find a matching PCB for a udp packet\n");
+               pbuf_free(p);
+               return -1;
+       }
+       /* checksum check */
+   if (udphdr->checksum != 0) {
+     if (inet_chksum_pseudo(p, (iphdr->src_addr), (iphdr->dst_addr), 
+                                IPPROTO_UDP, p->tot_len) != 0){
+                       warn("udp_input: UPD datagram discarded due to failed chksum!");
+                       pbuf_free(p);
+                       return -1;
+     }
+       }
+   /* ignore SO_REUSE */
+       if (pcb != NULL && pcb->pcbsock != NULL){
+               /* For each in the pbuf chain, disconnect from the chain and add it to the
+                * recv_buff of the correct socket 
+                */ 
+               struct socket *sock = pcb->pcbsock;
+               attach_pbuf(p, &sock->recv_buff);
+               struct kthread *kthread;
++              int8_t irq_state = 0;
+               /* First notify any blocking recv calls,
+                * then notify anyone who might be waiting in a select
+                */ 
+               // multiple people might be waiting on the socket here..
 -                LIST_FOREACH_SAFE(sentry, &(sock->waiters), link, sentry_tmp){
++              /* TODO: consider a helper with this and tcp.c */
++              if (!sem_up_irqsave(&sock->sem, &irq_state)) {
+                       // wake up all waiters
+                       struct semaphore_entry *sentry, *sentry_tmp;
+                       spin_lock(&sock->waiter_lock);
 -                              kthread = __up_sem(&sentry->sem, true);
 -                              if (kthread){
 -                              send_kernel_message(core_id(), (amr_t)wrap_restart_kthread, (long)kthread, 0, 0,
 -                                                                                                KMSG_ROUTINE);
 -                              }
++                      LIST_FOREACH_SAFE(sentry, &sock->waiters, link, sentry_tmp) {
+                               //should only wake up one waiter
 -                              /* do not need to free since all the sentry are stack-based vars */
++                              sem_up_irqsave(&sentry->sem, &irq_state);
+                               LIST_REMOVE(sentry, link);
++                              /* do not need to free since all the sentry are stack-based vars
++                               * */
+                       }
+                       spin_unlock(&sock->waiter_lock);
+               }
+               // the attaching of pbuf should have increfed pbuf ref, so free is simply a decref
+               pbuf_free(p);
+       }
+       return 0;
+ }
diff --combined kern/src/socket.c
index 0000000,1972e40..b9f4084
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,505 +1,502 @@@
 -#include <mbuf.h>
+ /*
+  * Copyright (c) 2011 The Regents of the University of California
+  * David Zhu <yuzhu@cs.berkeley.edu>
+  * See LICENSE for details.
+  * 
+  * Socket layer on top of TCP abstraction. Similar to the BSD implementation.
+  *
+  */
+ #include <ros/common.h>
+ #include <socket.h>
+ #include <vfs.h>
+ #include <time.h>
+ #include <kref.h>
+ #include <syscall.h>
+ #include <sys/uio.h>
 -      init_sem(&newsock->sem, 0);
 -      init_sem(&newsock->accept_sem, 0);
+ #include <ros/errno.h>
+ #include <net.h>
+ #include <net/udp.h>
+ #include <net/tcp.h>
+ #include <net/pbuf.h>
+ #include <net/tcp_impl.h>
+ #include <umem.h>
+ #include <kthread.h>
+ #include <bitmask.h>
+ #include <debug.h>
+ /*
+  *TODO: Figure out which socket.h is used where
+  *There are several socket.h in kern, and a couple more in glibc. Perhaps the glibc ones
+  *should grab from here..
+  */
+ struct kmem_cache *sock_kcache;
+ struct kmem_cache *mbuf_kcache;
+ struct kmem_cache *udp_pcb_kcache;
+ struct kmem_cache *tcp_pcb_kcache;
+ struct kmem_cache *tcp_pcb_listen_kcache;
+ struct kmem_cache *tcp_segment_kcache;
+ // file ops needed to support read/write on socket fd
+ static struct file_operations socket_op = {
+       0,
+       0,//soo_read,
+       0,//soo_write,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,//soo_poll,
+       0,
+       0,
+       0, // sendpage might apply here
+       0,
+ };
+ static struct socket* getsocket(struct proc *p, int fd){
+       /* look up fd -> file */
+       struct file *so_file = get_file_from_fd(&(p->open_files), fd);
+       /* get socket and verify its type */
+       if (so_file == NULL){
+               printd("getsocket() fd -> null file: fd %d\n", fd);
+               return NULL;
+       }
+       if (so_file->f_op != &socket_op) {
+               set_errno(ENOTSOCK);
+               printd("fd %d maps to non-socket file\n");
+               return NULL;
+       } else
+               return (struct socket*) so_file->f_privdata;
+ }
+ struct socket* alloc_sock(int socket_family, int socket_type, int protocol){
+       struct socket *newsock = kmem_cache_alloc(sock_kcache, 0);
+       assert(newsock);
+       newsock->so_family = socket_family;
+       newsock->so_type = socket_type;
+       newsock->so_protocol = protocol;
+       newsock->so_state = SS_ISDISCONNECTED;
+       STAILQ_INIT(&(newsock->acceptq));
+       pbuf_head_init(&newsock->recv_buff);
+       pbuf_head_init(&newsock->send_buff);
 -                      sleep_on(&sock->accept_sem);
++      sem_init_irqsave(&newsock->sem, 0);
++      sem_init_irqsave(&newsock->accept_sem, 0);
+       spinlock_init(&newsock->waiter_lock);
+       LIST_INIT(&newsock->waiters);
+       return newsock;
+ }
+ // TODO: refactor vfs so we can allocate fd and do the basic initialization
+ struct file *alloc_socket_file(struct socket* sock) {
+       struct file *file = alloc_file();
+       if (file == NULL) return 0;
+       // Linux fakes a dentry and an inode for socks, see socket.c : sock_alloc_file
+       file->f_dentry = NULL; // This might break things?
+       file->f_vfsmnt = 0;
+       file->f_flags = 0;
+       file->f_mode = S_IRUSR | S_IWUSR; // both read and write for socket files
+       file->f_pos = 0;
+       file->f_uid = 0;
+       file->f_gid = 0;
+       file->f_error = 0;
+       file->f_op = &socket_op;
+       file->f_privdata = sock;
+       file->f_mapping = 0;
+       return file;
+ }
+ void socket_init(){
+       
+       /* allocate buf for socket */
+       sock_kcache = kmem_cache_create("socket", sizeof(struct socket),
+                                                                       __alignof__(struct socket), 0, 0, 0);
+       udp_pcb_kcache = kmem_cache_create("udppcb", sizeof(struct udp_pcb),
+                                                                       __alignof__(struct udp_pcb), 0, 0, 0);
+       tcp_pcb_kcache = kmem_cache_create("tcppcb", sizeof(struct tcp_pcb),
+                                                                       __alignof__(struct tcp_pcb), 0, 0, 0);
+       tcp_pcb_listen_kcache = kmem_cache_create("tcppcblisten", sizeof(struct tcp_pcb_listen),
+                                                                       __alignof__(struct tcp_pcb_listen), 0, 0, 0);
+       tcp_segment_kcache = kmem_cache_create("tcpsegment", sizeof(struct tcp_seg),
+                                                                       __alignof__(struct tcp_seg), 0, 0, 0);
+       pbuf_init();
+ }
+ intreg_t sys_accept(struct proc *p, int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
+       printk ("sysaccept called\n");
+       struct socket* sock = getsocket(p, sockfd);
+       struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
+       uint16_t r_port;
+       struct socket *accepted = NULL;
++      int8_t irq_state = 0;
+       if (sock == NULL) {
+               set_errno(EBADF);
+               return -1;      
+       }
+       if (sock->so_type == SOCK_DGRAM){
+               return -1; // indicates false for connect
+       } else if (sock->so_type == SOCK_STREAM) {
++              /* XXX these do the same thing, what is it you actually wanted to do?
++               * (Originally the first was sleep_on, and the second __down_sem */
+               if (STAILQ_EMPTY(&(sock->acceptq))) {
+                       // block on the acceptq
 -                      __down_sem(&sock->accept_sem, NULL);
++                      sem_down_irqsave(&sock->accept_sem, &irq_state);
+               } else {
 -static void wrap_restart_kthread(struct trapframe *tf, uint32_t srcid,
 -                                      long a0, long a1, long a2){
 -      restart_kthread((struct kthread*) a0);
 -}
 -
++                      sem_down_irqsave(&sock->accept_sem, &irq_state);
+               }
+               spin_lock_irqsave(&sock->waiter_lock);
+               accepted = STAILQ_FIRST(&(sock->acceptq));
+               STAILQ_REMOVE_HEAD((&(sock->acceptq)), next);
+               spin_unlock_irqsave(&sock->waiter_lock);
+               if (accepted == NULL) return -1;
+               struct file *file = alloc_socket_file(accepted);
+               if (file == NULL) return -1;
+               int fd = insert_file(&p->open_files, file, 0);
+               if (fd < 0) {
+                       warn("File insertion for socket open failed");
+                       return -1;
+               }
+               kref_put(&file->f_kref);
+       }
+       return -1;
+ }
 -      struct kthread *kthread = __up_sem(&(sock->accept_sem), FALSE);
 -      if (kthread) {
 -              send_kernel_message(core_id(), (amr_t)wrap_restart_kthread, (long)kthread, 0, 0,
 -                                                                                                KMSG_ROUTINE);
 -      } 
+ static error_t accept_callback(void *arg, struct tcp_pcb *newpcb, error_t err) {
+       struct socket *sockold = (struct socket *) arg;
+       struct socket *sock = alloc_sock(sockold->so_family, sockold->so_type, sockold->so_protocol);
++      int8_t irq_state = 0;
+       
+       sock->so_pcb = newpcb;
+       newpcb->pcbsock = sock;
+       spin_lock_irqsave(&sockold->waiter_lock);
+       STAILQ_INSERT_TAIL(&sockold->acceptq, sock, next);
+       // wake up any kthread who is potentially waiting
+       spin_unlock_irqsave(&sockold->waiter_lock);
 -intreg_t sys_send(struct proc *p, int sockfd, const void *buf, size_t len, int flags) {
++      sem_up_irqsave(&sock->accept_sem, &irq_state);
+       return 0;
+ }
+ intreg_t sys_listen(struct proc *p, int sockfd, int backlog) {
+       struct socket* sock = getsocket(p, sockfd);
+       if (sock == NULL) {
+               set_errno(EBADF);
+               return -1;      
+       }
+       if (sock->so_type == SOCK_DGRAM){
+               return -1; // indicates false for connect
+       } else if (sock->so_type == SOCK_STREAM) {
+               // check if the socket is in WAIT state
+               struct tcp_pcb *tpcb = (struct tcp_pcb*)sock->so_pcb;
+               struct tcp_pcb* lpcb = tcp_listen_with_backlog(tpcb, backlog);
+               if (lpcb == NULL) {
+                       return -1;
+               }
+               sock->so_pcb = lpcb;
+               // register callback for new connection
+               tcp_arg(lpcb, sock);                                                  
+               tcp_accept(lpcb, accept_callback); 
+               return 0;
+               // XXX: add backlog later
+       }
+       return -1;
+ }
+ intreg_t sys_connect(struct proc *p, int sock_fd, const struct sockaddr* addr, int addrlen) {
+       printk("sys_connect called \n");
+       struct socket* sock = getsocket(p, sock_fd);
+       struct sockaddr_in *in_addr = (struct sockaddr_in *)addr;
+       uint16_t r_port;
+       if (sock == NULL) {
+               set_errno(EBADF);
+               return -1;      
+       }
+       if (sock->so_type == SOCK_DGRAM){
+               return -1; // indicates false for connect
+       } else if (sock->so_type == SOCK_STREAM) {
+               error_t err = tcp_connect((struct tcp_pcb*)sock->so_pcb, & (in_addr->sin_addr), in_addr->sin_port, NULL);
+               return err;
+       }
+       return -1;
+ }
 -      struct socket* sock = getsocket(p_proc, fd);
 -      const struct sockaddr_in *in_addr = (const struct sockaddr_in *)addr;
++intreg_t sys_send(struct proc *p, int sockfd, const void *buf, size_t len,
++                  int flags) {
+       printk("sys_send called \n");
 -                      sleep_on(&sock->sem);
++      struct socket* sock = getsocket(p, sockfd);
++      const struct sockaddr_in *in_addr = (const struct sockaddr_in *)buf;
+       uint16_t r_port;
+       if (sock == NULL) {
+               set_errno(EBADF);
+               return -1;      
+       }
+       return len;
+ }
+ intreg_t sys_recv(struct proc *p, int sockfd, void *buf, size_t len, int flags) {
+       printk("sys_recv called \n");
+       // return actual length filled
+       return len;
+ }
+ intreg_t sys_bind(struct proc* p_proc, int fd, const struct sockaddr *addr, socklen_t addrlen) {
+       struct socket* sock = getsocket(p_proc, fd);
+       const struct sockaddr_in *in_addr = (const struct sockaddr_in *)addr;
+       uint16_t r_port;
+       if (sock == NULL) {
+               set_errno(EBADF);
+               return -1;      
+       }
+       if (sock->so_type == SOCK_DGRAM){
+               return udp_bind((struct udp_pcb*)sock->so_pcb, & (in_addr->sin_addr), in_addr->sin_port);
+       } else if (sock->so_type == SOCK_STREAM) {
+               return tcp_bind((struct tcp_pcb*)sock->so_pcb, & (in_addr->sin_addr), in_addr->sin_port);
+       } else {
+               printk("SOCK type not supported in bind operation \n");
+               return -1;
+       }
+       return 0;
+ }
+  
+ intreg_t sys_socket(struct proc *p, int socket_family, int socket_type, int protocol){
+       //check validity of params
+       if (socket_family != AF_INET && socket_type != SOCK_DGRAM)
+               return 0;
+       struct socket *sock = alloc_sock(socket_family, socket_type, protocol);
+       if (socket_type == SOCK_DGRAM){
+               /* udp socket */
+               sock->so_pcb = udp_new();
+               /* back link */
+               ((struct udp_pcb*) (sock->so_pcb))->pcbsock = sock;
+       } else if (socket_type == SOCK_STREAM) {
+               /* tcp socket */
+               sock->so_pcb = tcp_new();
+               ((struct tcp_pcb*) (sock->so_pcb))->pcbsock = sock;
+       }
+       struct file *file = alloc_socket_file(sock);
+       
+       if (file == NULL) return -1;
+       int fd = insert_file(&p->open_files, file, 0);
+       if (fd < 0) {
+               warn("File insertion for socket open failed");
+               return -1;
+       }
+       kref_put(&file->f_kref);
+       printk("Socket open, res = %d\n", fd);
+       return fd;
+ }
+ intreg_t send_iov(struct socket* sock, struct iovec* iov, int flags){
+       // COPY_COUNT: for each iov, copy into mbuf, and send
+       // should not copy here, copy in the protocol..
+       // should be esomething like this sock->so_proto->pr_send(sock, iov, flags);
+       // make it datagram specific for now...
+       send_datagram(sock, iov, flags);
+       // finally time to check for validity of UA, in the protocol send
+       return 0;       
+ }
+ /*TODO: iov support currently broken */
+ int send_datagram(struct socket* sock, struct iovec* iov, int flags){
+       // is this a connection oriented protocol? 
+       struct pbuf *prev = NULL;
+       struct pbuf *curr = NULL;
+       if (sock->so_type == SOCK_STREAM){
+               set_errno(ENOTCONN);
+               return -1;
+       }
+       
+       // possible sock locks needed
+       if ((sock->so_state & SS_ISCONNECTED) == 0){
+               set_errno(EINVAL);
+               return -1;
+       }
+     // pbuf_ref needs to map in the user ref
+       for (int i = 0; i< sizeof(iov) / sizeof (struct iovec); i++){
+               prev = curr;
+               curr = pbuf_alloc(PBUF_TRANSPORT, iov[i].iov_len, PBUF_REF);
+               if (prev!=NULL) pbuf_chain(prev, curr);
+       }
+       // struct pbuf* pb = pbuf_alloc(PBUF_TRANSPORT, PBUF_REF);
+       udp_send(sock->so_pcb, prev);
+       return 0;
+       
+ }
+ /* sys_sendto can send SOCK_DGRAM and eventually SOCK_STREAM 
+  * SOCK_DGRAM uses PBUF_REF since UDP does not need to wait for ack
+  * SOCK_STREAM uses PBUF_
+  *
+  */
+ intreg_t sys_sendto(struct proc *p_proc, int fd, const void *buffer, size_t length, 
+                       int flags, const struct sockaddr *dest_addr, socklen_t dest_len){
+       // look up the socket
+       struct socket* sock = getsocket(p_proc, fd);
+       int error;
+       struct sockaddr_in *in_addr;
+       uint16_t r_port;
+       if (sock == NULL) {
+               set_errno(EBADF);
+               return -1;      
+       }
+       if (sock->so_type == SOCK_DGRAM){
+               in_addr = (struct sockaddr_in *)dest_addr;
+               struct pbuf* buf = pbuf_alloc(PBUF_TRANSPORT, length, PBUF_REF);
+               if (buf != NULL)
+                       buf->payload = (void*)buffer;
+               else 
+                       warn("pbuf alloc failed \n");
+               // potentially unsafe cast to udp_pcb 
+               return udp_sendto((struct udp_pcb*) sock->so_pcb, buf, &in_addr->sin_addr, in_addr->sin_port);
+       }
+       return -1;
+   //TODO: support for sendmsg and iovectors? Let's get the basics working first!
+       #if 0 
+       // use iovector to handle sendmsg calls too, and potentially scatter-gather
+       struct msghdr msg;
+       struct iovec iov;
+       struct uio auio;
+       
+       // checking for permission only when you are sending it
+       // potential bug TOCTOU, especially with async calls
+               
+     msg.msg_name = dest_addr;
+     msg.msg_namelen = dest_len;
+     msg.msg_iov = &iov;
+     msg.msg_iovlen = 1;
+     msg.msg_control = 0;
+     
+       iov.iov_base = buffer;
+     iov.iov_len = length;
+       
+       // this is why we need another function to populate auio
+       auio.uio_iov = iov;
+       auio.uio_iovcnt = 1;
+       auio.uio_offset = 0;
+       auio.uio_resid = 0;
+       auio.uio_rw = UIO_WRITE;
+       auio.uio_proc = p;
+       // consider changing to send_uaio, since we care about progress.
+     error = send_iov(soc, iov, flags);
+       #endif
+ }
+ /* UDP and TCP has different waiting semantics
+  * UDP requires any packet to be available. 
+  * TCP requires accumulation of certain size? 
+  */
+ intreg_t sys_recvfrom(struct proc *p, int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address, socklen_t *restrict address_len){
+       struct socket* sock = getsocket(p, socket);     
+       int copied = 0;
+       int returnval = 0;
++      int8_t irq_state = 0;
+       if (sock == NULL) {
+               set_errno(EBADF);
+               return -1;
+       }
+       if (sock->so_type == SOCK_DGRAM){
+               struct pbuf_head *ph = &(sock->recv_buff);
+               struct pbuf* buf = NULL;
+               buf = detach_pbuf(ph);
+               if (!buf){
+                       // about to sleep
 -                      __down_sem(&sock->sem, NULL);
++                      sem_down_irqsave(&sock->sem, &irq_state);
+                       buf = detach_pbuf(ph);
+                       // Someone woke me up, there should be data..
+                       assert(buf);
+               } else {
 -      init_sem(&(read_sem.sem), 0);
++                      sem_down_irqsave(&sock->sem, &irq_state);
+               }
+                       copied = buf->len - sizeof(struct udp_hdr);
+                       if (copied > length)
+                               copied = length;
+                       pbuf_header(buf, -UDP_HDR_SZ);
+                       // copy it to user space
+                       returnval = memcpy_to_user_errno(p, buffer, buf->payload, copied);
+               }
+       if (returnval < 0) 
+               return -1;
+       else
+               return copied;
+ }
+ static int selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
+              fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out){
+       return 0;
+ }
+ /* TODO: Start respecting the time out value */ 
+ /* TODO: start respecting writefds and exceptfds */
+ intreg_t sys_select(struct proc *p, int nfds, fd_set *readfds, fd_set *writefds,
+                               fd_set *exceptfds, struct timeval *timeout){
+       /* Create a semaphore */
+       struct semaphore_entry read_sem; 
++      int8_t irq_state = 0;
 -  sleep_on(&(read_sem.sem));
++      sem_init_irqsave(&(read_sem.sem), 0);
+       /* insert into the sem list of a fd / socket */
+       int low_fd = 0;
+       for (int i = low_fd; i< nfds; i++) {
+               if(FD_ISSET(i, readfds)){
+                 struct socket* sock = getsocket(p, i);
+                       /* if the fd is not open or if the file descriptor is not a socket 
+                        * go to the next in the fd set 
+                        */
+                       if (sock == NULL) continue;
+                       /* for each file that is open, insert this semaphore to be woken up when there
+                       * is data available to be read
+                       */
+                       spin_lock(&sock->waiter_lock);
+                       LIST_INSERT_HEAD(&sock->waiters, &read_sem, link);
+                       spin_unlock(&sock->waiter_lock);
+               }
+       }
+       /* At this point wait on the semaphore */
++      sem_down_irqsave(&read_sem.sem, &irq_state);
+       /* someone woke me up, so walk through the list of descriptors and find one that is ready */
+       /* remove itself from all the lists that it is waiting on */
+       for (int i = low_fd; i<nfds; i++) {
+               if (FD_ISSET(i, readfds)){
+                       struct socket* sock = getsocket(p,i);
+                       if (sock == NULL) continue;
+                       spin_lock(&sock->waiter_lock);
+                       LIST_REMOVE(&read_sem, link);
+                       spin_unlock(&sock->waiter_lock);
+               }
+       }
+       fd_set readout, writeout, exceptout;
+       FD_ZERO(&readout);
+       FD_ZERO(&writeout);
+       FD_ZERO(&exceptout);
+       for (int i = low_fd; i< nfds; i ++){
+               if (readfds && FD_ISSET(i, readfds)){
+                 struct socket* sock = getsocket(p, i);
+                       if ((sock->recv_buff).qlen > 0){
+                               FD_SET(i, &readout);
+                       }
+                       /* if the socket is ready, then we can return it */
+               }
+       }
+       if (readfds)
+               memcpy(readfds, &readout, sizeof(*readfds));
+       if (writefds)
+               memcpy(writefds, &writeout, sizeof(*writefds));
+       if (exceptfds)
+               memcpy(readfds, &readout, sizeof(*readfds));
+       /* Sleep on that semaphore */
+       /* Somehow get these file descriptors to wake me up when there is new data */
+       return 0;
+ }
diff --combined kern/src/syscall.c
@@@ -9,7 -9,7 +9,7 @@@
  #include <arch/arch.h>
  #include <arch/mmu.h>
  #include <arch/console.h>
 -#include <ros/time.h>
 +#include <time.h>
  #include <error.h>
  
  #include <elf.h>
@@@ -33,7 -33,7 +33,8 @@@
  #include <smp.h>
  #include <arsc_server.h>
  #include <event.h>
 +#include <termios.h>
+ #include <socket.h>
  
  
  #ifdef __CONFIG_NETWORKING__
@@@ -48,7 -48,7 +49,7 @@@ struct systrace_record *systrace_buffe
  uint32_t systrace_bufidx = 0;
  size_t systrace_bufsize = 0;
  struct proc *systrace_procs[MAX_NUM_TRACED] = {0};
 -spinlock_t systrace_lock = SPINLOCK_INITIALIZER;
 +spinlock_t systrace_lock = SPINLOCK_INITIALIZER_IRQSAVE;
  
  /* Not enforcing the packing of systrace_procs yet, but don't rely on that */
  static bool proc_is_traced(struct proc *p)
@@@ -72,11 -72,10 +73,11 @@@ static void finish_sysc(struct syscall 
        atomic_and(&sysc->flags, ~SC_K_LOCK); 
  }
  
 -/* Helper that "finishes" the current async syscall.  This should be used when
 - * we are calling a function in a syscall that might not return and won't be
 - * able to use the normal syscall return path, such as proc_yield().  Call this
 - * from within syscall.c (I don't want it global).
 +/* Helper that "finishes" the current async syscall.  This should be used with
 + * care when we are not using the normal syscall completion path.
 + *
 + * Do *NOT* complete the same syscall twice.  This is catastrophic for _Ms, and
 + * a bad idea for _S.
   *
   * It is possible for another user thread to see the syscall being done early -
   * they just need to be careful with the weird proc management calls (as in,
@@@ -223,14 -222,13 +224,14 @@@ static ssize_t sys_cputs(struct proc *p
  
  // Read a character from the system console.
  // Returns the character.
 +/* TODO: remove me */
  static uint16_t sys_cgetc(struct proc *p)
  {
        uint16_t c;
  
 -      // The cons_getc() primitive doesn't wait for a character,
 +      // The cons_get_any_char() primitive doesn't wait for a character,
        // but the sys_cgetc() system call does.
 -      while ((c = cons_getc()) == 0)
 +      while ((c = cons_get_any_char()) == 0)
                cpu_relax();
  
        return c;
@@@ -246,7 -244,7 +247,7 @@@ static uint32_t sys_getpcoreid(void
  // this is removed from the user interface
  static size_t sys_getvcoreid(struct proc *p)
  {
 -      return proc_get_vcoreid(p, core_id());
 +      return proc_get_vcoreid(p);
  }
  
  /************** Process management syscalls **************/
@@@ -313,31 -311,29 +314,31 @@@ static error_t sys_proc_run(struct pro
        struct proc *target = pid2proc(pid);
        error_t retval = 0;
  
 -      if (!target)
 -              return -EBADPROC;
 -      // note we can get interrupted here. it's not bad.
 -      spin_lock(&p->proc_lock);
 -      // make sure we have access and it's in the right state to be activated
 +      if (!target) {
 +              set_errno(ESRCH);
 +              return -1;
 +      }
 +      /* make sure we have access and it's in the right state to be activated */
        if (!proc_controls(p, target)) {
 -              proc_decref(target);
 -              retval = -EPERM;
 +              set_errno(EPERM);
 +              goto out_error;
        } else if (target->state != PROC_CREATED) {
 -              proc_decref(target);
 -              retval = -EINVAL;
 -      } else {
 -              __proc_set_state(target, PROC_RUNNABLE_S);
 -              schedule_scp(target);
 +              set_errno(EINVAL);
 +              goto out_error;
        }
 -      spin_unlock(&p->proc_lock);
 +      /* Note a proc can spam this for someone it controls.  Seems safe - if it
 +       * isn't we can change it. */
 +      proc_wakeup(target);
        proc_decref(target);
 -      return retval;
 +      return 0;
 +out_error:
 +      proc_decref(target);
 +      return -1;
  }
  
  /* Destroy proc pid.  If this is called by the dying process, it will never
   * return.  o/w it will return 0 on success, or an error.  Errors include:
 - * - EBADPROC: if there is no such process with pid
 + * - ESRCH: if there is no such process with pid
   * - EPERM: if caller does not control pid */
  static error_t sys_proc_destroy(struct proc *p, pid_t pid, int exitcode)
  {
        proc_destroy(p_to_die);
        /* we only get here if we weren't the one to die */
        proc_decref(p_to_die);
 -      return ESUCCESS;
 +      return 0;
  }
  
  static int sys_proc_yield(struct proc *p, bool being_nice)
  {
 +      struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
        /* proc_yield() often doesn't return - we need to set the syscall retval
         * early.  If it doesn't return, it expects to eat our reference (for now).
         */
 -      finish_current_sysc(0);
 +      finish_sysc(pcpui->cur_sysc, pcpui->cur_proc);
 +      pcpui->cur_sysc = 0;    /* don't touch sysc again */
        proc_incref(p, 1);
        proc_yield(p, being_nice);
        proc_decref(p);
 -      return 0;
 +      /* Shouldn't return, to prevent the chance of mucking with cur_sysc. */
 +      smp_idle();
 +      assert(0);
  }
  
 -static void sys_change_vcore(struct proc *p, uint32_t vcoreid,
 +static int sys_change_vcore(struct proc *p, uint32_t vcoreid,
                               bool enable_my_notif)
  {
 -      struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
 -      /* Change to vcore may start the vcore up remotely before we can finish the
 -       * async syscall, so we need to finish the sysc and not touch the struct.
 -       * Note this sysc has no return value. */
 -      finish_sysc(pcpui->cur_sysc, pcpui->cur_proc);
 -      pcpui->cur_sysc = 0;    /* don't touch sysc again */
 -      proc_change_to_vcore(p, vcoreid, enable_my_notif);
 -      /* Shouldn't return, to prevent the chance of mucking with cur_sysc.
 -       * smp_idle will make sure we run the appropriate cur_tf (which will be the
 -       * new vcore for successful calls). */
 -      smp_idle();
 +      /* Note retvals can be negative, but we don't mess with errno in case
 +       * callers use this in low-level code and want to extract the 'errno'. */
 +      return proc_change_to_vcore(p, vcoreid, enable_my_notif);
  }
  
  static ssize_t sys_fork(env_t* e)
  {
 +      struct proc *temp;
        int8_t state = 0;
        // TODO: right now we only support fork for single-core processes
        if (e->state != PROC_RUNNING_S) {
        env->env_tf = *current_tf;
        enable_irqsave(&state);
  
 -      /* We need to speculatively say the syscall worked before copying the memory
 -       * out, since the 'forked' process's call never actually goes through the
 -       * syscall return path, and will never think it is done.  This violates a
 -       * few things.  Just be careful with fork. */
 -      finish_current_sysc(0);
 -
        env->cache_colors_map = cache_colors_map_alloc();
        for(int i=0; i < llc_cache->num_colors; i++)
                if(GET_BITMASK_BIT(e->cache_colors_map,i))
                set_errno(ENOMEM);
                return -1;
        }
 +      /* Switch to the new proc's address space and finish the syscall.  We'll
 +       * never naturally finish this syscall for the new proc, since its memory
 +       * is cloned before we return for the original process.  If we ever do CoW
 +       * for forked memory, this will be the first place that gets CoW'd. */
 +      temp = switch_to(env);
 +      finish_current_sysc(0);
 +      switch_back(env, temp);
  
        /* In general, a forked process should be a fresh process, and we copy over
         * whatever stuff is needed between procinfo/procdata. */
        #endif
  
        clone_files(&e->open_files, &env->open_files);
 +      /* FYI: once we call ready, the proc is open for concurrent usage */
        __proc_ready(env);
 -      __proc_set_state(env, PROC_RUNNABLE_S);
 -      schedule_scp(env);
 +      proc_wakeup(env);
  
        // don't decref the new process.
        // that will happen when the parent waits for it.
        // TODO: if the parent doesn't wait, we need to change the child's parent
        // when the parent dies, or at least decref it
  
 -      printd("[PID %d] fork PID %d\n",e->pid,env->pid);
 +      printd("[PID %d] fork PID %d\n", e->pid, env->pid);
        return env->pid;
  }
  
@@@ -547,12 -545,12 +548,12 @@@ mid_error
  early_error:
        finish_current_sysc(-1);
  success:
 -      /* Here's how we'll restart the new (or old) process: */
 +      /* Here's how we restart the new (on success) or old (on failure) proc: */
        spin_lock(&p->proc_lock);
        __unmap_vcore(p, 0);    /* VC# keep in sync with proc_run_s */
 -      __proc_set_state(p, PROC_RUNNABLE_S);
 -      schedule_scp(p);
 +      __proc_set_state(p, PROC_WAITING);      /* fake a yield */
        spin_unlock(&p->proc_lock);
 +      proc_wakeup(p);
  all_out:
        /* we can't return, since we'd write retvals to the old location of the
         * syscall struct (which has been freed and is in the old userspace) (or has
        smp_idle();                             /* will reenable interrupts */
  }
  
 -static ssize_t sys_trywait(env_t* e, pid_t pid, int* status)
 -{
 -      /* TODO:
 -       * - WAIT should handle stop and start via signal too
 -       *      - what semantics?  need a wait for every change to state?  etc.
 -       * - should have an option for WNOHANG, and a bunch of other things.
 -       * - think about what functions we want to work with MCPS
 -       *   */
 -      struct proc* p = pid2proc(pid);
 +/* Helper, will attempt a particular wait on a proc.  Returns the pid of the
 + * process if we waited on it successfully, and the status will be passed back
 + * in ret_status (kernel memory).  Returns 0 if the wait failed and we should
 + * try again.  Returns -1 if we should abort.  Only handles DYING.  Callers
 + * need to lock to protect the children tailq and reaping bits. */
 +static pid_t try_wait(struct proc *parent, struct proc *child, int *ret_status,
 +                      int options)
 +{
 +      if (child->state == PROC_DYING) {
 +              /* Disown returns -1 if it's already been disowned or we should o/w
 +               * abort.  This can happen if we have concurrent waiters, both with
 +               * pointers to the child (only one should reap).  Note that if we don't
 +               * do this, we could go to sleep and never receive a cv_signal. */
 +              if (__proc_disown_child(parent, child))
 +                      return -1;
 +              /* despite disowning, the child won't be freed til we drop this ref
 +               * held by this function, so it is safe to access the memory.
 +               *
 +               * Note the exit code one byte in the 0xff00 spot.  Check out glibc's
 +               * posix/sys/wait.h and bits/waitstatus.h for more info.  If we ever
 +               * deal with signalling and stopping, we'll need to do some more work
 +               * here.*/
 +              *ret_status = (child->exitcode & 0xff) << 8;
 +              return child->pid;
 +      }
 +      return 0;
 +}
  
 -      // TODO: this syscall is racy, so we only support for single-core procs
 -      if(e->state != PROC_RUNNING_S)
 +/* Helper, like try_wait, but attempts a wait on any of the children, returning
 + * the specific PID we waited on, 0 to try again (a waitable exists), and -1 to
 + * abort (no children/waitables exist).  Callers need to lock to protect the
 + * children tailq and reaping bits.*/
 +static pid_t try_wait_any(struct proc *parent, int *ret_status, int options)
 +{
 +      struct proc *i, *temp;
 +      pid_t retval;
 +      if (TAILQ_EMPTY(&parent->children))
                return -1;
 +      /* Could have concurrent waiters mucking with the tailq, caller must lock */
 +      TAILQ_FOREACH_SAFE(i, &parent->children, sibling_link, temp) {
 +              retval = try_wait(parent, i, ret_status, options);
 +              /* This catches a thread causing a wait to fail but not taking the
 +               * child off the list before unlocking.  Should never happen. */
 +              assert(retval != -1);
 +              /* Succeeded, return the pid of the child we waited on */
 +              if (retval)
 +                      return retval;
 +      }
 +      assert(retval == 0);
 +      return 0;
 +}
  
 -      // TODO: need to use errno properly.  sadly, ROS error codes conflict..
 -
 -      if(p)
 -      {
 -              ssize_t ret;
 -
 -              if(current->pid == p->ppid)
 -              {
 -                      /* Block til there is some activity */
 -                      if (!(p->state == PROC_DYING)) {
 -                              sleep_on(&p->state_change);
 -                      }
 -                      if(p->state == PROC_DYING)
 -                      {
 -                              memcpy_to_user(e,status,&p->exitcode,sizeof(int));
 -                              printd("[PID %d] waited for PID %d (code %d)\n",
 -                                     e->pid,p->pid,p->exitcode);
 -                              ret = 0;
 -                      }
 -                      else // not dead yet
 -                      {
 -                              warn("Should not have reached here.");
 -                              set_errno(ESUCCESS);
 -                              ret = -1;
 -                      }
 -              }
 -              else // not a child of the calling process
 -              {
 -                      set_errno(EPERM);
 -                      ret = -1;
 -              }
 +/* Waits on a particular child, returns the pid of the child waited on, and
 + * puts the ret status in *ret_status.  Returns the pid if we succeeded, 0 if
 + * the child was not waitable and WNOHANG, and -1 on error. */
 +static pid_t wait_one(struct proc *parent, struct proc *child, int *ret_status,
 +                      int options)
 +{
 +      pid_t retval;
 +      cv_lock(&parent->child_wait);
 +      /* retval == 0 means we should block */
 +      retval = try_wait(parent, child, ret_status, options);
 +      if ((retval == 0) && (options & WNOHANG))
 +              goto out_unlock;
 +      while (!retval) {
 +              cpu_relax();
 +              cv_wait(&parent->child_wait);
 +              /* If we're dying, then we don't need to worry about waiting.  We don't
 +               * do this yet, but we'll need this outlet when we deal with orphaned
 +               * children and having init inherit them. */
 +              if (parent->state == PROC_DYING)
 +                      goto out_unlock;
 +              /* Any child can wake us up, but we check for the particular child we
 +               * care about */
 +              retval = try_wait(parent, child, ret_status, options);
 +      }
 +      if (retval == -1) {
 +              /* Child was already waited on by a concurrent syscall. */
 +              set_errno(ECHILD);
 +      }
 +      /* Fallthrough */
 +out_unlock:
 +      cv_unlock(&parent->child_wait);
 +      return retval;
 +}
  
 -              // if the wait succeeded, decref twice
 -              if (ret == 0)
 -                      proc_decref(p);
 -              proc_decref(p);
 -              return ret;
 +/* Waits on any child, returns the pid of the child waited on, and puts the ret
 + * status in *ret_status.  Is basically a waitpid(-1, ... );  See wait_one for
 + * more details.  Returns -1 if there are no children to wait on, and returns 0
 + * if there are children and we need to block but WNOHANG was set. */
 +static pid_t wait_any(struct proc *parent, int *ret_status, int options)
 +{
 +      pid_t retval;
 +      cv_lock(&parent->child_wait);
 +      retval = try_wait_any(parent, ret_status, options);
 +      if ((retval == 0) && (options & WNOHANG))
 +              goto out_unlock;
 +      while (!retval) {
 +              cpu_relax();
 +              cv_wait(&parent->child_wait);
 +              if (parent->state == PROC_DYING)
 +                      goto out_unlock;
 +              /* Any child can wake us up from the CV.  This is a linear try_wait
 +               * scan.  If we have a lot of children, we could optimize this. */
 +              retval = try_wait_any(parent, ret_status, options);
        }
 +      if (retval == -1)
 +              assert(TAILQ_EMPTY(&parent->children));
 +      /* Fallthrough */
 +out_unlock:
 +      cv_unlock(&parent->child_wait);
 +      return retval;
 +}
  
 -      set_errno(EPERM);
 -      return -1;
 +/* Note: we only allow waiting on children (no such thing as threads, for
 + * instance).  Right now we only allow waiting on termination (not signals),
 + * and we don't have a way for parents to disown their children (such as
 + * ignoring SIGCHLD, see man 2 waitpid's Notes).
 + *
 + * We don't bother with stop/start signals here, though we can probably build
 + * it in the helper above.
 + *
 + * Returns the pid of who we waited on, or -1 on error, or 0 if we couldn't
 + * wait (WNOHANG). */
 +static pid_t sys_waitpid(struct proc *parent, pid_t pid, int *status,
 +                         int options)
 +{
 +      struct proc *child;
 +      pid_t retval = 0;
 +      int ret_status = 0;
 +
 +      /* -1 is the signal for 'any child' */
 +      if (pid == -1) {
 +              retval = wait_any(parent, &ret_status, options);
 +              goto out;
 +      }
 +      child = pid2proc(pid);
 +      if (!child) {
 +              set_errno(ECHILD);      /* ECHILD also used for no proc */
 +              retval = -1;
 +              goto out;
 +      }
 +      if (!(parent->pid == child->ppid)) {
 +              set_errno(ECHILD);
 +              retval = -1;
 +              goto out_decref;
 +      }
 +      retval = wait_one(parent, child, &ret_status, options);
 +      /* fall-through */
 +out_decref:
 +      proc_decref(child);
 +out:
 +      /* ignoring / don't care about memcpy's retval here. */
 +      if (status)
 +              memcpy_to_user(parent, status, &ret_status, sizeof(ret_status));
 +      printd("[PID %d] waited for PID %d, got retval %d (status 0x%x)\n",
 +             parent->pid, pid, retval, ret_status);
 +      return retval;
  }
  
  /************** Memory Management Syscalls **************/
@@@ -755,43 -650,6 +756,43 @@@ static int sys_shared_page_free(env_t* 
        return -1;
  }
  
 +/* Helper, to do the actual provisioning of a resource to a proc */
 +static int prov_resource(struct proc *target, unsigned int res_type,
 +                         long res_val)
 +{
 +      switch (res_type) {
 +              case (RES_CORES):
 +                      /* in the off chance we have a kernel scheduler that can't
 +                       * provision, we'll need to change this. */
 +                      return provision_core(target, res_val);
 +              default:
 +                      printk("[kernel] received provisioning for unknown resource %d\n",
 +                             res_type);
 +                      set_errno(ENOENT);      /* or EINVAL? */
 +                      return -1;
 +      }
 +}
 +
 +/* Rough syscall to provision res_val of type res_type to target_pid */
 +static int sys_provision(struct proc *p, int target_pid,
 +                         unsigned int res_type, long res_val)
 +{
 +      struct proc *target = pid2proc(target_pid);
 +      int retval;
 +      if (!target) {
 +              if (target_pid == 0)
 +                      return prov_resource(0, res_type, res_val);
 +              /* debugging interface */
 +              if (target_pid == -1)
 +                      print_prov_map();
 +              set_errno(ESRCH);
 +              return -1;
 +      }
 +      retval = prov_resource(target, res_type, res_val);
 +      proc_decref(target);
 +      return retval;
 +}
 +
  /* Untested.  Will notify the target on the given vcore, if the caller controls
   * the target.  Will honor the target's wanted/vcoreid.  u_ne can be NULL. */
  static int sys_notify(struct proc *p, int target_pid, unsigned int ev_type,
        struct event_msg local_msg = {0};
        struct proc *target = pid2proc(target_pid);
        if (!target) {
 -              set_errno(EBADPROC);
 +              set_errno(ESRCH);
                return -1;
        }
        if (!proc_controls(p, target)) {
                        set_errno(EINVAL);
                        return -1;
                }
 +      } else {
 +              local_msg.ev_type = ev_type;
        }
        send_kernel_event(target, &local_msg, 0);
        proc_decref(target);
@@@ -882,12 -738,22 +883,12 @@@ static int sys_halt_core(struct proc *p
   * but that's fine thanks to the async kernel interface. */
  static int sys_change_to_m(struct proc *p)
  {
 -      int retval = 0;
 -      spin_lock(&p->proc_lock);
 -      if (!__proc_is_mcp(p)) {
 -              /* Catch user bugs */
 -              if (!p->procdata->res_req[RES_CORES].amt_wanted) {
 -                      printk("[kernel] process needs to specify amt_wanted\n");
 -                      p->procdata->res_req[RES_CORES].amt_wanted = 1;
 -              }
 -              __proc_change_to_m(p);
 -              /* Tell the ksched about us */
 -              register_mcp(p);
 -      } else {
 -              set_errno(EINVAL);
 +      int retval = proc_change_to_m(p);
 +      /* convert the kernel error code into (-1, errno) */
 +      if (retval) {
 +              set_errno(-retval);
                retval = -1;
        }
 -      spin_unlock(&p->proc_lock);
        return retval;
  }
  
@@@ -1145,6 -1011,7 +1146,6 @@@ static intreg_t sys_fstat(struct proc *
        /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
        if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
                kfree(kbuf);
 -              set_errno(EINVAL);
                return -1;
        }
        kfree(kbuf);
@@@ -1177,6 -1044,7 +1178,6 @@@ static intreg_t stat_helper(struct pro
        /* TODO: UMEM: pin the memory, copy directly, and skip the kernel buffer */
        if (memcpy_to_user_errno(p, u_stat, kbuf, sizeof(struct kstat))) {
                kfree(kbuf);
 -              set_errno(EINVAL);
                return -1;
        }
        kfree(kbuf);
@@@ -1274,30 -1142,17 +1275,30 @@@ intreg_t sys_chmod(struct proc *p, cons
        return retval;
  }
  
 -static intreg_t sys_lseek(struct proc *p, int fd, off_t offset, int whence)
 +/* 64 bit seek, with the off64_t passed in via two (potentially 32 bit) off_ts.
 + * We're supporting both 32 and 64 bit kernels/userspaces, but both use the
 + * llseek syscall with 64 bit parameters. */
 +static intreg_t sys_llseek(struct proc *p, int fd, off_t offset_hi,
 +                           off_t offset_lo, off64_t *result, int whence)
  {
 -      off_t ret;
 +      off64_t retoff = 0;
 +      off64_t tempoff = 0;
 +      int ret = 0;
        struct file *file = get_file_from_fd(&p->open_files, fd);
        if (!file) {
                set_errno(EBADF);
                return -1;
        }
 -      ret = file->f_op->llseek(file, offset, whence);
 +      tempoff = offset_hi;
 +      tempoff <<= 32;
 +      tempoff |= offset_lo;
 +      ret = file->f_op->llseek(file, tempoff, &retoff, whence);
        kref_put(&file->f_kref);
 -      return ret;
 +      if (ret)
 +              return -1;
 +      if (memcpy_to_user_errno(p, result, &retoff, sizeof(off64_t)))
 +              return -1;
 +      return 0;
  }
  
  intreg_t sys_link(struct proc *p, char *old_path, size_t old_l,
@@@ -1341,7 -1196,7 +1342,7 @@@ intreg_t sys_symlink(struct proc *p, ch
                user_memdup_free(p, t_oldpath);
                return -1;
        }
 -      ret = do_symlink(new_path, old_path, S_IRWXU | S_IRWXG | S_IRWXO);
 +      ret = do_symlink(t_newpath, t_oldpath, S_IRWXU | S_IRWXG | S_IRWXO);
        user_memdup_free(p, t_oldpath);
        user_memdup_free(p, t_newpath);
        return ret;
@@@ -1364,6 -1219,7 +1365,6 @@@ intreg_t sys_readlink(struct proc *p, c
        copy_amt = strnlen(symname, buf_l - 1) + 1;
        if (memcpy_to_user_errno(p, u_buf, symname, copy_amt)) {
                kref_put(&path_d->d_kref);
 -              set_errno(EINVAL);
                return -1;
        }
        kref_put(&path_d->d_kref);
@@@ -1441,69 -1297,32 +1442,69 @@@ intreg_t sys_gettimeofday(struct proc *
  
        long long dt = read_tsc();
        /* TODO: This probably wants its own function, using a struct timeval */
 -      int kbuf[2] = {t0+dt/system_timing.tsc_freq,
 +      long kbuf[2] = {t0+dt/system_timing.tsc_freq,
            (dt%system_timing.tsc_freq)*1000000/system_timing.tsc_freq};
  
        return memcpy_to_user_errno(p,buf,kbuf,sizeof(kbuf));
  }
  
 -#define SIZEOF_STRUCT_TERMIOS 60
  intreg_t sys_tcgetattr(struct proc *p, int fd, void *termios_p)
  {
 -      int* kbuf = kmalloc(SIZEOF_STRUCT_TERMIOS,0);
 -      int ret = ufe(tcgetattr,fd,PADDR(kbuf),0,0);
 -      if(ret != -1 && memcpy_to_user_errno(p,termios_p,kbuf,SIZEOF_STRUCT_TERMIOS))
 -              ret = -1;
 +      int retval = 0;
 +      /* TODO: actually support this call on tty FDs.  Right now, we just fake
 +       * what my linux box reports for a bash pty. */
 +      struct termios *kbuf = kmalloc(sizeof(struct termios), 0);
 +      kbuf->c_iflag = 0x2d02;
 +      kbuf->c_oflag = 0x0005;
 +      kbuf->c_cflag = 0x04bf;
 +      kbuf->c_lflag = 0x8a3b;
 +      kbuf->c_line = 0x0;
 +      kbuf->c_ispeed = 0xf;
 +      kbuf->c_ospeed = 0xf;
 +      kbuf->c_cc[0] = 0x03;
 +      kbuf->c_cc[1] = 0x1c;
 +      kbuf->c_cc[2] = 0x7f;
 +      kbuf->c_cc[3] = 0x15;
 +      kbuf->c_cc[4] = 0x04;
 +      kbuf->c_cc[5] = 0x00;
 +      kbuf->c_cc[6] = 0x01;
 +      kbuf->c_cc[7] = 0xff;
 +      kbuf->c_cc[8] = 0x11;
 +      kbuf->c_cc[9] = 0x13;
 +      kbuf->c_cc[10] = 0x1a;
 +      kbuf->c_cc[11] = 0xff;
 +      kbuf->c_cc[12] = 0x12;
 +      kbuf->c_cc[13] = 0x0f;
 +      kbuf->c_cc[14] = 0x17;
 +      kbuf->c_cc[15] = 0x16;
 +      kbuf->c_cc[16] = 0xff;
 +      kbuf->c_cc[17] = 0x00;
 +      kbuf->c_cc[18] = 0x00;
 +      kbuf->c_cc[19] = 0x00;
 +      kbuf->c_cc[20] = 0x00;
 +      kbuf->c_cc[21] = 0x00;
 +      kbuf->c_cc[22] = 0x00;
 +      kbuf->c_cc[23] = 0x00;
 +      kbuf->c_cc[24] = 0x00;
 +      kbuf->c_cc[25] = 0x00;
 +      kbuf->c_cc[26] = 0x00;
 +      kbuf->c_cc[27] = 0x00;
 +      kbuf->c_cc[28] = 0x00;
 +      kbuf->c_cc[29] = 0x00;
 +      kbuf->c_cc[30] = 0x00;
 +      kbuf->c_cc[31] = 0x00;
 +
 +      if (memcpy_to_user_errno(p, termios_p, kbuf, sizeof(struct termios)))
 +              retval = -1;
        kfree(kbuf);
 -      return ret;
 +      return retval;
  }
  
  intreg_t sys_tcsetattr(struct proc *p, int fd, int optional_actions,
                         const void *termios_p)
  {
 -      void* kbuf = user_memdup_errno(p,termios_p,SIZEOF_STRUCT_TERMIOS);
 -      if(kbuf == NULL)
 -              return -1;
 -      int ret = ufe(tcsetattr,fd,optional_actions,PADDR(kbuf),0);
 -      user_memdup_free(p,kbuf);
 -      return ret;
 +      /* TODO: do this properly too.  For now, we just say 'it worked' */
 +      return 0;
  }
  
  /* TODO: we don't have any notion of UIDs or GIDs yet, but don't let that stop a
@@@ -1540,13 -1359,12 +1541,13 @@@ const static struct sys_table_entry sys
        [SYS_change_vcore] = {(syscall_t)sys_change_vcore, "change_vcore"},
        [SYS_fork] = {(syscall_t)sys_fork, "fork"},
        [SYS_exec] = {(syscall_t)sys_exec, "exec"},
 -      [SYS_trywait] = {(syscall_t)sys_trywait, "trywait"},
 +      [SYS_waitpid] = {(syscall_t)sys_waitpid, "waitpid"},
        [SYS_mmap] = {(syscall_t)sys_mmap, "mmap"},
        [SYS_munmap] = {(syscall_t)sys_munmap, "munmap"},
        [SYS_mprotect] = {(syscall_t)sys_mprotect, "mprotect"},
        [SYS_shared_page_alloc] = {(syscall_t)sys_shared_page_alloc, "pa"},
        [SYS_shared_page_free] = {(syscall_t)sys_shared_page_free, "pf"},
 +      [SYS_provision] = {(syscall_t)sys_provision, "provision"},
        [SYS_notify] = {(syscall_t)sys_notify, "notify"},
        [SYS_self_notify] = {(syscall_t)sys_self_notify, "self_notify"},
        [SYS_halt_core] = {(syscall_t)sys_halt_core, "halt_core"},
  #endif
        [SYS_change_to_m] = {(syscall_t)sys_change_to_m, "change_to_m"},
        [SYS_poke_ksched] = {(syscall_t)sys_poke_ksched, "poke_ksched"},
+ // socket related syscalls
+       [SYS_socket] ={(syscall_t)sys_socket, "socket"},
+       [SYS_sendto] ={(syscall_t)sys_sendto, "sendto"},
+       [SYS_recvfrom] ={(syscall_t)sys_recvfrom, "recvfrom"},
+       [SYS_select] ={(syscall_t)sys_select, "select"},
+       [SYS_connect] = {(syscall_t)sys_connect, "connect"},
+       [SYS_send] ={(syscall_t)sys_send, "send"},
+       [SYS_recv] ={(syscall_t)sys_recv, "recvfrom"},
+       [SYS_bind] ={(syscall_t)sys_bind, "bind"},
+       [SYS_accept] ={(syscall_t)sys_accept, "accept"},
+       [SYS_listen] ={(syscall_t)sys_listen, "listen"},
        [SYS_read] = {(syscall_t)sys_read, "read"},
        [SYS_write] = {(syscall_t)sys_write, "write"},
        [SYS_open] = {(syscall_t)sys_open, "open"},
        [SYS_access] = {(syscall_t)sys_access, "access"},
        [SYS_umask] = {(syscall_t)sys_umask, "umask"},
        [SYS_chmod] = {(syscall_t)sys_chmod, "chmod"},
 -      [SYS_lseek] = {(syscall_t)sys_lseek, "lseek"},
 +      [SYS_llseek] = {(syscall_t)sys_llseek, "llseek"},
        [SYS_link] = {(syscall_t)sys_link, "link"},
        [SYS_unlink] = {(syscall_t)sys_unlink, "unlink"},
        [SYS_symlink] = {(syscall_t)sys_symlink, "symlink"},
@@@ -1609,7 -1441,7 +1624,7 @@@ intreg_t syscall(struct proc *p, uintre
        if (systrace_flags & SYSTRACE_ON) {
                if ((systrace_flags & SYSTRACE_ALLPROC) || (proc_is_traced(p))) {
                        coreid = core_id();
 -                      vcoreid = proc_get_vcoreid(p, coreid);
 +                      vcoreid = proc_get_vcoreid(p);
                        if (systrace_flags & SYSTRACE_LOUD) {
                                printk("[%16llu] Syscall %3d (%12s):(%08p, %08p, %08p, %08p, "
                                       "%08p, %08p) proc: %d core: %d vcore: %d\n", read_tsc(),
@@@ -1649,7 -1481,6 +1664,7 @@@ void run_local_syscall(struct syscall *
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
  
        /* TODO: (UMEM) assert / pin the memory for the sysc */
 +      assert(irq_is_enabled());       /* in case we proc destroy */
        user_mem_assert(pcpui->cur_proc, sysc, sizeof(struct syscall),
                        sizeof(uintptr_t), PTE_USER_RW);
        pcpui->cur_sysc = sysc;                 /* let the core know which sysc it is */
diff --combined kern/src/vfs.c
@@@ -1111,16 -1111,16 +1111,16 @@@ struct inode *icache_remove(struct supe
  
  /* File functions */
  
 -/* Read count bytes from the file into buf, starting at *offset, which is increased
 - * accordingly, returning the number of bytes transfered.  Most filesystems will
 - * use this function for their f_op->read.  Note, this uses the page cache.
 - * Want to try out page remapping later on... */
 +/* Read count bytes from the file into buf, starting at *offset, which is
 + * increased accordingly, returning the number of bytes transfered.  Most
 + * filesystems will use this function for their f_op->read.
 + * Note, this uses the page cache. */
  ssize_t generic_file_read(struct file *file, char *buf, size_t count,
 -                          off_t *offset)
 +                          off64_t *offset)
  {
        struct page *page;
        int error;
 -      off_t page_off;
 +      off64_t page_off;
        unsigned long first_idx, last_idx;
        size_t copy_amt;
        char *buf_end;
        return count;
  }
  
 -/* Write count bytes from buf to the file, starting at *offset, which is increased
 - * accordingly, returning the number of bytes transfered.  Most filesystems will
 - * use this function for their f_op->write.  Note, this uses the page cache.
 +/* Write count bytes from buf to the file, starting at *offset, which is
 + * increased accordingly, returning the number of bytes transfered.  Most
 + * filesystems will use this function for their f_op->write.  Note, this uses
 + * the page cache.
 + *
   * Changes don't get flushed to disc til there is an fsync, page cache eviction,
   * or other means of trying to writeback the pages. */
  ssize_t generic_file_write(struct file *file, const char *buf, size_t count,
 -                           off_t *offset)
 +                           off64_t *offset)
  {
        struct page *page;
        int error;
 -      off_t page_off;
 +      off64_t page_off;
        unsigned long first_idx, last_idx;
        size_t copy_amt;
        const char *buf_end;
   * currently expects us to do a readdir (short of doing linux's getdents).  Will
   * probably need work, based on whatever real programs want. */
  ssize_t generic_dir_read(struct file *file, char *u_buf, size_t count,
 -                         off_t *offset)
 +                         off64_t *offset)
  {
        struct kdirent dir_r = {0}, *dirent = &dir_r;
        int retval = 1;
                return 0;
        /* start readdir from where it left off: */
        dirent->d_off = *offset;
 -      for (; (u_buf < buf_end) && (retval == 1); u_buf += sizeof(struct kdirent)){
 +      for (   ;
 +              u_buf + sizeof(struct kdirent) <= buf_end;
 +              u_buf += sizeof(struct kdirent)) {
                /* TODO: UMEM/KFOP (pin the u_buf in the syscall, ditch the local copy,
                 * get rid of this memcpy and reliance on current, etc).  Might be
                 * tricky with the dirent->d_off and trust issues */
                        memcpy(u_buf, dirent, sizeof(struct dirent));
                }
                amt_copied += sizeof(struct dirent);
 +              /* 0 signals end of directory */
 +              if (retval == 0)
 +                      break;
        }
        /* Next time read is called, we pick up where we left off */
        *offset = dirent->d_off;        /* UMEM */
@@@ -1638,16 -1631,23 +1638,24 @@@ out_path_only
        return retval;
  }
  
- /* Opens and returns the file specified by dentry */
- struct file *dentry_open(struct dentry *dentry, int flags)
 -struct file *alloc_file()
++struct file *alloc_file(void)
  {
-       struct inode *inode;
-       int desired_mode;
        struct file *file = kmem_cache_alloc(file_kcache, 0);
        if (!file) {
                set_errno(ENOMEM);
                return 0;
        }
+       /* one for the ref passed out*/
+       kref_init(&file->f_kref, file_release, 1);
+       return file;
+ }
+ /* Opens and returns the file specified by dentry */
+ struct file *dentry_open(struct dentry *dentry, int flags)
+ {
+       struct inode *inode;
++      struct file *file;
+       int desired_mode;
        inode = dentry->d_inode;
        /* Do the mode first, since we can still error out.  f_mode stores how the
         * OS file is open, which can be more restrictive than the i_mode */
        }
        if (check_perms(inode, desired_mode))
                goto error_access;
 -      // Check permission before we allocate file struct      
 -      struct file *file = alloc_file();
 -      if (!file) return 0;
 -
++      file = alloc_file();
++      if (!file)
++              return 0;
        file->f_mode = desired_mode;
-       /* one for the ref passed out, and *none* for the sb TAILQ */
-       kref_init(&file->f_kref, file_release, 1);
        /* Add to the list of all files of this SB */
        TAILQ_INSERT_TAIL(&inode->i_sb->s_files, file, f_list);
        kref_get(&dentry->d_kref, 1);
        file->f_error = 0;
  //    struct event_poll_tailq         f_ep_links;
        spinlock_init(&file->f_ep_lock);
-       file->f_fs_info = 0;                                            /* prob overriden by the fs */
+       file->f_privdata = 0;                                           /* prob overriden by the fs */
        file->f_mapping = inode->i_mapping;
        file->f_op->open(inode, file);
        return file;
  error_access:
        set_errno(EACCES);
-       kmem_cache_free(file_kcache, file);
        return 0;
  }
  
@@@ -1762,7 -1763,6 +1770,6 @@@ struct file *put_file_from_fd(struct fi
        spin_unlock(&open_files->lock);
        return file;
  }
  /* Inserts the file in the files_struct, returning the corresponding new file
   * descriptor, or an error code.  We start looking for open fds from low_fd. */
  int insert_file(struct files_struct *open_files, struct file *file, int low_fd)