Remove all the old proto stack.
authorRonald G. Minnich <rminnich@google.com>
Thu, 16 Jan 2014 19:45:14 +0000 (11:45 -0800)
committerRonald G. Minnich <rminnich@google.com>
Thu, 16 Jan 2014 22:45:37 +0000 (14:45 -0800)
kern/src/net/Kbuild
kern/src/net/Kconfig
kern/src/net/ip.c [deleted file]
kern/src/net/nic_common.c [deleted file]
kern/src/net/pbuf.c [deleted file]
kern/src/net/tcp.c [deleted file]
kern/src/net/tcp_in.c [deleted file]
kern/src/net/tcp_out.c [deleted file]
kern/src/net/tcpip.h [deleted file]
kern/src/net/timers.c [deleted file]
kern/src/net/udp.c [deleted file]

index 12f72d1..e69de29 100644 (file)
@@ -1,8 +0,0 @@
-obj-y                                          += ip.o
-obj-y                                          += nic_common.o
-obj-y                                          += pbuf.o
-obj-y                                          += tcp.o
-obj-y                                          += tcp_in.o
-obj-y                                          += tcp_out.o
-obj-y                                          += timers.o
-obj-y                                          += udp.o
index b2be467..d07dbc4 100644 (file)
@@ -6,19 +6,5 @@ menuconfig NETWORKING
 
 if NETWORKING
 
-config SOCKET
-       bool "Socket support"
-       default y
-       help
-               Early socket work.  Say 'n' if you have issues compiling.
-
-config ETH_AUDIO
-       depends on NETWORKING && X86
-       bool "Ethernet audio"
-       default n
-       help
-               Build old support for David Wessel's ethernet audio device.  This is
-               less a driver than a NIC-level "intercept".
-
 endif # NETWORKING
 
diff --git a/kern/src/net/ip.c b/kern/src/net/ip.c
deleted file mode 100644 (file)
index b2ade7d..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-#include <ros/common.h>
-#include <assert.h>
-#include <socket.h>
-#include <bits/netinet.h>
-#include <net.h>
-#include <net/ip.h>
-#include <net/udp.h>
-#include <net/tcp_impl.h>
-#include <ros/errno.h>
-#include <net/nic_common.h>
-
-/* statically configured next gateway */
-const uint8_t GTWAY[6] = {0xda, 0x76, 0xe7, 0x4c, 0xca, 0x7e};
-
-/* TODO: ip id unique for all ip packets? or is it unique for a flow? */
-// can do atomic increment at a minimum
-static uint16_t ip_id = 0;
-
-/* TODO: build arp table, and look up */
-int eth_send(struct pbuf *p, struct in_addr *dest) {
-       uint32_t bytes_sent; 
-       printk("size of pbuf_header movement %d\n", sizeof(struct ethernet_hdr));
-       if (pbuf_header(p, sizeof(struct ethernet_hdr)) != 0){
-               warn("eth_send buffer ran out");
-               /* unsuccessful, needs to allocate */   
-               return -ENOBUFS;
-       }
-
-       struct ethernet_hdr *ethhdr = (struct ethernet_hdr *)p->payload; 
-       // TODO: for now just forward to gateway
-       memcpy(ethhdr->dst_mac, GTWAY, 6);
-       memcpy(ethhdr->src_mac, device_mac, 6);
-       ethhdr->eth_type = htons(IP_ETH_TYPE);
-       /* The reason for not sending to send_nic for each pbuf in the chain
-        * is so that we can send from multi-buffer later.
-        */
-       if (send_pbuf){
-               bytes_sent = send_pbuf(p);
-               return bytes_sent;
-       }
-       else {
-               warn("no pbuf send function \n");
-               return -1;
-       }
-       /* is the address local , if no, search for MAC of the gateway and dest to gateway */
-       /* if address is local, use arp etc */
-
-}
-
-/* while it would be nice to write a generic send_pbuf it is impossible to do so in
- * efficiently.
- */
-/* Assume no ip options */
-int ip_output(struct pbuf *p, struct in_addr *src, struct in_addr *dest, 
-                                                       uint8_t ttl, uint8_t tos, uint8_t proto) {
-       struct pbuf *q;
-       struct ip_hdr *iphdr;
-       printk ("ip output reached\n");
-       /* TODO: Check for IP_HDRINCL */
-       if (dest->s_addr == IP_HDRINCL) {
-               /*send right away since */
-               warn("header included in the ip packets");
-               return -1;
-       }
-       if (pbuf_header(p, IP_HDR_SZ)) {
-               warn("buffer ran out");
-               /* unsuccessful, needs to allocate */   
-               return -ENOBUFS;
-       }
-       iphdr = (struct ip_hdr *) p->payload;
-
-       /* successful */
-       iphdr->version = IPPROTO_IPV4;
-       /* assume no IP options */
-       iphdr->hdr_len = IP_HDR_SZ >> 2;
-       if (tos != 0) {
-               iphdr->tos = htons(tos);
-       }
-       else {
-               iphdr->tos = 0;
-       }
-       iphdr->packet_len = htons(p->tot_len);
-       // TODO: NET_LOCK
-       iphdr->id = htons (ip_id); // 1
-       ip_id++;
-       iphdr->flags_frags = htons(0); // 4000  may fragment
-       iphdr->protocol = proto;
-       iphdr->ttl = ttl; //DEFAULT_TTL;
-       /* Eventually if we support more than one device this may change */
-       printk("src ip %x, dest ip %x \n", src->s_addr, dest->s_addr);
-       iphdr->src_addr = htonl(src->s_addr);
-       iphdr->dst_addr = (dest->s_addr);
-       /* force hardware checksum
-        * TODO: provide option to do both hardware/software checksum
-        */
-       /* Since the IP header is set already, we can compute the checksum. */
-       /* TODO: Use the card to calculate the checksum */
-       iphdr->checksum = 0;
-       iphdr->checksum = ip_checksum(iphdr); //7ab6
-       if (p->tot_len > DEFAULT_MTU) /*MAX MTU? header included */
-               return -1;//ip_frag(p, dest);
-       else
-               return eth_send(p, dest);
-}
-
-int ip_input(struct pbuf *p) {
-       uint32_t iphdr_hlen, iphdr_len;
-       struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
-       //printk("start of ip %p \n", p->payload);
-       //print_pbuf(p);
-       /* use that info to build arp table */
-  if (iphdr->version != 4) {
-               warn("ip version not 4!\n");
-    pbuf_free(p);
-               return -1;
-       }
-       iphdr_hlen = iphdr->hdr_len * 4;
-       iphdr_len = ntohs(iphdr->packet_len);
-       // printk("ip input coming from %x of size %d", ntohs(iphdr->dst_addr), iphdr_len);
-  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
-  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
-    if (iphdr_hlen > p->len) {
-        warn("IP header (len 0x%X) does not fit in first pbuf (len %X), IP packet dropped.\n",
-        iphdr_hlen, p->len);
-    }
-    if (iphdr_len > p->tot_len) {
-        warn("IP (len %X) is longer than pbuf (len %X), IP packet dropped.\n",
-        iphdr_len, p->tot_len);
-    }
-    /* free (drop) packet pbufs */
-    pbuf_free(p);
-    return -1;
-  }
-       if (ip_checksum(iphdr) != 0) {
-               warn("checksum failed \n");
-               pbuf_free(p);
-               return -1;
-       }
-
-       /* check if it is destined for me? */
-       /* XXX: IP address for the interface is IP_ANY */
-       if (ntohl(iphdr->dst_addr) != LOCAL_IP_ADDR.s_addr){
-               printk("dest ip in network order%x\n", ntohl(iphdr->dst_addr));
-               printk("dest ip in network order%x\n", LOCAL_IP_ADDR.s_addr);
-               warn("ip mismatch \n");
-               pbuf_free(p);
-               /* TODO:forward packets */
-               // ip_forward(p, iphdr, inp);
-       }
-
-       if ((ntohs(iphdr->flags_frags) & (IP_OFFMASK | IP_MF)) != 0){
-               panic ("ip fragment detected\n");
-               pbuf_free(p);
-       }
-
-       //printk ("loc head %p, loc protocol %p\n", iphdr, &iphdr->protocol);
-       /* currently a noop, compared to the memory wasted, cutting out ipheader is not really saving much */
-       // pbuf_realloc(p, iphdr_len);
-       switch (iphdr->protocol) {
-               case IPPROTO_UDP:
-                       return udp_input(p);
-               case IPPROTO_TCP:
-                       tcp_input(p);
-                       // XXX: error handling for tcp
-                       return 0;
-               default:
-                       printk("IP protocol type %02x\n", iphdr->protocol);
-                       warn("protocol not supported! \n");
-       }
-       return -1;
-}
-
-void print_ipheader(struct ip_hdr* iph){
-
-       
-}
-
-
diff --git a/kern/src/net/nic_common.c b/kern/src/net/nic_common.c
deleted file mode 100644 (file)
index e854c9e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/** @file
- * @brief Common Nic Variables
- *
- * See Info below 
- *
- * @author Paul Pearce <pearce@eecs.berkeley.edu>
- *
- */
-
-#ifdef __SHARC__
-#pragma nosharc
-#endif
-
-#include <net/nic_common.h>
-#include <kmalloc.h>
-#include <stdio.h>
-
-// 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 
-// limited to only one for now
-unsigned char device_mac[6];
-uint8_t eth_up = 0; 
-uint32_t num_packet_buffers = 0;
-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_IRQSAVE;
-
diff --git a/kern/src/net/pbuf.c b/kern/src/net/pbuf.c
deleted file mode 100644 (file)
index 788474b..0000000
+++ /dev/null
@@ -1,1028 +0,0 @@
-#include <ros/common.h>
-#include <stdio.h>
-
-#include <string.h>
-#include <kmalloc.h>
-#include <slab.h>
-#include <assert.h>
-#include <net/pbuf.h>
-#include <sys/queue.h>
-#include <net.h>
-#include <debug.h>
-#include <net/nic_common.h>
-
-
-/* TODO: before running
- * 1. pbuf_free_auto currently decrefs the next one on the chain or queue
- * 2. copy_out currently copies out the chain following the next pointer
- *    could be dangerous if it runs on pbufs on a send/recv socket queue
- * 3. Tot_len could be useless at some point, especially if the max len is only two...
- * 4. pbuf_chain and pbuf_cat, pbuf_clen has no users yet
- */
-#define MTU_PBUF_SIZE (sizeof(struct pbuf) + MAX_FRAME_SIZE + ETH_PAD_SIZE)
-
-struct kmem_cache *pbuf_kcache;
-struct kmem_cache *mtupbuf_kcache;
-
-
-void pbuf_init(void){
-       pbuf_kcache = kmem_cache_create("pbuf", sizeof(struct pbuf),
-                                                                       __alignof__(struct pbuf), 0, 0, 0);
-  mtupbuf_kcache = kmem_cache_create("mtupbuf_kcache", MTU_PBUF_SIZE, 
-                                                                               __alignof__(struct pbuf), 0, 0, 0);
-}
-
-static void pbuf_free_auto(struct kref *kref){
-    struct pbuf *p = container_of(kref, struct pbuf, bufref);
-               if (!p) return;
-               struct pbuf *q = STAILQ_NEXT(p, next);
-               printd("deleting p %p of type %d\n", p, p->type);
-    switch (p->type){
-        case PBUF_REF:
-            kmem_cache_free(pbuf_kcache, p);
-            break;
-        case PBUF_RAM:
-            kfree(p);
-            break;
-                               case PBUF_MTU:
-                                               kmem_cache_free(mtupbuf_kcache,p);
-                                               break;
-        default:
-            panic("Invalid pbuf type");
-    }
-               if (q != NULL) 
-                       pbuf_deref(q);
-}
-
-/**
- * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
- *
- * The actual memory allocated for the pbuf is determined by the
- * layer at which the pbuf is allocated and the requested size
- * (from the size parameter).
- *
- * @param layer flag to define header size
- * @param length size of the pbuf's payload
- * @param type this parameter decides how and where the pbuf
- * should be allocated as follows:
- *
- * - PBUF_RAM: buffer memory for pbuf is allocated as one large
- *             chunk. This includes protocol headers as well.
- * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
- *             protocol headers. Additional headers must be prepended
- *             by allocating another pbuf and chain in to the front of
- *             the ROM pbuf. It is assumed that the memory used is really
- *             similar to ROM in that it is immutable and will not be
- *             changed. Memory which is dynamic should generally not
- *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.
- * - PBUF_REF: no buffer memory is allocated for the pbuf, even for
- *             protocol headers. It is assumed that the pbuf is only
- *             being used in a single thread. If the pbuf gets queued,
- *             then pbuf_take should be called to copy the buffer.
- * - PBUF_MTU: specific to ROS, additional type that comes out of a 
- *             slab dedicated for the most common size (MTU sized) pbuf.
- *
- * @return the allocated pbuf. If multiple pbufs where allocated, this
- * is the first pbuf of a pbuf chain.
- */
-struct pbuf *pbuf_alloc(pbuf_layer layer, uint16_t length, pbuf_type type)
-{
-  struct pbuf *p, *q, *r;
-  uint16_t offset;
-       uint16_t buf_size; 
-  int rem_len; /* remaining length */
-
-  /* determine header offset */
-  offset = 0;
-  switch (layer) {
-  case PBUF_TRANSPORT:
-    /* add room for transport (often TCP) layer header */
-    offset += PBUF_TRANSPORT_HLEN;
-    /* FALLTHROUGH */
-  case PBUF_IP:
-    /* add room for IP layer header */
-    offset += PBUF_IP_HLEN;
-    /* FALLTHROUGH */
-  case PBUF_LINK:
-    /* add room for link layer header */
-    offset += PBUF_LINK_HLEN;
-    break;
-  case PBUF_RAW:
-    break;
-  default:
-    warn("pbuf_alloc: bad pbuf layer", 0);
-    return NULL;
-  }
-       
-  switch (type) {
-       case PBUF_MTU:
-               /* special case PBUFs that are of a common size, notice the length has to be 0 in this case */
-               assert(length==0); // TODO: reconsider this
-    /* only allocate memory for the pbuf structure */
-    p = (struct pbuf *)kmem_cache_alloc(mtupbuf_kcache, 0);
-    if (p == NULL) {
-      return NULL;
-    }
-    p->payload = (void *)((uint8_t *)p + sizeof(struct pbuf) + offset);
-               STAILQ_NEXT(p, next) = NULL;
-               p->type = type;
-               p->alloc_len = MTU_PBUF_SIZE;
-               p->len = p->tot_len = 0;
-               break;
-
-       case PBUF_RAM:
-    /* If pbuf is to be allocated in RAM, allocate memory for it. */
-    buf_size =  (sizeof(struct pbuf) + offset) + ROUNDUP(length, sizeof(void*));
-    p = (struct pbuf*)kmalloc(buf_size, 0);
-
-    if (p == NULL) {
-      return NULL;
-    }
-    /* Set up internal structure of the pbuf. */
-    p->payload = (void *)((uint8_t *)p + sizeof(struct pbuf) + offset);
-    p->alloc_len = p->len = p->tot_len = length;
-               STAILQ_NEXT(p, next) = NULL;
-    p->type = type;
-    break;
-  case PBUF_REF:
-    /* only allocate memory for the pbuf structure */
-    p = (struct pbuf *)kmem_cache_alloc(pbuf_kcache, 0);
-    if (p == NULL) {
-      return NULL;
-    }
-    p->payload = NULL;
-    p->alloc_len = p->len = p->tot_len = length;
-               STAILQ_NEXT(p, next) = NULL;
-    p->type = type;
-    break;
-       case PBUF_POOL:
-               warn("POOL type not supported!");       
-               return NULL;    
-  default:
-    warn("pbuf_alloc: wrong type", 0);
-    return NULL;
-  }
-  kref_init(&p->bufref, pbuf_free_auto, 1); // TODO: pbuf_free
-  /* set flags */
-  p->flags = 0;
-  return p;
-}
-
-
-/**
- * Shrink a pbuf chain to a desired length.
- *
- * @param p pbuf to shrink.
- * @param new_len desired new length of pbuf chain
- *
- * Depending on the desired length, the first few pbufs in a chain might
- * be skipped and left unchanged. The new last pbuf in the chain will be
- * resized, and any remaining pbufs will be freed.
- *
- * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
- * @note May not be called on a packet queue.
- *
- * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
- */
-void
-pbuf_realloc(struct pbuf *p, uint16_t new_len)
-{
-  struct pbuf *q;
-  uint16_t rem_len; /* remaining length */
-  int32_t grow;
-
-  /* desired length larger than current length? */
-  if (new_len >= p->tot_len) {
-    /* enlarging not yet supported */
-    return;
-  }
-
-  /* the pbuf chain grows by (new_len - p->tot_len) bytes
-   * (which may be negative in case of shrinking) */
-  grow = new_len - p->tot_len;
-
-  /* first, step over any pbufs that should remain in the chain */
-  rem_len = new_len;
-  q = p;
-  /* should this pbuf be kept? */
-  while (rem_len > q->len) {
-    /* decrease remaining length by pbuf length */
-    rem_len -= q->len;
-    /* decrease total length indicator */
-    LWIP_ASSERT("grow < max_uint16_t", grow < 0xffff);
-    q->tot_len += (uint16_t)grow;
-    /* proceed to next pbuf in chain */
-               q = STAILQ_NEXT(q, next);
-    LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
-  }
-  /* we have now reached the new last pbuf (in q) */
-  /* rem_len == desired length for pbuf q */
-
-  /* adjust length fields for new last pbuf */
-  q->len = rem_len;
-  q->tot_len = q->len;
-
-  /* any remaining pbufs in chain? */
-  if (STAILQ_NEXT(q, next) != NULL) {
-    /* free remaining pbufs in chain */
-               pbuf_free(STAILQ_NEXT(q, next));
-  }
-  /* q is last packet in chain */
-       STAILQ_NEXT(q, next) = NULL;
-}
-
-void pbuf_ref(struct pbuf *p){
-       kref_get(&p->bufref, 1);
-}
-
-/**
- * true if the pbuf is deallocated as a result of pbuf_deref
- * false means just a simple deref
- */
-bool pbuf_deref(struct pbuf *p){
-       return kref_put(&p->bufref);
-}
-
-void attach_pbuf(struct pbuf *p, struct pbuf_head *ph){
-       spin_lock_irqsave(&ph->lock);
-       ph->qlen++;
-       pbuf_ref(p);
-       STAILQ_INSERT_TAIL(&ph->pbuf_fifo, p, next);
-       spin_unlock_irqsave(&ph->lock);
-}
-
-struct pbuf* detach_pbuf(struct pbuf_head *ph){
-       struct pbuf* buf = NULL;
-       if (ph->qlen == 0) return NULL;
-       spin_lock_irqsave(&ph->lock);
-       ph->qlen--;
-       buf = STAILQ_FIRST(&ph->pbuf_fifo);
-       STAILQ_REMOVE_HEAD(&ph->pbuf_fifo, next);
-       spin_unlock_irqsave(&ph->lock);
-       return buf;
-}
-
-/**
- * Copy (part of) the contents of a packet buffer
- * to an application supplied buffer.
- *
- * @param buf the pbuf from which to copy data
- * @param dataptr the application supplied buffer
- * @param len length of data to copy (dataptr must be big enough). No more 
- * than buf->tot_len will be copied, irrespective of len
- * @param offset offset into the packet buffer from where to begin copying len bytes
- * @return the number of bytes copied, or 0 on failure
- */
-int pbuf_copy_out(struct pbuf *buf, void *dataptr, size_t len, uint16_t offset)
-{
-  struct pbuf *p;
-  uint16_t left;
-  uint16_t buf_copy_len;
-  uint16_t copied_total = 0;
-       
-       if (dataptr == NULL || buf == NULL){
-               warn("Copying a pbuf_copy to null pointer");
-               return 0;
-       }
-
-  left = 0;
-  for(p = buf; len != 0 && p != NULL; p = STAILQ_NEXT(p, next)) {
-    if ((offset != 0) && (offset >= p->len)) {
-      /* don't copy from this buffer -> on to the next */
-      offset -= p->len;
-    } else {
-                       /* offset is 0 now, start copying */
-      buf_copy_len = p->len - offset;
-      if (buf_copy_len > len)
-          buf_copy_len = len;
-      /* copy the necessary parts of the buffer */
-      memcpy(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);
-      copied_total += buf_copy_len;
-      left += buf_copy_len;
-      len -= buf_copy_len;
-      offset = 0;
-    }
-  }
-  return copied_total;
-}
-
-/**
- * Chain two pbufs (or pbuf chains) together.
- * 
- * The caller MUST call pbuf_free(t) once it has stopped
- * using it. Use pbuf_cat() instead if you no longer use t.
- * 
- * @param h head pbuf (chain)
- * @param t tail pbuf (chain)
- * @note The pbufs MUST belong to the same packet.
- * @note MAY NOT be called on a packet queue.
- *
- * The ->tot_len fields of all pbufs of the head chain are adjusted.
- * The ->next field of the last pbuf of the head chain is adjusted.
- * The ->ref field of the first pbuf of the tail chain is adjusted.
- *
- */
-void
-pbuf_chain(struct pbuf *h, struct pbuf *t)
-{
-  pbuf_cat(h, t);
-  /* t is now referenced by h */
-  pbuf_ref(t);
-}
-
-void
-pbuf_cat(struct pbuf *h, struct pbuf *t)
-{
-  struct pbuf *p;
-  /* proceed to last pbuf of chain */
-  for (p = h; STAILQ_NEXT(p, next) != NULL; p = STAILQ_NEXT(p, next)) {
-    /* add total length of second chain to all totals of first chain */
-    p->tot_len += t->tot_len;
-  }
-  /* add total length of second chain to last pbuf total of first chain */
-  p->tot_len += t->tot_len;
-  /* chain last pbuf of head (p) with first of tail (t) */
-       STAILQ_NEXT(p,next) = t;
-}
-
-/**
- * Adjusts the payload pointer to hide or reveal headers in the payload.
- *
- * Adjusts the ->payload pointer so that space for a header
- * (dis)appears in the pbuf payload.
- *
- * The ->payload, ->tot_len and ->len fields are adjusted.
- *
- * @param p pbuf to change the header size.
- * @param header_size_increment Number of bytes to increment header size which
- * increases the size of the pbuf. New space is on the front.
- * (Using a negative value decreases the header size.)
- * If hdr_size_inc is 0, this function does nothing and returns succesful.
- *
- * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so
- * the call will fail. A check is made that the increase in header size does
- * not move the payload pointer in front of the start of the buffer.
- * @return non-zero on failure, zero on success.
- *
- */
-
-/* TODO: when do we need to lock a pbuf?? */
-int pbuf_header(struct pbuf *p, int delta){ // increase header size
-       uint8_t type = p->type;
-       void *payload = p->payload;
-       if (p == NULL || delta == 0)
-               return 0;
-       // This assertion used to apply when len meant allocated space..
-       // assert(-delta < p->len);
-
-  /* pbuf types containing payloads? */
-  if (type == PBUF_RAM || type == PBUF_POOL || type == PBUF_MTU) {
-    /* set new payload pointer */
-    p->payload = (uint8_t *)p->payload - delta;
-    /* boundary check fails? */
-    if ((uint8_t *)p->payload < (uint8_t *)p + sizeof(struct pbuf)) {
-      /* restore old payload pointer */
-      p->payload = payload;
-                       warn("boundary failed \n");
-      /* bail out unsuccesfully */
-      return 1;
-    }
-  /* pbuf types refering to external payloads? */
-  } else if (type == PBUF_REF || type == PBUF_ROM) {
-               /* header was embedded in the payload, we are extracting it */
-    if ((delta < 0) && ((-delta) <= p->len)) {
-      /* increase payload pointer */
-      p->payload = (uint8_t *)p->payload - delta;
-    } else {
-      /* cannot expand payload to front (yet!)
-       * bail out unsuccesfully */
-      return 1;
-    }
-  } else {
-    /* Unknown type */
-    assert("bad pbuf type");
-    return 1;
-  }
-  /* modify pbuf length fields */
-  p->len += delta;
-  p->tot_len += delta;
-
-  return 0;
-}
-
-void print_pbuf(struct pbuf *p) {
-       struct pbuf *next = p;
-       //basically while pbuf is not on the socket queue yet, we can't use STAILQ_NEXT 
-
-       /*XXX: this is wrong.. */
-       while (next != NULL) {
-               printk("pbuf start \n");
-               dumppacket(next->payload, next->len);
-               printk("\n");
-               next = STAILQ_NEXT(next, next);
-       }
-}
-
-
-/**
- * Dereference a pbuf chain or queue and deallocate any no-longer-used
- * pbufs at the head of this chain or queue.
- *
- * Decrements the pbuf reference count. If it reaches zero, the pbuf is
- * deallocated.
- *
- * For a pbuf chain, this is repeated for each pbuf in the chain,
- * up to the first pbuf which has a non-zero reference count after
- * decrementing. So, when all reference counts are one, the whole
- * chain is free'd.
- *
- * @param p The pbuf (chain) to be dereferenced.
- *
- * @return the number of pbufs that were de-allocated
- * from the head of the chain.
- *
- *
- */
-bool pbuf_free(struct pbuf *p) {
-       return pbuf_deref(p);
-}
-
-/**
- * Count number of pbufs in a chain
- *
- * @param p first pbuf of chain
- * @return the number of pbufs in a chain
- */
-
-uint8_t pbuf_clen(struct pbuf *p)
-{
-  uint8_t len;
-
-  len = 0;
-  while (p != NULL) {
-    ++len;
-    p = STAILQ_NEXT(p, next);
-  }
-  return len;
-}
-
-
-#if 0
-#if LWIP_SUPPORT_CUSTOM_PBUF
-/** Initialize a custom pbuf (already allocated).
- *
- * @param layer flag to define header size
- * @param length size of the pbuf's payload
- * @param type type of the pbuf (only used to treat the pbuf accordingly, as
- *        this function allocates no memory)
- * @param p pointer to the custom pbuf to initialize (already allocated)
- * @param payload_mem pointer to the buffer that is used for payload and headers,
- *        must be at least big enough to hold 'length' plus the header size,
- *        may be NULL if set later
- * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least
- *        big enough to hold 'length' plus the header size
- */
-struct pbuf*
-pbuf_alloced_custom(pbuf_layer l, uint16_t length, pbuf_type type, struct pbuf_custom *p,
-                    void *payload_mem, uint16_t payload_mem_len)
-{
-  uint16_t offset;
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length));
-
-  /* determine header offset */
-  offset = 0;
-  switch (l) {
-  case PBUF_TRANSPORT:
-    /* add room for transport (often TCP) layer header */
-    offset += PBUF_TRANSPORT_HLEN;
-    /* FALLTHROUGH */
-  case PBUF_IP:
-    /* add room for IP layer header */
-    offset += PBUF_IP_HLEN;
-    /* FALLTHROUGH */
-  case PBUF_LINK:
-    /* add room for link layer header */
-    offset += PBUF_LINK_HLEN;
-    break;
-  case PBUF_RAW:
-    break;
-  default:
-    LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0);
-    return NULL;
-  }
-
-  if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) {
-    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length));
-    return NULL;
-  }
-
-  p->pbuf.next = NULL;
-  if (payload_mem != NULL) {
-    p->pbuf.payload = LWIP_MEM_ALIGN((void *)((uint8_t *)payload_mem + offset));
-  } else {
-    p->pbuf.payload = NULL;
-  }
-  p->pbuf.flags = PBUF_FLAG_IS_CUSTOM;
-  p->pbuf.len = p->pbuf.tot_len = length;
-  p->pbuf.type = type;
-  p->pbuf.ref = 1;
-  return &p->pbuf;
-}
-#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
-
-/**
- * Shrink a pbuf chain to a desired length.
- *
- * @param p pbuf to shrink.
- * @param new_len desired new length of pbuf chain
- *
- * Depending on the desired length, the first few pbufs in a chain might
- * be skipped and left unchanged. The new last pbuf in the chain will be
- * resized, and any remaining pbufs will be freed.
- *
- * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.
- * @note May not be called on a packet queue.
- *
- * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).
- */
-void
-pbuf_realloc(struct pbuf *p, uint16_t new_len)
-{
-  struct pbuf *q;
-  uint16_t rem_len; /* remaining length */
-  int32_t grow;
-
-  LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
-  LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
-              p->type == PBUF_ROM ||
-              p->type == PBUF_RAM ||
-              p->type == PBUF_REF);
-
-  /* desired length larger than current length? */
-  if (new_len >= p->tot_len) {
-    /* enlarging not yet supported */
-    return;
-  }
-
-  /* the pbuf chain grows by (new_len - p->tot_len) bytes
-   * (which may be negative in case of shrinking) */
-  grow = new_len - p->tot_len;
-
-  /* first, step over any pbufs that should remain in the chain */
-  rem_len = new_len;
-  q = p;
-  /* should this pbuf be kept? */
-  while (rem_len > q->len) {
-    /* decrease remaining length by pbuf length */
-    rem_len -= q->len;
-    /* decrease total length indicator */
-    LWIP_ASSERT("grow < max_uint16_t", grow < 0xffff);
-    q->tot_len += (uint16_t)grow;
-    /* proceed to next pbuf in chain */
-    q = q->next;
-    LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
-  }
-  /* we have now reached the new last pbuf (in q) */
-  /* rem_len == desired length for pbuf q */
-
-  /* shrink allocated memory for PBUF_RAM */
-  /* (other types merely adjust their length fields */
-  if ((q->type == PBUF_RAM) && (rem_len != q->len)) {
-    /* reallocate and adjust the length of the pbuf that will be split */
-    q = (struct pbuf *)mem_trim(q, (uint16_t)((uint8_t *)q->payload - (uint8_t *)q) + rem_len);
-    LWIP_ASSERT("mem_trim returned q == NULL", q != NULL);
-  }
-  /* adjust length fields for new last pbuf */
-  q->len = rem_len;
-  q->tot_len = q->len;
-
-  /* any remaining pbufs in chain? */
-  if (q->next != NULL) {
-    /* free remaining pbufs in chain */
-    pbuf_free(q->next);
-  }
-  /* q is last packet in chain */
-  q->next = NULL;
-
-}
-
-
-
-/**
- * Increment the reference count of the pbuf.
- *
- * @param p pbuf to increase reference counter of
- *
- */
-void
-pbuf_ref(struct pbuf *p)
-{
-  SYS_ARCH_DECL_PROTECT(old_level);
-  /* pbuf given? */
-  if (p != NULL) {
-    SYS_ARCH_PROTECT(old_level);
-    ++(p->ref);
-    SYS_ARCH_UNPROTECT(old_level);
-  }
-}
-
-/**
- * Concatenate two pbufs (each may be a pbuf chain) and take over
- * the caller's reference of the tail pbuf.
- * 
- * @note The caller MAY NOT reference the tail pbuf afterwards.
- * Use pbuf_chain() for that purpose.
- * 
- * @see pbuf_chain()
- */
-
-void
-pbuf_cat(struct pbuf *h, struct pbuf *t)
-{
-  struct pbuf *p;
-
-  LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",
-             ((h != NULL) && (t != NULL)), return;);
-
-  /* proceed to last pbuf of chain */
-  for (p = h; p->next != NULL; p = p->next) {
-    /* add total length of second chain to all totals of first chain */
-    p->tot_len += t->tot_len;
-  }
-  /* { p is last pbuf of first h chain, p->next == NULL } */
-  LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);
-  LWIP_ASSERT("p->next == NULL", p->next == NULL);
-  /* add total length of second chain to last pbuf total of first chain */
-  p->tot_len += t->tot_len;
-  /* chain last pbuf of head (p) with first of tail (t) */
-  p->next = t;
-  /* p->next now references t, but the caller will drop its reference to t,
-   * so netto there is no change to the reference count of t.
-   */
-}
-
-/**
- * Chain two pbufs (or pbuf chains) together.
- * 
- * The caller MUST call pbuf_free(t) once it has stopped
- * using it. Use pbuf_cat() instead if you no longer use t.
- * 
- * @param h head pbuf (chain)
- * @param t tail pbuf (chain)
- * @note The pbufs MUST belong to the same packet.
- * @note MAY NOT be called on a packet queue.
- *
- * The ->tot_len fields of all pbufs of the head chain are adjusted.
- * The ->next field of the last pbuf of the head chain is adjusted.
- * The ->ref field of the first pbuf of the tail chain is adjusted.
- *
- */
-void
-pbuf_chain(struct pbuf *h, struct pbuf *t)
-{
-  pbuf_cat(h, t);
-  /* t is now referenced by h */
-  pbuf_ref(t);
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
-}
-
-/**
- * Dechains the first pbuf from its succeeding pbufs in the chain.
- *
- * Makes p->tot_len field equal to p->len.
- * @param p pbuf to dechain
- * @return remainder of the pbuf chain, or NULL if it was de-allocated.
- * @note May not be called on a packet queue.
- */
-struct pbuf *
-pbuf_dechain(struct pbuf *p)
-{
-  struct pbuf *q;
-  uint8_t tail_gone = 1;
-  /* tail */
-  q = p->next;
-  /* pbuf has successor in chain? */
-  if (q != NULL) {
-    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
-    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);
-    /* enforce invariant if assertion is disabled */
-    q->tot_len = p->tot_len - p->len;
-    /* decouple pbuf from remainder */
-    p->next = NULL;
-    /* total length of pbuf p is its own length only */
-    p->tot_len = p->len;
-    /* q is no longer referenced by p, free it */
-    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
-    tail_gone = pbuf_free(q);
-    if (tail_gone > 0) {
-      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
-                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
-    }
-    /* return remaining tail or NULL if deallocated */
-  }
-  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */
-  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);
-  return ((tail_gone > 0) ? NULL : q);
-}
-
-/**
- *
- * Create PBUF_RAM copies of pbufs.
- *
- * Used to queue packets on behalf of the lwIP stack, such as
- * ARP based queueing.
- *
- * @note You MUST explicitly use p = pbuf_take(p);
- *
- * @note Only one packet is copied, no packet queue!
- *
- * @param p_to pbuf destination of the copy
- * @param p_from pbuf source of the copy
- *
- * @return ERR_OK if pbuf was copied
- *         ERR_ARG if one of the pbufs is NULL or p_to is not big
- *                 enough to hold p_from
- */
-err_t
-pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
-{
-  uint16_t offset_to=0, offset_from=0, len;
-
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
-    (void*)p_to, (void*)p_from));
-
-  /* is the target big enough to hold the source? */
-  LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&
-             (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);
-
-  /* iterate through pbuf chain */
-  do
-  {
-    LWIP_ASSERT("p_to != NULL", p_to != NULL);
-    /* copy one part of the original chain */
-    if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {
-      /* complete current p_from fits into current p_to */
-      len = p_from->len - offset_from;
-    } else {
-      /* current p_from does not fit into current p_to */
-      len = p_to->len - offset_to;
-    }
-    MEMCPY((uint8_t*)p_to->payload + offset_to, (uint8_t*)p_from->payload + offset_from, len);
-    offset_to += len;
-    offset_from += len;
-    LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);
-    if (offset_to == p_to->len) {
-      /* on to next p_to (if any) */
-      offset_to = 0;
-      p_to = p_to->next;
-    }
-    LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);
-    if (offset_from >= p_from->len) {
-      /* on to next p_from (if any) */
-      offset_from = 0;
-      p_from = p_from->next;
-    }
-
-    if((p_from != NULL) && (p_from->len == p_from->tot_len)) {
-      /* don't copy more than one packet! */
-      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
-                 (p_from->next == NULL), return ERR_VAL;);
-    }
-    if((p_to != NULL) && (p_to->len == p_to->tot_len)) {
-      /* don't copy more than one packet! */
-      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",
-                  (p_to->next == NULL), return ERR_VAL;);
-    }
-  } while (p_from);
-  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
-  return ERR_OK;
-}
-
-
-/**
- * Copy application supplied data into a pbuf.
- * This function can only be used to copy the equivalent of buf->tot_len data.
- *
- * @param buf pbuf to fill with data
- * @param dataptr application supplied data buffer
- * @param len length of the application supplied data buffer
- *
- * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
- */
-err_t
-pbuf_take(struct pbuf *buf, const void *dataptr, uint16_t len)
-{
-  struct pbuf *p;
-  uint16_t buf_copy_len;
-  uint16_t total_copy_len = len;
-  uint16_t copied_total = 0;
-
-  LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
-  LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
-
-  if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
-    return ERR_ARG;
-  }
-
-  /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
-  for(p = buf; total_copy_len != 0; p = p->next) {
-    LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
-    buf_copy_len = total_copy_len;
-    if (buf_copy_len > p->len) {
-      /* this pbuf cannot hold all remaining data */
-      buf_copy_len = p->len;
-    }
-    /* copy the necessary parts of the buffer */
-    MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
-    total_copy_len -= buf_copy_len;
-    copied_total += buf_copy_len;
-  }
-  LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
-  return ERR_OK;
-}
-
-/**
- * Creates a single pbuf out of a queue of pbufs.
- *
- * @remark: Either the source pbuf 'p' is freed by this function or the original
- *          pbuf 'p' is returned, therefore the caller has to check the result!
- *
- * @param p the source pbuf
- * @param layer pbuf_layer of the new pbuf
- *
- * @return a new, single pbuf (p->next is NULL)
- *         or the old pbuf if allocation fails
- */
-struct pbuf*
-pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
-{
-  struct pbuf *q;
-  err_t err;
-  if (p->next == NULL) {
-    return p;
-  }
-  q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
-  if (q == NULL) {
-    /* @todo: what do we do now? */
-    return p;
-  }
-  err = pbuf_copy(q, p);
-  LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
-  pbuf_free(p);
-  return q;
-}
-
-#if LWIP_CHECKSUM_ON_COPY
-/**
- * Copies data into a single pbuf (*not* into a pbuf queue!) and updates
- * the checksum while copying
- *
- * @param p the pbuf to copy data into
- * @param start_offset offset of p->payload where to copy the data to
- * @param dataptr data to copy into the pbuf
- * @param len length of data to copy into the pbuf
- * @param chksum pointer to the checksum which is updated
- * @return ERR_OK if successful, another error if the data does not fit
- *         within the (first) pbuf (no pbuf queues!)
- */
-err_t
-pbuf_fill_chksum(struct pbuf *p, uint16_t start_offset, const void *dataptr,
-                 uint16_t len, uint16_t *chksum)
-{
-  u32_t acc;
-  uint16_t copy_chksum;
-  char *dst_ptr;
-  LWIP_ASSERT("p != NULL", p != NULL);
-  LWIP_ASSERT("dataptr != NULL", dataptr != NULL);
-  LWIP_ASSERT("chksum != NULL", chksum != NULL);
-  LWIP_ASSERT("len != 0", len != 0);
-
-  if ((start_offset >= p->len) || (start_offset + len > p->len)) {
-    return ERR_ARG;
-  }
-
-  dst_ptr = ((char*)p->payload) + start_offset;
-  copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len);
-  if ((start_offset & 1) != 0) {
-    copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum);
-  }
-  acc = *chksum;
-  acc += copy_chksum;
-  *chksum = FOLD_U32T(acc);
-  return ERR_OK;
-}
-#endif /* LWIP_CHECKSUM_ON_COPY */
-
- /** Get one byte from the specified position in a pbuf
- * WARNING: returns zero for offset >= p->tot_len
- *
- * @param p pbuf to parse
- * @param offset offset into p of the byte to return
- * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len
- */
-uint8_t
-pbuf_get_at(struct pbuf* p, uint16_t offset)
-{
-  uint16_t copy_from = offset;
-  struct pbuf* q = p;
-
-  /* get the correct pbuf */
-  while ((q != NULL) && (q->len <= copy_from)) {
-    copy_from -= q->len;
-    q = q->next;
-  }
-  /* return requested data if pbuf is OK */
-  if ((q != NULL) && (q->len > copy_from)) {
-    return ((uint8_t*)q->payload)[copy_from];
-  }
-  return 0;
-}
-
-/** Compare pbuf contents at specified offset with memory s2, both of length n
- *
- * @param p pbuf to compare
- * @param offset offset into p at wich to start comparing
- * @param s2 buffer to compare
- * @param n length of buffer to compare
- * @return zero if equal, nonzero otherwise
- *         (0xffff if p is too short, diffoffset+1 otherwise)
- */
-uint16_t
-pbuf_memcmp(struct pbuf* p, uint16_t offset, const void* s2, uint16_t n)
-{
-  uint16_t start = offset;
-  struct pbuf* q = p;
-
-  /* get the correct pbuf */
-  while ((q != NULL) && (q->len <= start)) {
-    start -= q->len;
-    q = q->next;
-  }
-  /* return requested data if pbuf is OK */
-  if ((q != NULL) && (q->len > start)) {
-    uint16_t i;
-    for(i = 0; i < n; i++) {
-      uint8_t a = pbuf_get_at(q, start + i);
-      uint8_t b = ((uint8_t*)s2)[i];
-      if (a != b) {
-        return i+1;
-      }
-    }
-    return 0;
-  }
-  return 0xffff;
-}
-
-/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset
- * start_offset.
- *
- * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
- *        return value 'not found'
- * @param mem search for the contents of this buffer
- * @param mem_len length of 'mem'
- * @param start_offset offset into p at which to start searching
- * @return 0xFFFF if substr was not found in p or the index where it was found
- */
-uint16_t
-pbuf_memfind(struct pbuf* p, const void* mem, uint16_t mem_len, uint16_t start_offset)
-{
-  uint16_t i;
-  uint16_t max = p->tot_len - mem_len;
-  if (p->tot_len >= mem_len + start_offset) {
-    for(i = start_offset; i <= max; ) {
-      uint16_t plus = pbuf_memcmp(p, i, mem, mem_len);
-      if (plus == 0) {
-        return i;
-      } else {
-        i += plus;
-      }
-    }
-  }
-  return 0xFFFF;
-}
-
-/** Find occurrence of substr with length substr_len in pbuf p, start at offset
- * start_offset
- * WARNING: in contrast to strstr(), this one does not stop at the first \0 in
- * the pbuf/source string!
- *
- * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as
- *        return value 'not found'
- * @param substr string to search for in p, maximum length is 0xFFFE
- * @return 0xFFFF if substr was not found in p or the index where it was found
- */
-uint16_t
-pbuf_strstr(struct pbuf* p, const char* substr)
-{
-  size_t substr_len;
-  if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) {
-    return 0xFFFF;
-  }
-  substr_len = strlen(substr);
-  if (substr_len >= 0xFFFF) {
-    return 0xFFFF;
-  }
-  return pbuf_memfind(p, substr, (uint16_t)substr_len, 0);
-}
-
-#endif /*EVERYTHING*/
diff --git a/kern/src/net/tcp.c b/kern/src/net/tcp.c
deleted file mode 100644 (file)
index bc3ce94..0000000
+++ /dev/null
@@ -1,1616 +0,0 @@
-/**
- * @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);
-}
-
-/**
- * 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..
-               if (!sem_up_irqsave(&sock->sem, &irq_state)) {
-                       // wake up all waiters
-                       struct semaphore_entry *sentry, *sentry_tmp;
-                       spin_lock(&sock->waiter_lock);
-                       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 --git a/kern/src/net/tcp_in.c b/kern/src/net/tcp_in.c
deleted file mode 100644 (file)
index ce08f3b..0000000
+++ /dev/null
@@ -1,1587 +0,0 @@
-/**
- * @file
- * Transmission Control Protocol, incoming traffic
- *
- * The input processing functions of the TCP layer.
- *
- * These functions are generally called in the order (ip_input() ->)
- * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).
- * 
- */
-
-/*
- * 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>
- *
- */
-
-#include "net/tcp.h"
-#include "net/tcp_impl.h"
-#include "bits/netinet.h"
-#include "net/pbuf.h"
-#include "debug.h"
-#include "error.h"
-#include <string.h>
-
-/* These variables are global to all functions involved in the input
-   processing of TCP segments. They are set by the tcp_input()
-   function. */
-// static struct tcp_hdr *tcphdr;
-// static struct tcp_seg inseg;
-
-//static uint32_t seqno, ackno;
-//static uint8_t flags;
-//static uint16_t tcplen;
-
-static uint8_t recv_flags;
-static struct pbuf *recv_data;
-
-struct tcp_pcb *tcp_input_pcb;
-
-/* Forward declarations. */
-static error_t tcp_process(struct tcp_pcb *pcb, struct tcp_seg *insegp, struct ip_hdr *iphdr, uint16_t tcplen);
-static void tcp_receive(struct tcp_pcb *pcb, struct tcp_seg *insegp, uint16_t tcplen);
-static void tcp_parseopt(struct tcp_pcb *pcb, struct tcp_hdr *tcphdr);
-
-static error_t tcp_listen_input(struct tcp_pcb_listen *pcb, struct tcp_seg *inseg, struct ip_hdr *iphdr, uint16_t tcplen);
-static error_t tcp_timewait_input(struct tcp_pcb *pcb, struct tcp_seg *inseg, struct ip_hdr *iphdr, uint16_t tcplen);
-
-/**
- * The initial input processing of TCP. It verifies the TCP header, demultiplexes
- * the segment between the PCBs and passes it on to tcp_process(), which implements
- * the TCP finite state machine. This function is called by the IP layer (in
- * ip_input()).
- *
- * @param p received TCP segment to process (p->payload pointing to the IP header)
- * @param inp network interface on which this segment was received
- */
-void
-tcp_input(struct pbuf *p)
-{
-  struct tcp_pcb *pcb, *prev;
-  struct tcp_pcb_listen *lpcb;
-#if SO_REUSE
-  struct tcp_pcb *lpcb_prev = NULL;
-  struct tcp_pcb_listen *lpcb_any = NULL;
-#endif /* SO_REUSE */
-  uint8_t hdrlen;
-  error_t err;
-
-  // TCP_STATS_INC(tcp.recv);
-  // snmp_inc_tcpinsegs();
-
-       struct tcp_seg inseg;
-  struct ip_hdr *iphdr = (struct ip_hdr *)p->payload;
-  struct tcp_hdr *tcphdr = (struct tcp_hdr *)((uint8_t *)p->payload + (iphdr->hdr_len) * 4);
-       ip_addr_t current_iphdr_src = {iphdr->src_addr};
-       ip_addr_t current_iphdr_dest = {iphdr->dst_addr};
-
-#if TCP_INPUT_DEBUG
-  tcp_debug_print(tcphdr);
-#endif
-
-  /* remove header from payload */
-  if (pbuf_header(p, -((int16_t)((iphdr->hdr_len) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {
-    /* drop short packets */
-    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));
-    //TCP_STATS_INC(tcp.lenerr);
-    //TCP_STATS_INC(tcp.drop);
-    //snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
-  }
-
-  /* Don't even process incoming broadcasts/multicasts. 
-  if (ip_addr_isbroadcast(&current_iphdr_dest, inp) ||
-      ip_addr_ismulticast(&current_iphdr_dest)) {
-    TCP_STATS_INC(tcp.proterr);
-    TCP_STATS_INC(tcp.drop);
-    snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
-  } */
-
-#if CHECKSUM_CHECK_TCP
-  /* Verify TCP checksum. */
-  if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
-      IP_PROTO_TCP, p->tot_len) != 0) {
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",
-        inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(),
-      IP_PROTO_TCP, p->tot_len)));
-#if TCP_DEBUG
-    tcp_debug_print(tcphdr);
-#endif /* TCP_DEBUG */
-    TCP_STATS_INC(tcp.chkerr);
-    TCP_STATS_INC(tcp.drop);
-    // snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
-  }
-#endif
-
-  /* Move the payload pointer in the pbuf so that it points to the
-     TCP data instead of the TCP header. */
-  hdrlen = TCPH_HDRLEN(tcphdr);
-  if(pbuf_header(p, -(hdrlen * 4))){
-    /* drop short packets */
-    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));
-    //TCP_STATS_INC(tcp.lenerr);
-    //TCP_STATS_INC(tcp.drop);
-    //snmp_inc_tcpinerrs();
-    pbuf_free(p);
-    return;
-  }
-
-  /* Convert fields in TCP header to host byte order. */
-  tcphdr->src = ntohs(tcphdr->src);
-  tcphdr->dest = ntohs(tcphdr->dest);
-  uint32_t seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
-  uint32_t ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
-  tcphdr->wnd = ntohs(tcphdr->wnd);
-
-  uint8_t flags = TCPH_FLAGS(tcphdr);
-       // if the packet is a FIN or a SYN, add 1?
-  uint16_t tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0);
-
-  /* Demultiplex an incoming segment. First, we check if it is destined
-     for an active connection. */
-  prev = NULL;
-
-  // XXX: find_pcb? 
-  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {
-    LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);
-    LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);
-    LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);
-    if (pcb->remote_port == tcphdr->src &&
-       pcb->local_port == tcphdr->dest &&
-       ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
-       ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
-
-      /* Move this PCB to the front of the list so that subsequent
-         lookups will be faster (we exploit locality in TCP segment
-         arrivals). */
-      LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);
-      if (prev != NULL) {
-        prev->next = pcb->next;
-        pcb->next = tcp_active_pcbs;
-        tcp_active_pcbs = pcb;
-      }
-      LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);
-      break;
-    }
-    prev = pcb;
-  }
-
-  if (pcb == NULL) {
-    /* If it did not go to an active connection, we check the connections
-       in the TIME-WAIT state. */
-    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {
-      LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);
-      if (pcb->remote_port == tcphdr->src &&
-         pcb->local_port == tcphdr->dest &&
-         ip_addr_cmp(&(pcb->remote_ip), &current_iphdr_src) &&
-         ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest)) {
-        /* We don't really care enough to move this PCB to the front
-           of the list since we are not very likely to receive that
-           many segments for connections in TIME-WAIT. */
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));
-        tcp_timewait_input(pcb, &inseg, iphdr, tcplen);
-        pbuf_free(p);
-        return;
-      }
-    }
-
-    /* Finally, if we still did not get a match, we check all PCBs that
-       are LISTENing for incoming connections. */
-    prev = NULL;
-    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
-      if (lpcb->local_port == tcphdr->dest) {
-#if SO_REUSE
-        if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest)) {
-          /* found an exact match */
-          break;
-        } else if(ip_addr_isany(&(lpcb->local_ip))) {
-          /* found an ANY-match */
-          lpcb_any = lpcb;
-          lpcb_prev = prev;
-        }
-#else /* SO_REUSE */
-        if (ip_addr_cmp(&(lpcb->local_ip), &current_iphdr_dest) ||
-            ip_addr_isany(&(lpcb->local_ip))) {
-          /* found a match */
-          break;
-        }
-#endif /* SO_REUSE */
-      }
-      prev = (struct tcp_pcb *)lpcb;
-    }
-#if SO_REUSE
-    /* first try specific local IP */
-    if (lpcb == NULL) {
-      /* only pass to ANY if no specific local IP has been found */
-      lpcb = lpcb_any;
-      prev = lpcb_prev;
-    }
-#endif /* SO_REUSE */
-    if (lpcb != NULL) {
-      /* Move this PCB to the front of the list so that subsequent
-         lookups will be faster (we exploit locality in TCP segment
-         arrivals). */
-      if (prev != NULL) {
-        ((struct tcp_pcb_listen *)prev)->next = lpcb->next;
-              /* our successor is the remainder of the listening list */
-        lpcb->next = tcp_listen_pcbs.listen_pcbs;
-              /* put this listening pcb at the head of the listening list */
-        tcp_listen_pcbs.listen_pcbs = lpcb;
-      }
-    
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));
-      tcp_listen_input(lpcb, &inseg, iphdr, tcplen);
-      pbuf_free(p);
-      return;
-    }
-  }
-
-#if TCP_INPUT_DEBUG
-  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));
-  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));
-  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));
-#endif /* TCP_INPUT_DEBUG */
-
-
-  if (pcb != NULL) {
-    /* The incoming segment belongs to a connection. */
-#if TCP_INPUT_DEBUG
-#if TCP_DEBUG
-    tcp_debug_print_state(pcb->state);
-#endif /* TCP_DEBUG */
-#endif /* TCP_INPUT_DEBUG */
-
-    /* Set up a tcp_seg structure. */
-    inseg.next = NULL;
-    inseg.len = p->tot_len;
-    inseg.dataptr = p->payload;
-    inseg.p = p;
-    inseg.tcphdr = tcphdr;
-
-    recv_data = NULL;
-    recv_flags = 0;
-
-    /* If there is data which was previously "refused" by upper layer */
-    if (pcb->refused_data != NULL) {
-      /* Notify again application with data previously received. */
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
-      TCP_EVENT_RECV(pcb, pcb->refused_data, ESUCCESS, err);
-                       // XXX: err is a global, need better indication of whether the socket receive was successful
-      if (err == ESUCCESS) {
-        pcb->refused_data = NULL;
-      } else if ((err == -ECONNABORTED) || (tcplen > 0)) {
-        /* if err == -ECONNABORTED, 'pcb' is already deallocated */
-        /* Drop incoming packets because pcb is "full" (only if the incoming
-           segment contains data). */
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
-        //TCP_STATS_INC(tcp.drop);
-        //snmp_inc_tcpinerrs();
-        pbuf_free(p);
-        return;
-      }
-    }
-    tcp_input_pcb = pcb;
-    err = tcp_process(pcb, &inseg, iphdr, tcplen);
-    /* A return value of -ECONNABORTED means that tcp_abort() was called
-       and that the pcb has been freed. If so, we don't do anything. */
-    if (err != -ECONNABORTED) {
-      if (recv_flags & TF_RESET) {
-        /* TF_RESET means that the connection was reset by the other
-           end. We then call the error callback to inform the
-           application that the connection is dead before we
-           deallocate the PCB. */
-        // XXX: worry about connection reset later
-                               //TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
-        tcp_pcb_remove(&tcp_active_pcbs, pcb);
-                               kmem_cache_free(tcp_pcb_kcache, pcb);
-      } else if (recv_flags & TF_CLOSED) {
-        /* The connection has been closed and we will deallocate the
-           PCB. */
-        tcp_pcb_remove(&tcp_active_pcbs, pcb);
-                               kmem_cache_free(tcp_pcb_kcache, pcb);
-      } else {
-        err = ESUCCESS;
-        /* If the application has registered a "sent" function to be
-           called when new send buffer space is available, we call it
-           now. */
-        if (pcb->acked > 0) {
-          TCP_EVENT_SENT(pcb, pcb->acked, err);
-          if (err == -ECONNABORTED) {
-            goto aborted;
-          }
-        }
-
-        if (recv_data != NULL) {
-          LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
-          if (pcb->flags & TF_RXCLOSED) {
-            /* received data although already closed -> abort (send RST) to
-               notify the remote host that not all data has been processed */
-            pbuf_free(recv_data);
-            tcp_abort(pcb);
-            goto aborted;
-          }
-          if (flags & TCP_PSH) {
-            recv_data->flags |= PBUF_FLAG_PUSH;
-          }
-
-          /* Notify application that data has been received. */
-          TCP_EVENT_RECV(pcb, recv_data, ESUCCESS, err);
-          if (err == -ECONNABORTED) {
-            goto aborted;
-          }
-
-          /* If the upper layer can't receive this data, store it */
-          if (err != ESUCCESS) {
-            pcb->refused_data = recv_data;
-            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
-          }
-        }
-
-        /* If a FIN segment was received, we call the callback
-           function with a NULL buffer to indicate EOF. */
-        if (recv_flags & TF_GOT_FIN) {
-          /* correct rcv_wnd as the application won't call tcp_recved()
-             for the FIN's seqno */
-          if (pcb->rcv_wnd != TCP_WND) {
-            pcb->rcv_wnd++;
-          }
-          TCP_EVENT_CLOSED(pcb, err);
-          if (err == -ECONNABORTED) {
-            goto aborted;
-          }
-        }
-
-        tcp_input_pcb = NULL;
-        /* Try to send something out. */
-        tcp_output(pcb);
-#if TCP_INPUT_DEBUG
-#if TCP_DEBUG
-        tcp_debug_print_state(pcb->state);
-#endif /* TCP_DEBUG */
-#endif /* TCP_INPUT_DEBUG */
-      }
-    }
-    /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
-       Below this line, 'pcb' may not be dereferenced! */
-aborted:
-    tcp_input_pcb = NULL;
-    recv_data = NULL;
-
-    /* give up our reference to inseg.p */
-    if (inseg.p != NULL)
-    {
-      pbuf_free(inseg.p);
-      inseg.p = NULL;
-    }
-  } else {
-
-    /* If no matching PCB was found, send a TCP RST (reset) to the
-       sender. */
-    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
-    if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
-      //TCP_STATS_INC(tcp.proterr);
-      //TCP_STATS_INC(tcp.drop);
-      tcp_rst(ackno, seqno + tcplen,
-        &current_iphdr_dest, &current_iphdr_src,
-        tcphdr->dest, tcphdr->src);
-    }
-    pbuf_free(p);
-  }
-
-  LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
-}
-
-/**
- * Called by tcp_input() when a segment arrives for a listening
- * connection (from tcp_input()).
- *
- * @param pcb the tcp_pcb_listen for which a segment arrived
- * @return ESUCCESS if the segment was processed
- *         another error_t on error
- *
- * @note the return value is not (yet?) used in tcp_input()
- * @note the segment which arrived is saved in global variables, therefore only the pcb
- *       involved is passed as a parameter to this function
- */
-static error_t
-tcp_listen_input(struct tcp_pcb_listen *pcb, struct tcp_seg *insegp, struct ip_hdr *iphdr, uint16_t tcplen)
-{
-  struct tcp_pcb *npcb;
-       struct tcp_hdr *tcphdr = insegp->tcphdr;
-
-  error_t rc;
-
-       ip_addr_t current_iphdr_src = {iphdr->src_addr};
-       ip_addr_t current_iphdr_dest = {iphdr->dst_addr};
-  uint8_t flags = TCPH_FLAGS(tcphdr);
-  uint32_t ackno = tcphdr->ackno;
-  uint32_t seqno = tcphdr->seqno;
-  /* In the LISTEN state, we check for incoming SYN segments,
-     creates a new PCB, and responds with a SYN|ACK. */
-  if (flags & TCP_ACK) {
-    /* For incoming segments with the ACK flag set, respond with a
-       RST. */
-    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
-    tcp_rst(ackno + 1, seqno + tcplen,
-      &current_iphdr_dest, &current_iphdr_src,
-      tcphdr->dest, tcphdr->src);
-  } else if (flags & TCP_SYN) {
-    LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
-#if TCP_LISTEN_BACKLOG
-    if (pcb->accepts_pending >= pcb->backlog) {
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
-      return -ECONNABORTED;
-    }
-#endif /* TCP_LISTEN_BACKLOG */
-    npcb = tcp_alloc(pcb->prio);
-    /* If a new PCB could not be created (probably due to lack of memory),
-       we don't do anything, but rely on the sender will retransmit the
-       SYN at a time when we have more memory available. */
-    if (npcb == NULL) {
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
-      //TCP_STATS_INC(tcp.memerr);
-      return -ENOMEM;
-    }
-#if TCP_LISTEN_BACKLOG
-    pcb->accepts_pending++;
-#endif /* TCP_LISTEN_BACKLOG */
-    /* Set up the new PCB. */
-    ip_addr_copy(npcb->local_ip, current_iphdr_dest);
-    npcb->local_port = pcb->local_port;
-    ip_addr_copy(npcb->remote_ip, current_iphdr_src);
-    npcb->remote_port = tcphdr->src;
-    npcb->state = SYN_RCVD;
-    npcb->rcv_nxt = seqno + 1;
-    npcb->rcv_ann_right_edge = npcb->rcv_nxt;
-    npcb->snd_wnd = tcphdr->wnd;
-    npcb->ssthresh = npcb->snd_wnd;
-    npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
-    npcb->callback_arg = pcb->callback_arg;
-#if LWIP_CALLBACK_API
-    npcb->accept = pcb->accept;
-#endif /* LWIP_CALLBACK_API */
-    /* inherit socket options */
-    npcb->so_options = pcb->so_options & SO_INHERITED;
-    /* Register the new PCB so that we can begin receiving segments
-       for it. */
-    TCP_REG(&tcp_active_pcbs, npcb);
-
-    /* Parse any options in the SYN. */
-    tcp_parseopt(npcb, tcphdr);
-#if TCP_CALCULATE_EFF_SEND_MSS
-    npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
-#endif /* TCP_CALCULATE_EFF_SEND_MSS */
-
-    // snmp_inc_tcppassiveopens();
-
-    /* Send a SYN|ACK together with the MSS option. */
-    rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
-    if (rc != ESUCCESS) {
-      tcp_abandon(npcb, 0);
-      return rc;
-    }
-    return tcp_output(npcb);
-  }
-  return ESUCCESS;
-}
-
-/**
- * Called by tcp_input() when a segment arrives for a connection in
- * TIME_WAIT.
- *
- * @param pcb the tcp_pcb for which a segment arrived
- *
- * @note the segment which arrived is saved in global variables, therefore only the pcb
- *       involved is passed as a parameter to this function
- */
-static error_t tcp_timewait_input(struct tcp_pcb *pcb, struct tcp_seg *insegp, struct ip_hdr *iphdr, uint16_t tcplen)
-{
-  /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
-  /* RFC 793 3.9 Event Processing - Segment Arrives:
-   * - first check sequence number - we skip that one in TIME_WAIT (always
-   *   acceptable since we only send ACKs)
-   * - second check the RST bit (... return) */
-       struct tcp_hdr *tcphdr = insegp->tcphdr;
-  uint8_t flags = TCPH_FLAGS(tcphdr);
-       ip_addr_t current_iphdr_src = {iphdr->src_addr};
-       ip_addr_t current_iphdr_dest = {iphdr->dst_addr};
-  uint32_t ackno = tcphdr->ackno;
-  uint32_t seqno = tcphdr->seqno;
-  if (flags & TCP_RST)  {
-    return ESUCCESS;
-  }
-  /* - fourth, check the SYN bit, */
-  if (flags & TCP_SYN) {
-    /* If an incoming segment is not acceptable, an acknowledgment
-       should be sent in reply */
-    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
-      /* If the SYN is in the window it is an error, send a reset */
-      tcp_rst(ackno, seqno + tcplen, &current_iphdr_dest, &current_iphdr_src,
-        tcphdr->dest, tcphdr->src);
-      return ESUCCESS;
-    }
-  } else if (flags & TCP_FIN) {
-    /* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
-         Restart the 2 MSL time-wait timeout.*/
-    pcb->tmr = tcp_ticks;
-  }
-
-  if ((tcplen > 0))  {
-    /* Acknowledge data, FIN or out-of-window SYN */
-    pcb->flags |= TF_ACK_NOW;
-    return tcp_output(pcb);
-  }
-  return ESUCCESS;
-}
-
-/**
- * Implements the TCP state machine. Called by tcp_input. In some
- * states tcp_receive() is called to receive data. The tcp_seg
- * argument will be freed by the caller (tcp_input()) unless the
- * recv_data pointer in the pcb is set.
- *
- * @param pcb the tcp_pcb for which a segment arrived
- *
- * @note the segment which arrived is saved in global variables, therefore only the pcb
- *       involved is passed as a parameter to this function
- */
-static error_t
-tcp_process(struct tcp_pcb *pcb, struct tcp_seg *insegp, struct ip_hdr *iphdr, uint16_t tcplen)
-{
-       struct tcp_hdr *tcphdr = insegp->tcphdr;
-  struct tcp_seg *rseg;
-  uint8_t acceptable = 0;
-  error_t err;
-  uint8_t flags = TCPH_FLAGS(tcphdr);
-  uint32_t ackno = tcphdr->ackno;
-  uint32_t seqno = tcphdr->seqno;
-
-       ip_addr_t current_iphdr_src = {iphdr->src_addr};
-       ip_addr_t current_iphdr_dest = {iphdr->dst_addr};
-  err = ESUCCESS;
-
-  /* Process incoming RST segments. */
-  if (flags & TCP_RST) {
-    /* First, determine if the reset is acceptable. */
-    if (pcb->state == SYN_SENT) {
-      if (ackno == pcb->snd_nxt) {
-        acceptable = 1;
-      }
-    } else {
-      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 
-                          pcb->rcv_nxt+pcb->rcv_wnd)) {
-        acceptable = 1;
-      }
-    }
-
-    if (acceptable) {
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
-      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
-      recv_flags |= TF_RESET;
-      pcb->flags &= ~TF_ACK_DELAY;
-      return -ENETRESET;
-    } else {
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
-       seqno, pcb->rcv_nxt));
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
-       seqno, pcb->rcv_nxt));
-      return ESUCCESS;
-    }
-  }
-
-  if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { 
-    /* Cope with new connection attempt after remote end crashed */
-    tcp_ack_now(pcb);
-    return ESUCCESS;
-  }
-  
-  if ((pcb->flags & TF_RXCLOSED) == 0) {
-    /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
-    pcb->tmr = tcp_ticks;
-  }
-  pcb->keep_cnt_sent = 0;
-
-  tcp_parseopt(pcb, tcphdr);
-
-  /* Do different things depending on the TCP state. */
-  switch (pcb->state) {
-  case SYN_SENT:
-    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
-     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
-    /* received SYN ACK with expected sequence number? */
-    if ((flags & TCP_ACK) && (flags & TCP_SYN)
-        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
-      pcb->snd_buf++;
-      pcb->rcv_nxt = seqno + 1;
-      pcb->rcv_ann_right_edge = pcb->rcv_nxt;
-      pcb->lastack = ackno;
-      pcb->snd_wnd = tcphdr->wnd;
-      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
-      pcb->state = ESTABLISHED;
-
-#if TCP_CALCULATE_EFF_SEND_MSS
-      pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
-#endif /* TCP_CALCULATE_EFF_SEND_MSS */
-
-      /* Set ssthresh again after changing pcb->mss (already set in tcp_connect
-       * but for the default value of pcb->mss) */
-      pcb->ssthresh = pcb->mss * 10;
-
-      pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
-      LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
-      --pcb->snd_queuelen;
-      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (uint16_t)pcb->snd_queuelen));
-      rseg = pcb->unacked;
-      pcb->unacked = rseg->next;
-
-      /* If there's nothing left to acknowledge, stop the retransmit
-         timer, otherwise reset it to start again */
-      if(pcb->unacked == NULL)
-        pcb->rtime = -1;
-      else {
-        pcb->rtime = 0;
-        pcb->nrtx = 0;
-      }
-
-      tcp_seg_free(rseg);
-
-      /* Call the user specified function to call when sucessfully
-       * connected. */
-      TCP_EVENT_CONNECTED(pcb, ESUCCESS, err);
-      if (err == -ECONNABORTED) {
-        return -ECONNABORTED;
-      }
-      tcp_ack_now(pcb);
-    }
-    /* received ACK? possibly a half-open connection */
-    else if (flags & TCP_ACK) {
-      /* send a RST to bring the other side in a non-synchronized state. */
-      tcp_rst(ackno, seqno + tcplen, &current_iphdr_dest, &current_iphdr_src,
-        tcphdr->dest, tcphdr->src);
-    }
-    break;
-  case SYN_RCVD:
-    if (flags & TCP_ACK) {
-      /* expected ACK number? */
-      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
-        uint16_t old_cwnd;
-        pcb->state = ESTABLISHED;
-        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-#if LWIP_CALLBACK_API
-        LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
-#endif
-        /* Call the accept function. */
-        TCP_EVENT_ACCEPT(pcb, ESUCCESS, err);
-        if (err != ESUCCESS) {
-          /* If the accept function returns with an error, we abort
-           * the connection. */
-          /* Already aborted? */
-          if (err != -ECONNABORTED) {
-            tcp_abort(pcb);
-          }
-          return -ECONNABORTED;
-        }
-        old_cwnd = pcb->cwnd;
-        /* If there was any data contained within this ACK,
-         * we'd better pass it on to the application as well. */
-        tcp_receive(pcb, insegp, tcplen);
-
-        /* Prevent ACK for SYN to generate a sent event */
-        if (pcb->acked != 0) {
-          pcb->acked--;
-        }
-
-        pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
-
-        if (recv_flags & TF_GOT_FIN) {
-          tcp_ack_now(pcb);
-          pcb->state = CLOSE_WAIT;
-        }
-      } else {
-        /* incorrect ACK number, send RST */
-       tcp_rst(ackno, seqno + tcplen, &current_iphdr_dest, &current_iphdr_src,
-               tcphdr->dest, tcphdr->src);
-      }
-    } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
-      /* Looks like another copy of the SYN - retransmit our SYN-ACK */
-      tcp_rexmit(pcb);
-    }
-    break;
-  case CLOSE_WAIT:
-    /* FALLTHROUGH */
-  case ESTABLISHED:
-               tcp_receive(pcb, insegp, tcplen);
-    if (recv_flags & TF_GOT_FIN) { /* passive close */
-      tcp_ack_now(pcb);
-      pcb->state = CLOSE_WAIT;
-    }
-    break;
-  case FIN_WAIT_1:
-    tcp_receive(pcb, insegp, tcplen);
-    if (recv_flags & TF_GOT_FIN) {
-      if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
-        LWIP_DEBUGF(TCP_DEBUG,
-          ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-        tcp_ack_now(pcb);
-        tcp_pcb_purge(pcb);
-        TCP_RMV(&tcp_active_pcbs, pcb);
-        pcb->state = TIME_WAIT;
-        TCP_REG(&tcp_tw_pcbs, pcb);
-      } else {
-        tcp_ack_now(pcb);
-        pcb->state = CLOSING;
-      }
-    } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
-      pcb->state = FIN_WAIT_2;
-    }
-    break;
-  case FIN_WAIT_2:
-    tcp_receive(pcb, insegp, tcplen);
-    if (recv_flags & TF_GOT_FIN) {
-      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-      tcp_ack_now(pcb);
-      tcp_pcb_purge(pcb);
-      TCP_RMV(&tcp_active_pcbs, pcb);
-      pcb->state = TIME_WAIT;
-      TCP_REG(&tcp_tw_pcbs, pcb);
-    }
-    break;
-  case CLOSING:
-    tcp_receive(pcb, insegp, tcplen);
-    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
-      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-      tcp_pcb_purge(pcb);
-      TCP_RMV(&tcp_active_pcbs, pcb);
-      pcb->state = TIME_WAIT;
-      TCP_REG(&tcp_tw_pcbs, pcb);
-    }
-    break;
-  case LAST_ACK:
-    tcp_receive(pcb, insegp, tcplen);
-    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
-      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
-      /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
-      recv_flags |= TF_CLOSED;
-    }
-    break;
-  default:
-    break;
-  }
-  return ESUCCESS;
-}
-
-#if TCP_QUEUE_OOSEQ
-/**
- * Insert segment into the list (segments covered with new one will be deleted)
- *
- * Called from tcp_receive()
- */
-static void
-tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
-{
-  struct tcp_seg *old_seg;
-
-  if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
-    /* received segment overlaps all following segments */
-    tcp_segs_free(next);
-    next = NULL;
-  }
-  else {
-    /* delete some following segments
-       oos queue may have segments with FIN flag */
-    while (next &&
-           TCP_SEQ_GEQ((seqno + cseg->len),
-                      (next->tcphdr->seqno + next->len))) {
-      /* cseg with FIN already processed */
-      if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
-        TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN);
-      }
-      old_seg = next;
-      next = next->next;
-      tcp_seg_free(old_seg);
-    }
-    if (next &&
-        TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {
-      /* We need to trim the incoming segment. */
-      cseg->len = (uint16_t)(next->tcphdr->seqno - seqno);
-      pbuf_realloc(cseg->p, cseg->len);
-    }
-  }
-  cseg->next = next;
-}
-#endif /* TCP_QUEUE_OOSEQ */
-
-/**
- * Called by tcp_process. Checks if the given segment is an ACK for outstanding
- * data, and if so frees the memory of the buffered data. Next, is places the
- * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment
- * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until
- * i it has been removed from the buffer.
- *
- * If the incoming segment constitutes an ACK for a segment that was used for RTT
- * estimation, the RTT is estimated here as well.
- *
- * Called from tcp_process().
- */
-static void
-tcp_receive(struct tcp_pcb *pcb, struct tcp_seg *insegp, uint16_t tcplen) {
-  struct tcp_seg *next;
-#if TCP_QUEUE_OOSEQ
-  struct tcp_seg *prev, *cseg;
-#endif /* TCP_QUEUE_OOSEQ */
-       struct tcp_hdr *tcphdr = insegp->tcphdr;
-  struct pbuf *p;
-  int32_t off;
-  int16_t m;
-  uint32_t right_wnd_edge;
-  uint16_t new_tot_len;
-  uint8_t flags = TCPH_FLAGS(tcphdr);
-  uint32_t ackno = tcphdr->ackno;
-  uint32_t seqno = tcphdr->seqno;
-  int found_dupack = 0;
-
-  if (flags & TCP_ACK) {
-    right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2;
-
-    /* Update window. */
-    if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
-       (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
-       (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
-      pcb->snd_wnd = tcphdr->wnd;
-      pcb->snd_wl1 = seqno;
-      pcb->snd_wl2 = ackno;
-      if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
-          pcb->persist_backoff = 0;
-      }
-      LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
-#if TCP_WND_DEBUG
-    } else {
-      if (pcb->snd_wnd != tcphdr->wnd) {
-        LWIP_DEBUGF(TCP_WND_DEBUG, 
-                    ("tcp_receive: no window update lastack %"U32_F" ackno %"
-                     U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",
-                     pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));
-      }
-#endif /* TCP_WND_DEBUG */
-    }
-
-    /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a
-     * duplicate ack if:
-     * 1) It doesn't ACK new data 
-     * 2) length of received packet is zero (i.e. no payload) 
-     * 3) the advertised window hasn't changed 
-     * 4) There is outstanding unacknowledged data (retransmission timer running)
-     * 5) The ACK is == biggest ACK sequence number so far seen (snd_una)
-     * 
-     * If it passes all five, should process as a dupack: 
-     * a) dupacks < 3: do nothing 
-     * b) dupacks == 3: fast retransmit 
-     * c) dupacks > 3: increase cwnd 
-     * 
-     * If it only passes 1-3, should reset dupack counter (and add to
-     * stats, which we don't do in lwIP)
-     *
-     * If it only passes 1, should reset dupack counter
-     *
-     */
-
-    /* Clause 1 */
-    if (TCP_SEQ_LEQ(ackno, pcb->lastack)) {
-      pcb->acked = 0;
-      /* Clause 2 */
-      if (tcplen == 0) {
-        /* Clause 3 */
-        if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){
-          /* Clause 4 */
-          if (pcb->rtime >= 0) {
-            /* Clause 5 */
-            if (pcb->lastack == ackno) {
-              found_dupack = 1;
-              if (pcb->dupacks + 1 > pcb->dupacks)
-                ++pcb->dupacks;
-              if (pcb->dupacks > 3) {
-                /* Inflate the congestion window, but not if it means that
-                   the value overflows. */
-                if ((uint16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
-                  pcb->cwnd += pcb->mss;
-                }
-              } else if (pcb->dupacks == 3) {
-                /* Do fast retransmit */
-                tcp_rexmit_fast(pcb);
-              }
-            }
-          }
-        }
-      }
-      /* If Clause (1) or more is true, but not a duplicate ack, reset
-       * count of consecutive duplicate acks */
-      if (!found_dupack) {
-        pcb->dupacks = 0;
-      }
-    } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){
-      /* We come here when the ACK acknowledges new data. */
-
-      /* Reset the "IN Fast Retransmit" flag, since we are no longer
-         in fast retransmit. Also reset the congestion window to the
-         slow start threshold. */
-      if (pcb->flags & TF_INFR) {
-        pcb->flags &= ~TF_INFR;
-        pcb->cwnd = pcb->ssthresh;
-      }
-
-      /* Reset the number of retransmissions. */
-      pcb->nrtx = 0;
-
-      /* Reset the retransmission time-out. */
-      pcb->rto = (pcb->sa >> 3) + pcb->sv;
-
-      /* Update the send buffer space. Diff between the two can never exceed 64K? */
-      pcb->acked = (uint16_t)(ackno - pcb->lastack);
-
-      pcb->snd_buf += pcb->acked;
-
-      /* Reset the fast retransmit variables. */
-      pcb->dupacks = 0;
-      pcb->lastack = ackno;
-
-      /* Update the congestion control variables (cwnd and
-         ssthresh). */
-      if (pcb->state >= ESTABLISHED) {
-        if (pcb->cwnd < pcb->ssthresh) {
-          if ((uint16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
-            pcb->cwnd += pcb->mss;
-          }
-          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
-        } else {
-          uint16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
-          if (new_cwnd > pcb->cwnd) {
-            pcb->cwnd = new_cwnd;
-          }
-          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
-        }
-      }
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
-                                    ackno,
-                                    pcb->unacked != NULL?
-                                    ntohl(pcb->unacked->tcphdr->seqno): 0,
-                                    pcb->unacked != NULL?
-                                    ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
-
-      /* Remove segment from the unacknowledged list if the incoming
-         ACK acknowlegdes them. */
-      while (pcb->unacked != NULL &&
-             TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
-                         TCP_TCPLEN(pcb->unacked), ackno)) {
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
-                                      ntohl(pcb->unacked->tcphdr->seqno),
-                                      ntohl(pcb->unacked->tcphdr->seqno) +
-                                      TCP_TCPLEN(pcb->unacked)));
-
-        next = pcb->unacked;
-        pcb->unacked = pcb->unacked->next;
-
-        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (uint16_t)pcb->snd_queuelen));
-        LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
-        /* Prevent ACK for FIN to generate a sent event */
-        if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
-          pcb->acked--;
-        }
-
-        pcb->snd_queuelen -= pbuf_clen(next->p);
-        tcp_seg_free(next);
-
-        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (uint16_t)pcb->snd_queuelen));
-        if (pcb->snd_queuelen != 0) {
-          LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
-                      pcb->unsent != NULL);
-        }
-      }
-
-      /* If there's nothing left to acknowledge, stop the retransmit
-         timer, otherwise reset it to start again */
-      if(pcb->unacked == NULL)
-        pcb->rtime = -1;
-      else
-        pcb->rtime = 0;
-
-      pcb->polltmr = 0;
-    } else {
-      /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */
-      pcb->acked = 0;
-    }
-
-    /* We go through the ->unsent list to see if any of the segments
-       on the list are acknowledged by the ACK. This may seem
-       strange since an "unsent" segment shouldn't be acked. The
-       rationale is that lwIP puts all outstanding segments on the
-       ->unsent list after a retransmission, so these segments may
-       in fact have been sent once. */
-    while (pcb->unsent != NULL &&
-           TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + 
-                           TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) {
-      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
-                                    ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +
-                                    TCP_TCPLEN(pcb->unsent)));
-
-      next = pcb->unsent;
-      pcb->unsent = pcb->unsent->next;
-      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (uint16_t)pcb->snd_queuelen));
-      LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
-      /* Prevent ACK for FIN to generate a sent event */
-      if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
-        pcb->acked--;
-      }
-      pcb->snd_queuelen -= pbuf_clen(next->p);
-      tcp_seg_free(next);
-      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (uint16_t)pcb->snd_queuelen));
-      if (pcb->snd_queuelen != 0) {
-        LWIP_ASSERT("tcp_receive: valid queue length",
-          pcb->unacked != NULL || pcb->unsent != NULL);
-      }
-    }
-    /* End of ACK for new data processing. */
-
-    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",
-                                pcb->rttest, pcb->rtseq, ackno));
-
-    /* RTT estimation calculations. This is done by checking if the
-       incoming segment acknowledges the segment we use to take a
-       round-trip time measurement. */
-    if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {
-      /* diff between this shouldn't exceed 32K since this are tcp timer ticks
-         and a round-trip shouldn't be that long... */
-      m = (int16_t)(tcp_ticks - pcb->rttest);
-
-      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",
-                                  m, m * TCP_SLOW_INTERVAL));
-
-      /* This is taken directly from VJs original code in his paper */
-      m = m - (pcb->sa >> 3);
-      pcb->sa += m;
-      if (m < 0) {
-        m = -m;
-      }
-      m = m - (pcb->sv >> 2);
-      pcb->sv += m;
-      pcb->rto = (pcb->sa >> 3) + pcb->sv;
-
-      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",
-                                  pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
-
-      pcb->rttest = 0;
-    }
-  }
-
-  /* If the incoming segment contains data, we must process it
-     further. */
-  if (tcplen > 0) {
-    /* This code basically does three things:
-
-    +) If the incoming segment contains data that is the next
-    in-sequence data, this data is passed to the application. This
-    might involve trimming the first edge of the data. The rcv_nxt
-    variable and the advertised window are adjusted.
-
-    +) If the incoming segment has data that is above the next
-    sequence number expected (->rcv_nxt), the segment is placed on
-    the ->ooseq queue. This is done by finding the appropriate
-    place in the ->ooseq queue (which is ordered by sequence
-    number) and trim the segment in both ends if needed. An
-    immediate ACK is sent to indicate that we received an
-    out-of-sequence segment.
-
-    +) Finally, we check if the first segment on the ->ooseq queue
-    now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
-    rcv_nxt > ooseq->seqno, we must trim the first edge of the
-    segment on ->ooseq before we adjust rcv_nxt. The data in the
-    segments that are now on sequence are chained onto the
-    incoming segment so that we only need to call the application
-    once.
-    */
-
-    /* First, we check if we must trim the first edge. We have to do
-       this if the sequence number of the incoming segment is less
-       than rcv_nxt, and the sequence number plus the length of the
-       segment is larger than rcv_nxt. */
-    /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
-          if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/
-    if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){
-      /* Trimming the first edge is done by pushing the payload
-         pointer in the pbuf downwards. This is somewhat tricky since
-         we do not want to discard the full contents of the pbuf up to
-         the new starting point of the data since we have to keep the
-         TCP header which is present in the first pbuf in the chain.
-
-         What is done is really quite a nasty hack: the first pbuf in
-         the pbuf chain is pointed to by inseg.p. Since we need to be
-         able to deallocate the whole pbuf, we cannot change this
-         inseg.p pointer to point to any of the later pbufs in the
-         chain. Instead, we point the ->payload pointer in the first
-         pbuf to data in one of the later pbufs. We also set the
-         inseg.data pointer to point to the right place. This way, the
-         ->p pointer will still point to the first pbuf, but the
-         ->p->payload pointer will point to data in another pbuf.
-
-         After we are done with adjusting the pbuf pointers we must
-         adjust the ->data pointer in the seg and the segment
-         length.*/
-
-      off = pcb->rcv_nxt - seqno;
-      p = insegp->p;
-      LWIP_ASSERT("inseg.p != NULL", insegp->p);
-      LWIP_ASSERT("insane offset!", (off < 0x7fff));
-      if (insegp->p->len < off) {
-        LWIP_ASSERT("pbuf too short!", (((int32_t)insegp->p->tot_len) >= off));
-        new_tot_len = (uint16_t)(insegp->p->tot_len - off);
-        while (p->len < off) {
-          off -= p->len;
-          /* KJM following line changed (with addition of new_tot_len var)
-             to fix bug #9076
-             inseg.p->tot_len -= p->len; */
-          p->tot_len = new_tot_len;
-          p->len = 0;
-          p = STAILQ_NEXT(p, next);
-        }
-        if(pbuf_header(p, (int16_t)-off)) {
-          /* Do we need to cope with this failing?  Assert for now */
-          LWIP_ASSERT("pbuf_header failed", 0);
-        }
-      } else {
-        if(pbuf_header(insegp->p, (int16_t)-off)) {
-          /* Do we need to cope with this failing?  Assert for now */
-          LWIP_ASSERT("pbuf_header failed", 0);
-        }
-      }
-      /* KJM following line changed to use p->payload rather than inseg->p->payload
-         to fix bug #9076 */
-      insegp->dataptr = p->payload;
-      insegp->len -= (uint16_t)(pcb->rcv_nxt - seqno);
-      insegp->tcphdr->seqno = seqno = pcb->rcv_nxt;
-    }
-    else {
-      if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
-        /* the whole segment is < rcv_nxt */
-        /* must be a duplicate of a packet that has already been correctly handled */
-
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));
-        tcp_ack_now(pcb);
-      }
-    }
-
-    /* The sequence number must be within the window (above rcv_nxt
-       and below rcv_nxt + rcv_wnd) in order to be further
-       processed. */
-    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, 
-                        pcb->rcv_nxt + pcb->rcv_wnd - 1)){
-      if (pcb->rcv_nxt == seqno) {
-        /* The incoming segment is the next in sequence. We check if
-           we have to trim the end of the segment and update rcv_nxt
-           and pass the data to the application. */
-        tcplen = TCP_TCPLEN(insegp);
-
-        if (tcplen > pcb->rcv_wnd) {
-          LWIP_DEBUGF(TCP_INPUT_DEBUG, 
-                      ("tcp_receive: other end overran receive window"
-                       "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
-                       seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
-          if (TCPH_FLAGS(insegp->tcphdr) & TCP_FIN) {
-            /* Must remove the FIN from the header as we're trimming 
-             * that byte of sequence-space from the packet */
-            TCPH_FLAGS_SET(insegp->tcphdr, TCPH_FLAGS(insegp->tcphdr) &~ TCP_FIN);
-          }
-          /* Adjust length of segment to fit in the window. */
-          insegp->len = pcb->rcv_wnd;
-          if (TCPH_FLAGS(insegp->tcphdr) & TCP_SYN) {
-            insegp->len -= 1;
-          }
-          pbuf_realloc(insegp->p, insegp->len);
-          tcplen = TCP_TCPLEN(insegp);
-          LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
-                      (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
-        }
-#if TCP_QUEUE_OOSEQ
-        /* Received in-sequence data, adjust ooseq data if:
-           - FIN has been received or
-           - inseq overlaps with ooseq */
-        if (pcb->ooseq != NULL) {
-          if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
-            LWIP_DEBUGF(TCP_INPUT_DEBUG, 
-                        ("tcp_receive: received in-order FIN, binning ooseq queue\n"));
-            /* Received in-order FIN means anything that was received
-             * out of order must now have been received in-order, so
-             * bin the ooseq queue */
-            while (pcb->ooseq != NULL) {
-              struct tcp_seg *old_ooseq = pcb->ooseq;
-              pcb->ooseq = pcb->ooseq->next;
-              tcp_seg_free(old_ooseq);
-            }
-          }
-          else {
-            next = pcb->ooseq;
-            /* Remove all segments on ooseq that are covered by inseg already.
-             * FIN is copied from ooseq to inseg if present. */
-            while (next &&
-                   TCP_SEQ_GEQ(seqno + tcplen,
-                               next->tcphdr->seqno + next->len)) {
-              /* inseg cannot have FIN here (already processed above) */
-              if (TCPH_FLAGS(next->tcphdr) & TCP_FIN &&
-                  (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) {
-                TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN);
-                tcplen = TCP_TCPLEN(&inseg);
-              }
-              prev = next;
-              next = next->next;
-              tcp_seg_free(prev);
-            }
-            /* Now trim right side of inseg if it overlaps with the first
-             * segment on ooseq */
-            if (next &&
-                TCP_SEQ_GT(seqno + tcplen,
-                           next->tcphdr->seqno)) {
-              /* inseg cannot have FIN here (already processed above) */
-              inseg.len = (uint16_t)(next->tcphdr->seqno - seqno);
-              if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) {
-                inseg.len -= 1;
-              }
-              pbuf_realloc(inseg.p, inseg.len);
-              tcplen = TCP_TCPLEN(&inseg);
-              LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n",
-                          (seqno + tcplen) == next->tcphdr->seqno);
-            }
-            pcb->ooseq = next;
-          }
-        }
-#endif /* TCP_QUEUE_OOSEQ */
-
-        pcb->rcv_nxt = seqno + tcplen;
-
-        /* Update the receiver's (our) window. */
-        LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen);
-        pcb->rcv_wnd -= tcplen;
-
-        tcp_update_rcv_ann_wnd(pcb);
-
-        /* If there is data in the segment, we make preparations to
-           pass this up to the application. The ->recv_data variable
-           is used for holding the pbuf that goes to the
-           application. The code for reassembling out-of-sequence data
-           chains its data on this pbuf as well.
-
-           If the segment was a FIN, we set the TF_GOT_FIN flag that will
-           be used to indicate to the application that the remote side has
-           closed its end of the connection. */
-        if (insegp->p->tot_len > 0) {
-          recv_data = insegp->p;
-          /* Since this pbuf now is the responsibility of the
-             application, we delete our reference to it so that we won't
-             (mistakingly) deallocate it. */
-          insegp->p = NULL;
-        }
-        if (TCPH_FLAGS(insegp->tcphdr) & TCP_FIN) {
-          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
-          recv_flags |= TF_GOT_FIN;
-        }
-
-#if TCP_QUEUE_OOSEQ
-        /* We now check if we have segments on the ->ooseq queue that
-           are now in sequence. */
-        while (pcb->ooseq != NULL &&
-               pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
-
-          cseg = pcb->ooseq;
-          seqno = pcb->ooseq->tcphdr->seqno;
-
-          pcb->rcv_nxt += TCP_TCPLEN(cseg);
-          LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n",
-                      pcb->rcv_wnd >= TCP_TCPLEN(cseg));
-          pcb->rcv_wnd -= TCP_TCPLEN(cseg);
-
-          tcp_update_rcv_ann_wnd(pcb);
-
-          if (cseg->p->tot_len > 0) {
-            /* Chain this pbuf onto the pbuf that we will pass to
-               the application. */
-            if (recv_data) {
-              pbuf_cat(recv_data, cseg->p);
-            } else {
-              recv_data = cseg->p;
-            }
-            cseg->p = NULL;
-          }
-          if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
-            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
-            recv_flags |= TF_GOT_FIN;
-            if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */
-              pcb->state = CLOSE_WAIT;
-            } 
-          }
-
-          pcb->ooseq = cseg->next;
-          tcp_seg_free(cseg);
-        }
-#endif /* TCP_QUEUE_OOSEQ */
-
-
-        /* Acknowledge the segment(s). */
-        tcp_ack(pcb);
-
-      } else {
-        /* We get here if the incoming segment is out-of-sequence. */
-        tcp_send_empty_ack(pcb);
-#if TCP_QUEUE_OOSEQ
-        /* We queue the segment on the ->ooseq queue. */
-        if (pcb->ooseq == NULL) {
-          pcb->ooseq = tcp_seg_copy(&inseg);
-        } else {
-          /* If the queue is not empty, we walk through the queue and
-             try to find a place where the sequence number of the
-             incoming segment is between the sequence numbers of the
-             previous and the next segment on the ->ooseq queue. That is
-             the place where we put the incoming segment. If needed, we
-             trim the second edges of the previous and the incoming
-             segment so that it will fit into the sequence.
-
-             If the incoming segment has the same sequence number as a
-             segment on the ->ooseq queue, we discard the segment that
-             contains less data. */
-
-          prev = NULL;
-          for(next = pcb->ooseq; next != NULL; next = next->next) {
-            if (seqno == next->tcphdr->seqno) {
-              /* The sequence number of the incoming segment is the
-                 same as the sequence number of the segment on
-                 ->ooseq. We check the lengths to see which one to
-                 discard. */
-              if (inseg.len > next->len) {
-                /* The incoming segment is larger than the old
-                   segment. We replace some segments with the new
-                   one. */
-                cseg = tcp_seg_copy(&inseg);
-                if (cseg != NULL) {
-                  if (prev != NULL) {
-                    prev->next = cseg;
-                  } else {
-                    pcb->ooseq = cseg;
-                  }
-                  tcp_oos_insert_segment(cseg, next);
-                }
-                break;
-              } else {
-                /* Either the lenghts are the same or the incoming
-                   segment was smaller than the old one; in either
-                   case, we ditch the incoming segment. */
-                break;
-              }
-            } else {
-              if (prev == NULL) {
-                if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
-                  /* The sequence number of the incoming segment is lower
-                     than the sequence number of the first segment on the
-                     queue. We put the incoming segment first on the
-                     queue. */
-                  cseg = tcp_seg_copy(&inseg);
-                  if (cseg != NULL) {
-                    pcb->ooseq = cseg;
-                    tcp_oos_insert_segment(cseg, next);
-                  }
-                  break;
-                }
-              } else {
-                /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
-                  TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/
-                if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) {
-                  /* The sequence number of the incoming segment is in
-                     between the sequence numbers of the previous and
-                     the next segment on ->ooseq. We trim trim the previous
-                     segment, delete next segments that included in received segment
-                     and trim received, if needed. */
-                  cseg = tcp_seg_copy(&inseg);
-                  if (cseg != NULL) {
-                    if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
-                      /* We need to trim the prev segment. */
-                      prev->len = (uint16_t)(seqno - prev->tcphdr->seqno);
-                      pbuf_realloc(prev->p, prev->len);
-                    }
-                    prev->next = cseg;
-                    tcp_oos_insert_segment(cseg, next);
-                  }
-                  break;
-                }
-              }
-              /* If the "next" segment is the last segment on the
-                 ooseq queue, we add the incoming segment to the end
-                 of the list. */
-              if (next->next == NULL &&
-                  TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
-                if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) {
-                  /* segment "next" already contains all data */
-                  break;
-                }
-                next->next = tcp_seg_copy(&inseg);
-                if (next->next != NULL) {
-                  if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
-                    /* We need to trim the last segment. */
-                    next->len = (uint16_t)(seqno - next->tcphdr->seqno);
-                    pbuf_realloc(next->p, next->len);
-                  }
-                  /* check if the remote side overruns our receive window */
-                  if ((uint32_t)tcplen + seqno > pcb->rcv_nxt + (uint32_t)pcb->rcv_wnd) {
-                    LWIP_DEBUGF(TCP_INPUT_DEBUG, 
-                                ("tcp_receive: other end overran receive window"
-                                 "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n",
-                                 seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd));
-                    if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) {
-                      /* Must remove the FIN from the header as we're trimming 
-                       * that byte of sequence-space from the packet */
-                      TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN);
-                    }
-                    /* Adjust length of segment to fit in the window. */
-                    next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno;
-                    pbuf_realloc(next->next->p, next->next->len);
-                    tcplen = TCP_TCPLEN(next->next);
-                    LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n",
-                                (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd));
-                  }
-                }
-                break;
-              }
-            }
-            prev = next;
-          }
-        }
-#endif /* TCP_QUEUE_OOSEQ */
-
-      }
-    } else {
-      /* The incoming segment is not withing the window. */
-      tcp_send_empty_ack(pcb);
-    }
-  } else {
-    /* Segments with length 0 is taken care of here. Segments that
-       fall out of the window are ACKed. */
-    /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
-      TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/
-    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){
-      tcp_ack_now(pcb);
-    }
-  }
-}
-
-/**
- * Parses the options contained in the incoming segment. 
- *
- * Called from tcp_listen_input() and tcp_process().
- * Currently, only the MSS option is supported!
- *
- * @param pcb the tcp_pcb for which a segment arrived
- */
-static void
-tcp_parseopt(struct tcp_pcb *pcb, struct tcp_hdr *tcphdr)
-{
-  uint16_t c, max_c;
-  uint16_t mss;
-  uint8_t *opts, opt;
-#if LWIP_TCP_TIMESTAMPS
-  uint32_t tsval;
-#endif
-
-  opts = (uint8_t *)tcphdr + TCP_HLEN;
-
-  /* Parse the TCP MSS option, if present. */
-  if(TCPH_HDRLEN(tcphdr) > 0x5) {
-    max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2;
-    for (c = 0; c < max_c; ) {
-      opt = opts[c];
-      switch (opt) {
-      case 0x00:
-        /* End of options. */
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n"));
-        return;
-      case 0x01:
-        /* NOP option. */
-        ++c;
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n"));
-        break;
-      case 0x02:
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n"));
-        if (opts[c + 1] != 0x04 || c + 0x04 > max_c) {
-          /* Bad length */
-          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
-          return;
-        }
-        /* An MSS option with the right option length. */
-        mss = (opts[c + 2] << 8) | opts[c + 3];
-        /* Limit the mss to the configured TCP_MSS and prevent division by zero */
-        pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss;
-        /* Advance to next option */
-        c += 0x04;
-        break;
-#if LWIP_TCP_TIMESTAMPS
-      case 0x08:
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
-        if (opts[c + 1] != 0x0A || c + 0x0A > max_c) {
-          /* Bad length */
-          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
-          return;
-        }
-        /* TCP timestamp option with valid length */
-        tsval = (opts[c+2]) | (opts[c+3] << 8) | 
-          (opts[c+4] << 16) | (opts[c+5] << 24);
-        if (flags & TCP_SYN) {
-          pcb->ts_recent = ntohl(tsval);
-          pcb->flags |= TF_TIMESTAMP;
-        } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) {
-          pcb->ts_recent = ntohl(tsval);
-        }
-        /* Advance to next option */
-        c += 0x0A;
-        break;
-#endif
-      default:
-        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n"));
-        if (opts[c + 1] == 0) {
-          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
-          /* If the length field is zero, the options are malformed
-             and we don't process them further. */
-          return;
-        }
-        /* All other options have a length field, so that we easily
-           can skip past them. */
-        c += opts[c + 1];
-      }
-    }
-  }
-}
-
diff --git a/kern/src/net/tcp_out.c b/kern/src/net/tcp_out.c
deleted file mode 100644 (file)
index d6ba7f1..0000000
+++ /dev/null
@@ -1,1465 +0,0 @@
-/**
- * @file
- * Transmission Control Protocol, outgoing traffic
- *
- * The output functions of TCP.
- *
- */
-
-/*
- * 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>
- * Adapted by David Zhu for Akaros <yuzhu@cs.berkeley.edu>
- *
- */
-#include "net/tcp.h"
-#include "net/tcp_impl.h"
-#include "bits/netinet.h"
-#include "net/pbuf.h"
-#include "debug.h"
-#include "error.h"
-#include <string.h>
-
-/* Define some copy-macros for checksum-on-copy so that the code looks
-   nicer by preventing too many ifdef's. */
-#if TCP_CHECKSUM_ON_COPY
-#define TCP_DATA_COPY(dst, src, len, seg) do { \
-  tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \
-                     len, &seg->chksum, &seg->chksum_swapped); \
-  seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0)
-#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped)  \
-  tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped);
-#else /* TCP_CHECKSUM_ON_COPY*/
-#define TCP_DATA_COPY(dst, src, len, seg)                     memcpy(dst, src, len)
-#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) memcpy(dst, src, len)
-#endif /* TCP_CHECKSUM_ON_COPY*/
-
-/** Define this to 1 for an extra check that the output checksum is valid
- * (usefule when the checksum is generated by the application, not the stack) */
-#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK
-#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK   0
-#endif
-
-/* Forward declarations.*/
-static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);
-
-/** Allocate a pbuf and create a tcphdr at p->payload, used for output
- * functions other than the default tcp_output -> tcp_output_segment
- * (e.g. tcp_send_empty_ack, etc.)
- *
- * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr)
- * @param optlen length of header-options
- * @param datalen length of tcp data to reserve in pbuf
- * @param seqno_be seqno in network byte order (big-endian)
- * @return pbuf with p->payload being the tcp_hdr
- */
-static struct pbuf *
-tcp_output_alloc_header(struct tcp_pcb *pcb, uint16_t optlen, uint16_t datalen,
-                      uint32_t seqno_be /* already in network byte order */)
-{
-  struct tcp_hdr *tcphdr;
-  struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM);
-  if (p != NULL) {
-    LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
-                 (p->len >= TCP_HLEN + optlen));
-    tcphdr = (struct tcp_hdr *)p->payload;
-    tcphdr->src = htons(pcb->local_port);
-    tcphdr->dest = htons(pcb->remote_port);
-    tcphdr->seqno = seqno_be;
-    tcphdr->ackno = htonl(pcb->rcv_nxt);
-    TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
-    tcphdr->wnd = htons(pcb->rcv_ann_wnd);
-    tcphdr->chksum = 0;
-    tcphdr->urgp = 0;
-
-    /* If we're sending a packet, update the announced right window edge */
-    pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
-  }
-  return p;
-}
-
-/**
- * Called by tcp_close() to send a segment including FIN flag but not data.
- *
- * @param pcb the tcp_pcb over which to send a segment
- * @return ESUCCESS if sent, another error_t otherwise
- */
-error_t
-tcp_send_fin(struct tcp_pcb *pcb)
-{
-  /* first, try to add the fin to the last unsent segment */
-  if (pcb->unsent != NULL) {
-    struct tcp_seg *last_unsent;
-    for (last_unsent = pcb->unsent; last_unsent->next != NULL;
-         last_unsent = last_unsent->next);
-
-    if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) {
-      /* no SYN/FIN/RST flag in the header, we can add the FIN flag */
-      TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN);
-      return ESUCCESS;
-    }
-  }
-  /* no data, no length, flags, copy=1, no optdata */
-  return tcp_enqueue_flags(pcb, TCP_FIN);
-}
-
-/**
- * Create a TCP segment with prefilled header.
- *
- * Called by tcp_write and tcp_enqueue_flags.
- *
- * @param pcb Protocol control block for the TCP connection.
- * @param p pbuf that is used to hold the TCP header.
- * @param flags TCP flags for header.
- * @param seqno TCP sequence number of this packet
- * @param optflags options to include in TCP header
- * @return a new tcp_seg pointing to p, or NULL.
- * The TCP header is filled in except ackno and wnd.
- * p is freed on failure.
- */
-static struct tcp_seg *
-tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, uint8_t flags, uint32_t seqno, uint8_t optflags)
-{
-  struct tcp_seg *seg;
-  uint8_t optlen = LWIP_TCP_OPT_LENGTH(optflags);
-
-  if ((seg = (struct tcp_seg *)kmem_cache_alloc(tcp_segment_kcache, 0)) == NULL) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n"));
-    pbuf_free(p);
-    return NULL;
-  }
-  seg->flags = optflags;
-  seg->next = NULL;
-  seg->p = p;
-  seg->dataptr = p->payload;
-  seg->len = p->tot_len - optlen;
-#if TCP_OVERSIZE_DBGCHECK
-  seg->oversize_left = 0;
-#endif /* TCP_OVERSIZE_DBGCHECK */
-#if TCP_CHECKSUM_ON_COPY
-  seg->chksum = 0;
-  seg->chksum_swapped = 0;
-  /* check optflags */
-  LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED",
-              (optflags & TF_SEG_DATA_CHECKSUMMED) == 0);
-#endif /* TCP_CHECKSUM_ON_COPY */
-
-  /* build TCP header */
-  if (pbuf_header(p, TCP_HLEN)) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n"));
-    //TCP_STATS_INC(tcp.err);
-    tcp_seg_free(seg);
-    return NULL;
-  }
-  seg->tcphdr = (struct tcp_hdr *)seg->p->payload;
-  seg->tcphdr->src = htons(pcb->local_port);
-  seg->tcphdr->dest = htons(pcb->remote_port);
-  seg->tcphdr->seqno = htonl(seqno);
-  /* ackno is set in tcp_output */
-  TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags);
-  /* wnd and chksum are set in tcp_output */
-  seg->tcphdr->urgp = 0;
-  return seg;
-} 
-
-/**
- * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end.
- *
- * This function is like pbuf_alloc(layer, length, PBUF_RAM) except
- * there may be extra bytes available at the end.
- *
- * @param layer flag to define header size.
- * @param length size of the pbuf's payload.
- * @param max_length maximum usable size of payload+oversize.
- * @param oversize pointer to a uint16_t that will receive the number of usable tail bytes.
- * @param pcb The TCP connection that willo enqueue the pbuf.
- * @param apiflags API flags given to tcp_write.
- * @param first_seg true when this pbuf will be used in the first enqueued segment.
- * @param 
- */
-#if TCP_OVERSIZE
-static struct pbuf *
-tcp_pbuf_prealloc(pbuf_layer layer, uint16_t length, uint16_t max_length,
-                  uint16_t *oversize, struct tcp_pcb *pcb, uint8_t apiflags,
-                  uint8_t first_seg)
-{
-  struct pbuf *p;
-  uint16_t alloc = length;
-
-#if LWIP_NETIF_TX_SINGLE_PBUF
-  LWIP_UNUSED_ARG(max_length);
-  LWIP_UNUSED_ARG(pcb);
-  LWIP_UNUSED_ARG(apiflags);
-  LWIP_UNUSED_ARG(first_seg);
-  /* always create MSS-sized pbufs */
-  alloc = TCP_MSS;
-#else /* LWIP_NETIF_TX_SINGLE_PBUF */
-  if (length < max_length) {
-    /* Should we allocate an oversized pbuf, or just the minimum
-     * length required? If tcp_write is going to be called again
-     * before this segment is transmitted, we want the oversized
-     * buffer. If the segment will be transmitted immediately, we can
-     * save memory by allocating only length. We use a simple
-     * heuristic based on the following information:
-     *
-     * Did the user set TCP_WRITE_FLAG_MORE?
-     *
-     * Will the Nagle algorithm defer transmission of this segment?
-     */
-    if ((apiflags & TCP_WRITE_FLAG_MORE) ||
-        (!(pcb->flags & TF_NODELAY) &&
-         (!first_seg ||
-          pcb->unsent != NULL ||
-          pcb->unacked != NULL))) {
-      alloc = MIN(max_length, ROUNDUP(length + TCP_OVERSIZE, sizeof(void*)));
-    }
-  }
-#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
-  p = pbuf_alloc(layer, alloc, PBUF_RAM);
-  if (p == NULL) {
-    return NULL;
-  }
-  LWIP_ASSERT("need unchained pbuf", (STAILQ_NEXT(p, next) == NULL));
-  *oversize = p->len - length;
-  /* trim p->len to the currently used size */
-  p->len = p->tot_len = length;
-  return p;
-}
-#else /* TCP_OVERSIZE */
-#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM)
-#endif /* TCP_OVERSIZE */
-
-#if TCP_CHECKSUM_ON_COPY
-/** Add a checksum of newly added data to the segment */
-static void
-tcp_seg_add_chksum(uint16_t chksum, uint16_t len, uint16_t *seg_chksum,
-                   uint8_t *seg_chksum_swapped)
-{
-  uint32_t helper;
-  /* add chksum to old chksum and fold to uint16_t */
-  helper = chksum + *seg_chksum;
-  chksum = FOLD_U32T(helper);
-  if ((len & 1) != 0) {
-    *seg_chksum_swapped = 1 - *seg_chksum_swapped;
-    chksum = SWAP_BYTES_IN_WORD(chksum);
-  }
-  *seg_chksum = chksum;
-}
-#endif /* TCP_CHECKSUM_ON_COPY */
-
-/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen).
- *
- * @param pcb the tcp pcb to check for
- * @param len length of data to send (checked agains snd_buf)
- * @return ESUCCESS if tcp_write is allowed to proceed, another error_t otherwise
- */
-static error_t
-tcp_write_checks(struct tcp_pcb *pcb, uint16_t len)
-{
-  /* connection is in invalid state for data transmission? */
-  if ((pcb->state != ESTABLISHED) &&
-      (pcb->state != CLOSE_WAIT) &&
-      (pcb->state != SYN_SENT) &&
-      (pcb->state != SYN_RCVD)) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n"));
-    return -ENOTCONN;
-  } else if (len == 0) {
-    return ESUCCESS;
-  }
-
-  /* fail on too much data */
-  if (len > pcb->snd_buf) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n",
-      len, pcb->snd_buf));
-    pcb->flags |= TF_NAGLEMEMERR;
-    return -ENOMEM;
-  }
-
-  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (uint16_t)pcb->snd_queuelen));
-
-  /* If total number of pbufs on the unsent/unacked queues exceeds the
-   * configured maximum, return an error */
-  /* check for configured max queuelen and possible overflow */
-  if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n",
-      pcb->snd_queuelen, TCP_SND_QUEUELEN));
-    //TCP_STATS_INC(tcp.memerr);
-    pcb->flags |= TF_NAGLEMEMERR;
-    return -ENOMEM;
-  }
-  if (pcb->snd_queuelen != 0) {
-    LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty",
-      pcb->unacked != NULL || pcb->unsent != NULL);
-  } else {
-    LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty",
-      pcb->unacked == NULL && pcb->unsent == NULL);
-  }
-  return ESUCCESS;
-}
-
-/**
- * Write data for sending (but does not send it immediately).
- *
- * It waits in the expectation of more data being sent soon (as
- * it can send them more efficiently by combining them together).
- * To prompt the system to send data now, call tcp_output() after
- * calling tcp_write().
- *
- * @param pcb Protocol control block for the TCP connection to enqueue data for.
- * @param arg Pointer to the data to be enqueued for sending.
- * @param len Data length in bytes
- * @param apiflags combination of following flags :
- * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack
- * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,
- * @return ESUCCESS if enqueued, another error_t on error
- */
-error_t
-tcp_write(struct tcp_pcb *pcb, const void *arg, uint16_t len, uint8_t apiflags)
-{
-  struct pbuf *concat_p = NULL;
-  struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL;
-  uint16_t pos = 0; /* position in 'arg' data */
-  uint16_t queuelen;
-  uint8_t optlen = 0;
-  uint8_t optflags = 0;
-#if TCP_OVERSIZE
-  uint16_t oversize = 0;
-  uint16_t oversize_used = 0;
-#endif /* TCP_OVERSIZE */
-#if TCP_CHECKSUM_ON_COPY
-  uint16_t concat_chksum = 0;
-  uint8_t concat_chksum_swapped = 0;
-  uint16_t concat_chksummed = 0;
-#endif /* TCP_CHECKSUM_ON_COPY */
-  error_t err;
-
-#if LWIP_NETIF_TX_SINGLE_PBUF
-  /* Always copy to try to create single pbufs for TX */
-  apiflags |= TCP_WRITE_FLAG_COPY;
-#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
-
-  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n",
-    (void *)pcb, arg, len, (uint16_t)apiflags));
-  LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", 
-             arg != NULL, return -EFAIL;);
-
-  err = tcp_write_checks(pcb, len);
-  if (err != ESUCCESS) {
-    return err;
-  }
-  queuelen = pcb->snd_queuelen;
-
-#if LWIP_TCP_TIMESTAMPS
-  if ((pcb->flags & TF_TIMESTAMP)) {
-    optflags = TF_SEG_OPTS_TS;
-    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
-  }
-#endif /* LWIP_TCP_TIMESTAMPS */
-
-
-  /*
-   * TCP segmentation is done in three phases with increasing complexity:
-   *
-   * 1. Copy data directly into an oversized pbuf.
-   * 2. Chain a new pbuf to the end of pcb->unsent.
-   * 3. Create new segments.
-   *
-   * We may run out of memory at any point. In that case we must
-   * return -ENOMEM and not change anything in pcb. Therefore, all
-   * changes are recorded in local variables and committed at the end
-   * of the function. Some pcb fields are maintained in local copies:
-   *
-   * queuelen = pcb->snd_queuelen
-   * oversize = pcb->unsent_oversize
-   *
-   * These variables are set consistently by the phases:
-   *
-   * seg points to the last segment tampered with.
-   *
-   * pos records progress as data is segmented.
-   */
-
-  /* Find the tail of the unsent queue. */
-  if (pcb->unsent != NULL) {
-    uint16_t space;
-    uint16_t unsent_optlen;
-
-    /* @todo: this could be sped up by keeping last_unsent in the pcb */
-    for (last_unsent = pcb->unsent; last_unsent->next != NULL;
-         last_unsent = last_unsent->next);
-
-    /* Usable space at the end of the last unsent segment */
-    unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags);
-    space = pcb->mss - (last_unsent->len + unsent_optlen);
-
-    /*
-     * Phase 1: Copy data directly into an oversized pbuf.
-     *
-     * The number of bytes copied is recorded in the oversize_used
-     * variable. The actual copying is done at the bottom of the
-     * function.
-     */
-#if TCP_OVERSIZE
-#if TCP_OVERSIZE_DBGCHECK
-    /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */
-    LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)",
-                pcb->unsent_oversize == last_unsent->oversize_left);
-#endif /* TCP_OVERSIZE_DBGCHECK */
-    oversize = pcb->unsent_oversize;
-    if (oversize > 0) {
-      LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space);
-      seg = last_unsent;
-      oversize_used = oversize < len ? oversize : len;
-      pos += oversize_used;
-      oversize -= oversize_used;
-      space -= oversize_used;
-    }
-    /* now we are either finished or oversize is zero */
-    LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len));
-#endif /* TCP_OVERSIZE */
-
-    /*
-     * Phase 2: Chain a new pbuf to the end of pcb->unsent.
-     *
-     * We don't extend segments containing SYN/FIN flags or options
-     * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at
-     * the end.
-     */
-    if ((pos < len) && (space > 0) && (last_unsent->len > 0)) {
-      uint16_t seglen = space < len - pos ? space : len - pos;
-      seg = last_unsent;
-
-      /* Create a pbuf with a copy or reference to seglen bytes. We
-       * can use PBUF_RAW here since the data appears in the middle of
-       * a segment. A header will never be prepended. */
-      if (apiflags & TCP_WRITE_FLAG_COPY) {
-        /* Data is copied */
-        if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) {
-          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
-                      ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n",
-                       seglen));
-          goto memerr;
-        }
-#if TCP_OVERSIZE_DBGCHECK
-        last_unsent->oversize_left = oversize;
-#endif /* TCP_OVERSIZE_DBGCHECK */
-        TCP_DATA_COPY2(concat_p->payload, (uint8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped);
-#if TCP_CHECKSUM_ON_COPY
-        concat_chksummed += seglen;
-#endif /* TCP_CHECKSUM_ON_COPY */
-      } else {
-        /* Data is not copied */
-        if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) {
-          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,
-                      ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
-          goto memerr;
-        }
-#if TCP_CHECKSUM_ON_COPY
-        /* calculate the checksum of nocopy-data */
-        tcp_seg_add_chksum(~inet_chksum((uint8_t*)arg + pos, seglen), seglen,
-          &concat_chksum, &concat_chksum_swapped);
-        concat_chksummed += seglen;
-#endif /* TCP_CHECKSUM_ON_COPY */
-        /* reference the non-volatile payload data */
-        concat_p->payload = (uint8_t*)arg + pos;
-      }
-
-      pos += seglen;
-      queuelen += pbuf_clen(concat_p);
-    }
-  } else {
-#if TCP_OVERSIZE
-    LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)",
-                pcb->unsent_oversize == 0);
-#endif /* TCP_OVERSIZE */
-  }
-
-  /*
-   * Phase 3: Create new segments.
-   *
-   * The new segments are chained together in the local 'queue'
-   * variable, ready to be appended to pcb->unsent.
-   */
-  while (pos < len) {
-    struct pbuf *p;
-    uint16_t left = len - pos;
-    uint16_t max_len = pcb->mss - optlen;
-    uint16_t seglen = left > max_len ? max_len : left;
-#if TCP_CHECKSUM_ON_COPY
-    uint16_t chksum = 0;
-    uint8_t chksum_swapped = 0;
-#endif /* TCP_CHECKSUM_ON_COPY */
-
-    if (apiflags & TCP_WRITE_FLAG_COPY) {
-      /* If copy is set, memory should be allocated and data copied
-       * into pbuf */
-      if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) {
-        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));
-        goto memerr;
-      }
-      LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen",
-                  (p->len >= seglen));
-      TCP_DATA_COPY2((char *)p->payload + optlen, (uint8_t*)arg + pos, seglen, &chksum, &chksum_swapped);
-    } else {
-      /* Copy is not set: First allocate a pbuf for holding the data.
-       * Since the referenced data is available at least until it is
-       * sent out on the link (as it has to be ACKed by the remote
-       * party) we can safely use PBUF_ROM instead of PBUF_REF here.
-       */
-      struct pbuf *p2;
-#if TCP_OVERSIZE
-      LWIP_ASSERT("oversize == 0", oversize == 0);
-#endif /* TCP_OVERSIZE */
-      if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
-        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n"));
-        goto memerr;
-      }
-#if TCP_CHECKSUM_ON_COPY
-      /* calculate the checksum of nocopy-data */
-      chksum = ~inet_chksum((uint8_t*)arg + pos, seglen);
-#endif /* TCP_CHECKSUM_ON_COPY */
-      /* reference the non-volatile payload data */
-      p2->payload = (uint8_t*)arg + pos;
-
-      /* Second, allocate a pbuf for the headers. */
-      if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
-        /* If allocation fails, we have to deallocate the data pbuf as
-         * well. */
-        pbuf_free(p2);
-        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n"));
-        goto memerr;
-      }
-      /* Concatenate the headers and data pbufs together. */
-      pbuf_cat(p/*header*/, p2/*data*/);
-    }
-
-    queuelen += pbuf_clen(p);
-
-    /* Now that there are more segments queued, we check again if the
-     * length of the queue exceeds the configured maximum or
-     * overflows. */
-    if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
-      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
-      pbuf_free(p);
-      goto memerr;
-    }
-
-    if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {
-      goto memerr;
-    }
-#if TCP_OVERSIZE_DBGCHECK
-    seg->oversize_left = oversize;
-#endif /* TCP_OVERSIZE_DBGCHECK */
-#if TCP_CHECKSUM_ON_COPY
-    seg->chksum = chksum;
-    seg->chksum_swapped = chksum_swapped;
-    seg->flags |= TF_SEG_DATA_CHECKSUMMED;
-#endif /* TCP_CHECKSUM_ON_COPY */
-    /* Fix dataptr for the nocopy case */
-    if ((apiflags & TCP_WRITE_FLAG_COPY) == 0) {
-      seg->dataptr = (uint8_t*)arg + pos;
-    }
-
-    /* first segment of to-be-queued data? */
-    if (queue == NULL) {
-      queue = seg;
-    } else {
-      /* Attach the segment to the end of the queued segments */
-      LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL);
-      prev_seg->next = seg;
-    }
-    /* remember last segment of to-be-queued data for next iteration */
-    prev_seg = seg;
-
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n",
-      ntohl(seg->tcphdr->seqno),
-      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
-
-    pos += seglen;
-  }
-
-  /*
-   * All three segmentation phases were successful. We can commit the
-   * transaction.
-   */
-
-  /*
-   * Phase 1: If data has been added to the preallocated tail of
-   * last_unsent, we update the length fields of the pbuf chain.
-   */
-#if TCP_OVERSIZE
-  if (oversize_used > 0) {
-    struct pbuf *p;
-    /* Bump tot_len of whole chain, len of tail */
-    for (p = last_unsent->p; p; p = STAILQ_NEXT(p, next)) {
-      p->tot_len += oversize_used;
-      if (STAILQ_NEXT(p, next) == NULL) {
-        TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent);
-        p->len += oversize_used;
-      }
-    }
-    last_unsent->len += oversize_used;
-#if TCP_OVERSIZE_DBGCHECK
-    last_unsent->oversize_left -= oversize_used;
-#endif /* TCP_OVERSIZE_DBGCHECK */
-  }
-  pcb->unsent_oversize = oversize;
-#endif /* TCP_OVERSIZE */
-
-  /*
-   * Phase 2: concat_p can be concatenated onto last_unsent->p
-   */
-  if (concat_p != NULL) {
-    LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty",
-      (last_unsent != NULL));
-    pbuf_cat(last_unsent->p, concat_p);
-    last_unsent->len += concat_p->tot_len;
-#if TCP_CHECKSUM_ON_COPY
-    if (concat_chksummed) {
-      tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum,
-        &last_unsent->chksum_swapped);
-      last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED;
-    }
-#endif /* TCP_CHECKSUM_ON_COPY */
-  }
-
-  /*
-   * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that
-   * is harmless
-   */
-  if (last_unsent == NULL) {
-    pcb->unsent = queue;
-  } else {
-    last_unsent->next = queue;
-  }
-
-  /*
-   * Finally update the pcb state.
-   */
-  pcb->snd_lbb += len;
-  pcb->snd_buf -= len;
-  pcb->snd_queuelen = queuelen;
-
-  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n",
-    pcb->snd_queuelen));
-  if (pcb->snd_queuelen != 0) {
-    LWIP_ASSERT("tcp_write: valid queue length",
-                pcb->unacked != NULL || pcb->unsent != NULL);
-  }
-
-  /* Set the PSH flag in the last segment that we enqueued. */
-  if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) {
-    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
-  }
-
-  return ESUCCESS;
-memerr:
-  pcb->flags |= TF_NAGLEMEMERR;
-  // TCP_STATS_INC(tcp.memerr);
-
-  if (concat_p != NULL) {
-    pbuf_free(concat_p);
-  }
-  if (queue != NULL) {
-    tcp_segs_free(queue);
-  }
-  if (pcb->snd_queuelen != 0) {
-    LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL ||
-      pcb->unsent != NULL);
-  }
-  LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen));
-  return -ENOMEM;
-}
-
-/**
- * Enqueue TCP options for transmission.
- *
- * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl().
- *
- * @param pcb Protocol control block for the TCP connection.
- * @param flags TCP header flags to set in the outgoing segment.
- * @param optdata pointer to TCP options, or NULL.
- * @param optlen length of TCP options in bytes.
- */
-error_t
-tcp_enqueue_flags(struct tcp_pcb *pcb, uint8_t flags)
-{
-  struct pbuf *p;
-  struct tcp_seg *seg;
-  uint8_t optflags = 0;
-  uint8_t optlen = 0;
-
-  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (uint16_t)pcb->snd_queuelen));
-
-  LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)",
-              (flags & (TCP_SYN | TCP_FIN)) != 0);
-
-  /* check for configured max queuelen and possible overflow */
-  if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n",
-                                       pcb->snd_queuelen, TCP_SND_QUEUELEN));
-    // TCP_STATS_INC(tcp.memerr);
-    pcb->flags |= TF_NAGLEMEMERR;
-    return -ENOMEM;
-  }
-
-  if (flags & TCP_SYN) {
-    optflags = TF_SEG_OPTS_MSS;
-  }
-#if LWIP_TCP_TIMESTAMPS
-  if ((pcb->flags & TF_TIMESTAMP)) {
-    optflags |= TF_SEG_OPTS_TS;
-  }
-#endif /* LWIP_TCP_TIMESTAMPS */
-  optlen = LWIP_TCP_OPT_LENGTH(optflags);
-
-  /* tcp_enqueue_flags is always called with either SYN or FIN in flags.
-   * We need one available snd_buf byte to do that.
-   * This means we can't send FIN while snd_buf==0. A better fix would be to
-   * not include SYN and FIN sequence numbers in the snd_buf count. */
-  if (pcb->snd_buf == 0) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n"));
-    // TCP_STATS_INC(tcp.memerr);
-    return -ENOMEM;
-  }
-
-  /* Allocate pbuf with room for TCP header + options */
-  if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
-    pcb->flags |= TF_NAGLEMEMERR;
-    // TCP_STATS_INC(tcp.memerr);
-    return -ENOMEM;
-  }
-  LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen",
-              (p->len >= optlen));
-
-  /* Allocate memory for tcp_seg, and fill in fields. */
-  if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) {
-    pcb->flags |= TF_NAGLEMEMERR;
-    //TCP_STATS_INC(tcp.memerr);
-    return -ENOMEM;
-  }
-  LWIP_ASSERT("seg->tcphdr not aligned",
-              ((uintptr_t)seg->tcphdr % sizeof(void*)) == 0);
-  LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0);
-
-  LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE,
-              ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",
-               ntohl(seg->tcphdr->seqno),
-               ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
-               (uint16_t)flags));
-
-  /* Now append seg to pcb->unsent queue */
-  if (pcb->unsent == NULL) {
-    pcb->unsent = seg;
-  } else {
-    struct tcp_seg *useg;
-    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);
-    useg->next = seg;
-  }
-#if TCP_OVERSIZE
-  /* The new unsent tail has no space */
-  pcb->unsent_oversize = 0;
-#endif /* TCP_OVERSIZE */
-
-  /* SYN and FIN bump the sequence number */
-  if ((flags & TCP_SYN) || (flags & TCP_FIN)) {
-    pcb->snd_lbb++;
-    /* optlen does not influence snd_buf */
-    pcb->snd_buf--;
-  }
-  if (flags & TCP_FIN) {
-    pcb->flags |= TF_FIN;
-  }
-
-  /* update number of segments on the queues */
-  pcb->snd_queuelen += pbuf_clen(seg->p);
-  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));
-  if (pcb->snd_queuelen != 0) {
-    LWIP_ASSERT("tcp_enqueue_flags: invalid queue length",
-      pcb->unacked != NULL || pcb->unsent != NULL);
-  }
-
-  return ESUCCESS;
-}
-
-#if LWIP_TCP_TIMESTAMPS
-/* Build a timestamp option (12 bytes long) at the specified options pointer)
- *
- * @param pcb tcp_pcb
- * @param opts option pointer where to store the timestamp option
- */
-static void
-tcp_build_timestamp_option(struct tcp_pcb *pcb, uint32_t *opts)
-{
-  /* Pad with two NOP options to make everything nicely aligned */
-  opts[0] = PP_HTONL(0x0101080A);
-  opts[1] = htonl(sys_now());
-  opts[2] = htonl(pcb->ts_recent);
-}
-#endif
-
-/** Send an ACK without data.
- *
- * @param pcb Protocol control block for the TCP connection to send the ACK
- */
-error_t
-tcp_send_empty_ack(struct tcp_pcb *pcb)
-{
-  struct pbuf *p;
-  struct tcp_hdr *tcphdr;
-  uint8_t optlen = 0;
-
-#if LWIP_TCP_TIMESTAMPS
-  if (pcb->flags & TF_TIMESTAMP) {
-    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
-  }
-#endif
-
-  p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt));
-  if (p == NULL) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));
-    return -ENOMEM;
-  }
-  tcphdr = (struct tcp_hdr *)p->payload;
-  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, 
-              ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));
-  /* remove ACK flags from the PCB, as we send an empty ACK now */
-  pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
-
-  /* NB. MSS option is only sent on SYNs, so ignore it here */
-#if LWIP_TCP_TIMESTAMPS
-  pcb->ts_lastacksent = pcb->rcv_nxt;
-
-  if (pcb->flags & TF_TIMESTAMP) {
-    tcp_build_timestamp_option(pcb, (uint32_t *)(tcphdr + 1));
-  }
-#endif 
-
-#if CHECKSUM_GEN_TCP
-  tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),
-        IP_PROTO_TCP, p->tot_len);
-#endif
-#if LWIP_NETIF_HWADDRHINT
-   ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-      IPPROTO_TCP, &(pcb->addr_hint));
-#else /* LWIP_NETIF_HWADDRHINT*/
-   ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-      IPPROTO_TCP);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-  pbuf_free(p);
-
-  return ESUCCESS;
-}
-
-/**
- * Find out what we can send and send it
- *
- * @param pcb Protocol control block for the TCP connection to send data
- * @return ESUCCESS if data has been sent or nothing to send
- *         another error_t on error
- */
-error_t
-tcp_output(struct tcp_pcb *pcb)
-{
-  struct tcp_seg *seg, *useg;
-  uint32_t wnd, snd_nxt;
-#if TCP_CWND_DEBUG
-  s16_t i = 0;
-#endif /* TCP_CWND_DEBUG */
-
-  /* First, check if we are invoked by the TCP input processing
-     code. If so, we do not output anything. Instead, we rely on the
-     input processing code to call us when input processing is done
-     with. */
-  if (tcp_input_pcb == pcb) {
-    return ESUCCESS;
-  }
-
-  wnd = MIN(pcb->snd_wnd, pcb->cwnd);
-
-  seg = pcb->unsent;
-
-  /* If the TF_ACK_NOW flag is set and no data will be sent (either
-   * because the ->unsent queue is empty or because the window does
-   * not allow it), construct an empty ACK segment and send it.
-   *
-   * If data is to be sent, we will just piggyback the ACK (see below).
-   */
-  if (pcb->flags & TF_ACK_NOW &&
-     (seg == NULL ||
-      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {
-     return tcp_send_empty_ack(pcb);
-  }
-
-  /* useg should point to last segment on unacked queue */
-  useg = pcb->unacked;
-  if (useg != NULL) {
-    for (; useg->next != NULL; useg = useg->next);
-  }
-
-#if TCP_OUTPUT_DEBUG
-  if (seg == NULL) {
-    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
-                                   (void*)pcb->unsent));
-  }
-#endif /* TCP_OUTPUT_DEBUG */
-#if TCP_CWND_DEBUG
-  if (seg == NULL) {
-    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
-                                 ", cwnd %"U16_F", wnd %"U32_F
-                                 ", seg == NULL, ack %"U32_F"\n",
-                                 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
-  } else {
-    LWIP_DEBUGF(TCP_CWND_DEBUG, 
-                ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
-                 ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
-                 pcb->snd_wnd, pcb->cwnd, wnd,
-                 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
-                 ntohl(seg->tcphdr->seqno), pcb->lastack));
-  }
-#endif /* TCP_CWND_DEBUG */
-  /* data available and window allows it to be sent? */
-  while (seg != NULL &&
-         ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
-    LWIP_ASSERT("RST not expected here!", 
-                (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
-    /* Stop sending if the nagle algorithm would prevent it
-     * Don't stop:
-     * - if tcp_write had a memory error before (prevent delayed ACK timeout) or
-     * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -
-     *   either seg->next != NULL or pcb->unacked == NULL;
-     *   RST is no sent using tcp_write/tcp_output.
-     */
-    if((tcp_do_output_nagle(pcb) == 0) &&
-      ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){
-      break;
-    }
-#if TCP_CWND_DEBUG
-    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
-                            pcb->snd_wnd, pcb->cwnd, wnd,
-                            ntohl(seg->tcphdr->seqno) + seg->len -
-                            pcb->lastack,
-                            ntohl(seg->tcphdr->seqno), pcb->lastack, i));
-    ++i;
-#endif /* TCP_CWND_DEBUG */
-
-    pcb->unsent = seg->next;
-
-    if (pcb->state != SYN_SENT) {
-      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
-      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
-    }
-
-    tcp_output_segment(seg, pcb);
-    snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
-    if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
-      pcb->snd_nxt = snd_nxt;
-    }
-    /* put segment on unacknowledged list if length > 0 */
-    if (TCP_TCPLEN(seg) > 0) {
-      seg->next = NULL;
-      /* unacked list is empty? */
-      if (pcb->unacked == NULL) {
-        pcb->unacked = seg;
-        useg = seg;
-      /* unacked list is not empty? */
-      } else {
-        /* In the case of fast retransmit, the packet should not go to the tail
-         * of the unacked queue, but rather somewhere before it. We need to check for
-         * this case. -STJ Jul 27, 2004 */
-        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) {
-          /* add segment to before tail of unacked list, keeping the list sorted */
-          struct tcp_seg **cur_seg = &(pcb->unacked);
-          while (*cur_seg &&
-            TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
-              cur_seg = &((*cur_seg)->next );
-          }
-          seg->next = (*cur_seg);
-          (*cur_seg) = seg;
-        } else {
-          /* add segment to tail of unacked list */
-          useg->next = seg;
-          useg = useg->next;
-        }
-      }
-    /* do not queue empty segments on the unacked list */
-    } else {
-      tcp_seg_free(seg);
-    }
-    seg = pcb->unsent;
-  }
-#if TCP_OVERSIZE
-  if (pcb->unsent == NULL) {
-    /* last unsent has been removed, reset unsent_oversize */
-    pcb->unsent_oversize = 0;
-  }
-#endif /* TCP_OVERSIZE */
-
-  if (seg != NULL && pcb->persist_backoff == 0 && 
-      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {
-    /* prepare for persist timer */
-    pcb->persist_cnt = 0;
-    pcb->persist_backoff = 1;
-  }
-
-  pcb->flags &= ~TF_NAGLEMEMERR;
-  return ESUCCESS;
-}
-
-/**
- * Called by tcp_output() to actually send a TCP segment over IP.
- *
- * @param seg the tcp_seg to send
- * @param pcb the tcp_pcb for the TCP connection used to send the segment
- */
-static void
-tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
-{
-  uint16_t len;
-  struct netif *netif;
-  uint32_t *opts;
-
-  /** @bug Exclude retransmitted segments from this count. */
-  //snmp_inc_tcpoutsegs();
-
-  /* The TCP header has already been constructed, but the ackno and
-   wnd fields remain. */
-  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
-
-  /* advertise our receive window size in this TCP segment */
-  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
-
-  pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
-
-  /* Add any requested options.  NB MSS option is only set on SYN
-     packets, so ignore it here */
-  LWIP_ASSERT("seg->tcphdr not aligned",
-              ((uintptr_t)seg->tcphdr % sizeof(void*)) == 0);
-  opts = (uint32_t *)(void *)(seg->tcphdr + 1);
-  if (seg->flags & TF_SEG_OPTS_MSS) {
-    TCP_BUILD_MSS_OPTION(*opts);
-    opts += 1;
-  }
-#if LWIP_TCP_TIMESTAMPS
-  pcb->ts_lastacksent = pcb->rcv_nxt;
-
-  if (seg->flags & TF_SEG_OPTS_TS) {
-    tcp_build_timestamp_option(pcb, opts);
-    opts += 3;
-  }
-#endif
-
-  /* If we don't have a local IP address, we get one by
-     calling ip_route(). */
-  if (ip_addr_isany(&(pcb->local_ip))) {
-               pcb->local_ip = LOCAL_IP_ADDR;
-               /*
-    netif = ip_route(&(pcb->remote_ip));
-    if (netif == NULL) {
-      return;
-    }
-    ip_addr_copy(pcb->local_ip, netif->ip_addr);
-               */
-  }
-
-  /* Set retransmission timer running if it is not currently enabled */
-  if(pcb->rtime == -1) {
-    pcb->rtime = 0;
-  }
-
-  if (pcb->rttest == 0) {
-    pcb->rttest = tcp_ticks;
-    pcb->rtseq = ntohl(seg->tcphdr->seqno);
-
-    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));
-  }
-  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",
-          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
-          seg->len));
-
-  len = (uint16_t)((uint8_t *)seg->tcphdr - (uint8_t *)seg->p->payload);
-
-  seg->p->len -= len;
-  seg->p->tot_len -= len;
-
-  seg->p->payload = seg->tcphdr;
-
-  seg->tcphdr->chksum = 0;
-#if CHECKSUM_GEN_TCP
-#if TCP_CHECKSUM_ON_COPY
-  {
-    uint32_t acc;
-#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
-    uint16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
-           &(pcb->remote_ip),
-           IP_PROTO_TCP, seg->p->tot_len);
-#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
-    if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
-      LWIP_ASSERT("data included but not checksummed",
-        seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));
-    }
-
-    /* rebuild TCP header checksum (TCP header changes for retransmissions!) */
-    acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
-             &(pcb->remote_ip),
-             IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
-    /* add payload checksum */
-    if (seg->chksum_swapped) {
-      seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
-      seg->chksum_swapped = 0;
-    }
-    acc += (uint16_t)~(seg->chksum);
-    seg->tcphdr->chksum = FOLD_U32T(acc);
-#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
-    if (chksum_slow != seg->tcphdr->chksum) {
-      LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
-                  ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n",
-                  seg->tcphdr->chksum, chksum_slow));
-      seg->tcphdr->chksum = chksum_slow;
-    }
-#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
-  }
-#else /* TCP_CHECKSUM_ON_COPY */
-  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
-         &(pcb->remote_ip),
-         IP_PROTO_TCP, seg->p->tot_len);
-#endif /* TCP_CHECKSUM_ON_COPY */
-#endif /* CHECKSUM_GEN_TCP */
-  //TCP_STATS_INC(tcp.xmit);
-
-#if LWIP_NETIF_HWADDRHINT
-  ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-      IPPROTO_TCP, &(pcb->addr_hint));
-#else /* LWIP_NETIF_HWADDRHINT*/
-  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
-      IPPROTO_TCP);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-}
-
-/**
- * Send a TCP RESET packet (empty segment with RST flag set) either to
- * abort a connection or to show that there is no matching local connection
- * for a received segment.
- *
- * Called by tcp_abort() (to abort a local connection), tcp_input() (if no
- * matching local pcb was found), tcp_listen_input() (if incoming segment
- * has ACK flag set) and tcp_process() (received segment in the wrong state)
- *
- * Since a RST segment is in most cases not sent for an active connection,
- * tcp_rst() has a number of arguments that are taken from a tcp_pcb for
- * most other segment output functions.
- *
- * @param seqno the sequence number to use for the outgoing segment
- * @param ackno the acknowledge number to use for the outgoing segment
- * @param local_ip the local IP address to send the segment from
- * @param remote_ip the remote IP address to send the segment to
- * @param local_port the local TCP port to send the segment from
- * @param remote_port the remote TCP port to send the segment to
- */
-void
-tcp_rst(uint32_t seqno, uint32_t ackno,
-  ip_addr_t *local_ip, ip_addr_t *remote_ip,
-  uint16_t local_port, uint16_t remote_port)
-{
-  struct pbuf *p;
-  struct tcp_hdr *tcphdr;
-  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
-  if (p == NULL) {
-      LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
-      return;
-  }
-  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
-              (p->len >= sizeof(struct tcp_hdr)));
-
-  tcphdr = (struct tcp_hdr *)p->payload;
-  tcphdr->src = htons(local_port);
-  tcphdr->dest = htons(remote_port);
-  tcphdr->seqno = htonl(seqno);
-  tcphdr->ackno = htonl(ackno);
-  TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
-  tcphdr->wnd = PP_HTONS(TCP_WND);
-  tcphdr->chksum = 0;
-  tcphdr->urgp = 0;
-
-#if CHECKSUM_GEN_TCP
-  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
-              IP_PROTO_TCP, p->tot_len);
-#endif
-  //TCP_STATS_INC(tcp.xmit);
-  // snmp_inc_tcpoutrsts();
-   /* Send output with hardcoded TTL since we have no access to the pcb */
-  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IPPROTO_TCP);
-  pbuf_free(p);
-  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
-}
-
-/**
- * Requeue all unacked segments for retransmission
- *
- * Called by tcp_slowtmr() for slow retransmission.
- *
- * @param pcb the tcp_pcb for which to re-enqueue all unacked segments
- */
-void
-tcp_rexmit_rto(struct tcp_pcb *pcb)
-{
-  struct tcp_seg *seg;
-
-  if (pcb->unacked == NULL) {
-    return;
-  }
-
-  /* Move all unacked segments to the head of the unsent queue */
-  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);
-  /* concatenate unsent queue after unacked queue */
-  seg->next = pcb->unsent;
-  /* unsent queue is the concatenated queue (of unacked, unsent) */
-  pcb->unsent = pcb->unacked;
-  /* unacked queue is now empty */
-  pcb->unacked = NULL;
-
-  /* increment number of retransmissions */
-  ++pcb->nrtx;
-
-  /* Don't take any RTT measurements after retransmitting. */
-  pcb->rttest = 0;
-
-  /* Do the actual retransmission */
-  tcp_output(pcb);
-}
-
-/**
- * Requeue the first unacked segment for retransmission
- *
- * Called by tcp_receive() for fast retramsmit.
- *
- * @param pcb the tcp_pcb for which to retransmit the first unacked segment
- */
-void
-tcp_rexmit(struct tcp_pcb *pcb)
-{
-  struct tcp_seg *seg;
-  struct tcp_seg **cur_seg;
-
-  if (pcb->unacked == NULL) {
-    return;
-  }
-
-  /* Move the first unacked segment to the unsent queue */
-  /* Keep the unsent queue sorted. */
-  seg = pcb->unacked;
-  pcb->unacked = seg->next;
-
-  cur_seg = &(pcb->unsent);
-  while (*cur_seg &&
-    TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) {
-      cur_seg = &((*cur_seg)->next );
-  }
-  seg->next = *cur_seg;
-  *cur_seg = seg;
-
-  ++pcb->nrtx;
-
-  /* Don't take any rtt measurements after retransmitting. */
-  pcb->rttest = 0;
-
-  /* Do the actual retransmission. */
-  //snmp_inc_tcpretranssegs();
-  /* No need to call tcp_output: we are always called from tcp_input()
-     and thus tcp_output directly returns. */
-}
-
-
-/**
- * Handle retransmission after three dupacks received
- *
- * @param pcb the tcp_pcb for which to retransmit the first unacked segment
- */
-void 
-tcp_rexmit_fast(struct tcp_pcb *pcb)
-{
-  if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) {
-    /* This is fast retransmit. Retransmit the first unacked segment. */
-    LWIP_DEBUGF(TCP_FR_DEBUG, 
-                ("tcp_receive: dupacks %"U16_F" (%"U32_F
-                 "), fast retransmit %"U32_F"\n",
-                 (uint16_t)pcb->dupacks, pcb->lastack,
-                 ntohl(pcb->unacked->tcphdr->seqno)));
-    tcp_rexmit(pcb);
-
-    /* Set ssthresh to half of the minimum of the current
-     * cwnd and the advertised window */
-    if (pcb->cwnd > pcb->snd_wnd) {
-      pcb->ssthresh = pcb->snd_wnd / 2;
-    } else {
-      pcb->ssthresh = pcb->cwnd / 2;
-    }
-    
-    /* The minimum value for ssthresh should be 2 MSS */
-    if (pcb->ssthresh < 2*pcb->mss) {
-      LWIP_DEBUGF(TCP_FR_DEBUG, 
-                  ("tcp_receive: The minimum value for ssthresh %"U16_F
-                   " should be min 2 mss %"U16_F"...\n",
-                   pcb->ssthresh, 2*pcb->mss));
-      pcb->ssthresh = 2*pcb->mss;
-    }
-    
-    pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
-    pcb->flags |= TF_INFR;
-  } 
-}
-
-
-/**
- * Send keepalive packets to keep a connection active although
- * no data is sent over it.
- *
- * Called by tcp_slowtmr()
- *
- * @param pcb the tcp_pcb for which to send a keepalive packet
- */
-void
-tcp_keepalive(struct tcp_pcb *pcb)
-{
-  struct pbuf *p;
-  struct tcp_hdr *tcphdr;
-
-  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe 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)));
-
-  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", 
-                          tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
-   
-  p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1));
-  if(p == NULL) {
-    LWIP_DEBUGF(TCP_DEBUG, 
-                ("tcp_keepalive: could not allocate memory for pbuf\n"));
-    return;
-  }
-  tcphdr = (struct tcp_hdr *)p->payload;
-
-#if CHECKSUM_GEN_TCP
-  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
-                                      IP_PROTO_TCP, p->tot_len);
-#endif
-  //TCP_STATS_INC(tcp.xmit);
-
-  /* Send output to IP */
-#if LWIP_NETIF_HWADDRHINT
-  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
-    &(pcb->addr_hint));
-#else /* LWIP_NETIF_HWADDRHINT*/
-  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IPPROTO_TCP);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-
-  pbuf_free(p);
-
-  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",
-                          pcb->snd_nxt - 1, pcb->rcv_nxt));
-}
-
-
-/**
- * Send persist timer zero-window probes to keep a connection active
- * when a window update is lost.
- *
- * Called by tcp_slowtmr()
- *
- * @param pcb the tcp_pcb for which to send a zero-window probe packet
- */
-void
-tcp_zero_window_probe(struct tcp_pcb *pcb)
-{
-  struct pbuf *p;
-  struct tcp_hdr *tcphdr;
-  struct tcp_seg *seg;
-  uint16_t len;
-  uint8_t is_fin;
-
-  LWIP_DEBUGF(TCP_DEBUG, 
-              ("tcp_zero_window_probe: sending ZERO WINDOW probe 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)));
-
-  LWIP_DEBUGF(TCP_DEBUG, 
-              ("tcp_zero_window_probe: tcp_ticks %"U32_F
-               "   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", 
-               tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
-
-  seg = pcb->unacked;
-
-  if(seg == NULL) {
-    seg = pcb->unsent;
-  }
-  if(seg == NULL) {
-    return;
-  }
-
-  is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
-  /* we want to send one seqno: either FIN or data (no options) */
-  len = is_fin ? 0 : 1;
-
-  p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno);
-  if(p == NULL) {
-    LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
-    return;
-  }
-  tcphdr = (struct tcp_hdr *)p->payload;
-
-  if (is_fin) {
-    /* FIN segment, no data */
-    TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
-  } else {
-    /* Data segment, copy in one byte from the head of the unacked queue */
-    *((char *)p->payload + TCP_HLEN) = *(char *)seg->dataptr;
-  }
-
-#if CHECKSUM_GEN_TCP
-  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
-                                      IP_PROTO_TCP, p->tot_len);
-#endif
-  //TCP_STATS_INC(tcp.xmit);
-
-  /* Send output to IP */
-#if LWIP_NETIF_HWADDRHINT
-  ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP,
-    &(pcb->addr_hint));
-#else /* LWIP_NETIF_HWADDRHINT*/
-  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IPPROTO_TCP);
-#endif /* LWIP_NETIF_HWADDRHINT*/
-
-  pbuf_free(p);
-
-  LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
-                          " ackno %"U32_F".\n",
-                          pcb->snd_nxt - 1, pcb->rcv_nxt));
-}
diff --git a/kern/src/net/tcpip.h b/kern/src/net/tcpip.h
deleted file mode 100644 (file)
index 995ba8a..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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>
- *
- */
-#ifndef __LWIP_TCPIP_H__
-#define __LWIP_TCPIP_H__
-
-#include "lwip/opt.h"
-
-#if !NO_SYS /* don't build if not configured for use in lwipopts.h */
-
-#include "lwip/api_msg.h"
-#include "lwip/netifapi.h"
-#include "lwip/pbuf.h"
-#include "lwip/api.h"
-#include "lwip/sys.h"
-#include "lwip/timers.h"
-#include "lwip/netif.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Define this to something that triggers a watchdog. This is called from
- * tcpip_thread after processing a message. */
-#ifndef LWIP_TCPIP_THREAD_ALIVE
-#define LWIP_TCPIP_THREAD_ALIVE()
-#endif
-
-#if LWIP_TCPIP_CORE_LOCKING
-/** The global semaphore to lock the stack. */
-extern sys_mutex_t lock_tcpip_core;
-#define LOCK_TCPIP_CORE()     sys_mutex_lock(&lock_tcpip_core)
-#define UNLOCK_TCPIP_CORE()   sys_mutex_unlock(&lock_tcpip_core)
-#define TCPIP_APIMSG(m)       tcpip_apimsg_lock(m)
-#define TCPIP_APIMSG_ACK(m)
-#define TCPIP_NETIFAPI(m)     tcpip_netifapi_lock(m)
-#define TCPIP_NETIFAPI_ACK(m)
-#else /* LWIP_TCPIP_CORE_LOCKING */
-#define LOCK_TCPIP_CORE()
-#define UNLOCK_TCPIP_CORE()
-#define TCPIP_APIMSG(m)       tcpip_apimsg(m)
-#define TCPIP_APIMSG_ACK(m)   sys_sem_signal(&m->conn->op_completed)
-#define TCPIP_NETIFAPI(m)     tcpip_netifapi(m)
-#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem)
-#endif /* LWIP_TCPIP_CORE_LOCKING */
-
-/** Function prototype for the init_done function passed to tcpip_init */
-typedef void (*tcpip_init_done_fn)(void *arg);
-/** Function prototype for functions passed to tcpip_callback() */
-typedef void (*tcpip_callback_fn)(void *ctx);
-
-void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg);
-
-#if LWIP_NETCONN
-err_t tcpip_apimsg(struct api_msg *apimsg);
-#if LWIP_TCPIP_CORE_LOCKING
-err_t tcpip_apimsg_lock(struct api_msg *apimsg);
-#endif /* LWIP_TCPIP_CORE_LOCKING */
-#endif /* LWIP_NETCONN */
-
-err_t tcpip_input(struct pbuf *p, struct netif *inp);
-
-#if LWIP_NETIF_API
-err_t tcpip_netifapi(struct netifapi_msg *netifapimsg);
-#if LWIP_TCPIP_CORE_LOCKING
-err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);
-#endif /* LWIP_TCPIP_CORE_LOCKING */
-#endif /* LWIP_NETIF_API */
-
-err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block);
-#define tcpip_callback(f, ctx)              tcpip_callback_with_block(f, ctx, 1)
-
-/* free pbufs or heap memory from another context without blocking */
-err_t pbuf_free_callback(struct pbuf *p);
-err_t mem_free_callback(void *m);
-
-#if LWIP_TCPIP_TIMEOUT
-err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg);
-err_t tcpip_untimeout(sys_timeout_handler h, void *arg);
-#endif /* LWIP_TCPIP_TIMEOUT */
-
-enum tcpip_msg_type {
-#if LWIP_NETCONN
-  TCPIP_MSG_API,
-#endif /* LWIP_NETCONN */
-  TCPIP_MSG_INPKT,
-#if LWIP_NETIF_API
-  TCPIP_MSG_NETIFAPI,
-#endif /* LWIP_NETIF_API */
-#if LWIP_TCPIP_TIMEOUT
-  TCPIP_MSG_TIMEOUT,
-  TCPIP_MSG_UNTIMEOUT,
-#endif /* LWIP_TCPIP_TIMEOUT */
-  TCPIP_MSG_CALLBACK
-};
-
-struct tcpip_msg {
-  enum tcpip_msg_type type;
-  sys_sem_t *sem;
-  union {
-#if LWIP_NETCONN
-    struct api_msg *apimsg;
-#endif /* LWIP_NETCONN */
-#if LWIP_NETIF_API
-    struct netifapi_msg *netifapimsg;
-#endif /* LWIP_NETIF_API */
-    struct {
-      struct pbuf *p;
-      struct netif *netif;
-    } inp;
-    struct {
-      tcpip_callback_fn function;
-      void *ctx;
-    } cb;
-#if LWIP_TCPIP_TIMEOUT
-    struct {
-      u32_t msecs;
-      sys_timeout_handler h;
-      void *arg;
-    } tmo;
-#endif /* LWIP_TCPIP_TIMEOUT */
-  } msg;
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !NO_SYS */
-
-#endif /* __LWIP_TCPIP_H__ */
diff --git a/kern/src/net/timers.c b/kern/src/net/timers.c
deleted file mode 100644 (file)
index 0d8a4ec..0000000
+++ /dev/null
@@ -1,398 +0,0 @@
-/**
- * @file
- * Stack-internal timers implementation.
- * This file includes timer callbacks for stack-internal timers as well as
- * functions to set up or stop timers and check for expired timers.
- *
- */
-
-/*
- * 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>
- *         Simon Goldschmidt
- *
- */
-#include "smp.h"
-#include "net/timers.h"
-#include "net/tcp_impl.h"
-#include "net/tcp.h"
-
-/** The one and only timeout list */
-static struct sys_timeo *next_timeout;
-
-/** global variable that shows if the tcp timer is currently scheduled or not */
-static bool tcpip_tcp_timer_active = false;  // default to not active
-static struct alarm_waiter *tcp_waiter = NULL; // initialized to empty waiter
-
-/**
- * Timer callback function that calls tcp_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void tcpip_tcp_timer(struct alarm_waiter *aw) {
-  /* call TCP timer handler */
-  tcp_tmr();
-       if (aw == NULL) {
-               // need to allocate a fresh waiter
-       }
-  /* timer still needed? */
-  if (tcp_active_pcbs || tcp_tw_pcbs) {
-               struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
-               set_awaiter_rel(aw, TCP_TMR_INTERVAL);
-               set_alarm(tchain, aw);
-               tcpip_tcp_timer_active = true;
-  } else {
-    /* disable timer */
-    tcpip_tcp_timer_active = false;
-  }
-}
-
-/**
- * Called from TCP_REG when registering a new PCB:
- * the reason is to have the TCP timer only running when
- * there are active (or time-wait) PCBs.
- */
-void tcp_timer_needed(void) {
-  /* timer is off but needed again? */
-  if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
-    /* enable and start timer */
-    tcpip_tcp_timer_active = true;
-               tcp_waiter = sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, tcp_waiter);
-       } else {
-               if (tcp_waiter != NULL) {
-                       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
-                       unset_alarm(tchain, tcp_waiter);
-               }
-       }
-}
-
-#if IP_REASSEMBLY
-/**
- * Timer callback function that calls ip_reass_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-ip_reass_timer(void *arg)
-{
-  LWIP_UNUSED_ARG(arg);
-  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
-  ip_reass_tmr();
-  sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
-}
-#endif /* IP_REASSEMBLY */
-
-#if LWIP_ARP
-/**
- * Timer callback function that calls etharp_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-arp_timer(void *arg)
-{
-  LWIP_UNUSED_ARG(arg);
-  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
-  etharp_tmr();
-  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
-}
-#endif /* LWIP_ARP */
-
-#if LWIP_DHCP
-/**
- * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-dhcp_timer_coarse(void *arg)
-{
-  LWIP_UNUSED_ARG(arg);
-  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
-  dhcp_coarse_tmr();
-  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
-}
-
-/**
- * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-dhcp_timer_fine(void *arg)
-{
-  LWIP_UNUSED_ARG(arg);
-  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
-  dhcp_fine_tmr();
-  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
-}
-#endif /* LWIP_DHCP */
-
-#if LWIP_AUTOIP
-/**
- * Timer callback function that calls autoip_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-autoip_timer(void *arg)
-{
-  LWIP_UNUSED_ARG(arg);
-  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
-  autoip_tmr();
-  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
-}
-#endif /* LWIP_AUTOIP */
-
-#if LWIP_IGMP
-/**
- * Timer callback function that calls igmp_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-igmp_timer(void *arg)
-{
-  LWIP_UNUSED_ARG(arg);
-  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
-  igmp_tmr();
-  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
-}
-#endif /* LWIP_IGMP */
-
-#if LWIP_DNS
-/**
- * Timer callback function that calls dns_tmr() and reschedules itself.
- *
- * @param arg unused argument
- */
-static void
-dns_timer(void *arg)
-{
-  LWIP_UNUSED_ARG(arg);
-  LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
-  dns_tmr();
-  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
-}
-#endif /* LWIP_DNS */
-
-/** Initialize this module */
-void sys_timeouts_init(void)
-{
-
-       //we don't support ipreassembly
-  // ip_reass_waiter = sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, ip_reass_waiter);
-#if 0 
-#if LWIP_ARP
-  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
-#endif /* LWIP_ARP */
-#if LWIP_DHCP
-  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
-  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
-#endif /* LWIP_DHCP */
-#if LWIP_AUTOIP
-  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
-#endif /* LWIP_AUTOIP */
-#if LWIP_IGMP
-  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
-#endif /* LWIP_IGMP */
-#if LWIP_DNS
-  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
-#endif /* LWIP_DNS */
-       */
-#endif
-}
-
-/**
- * Create a one-shot timer (aka timeout). Timeouts are processed in the
- * following cases:
- * @param msecs time in milliseconds after that the timer should expire
- * @param handler callback function to call when msecs have elapsed, this handler takes no arguments
- */
-struct alarm_waiter* sys_timeout(uint32_t msecs, sys_timeout_handler func, struct alarm_waiter* waiter) {
-       if (waiter == NULL) {
-               waiter = kmalloc(sizeof(struct alarm_waiter), 0);
-       }
-       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
-       // initialize the waiter
-       init_awaiter(waiter, func);
-       // explicitly setting the waiter data to be null, since we do not need it in our handler
-       waiter->data = NULL;
-       // set waiting time
-       set_awaiter_rel(waiter, 1000 * msecs);
-       // attach the waiter to a chain to wait
-       set_alarm(tchain, waiter);
-
-       // XXX: when to destroy the waiter, handlers responsibility?
-       return waiter;
-}
-
-/**
- * Go through timeout list (for this task only) and remove the first matching
- * entry, even though the timeout has not triggered yet.
- *
- * @note This function only works as expected if there is only one timeout
- * calling 'handler' in the list of timeouts.
- *
- * @param handler callback function that would be called by the timeout
- * @param arg callback argument that would be passed to handler
-*/
-void
-sys_untimeout(alarm_handler handler, void *arg)
-{
-}
-
-#if 0
-
-/** Handle timeouts for NO_SYS==1 (i.e. without using
- * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
- * handler functions when timeouts expire.
- *
- * Must be called periodically from your main loop.
- */
-void
-sys_check_timeouts(void)
-{
-  struct sys_timeo *tmptimeout;
-  uint32_t diff;
-  sys_timeout_handler handler;
-  void *arg;
-  int had_one;
-  uint32_t now;
-
-  now = sys_now();
-  if (next_timeout) {
-    /* this cares for wraparounds */
-    diff = LWIP_U32_DIFF(now, timeouts_last_time);
-    do
-    {
-      had_one = 0;
-      tmptimeout = next_timeout;
-      if (tmptimeout->time <= diff) {
-        /* timeout has expired */
-        had_one = 1;
-        timeouts_last_time = now;
-        diff -= tmptimeout->time;
-        next_timeout = tmptimeout->next;
-        handler = tmptimeout->h;
-        arg = tmptimeout->arg;
-#if LWIP_DEBUG_TIMERNAMES
-        if (handler != NULL) {
-          LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
-            tmptimeout->handler_name, arg));
-        }
-#endif /* LWIP_DEBUG_TIMERNAMES */
-        memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
-        if (handler != NULL) {
-          handler(arg);
-        }
-      }
-    /* repeat until all expired timers have been called */
-    }while(had_one);
-  }
-}
-
-/** Set back the timestamp of the last call to sys_check_timeouts()
- * This is necessary if sys_check_timeouts() hasn't been called for a long
- * time (e.g. while saving energy) to prevent all timer functions of that
- * period being called.
- */
-void
-sys_restart_timeouts(void)
-{
-  timeouts_last_time = sys_now();
-}
-
-// #else /* NO_SYS */
-
-/**
- * Wait (forever) for a message to arrive in an mbox.
- * While waiting, timeouts are processed.
- *
- * @param mbox the mbox to fetch the message from
- * @param msg the place to store the message
- */
-void
-sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
-{
-  uint32_t time_needed;
-  struct sys_timeo *tmptimeout;
-  sys_timeout_handler handler;
-  void *arg;
-
- again:
-  if (!next_timeout) {
-    time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
-  } else {
-    if (next_timeout->time > 0) {
-      time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
-    } else {
-      time_needed = SYS_ARCH_TIMEOUT;
-    }
-
-    if (time_needed == SYS_ARCH_TIMEOUT) {
-      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
-         could be fetched. We should now call the timeout handler and
-         deallocate the memory allocated for the timeout. */
-      tmptimeout = next_timeout;
-      next_timeout = tmptimeout->next;
-      handler = tmptimeout->h;
-      arg = tmptimeout->arg;
-#if LWIP_DEBUG_TIMERNAMES
-      if (handler != NULL) {
-        LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
-          tmptimeout->handler_name, arg));
-      }
-#endif /* LWIP_DEBUG_TIMERNAMES */
-      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
-      if (handler != NULL) {
-        /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
-           timeout handler function. */
-        LOCK_TCPIP_CORE();
-        handler(arg);
-        UNLOCK_TCPIP_CORE();
-      }
-      LWIP_TCPIP_THREAD_ALIVE();
-
-      /* We try again to fetch a message from the mbox. */
-      goto again;
-    } else {
-      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
-         occured. The time variable is set to the number of
-         milliseconds we waited for the message. */
-      if (time_needed < next_timeout->time) {
-        next_timeout->time -= time_needed;
-      } else {
-        next_timeout->time = 0;
-      }
-    }
-  }
-}
-
-#endif
diff --git a/kern/src/net/udp.c b/kern/src/net/udp.c
deleted file mode 100644 (file)
index 6f1e7ad..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/**
- * 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
-
-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..
-               /* 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);
-                       LIST_FOREACH_SAFE(sentry, &sock->waiters, link, sentry_tmp) {
-                               //should only wake up one waiter
-                               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;
-}