Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Revision:
70:cd218dd180e5
Parent:
68:0847e35d08a6
Child:
73:dfb737147f6e
--- a/modules/pico_tcp.c	Wed Sep 25 12:20:39 2013 +0000
+++ b/modules/pico_tcp.c	Thu Sep 26 07:05:22 2013 +0000
@@ -24,7 +24,7 @@
 #define PICO_TCP_RTO_MIN 10
 #define PICO_TCP_RTO_MAX 120000
 #define PICO_TCP_IW 		 2
-#define PICO_TCP_SYN_TO	 1000
+#define PICO_TCP_SYN_TO	 1000u
 #define PICO_TCP_ZOMBIE_TO 30000
 
 #define PICO_TCP_MAX_CONNECT_RETRIES 7
@@ -52,12 +52,6 @@
 #define tcp_dbg(...) do{}while(0)
 //#define tcp_dbg dbg
 
-struct tcp_port_pair
-{
-	uint16_t local;
-	uint16_t remote;
-};
-
 #ifdef PICO_SUPPORT_MUTEX
 static void * Mutex = NULL;
 #define LOCK(x) {\
@@ -126,9 +120,9 @@
   return peek_segment(tq, SEQN(cur) + cur->payload_len);
 }
 
-static int pico_enqueue_segment(struct pico_tcp_queue *tq, struct pico_frame *f)
+static int32_t pico_enqueue_segment(struct pico_tcp_queue *tq, struct pico_frame *f)
 {
-	int ret = -1;
+	int32_t ret = -1;
   if (f->payload_len <= 0) {
     tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n");
     //abort();
@@ -148,7 +142,7 @@
   tq->size += f->payload_len;
   if (f->payload_len > 0)
     tq->frames++;
-  ret = f->payload_len;
+  ret = (int32_t)f->payload_len;
 
 out :
   UNLOCK(Mutex);
@@ -197,6 +191,7 @@
   uint32_t rto;
   uint32_t in_flight;
   uint8_t  timer_running;
+  struct pico_timer * retrans_tmr;
   uint8_t  keepalive_timer_running;
   uint16_t cwnd_counter;
   uint16_t cwnd;
@@ -301,7 +296,7 @@
   }
   pseudo.zeros = 0;
   pseudo.proto = PICO_PROTO_TCP;
-  pseudo.len = short_be(f->transport_len);
+  pseudo.len = (uint16_t)short_be(f->transport_len);
 
   return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len);
 }
@@ -356,11 +351,11 @@
   return long_be(_paws); /*XXX: implement paws */
 }
 
-static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, int optsiz)
+static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint16_t optsiz)
 {
-  uint32_t tsval = long_be(pico_tick);
+  uint64_t tsval = long_long_be(pico_tick);
   uint32_t tsecr = long_be(ts->ts_nxt);
-  int i = 0;
+  uint32_t i = 0;
   f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
 
   memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */
@@ -368,15 +363,15 @@
   if (flags & PICO_TCP_SYN) {
     f->start[i++] = PICO_TCP_OPTION_MSS;
     f->start[i++] = PICO_TCPOPTLEN_MSS;
-    f->start[i++] = (ts->mss >> 8) & 0xFF;
-    f->start[i++] = ts->mss & 0xFF;
+    f->start[i++] = (uint8_t)((ts->mss >> 8) & 0xFF);
+    f->start[i++] = (uint8_t)(ts->mss & 0xFF);
     f->start[i++] = PICO_TCP_OPTION_SACK_OK;
     f->start[i++] = PICO_TCPOPTLEN_SACK_OK;
   }
 
   f->start[i++] = PICO_TCP_OPTION_WS;
   f->start[i++] = PICO_TCPOPTLEN_WS;
-  f->start[i++] = ts->wnd_scale;
+  f->start[i++] = (uint8_t)(ts->wnd_scale);
 
   if (optsiz >= 12) {
     f->start[i++] = PICO_TCP_OPTION_TIMESTAMP;
@@ -389,7 +384,7 @@
 
   if (flags & PICO_TCP_ACK) {
     struct tcp_sack_block *sb;
-    int len_off;
+    uint32_t len_off;
 
     if (ts->sack_ok && ts->sacks) {
       f->start[i++] = PICO_TCP_OPTION_SACK;
@@ -413,14 +408,15 @@
 
 static void tcp_set_space(struct pico_socket_tcp *t)
 {
-  int mtu, space;
-  int shift = 0;
+  uint32_t mtu;
+  int32_t space;
+  uint32_t shift = 0;
 
   mtu = t->mss + PICO_SIZE_TCPHDR + PICO_SIZE_TCPOPT_SYN ;
   if (t->tcpq_in.max_size == 0) {
     space = 1024 * 1024 * 1024; /* One Gigabyte, for unlimited sockets. */
   } else {
-    space = ((t->tcpq_in.max_size - t->tcpq_in.size) / mtu) * t->mss;
+    space = (int32_t)(((t->tcpq_in.max_size - t->tcpq_in.size) / mtu) * t->mss);
   }
   if (space < 0)
     space = 0;
@@ -429,15 +425,15 @@
     shift++;
   }
   if ((space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (space>>2))) {
-    t->wnd = space;
-    t->wnd_scale = shift;
+    t->wnd = (uint16_t)space;
+    t->wnd_scale = (uint16_t)shift;
   }
 }
 
 /* Return 32-bit aligned option size */
-static int tcp_options_size(struct pico_socket_tcp *t, uint16_t flags)
+static uint16_t tcp_options_size(struct pico_socket_tcp *t, uint16_t flags)
 {
-  int size = 0;
+	uint16_t size = 0;
   struct tcp_sack_block *sb = t->sacks;
 
   if (flags & PICO_TCP_SYN) {  /* Full options */
@@ -453,22 +449,22 @@
     size+= PICO_TCPOPTLEN_END;
   }
   if ((flags & PICO_TCP_ACK) && (t->sack_ok && sb)) {
-    size += 2;
+    size += 2u;
     while(sb) {
       size += (2 * sizeof(uint32_t));
       sb = sb->next;
     }
   }
-  size = (((size + 3) >> 2) << 2);
+  size = (uint16_t)(((size + 3) >> 2) << 2);
   return size;
 }
 
-int pico_tcp_overhead(struct pico_socket *s)
+uint16_t pico_tcp_overhead(struct pico_socket *s)
 {
   if (!s)
     return 0;
 
-  return PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, 0); /* hdr + Options size for data pkt */
+  return (uint16_t)(PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, (uint16_t)0)); /* hdr + Options size for data pkt */
 
 }
 
@@ -511,6 +507,18 @@
   }
 }
 
+inline static void tcp_add_header(struct pico_socket_tcp *t, struct pico_frame * f)
+{
+  struct pico_tcp_hdr *	hdr = (struct pico_tcp_hdr *)f->transport_hdr;
+  f->timestamp = pico_tick;
+  tcp_add_options(t, f, 0, (uint16_t)(f->transport_len - f->payload_len - (uint16_t)PICO_SIZE_TCPHDR));
+  hdr->rwnd = short_be(t->wnd);
+  hdr->flags |= PICO_TCP_PSH;
+  hdr->ack = long_be(t->rcv_nxt);
+  hdr->crc = 0;
+  hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
+}
+
 static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len)
 {
   uint32_t start, end;
@@ -658,7 +666,7 @@
 //#define PICO_TCP_SUPPORT_SOCKET_STATS
 
 #ifdef PICO_TCP_SUPPORT_SOCKET_STATS
-static void sock_stats(unsigned long when, void *arg)
+static void sock_stats(uint64_t when, void *arg)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
   tcp_dbg("STATISTIC> [%lu] socket state: %02x --> local port:%d remote port: %d queue size: %d snd_una: %08x snd_nxt: %08x timer: %d cwnd: %d\n",
@@ -695,12 +703,12 @@
   return &t->sock;
 }
 
-int pico_tcp_read(struct pico_socket *s, void *buf, int len)
+uint32_t pico_tcp_read(struct pico_socket *s, void *buf, uint32_t len)
 {
   struct pico_socket_tcp *t = TCP_SOCK(s);
   struct pico_frame *f;
   uint32_t in_frame_off, in_frame_len;
-  int tot_rd_len = 0;
+  uint32_t tot_rd_len = 0;
 
   while (tot_rd_len < len) {
     /* To be sure we don't have garbage at the beginning */
@@ -743,13 +751,13 @@
 out:
   tcp_set_space(t);
   if (t->tcpq_in.size == 0) {
-    s->ev_pending &= (~PICO_SOCK_EV_RD);
+    s->ev_pending &= (uint16_t)(~PICO_SOCK_EV_RD);
   }
   return tot_rd_len;
 }
 
 int pico_tcp_initconn(struct pico_socket *s);
-static void initconn_retry(unsigned long when, void *arg)
+static void initconn_retry(uint64_t when, void *arg)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
   IGNORE_PARAMETER(when);
@@ -773,9 +781,9 @@
   struct pico_socket_tcp *ts = TCP_SOCK(s);
   struct pico_frame *syn;
   struct pico_tcp_hdr *hdr;
-  int opt_len = tcp_options_size(ts, PICO_TCP_SYN);
+  uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN);
 
-  syn = s->net->alloc(s->net, PICO_SIZE_TCPHDR + opt_len);
+  syn = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
   if (!syn)
     return -1;
   hdr = (struct pico_tcp_hdr *) syn->transport_hdr;
@@ -787,7 +795,7 @@
   ts->ssthresh = 40;
   syn->sock = s;
   hdr->seq = long_be(ts->snd_nxt);
-  hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo;
+  hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo);
   hdr->flags = PICO_TCP_SYN;
   tcp_set_space(ts);
   hdr->rwnd = short_be(ts->wnd);
@@ -810,15 +818,15 @@
   struct pico_socket_tcp *ts = TCP_SOCK(s);
   struct pico_frame *synack;
   struct pico_tcp_hdr *hdr;
-  int opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK);
+  uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK);
 
-  synack = s->net->alloc(s->net, PICO_SIZE_TCPHDR + opt_len);
+  synack = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
   if (!synack)
     return -1;
   hdr = (struct pico_tcp_hdr *) synack->transport_hdr;
 
   synack->sock = s;
-  hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo;
+  hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo);
   hdr->flags = PICO_TCP_SYN | PICO_TCP_ACK;
   hdr->rwnd = short_be(ts->wnd);
   hdr->seq = long_be(ts->snd_nxt);
@@ -837,15 +845,15 @@
 {
   struct pico_frame *f;
   struct pico_tcp_hdr *hdr;
-  int opt_len = tcp_options_size(t, flags);
-  f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len);
+  uint16_t opt_len = tcp_options_size(t, flags);
+  f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
   if (!f) {
     return;
   }
   f->sock = &t->sock;
   hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-  hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo;
-  hdr->flags = flags;
+  hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
+  hdr->flags = (uint8_t)flags;
   hdr->rwnd = short_be(t->wnd);
   tcp_set_space(t);
   tcp_add_options(t,f, flags, opt_len);
@@ -875,12 +883,12 @@
   struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
   struct pico_frame *f;
   struct pico_tcp_hdr *hdr, *hdr_rcv;
-  int opt_len = tcp_options_size(t, PICO_TCP_RST);
+  uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST);
   int close;
 
   tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> START\n");
 
-  f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len);
+  f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
 
   if (!f) {
     return -1;
@@ -890,7 +898,7 @@
 
   f->sock = &t->sock;
   hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-  hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo;
+  hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
   hdr->flags = PICO_TCP_RST;
   hdr->rwnd = short_be(t->wnd);
   tcp_set_space(t);
@@ -944,7 +952,7 @@
 {
   struct pico_tcp_hdr *hdr;
   struct pico_frame *f;
-  int size = PICO_SIZE_TCPHDR;
+  uint16_t size = PICO_SIZE_TCPHDR;
 
   tcp_dbg("TCP>>>>>>>>>>>>>>>> sending RST ... <<<<<<<<<<<<<<<<<<\n");
 
@@ -959,7 +967,7 @@
   ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport;
   ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.sport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.dport;
   hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-  hdr->len   = size << 2;
+  hdr->len   = (uint8_t)(size << 2);
   hdr->flags = PICO_TCP_RST | PICO_TCP_ACK;
   hdr->rwnd  = 0;
   if (((struct pico_tcp_hdr *)(fr->transport_hdr))->flags & PICO_TCP_ACK) {
@@ -981,7 +989,7 @@
   struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
   struct pico_frame *f;
   struct pico_tcp_hdr *hdr, *hdr_rcv;
-  int opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK);
+  uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK);
 
   tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n",(s->state & PICO_SOCKET_STATE_TCP));
   if (((s->state & PICO_SOCKET_STATE_TCP) ==  PICO_SOCKET_STATE_TCP_LISTEN)) {
@@ -991,7 +999,7 @@
 
   /***************************************************************************/
   /* sending RST */
-  f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len);
+  f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
 
   if (!f) {
     return -1;
@@ -1001,7 +1009,7 @@
 
   f->sock = &t->sock;
   hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-  hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo;
+  hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
   hdr->flags = PICO_TCP_RST | PICO_TCP_ACK;
   hdr->rwnd = short_be(t->wnd);
   tcp_set_space(t);
@@ -1038,14 +1046,14 @@
 {
   struct pico_frame *f;
   struct pico_tcp_hdr *hdr;
-  int opt_len = tcp_options_size(t, PICO_TCP_FIN);
-  f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len);
+  uint16_t opt_len = tcp_options_size(t, PICO_TCP_FIN);
+  f = t->sock.net->alloc(t->sock.net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
   if (!f) {
     return;
   }
   f->sock = &t->sock;
   hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-  hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo;
+  hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo);
   hdr->flags = PICO_TCP_FIN | PICO_TCP_ACK;
   hdr->ack = long_be(t->rcv_nxt);
   t->rcv_ackd = t->rcv_nxt;
@@ -1130,7 +1138,7 @@
   if (((hdr->len & 0xf0) >> 2) <= f->transport_len) {
     tcp_parse_options(f);
     f->payload = f->transport_hdr + ((hdr->len & 0xf0) >>2);
-    f->payload_len = f->transport_len - ((hdr->len & 0xf0) >>2);
+    f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0) >>2));
     tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
 
     if (seq_compare(SEQN(f), t->rcv_nxt) <= 0) {
@@ -1181,12 +1189,12 @@
   return ret;
 }
 
-static uint16_t time_diff(unsigned long a, unsigned long b)
+static uint32_t time_diff(uint64_t a, uint64_t b)
 {
   if (a >= b)
-    return (a - b);
+    return (uint32_t)(a - b);
   else
-    return (b - a);
+    return (uint32_t)(b - a);
 }
 
 static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt)
@@ -1206,7 +1214,7 @@
     t->rttvar = rtt >> 1;
     t->rto = t->avg_rtt + (t->rttvar << 4);
   } else {
-    int var = (t->avg_rtt - rtt);
+    int32_t var = (int32_t)(t->avg_rtt - rtt);
     if (var < 0)
       var = 0-var;
     /* RFC2988, section (2.3). Alpha and beta are the ones suggested. */
@@ -1214,7 +1222,7 @@
     /* First, evaluate a new value for the rttvar */
     t->rttvar <<= 2;
     t->rttvar -= rvar;
-    t->rttvar += var;
+    t->rttvar += (uint32_t)var;
     t->rttvar >>= 2;
 
     /* Then, calculate the new avg_rtt */
@@ -1252,13 +1260,12 @@
   tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
 }
 
-static void add_retransmission_timer(struct pico_socket_tcp *t, unsigned long next_ts);
-static void tcp_retrans_timeout(unsigned long val, void *sock)
+static void add_retransmission_timer(struct pico_socket_tcp *t, uint64_t next_ts);
+static void tcp_retrans_timeout(uint64_t val, void *sock)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *) sock;
   struct pico_frame *f = NULL;
-  unsigned long limit = val - t->rto;
-  struct pico_tcp_hdr *hdr;
+  uint64_t limit = val - t->rto;
   if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED
   		|| (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) )
   {
@@ -1275,7 +1282,6 @@
 			if ((t->x_mode == PICO_TCP_WINDOW_FULL) ||
 					((f->timestamp != 0) && (f->timestamp <= limit))) {
 				struct pico_frame *cpy;
-				hdr = (struct pico_tcp_hdr *)f->transport_hdr;
 				tcp_dbg("TCP BLACKOUT> TIMED OUT (output) frame %08x, len= %d rto=%d Win full: %d frame flags: %04x\n", SEQN(f), f->payload_len, t->rto, t->x_mode == PICO_TCP_WINDOW_FULL, f->flags);
 				if ((t->x_mode != PICO_TCP_WINDOW_FULL) ) {
 					t->x_mode = PICO_TCP_BLACKOUT;
@@ -1283,13 +1289,7 @@
 					t->cwnd = PICO_TCP_IW;
 					t->in_flight = 0;
 				}
-				f->timestamp = pico_tick;
-				tcp_add_options(t, f, 0, f->transport_len - f->payload_len - PICO_SIZE_TCPHDR);
-				hdr->rwnd = short_be(t->wnd);
-				hdr->flags |= PICO_TCP_PSH;
-				hdr->ack = long_be(t->rcv_nxt);
-				hdr->crc = 0;
-				hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
+				tcp_add_header(t,f);
 				/* TCP: ENQUEUE to PROTO ( retransmit )*/
 				cpy = pico_frame_copy(f);
 				if (pico_enqueue(&tcp_out, cpy) > 0) {
@@ -1312,7 +1312,7 @@
 	}
 }
 
-static void add_retransmission_timer(struct pico_socket_tcp *t, unsigned long next_ts)
+static void add_retransmission_timer(struct pico_socket_tcp *t, uint64_t next_ts)
 {
   struct pico_tree_node * index;
 
@@ -1331,9 +1331,9 @@
   }
   if (next_ts > 0) {
     if ((next_ts + t->rto) > pico_tick) {
-      pico_timer_add(next_ts + t->rto - pico_tick, tcp_retrans_timeout, t);
+      t->retrans_tmr = pico_timer_add(next_ts + t->rto - pico_tick, tcp_retrans_timeout, t);
     } else {
-      pico_timer_add(1, tcp_retrans_timeout, t);
+        t->retrans_tmr = pico_timer_add(1, tcp_retrans_timeout, t);
     }
     t->timer_running++;
   }
@@ -1342,17 +1342,9 @@
 static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f)
 {
   struct pico_frame *cpy;
-  struct pico_tcp_hdr *hdr;
   if (f) {
-    hdr = (struct pico_tcp_hdr *)f->transport_hdr;
     tcp_dbg("TCP> RETRANS (by dupack) frame %08x, len= %d\n", SEQN(f), f->payload_len);
-    f->timestamp = pico_tick;
-    tcp_add_options(t, f, 0, f->transport_len - f->payload_len - PICO_SIZE_TCPHDR);
-    hdr->rwnd = short_be(t->wnd);
-    hdr->flags |= PICO_TCP_PSH;
-    hdr->ack = long_be(t->rcv_nxt);
-    hdr->crc = 0;
-    hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
+    tcp_add_header(t,f);
     /* TCP: ENQUEUE to PROTO ( retransmit )*/
     cpy = pico_frame_copy(f);
     if (pico_enqueue(&tcp_out, cpy) > 0) {
@@ -1433,7 +1425,7 @@
   tcp_parse_options(f);
   t->recv_wnd = short_be(hdr->rwnd);
 
-  acked = tcp_ack_advance_una(t, f);
+  acked = (uint16_t)tcp_ack_advance_una(t, f);
   una = first_segment(&t->tcpq_out);
 
   if ((t->x_mode == PICO_TCP_BLACKOUT) || 
@@ -1553,7 +1545,7 @@
   tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
   if (t->x_mode ==  PICO_TCP_LOOKAHEAD) {
     if ((t->cwnd >= t->in_flight) && (t->snd_nxt > t->snd_last_out)) {
-      pico_tcp_output(&t->sock, t->cwnd - t->in_flight);
+      pico_tcp_output(&t->sock, (int)t->cwnd - (int)t->in_flight);
     }
   }
 
@@ -1575,7 +1567,7 @@
   return 0;
 }
 
-static void tcp_deltcb(unsigned long when, void *arg)
+static void tcp_deltcb(uint64_t when, void *arg)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
   IGNORE_PARAMETER(when);
@@ -1840,6 +1832,23 @@
   return 0;
 }
 
+static void tcp_force_closed(struct pico_socket *s)
+{
+  struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
+  /* update state */
+  (t->sock).state &= 0x00FFU;
+  (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
+  (t->sock).state &= 0xFF00U;
+  (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
+}
+
+static void tcp_wakeup_pending(struct pico_socket *s, uint16_t ev)
+{
+  struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
+  if ((t->sock).wakeup)
+    (t->sock).wakeup(ev, &(t->sock));
+}
+
 static int tcp_rst(struct pico_socket *s, struct pico_frame *f)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
@@ -1849,23 +1858,11 @@
   if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) {
     /* the RST is acceptable if the ACK field acknowledges the SYN */
     if ((t->snd_nxt + 1) == ACKN(f)) {  /* valid, got to closed state */
-      /* update state */
-      (t->sock).state &= 0x00FFU;
-      (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
-      (t->sock).state &= 0xFF00U;
-      (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
-
-      /* call EV_FIN wakeup before deleting */
-      if ((t->sock).wakeup)
-        (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
-
-      /* call EV_ERR wakeup before deleting */
+      tcp_force_closed(s);
+      tcp_wakeup_pending(s, PICO_SOCK_EV_FIN);
       pico_err = PICO_ERR_ECONNRESET;
-      if ((t->sock).wakeup)
-        (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock));
-
-      /* delete socket */
-      pico_socket_del(&t->sock);
+      tcp_wakeup_pending(s, PICO_SOCK_EV_ERR);
+      pico_socket_del(&t->sock);  /* delete socket */
     } else {                      /* not valid, ignore */
       tcp_dbg("TCP RST> IGNORE\n");
       return 0;
@@ -1873,36 +1870,20 @@
   } else {  /* all other states */
     /* all reset (RST) segments are validated by checking their SEQ-fields,
     a reset is valid if its sequence number is in the window */
-    if ((long_be(hdr->seq) >= t->rcv_ackd) && (long_be(hdr->seq) <= ((short_be(hdr->rwnd)<<(t->wnd_scale)) + t->rcv_ackd))) {
+    if ((long_be(hdr->seq) >= t->rcv_ackd) && (long_be(hdr->seq) <= ((uint32_t)(short_be(hdr->rwnd)<<(t->wnd_scale)) + t->rcv_ackd))) {
       if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_RECV) {
-        /* go to closed */
-        (t->sock).state &= 0x00FFU;
-        (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
-        (t->sock).state &= 0xFF00U;
-        (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
-        /* call EV_ERR wakeup */
+        tcp_force_closed(s);
         pico_err = PICO_ERR_ECONNRESET;
-        if ((t->sock).wakeup)
-          (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock));
+        tcp_wakeup_pending(s, PICO_SOCK_EV_ERR);
+        pico_socket_del(&t->sock);  /* delete socket */
         tcp_dbg("TCP RST> SOCKET BACK TO LISTEN\n");
         pico_socket_del(s);
       } else {
-        /* go to closed */
-        (t->sock).state &= 0x00FFU;
-        (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
-        (t->sock).state &= 0xFF00U;
-        (t->sock).state |= PICO_SOCKET_STATE_CLOSED;
-
-        /* call EV_FIN wakeup before deleting */
-        if ((t->sock).wakeup)
-          (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock));
-        /* call EV_ERR wakeup before deleting */
+        tcp_force_closed(s);
+        tcp_wakeup_pending(s, PICO_SOCK_EV_FIN);
         pico_err = PICO_ERR_ECONNRESET;
-        if ((t->sock).wakeup)
-          (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock));
-
-        /* delete socket */
-        pico_socket_del(&t->sock);
+        tcp_wakeup_pending(s, PICO_SOCK_EV_ERR);
+        pico_socket_del(&t->sock);  /* delete socket */
       }
     } else {                      /* not valid, ignore */
       tcp_dbg("TCP RST> IGNORE\n");
@@ -1952,7 +1933,7 @@
   struct tcp_action_entry *action = &tcp_fsm[s->state >> 8];
 
   f->payload = (f->transport_hdr + ((hdr->len & 0xf0) >> 2));
-  f->payload_len = f->transport_len - ((hdr->len & 0xf0) >> 2);
+  f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0) >> 2));
 
   tcp_dbg("[%lu] TCP> [tcp input] socket: %p state: %d <-- local port:%d remote port: %d seq: %08x ack: %08x flags: %02x = t_len: %d, hdr: %u payload: %d\n", pico_tick,
       s, s->state >> 8, short_be(hdr->trans.dport), short_be(hdr->trans.sport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len );
@@ -1999,7 +1980,7 @@
   return ret;
 }
 
-static void tcp_send_keepalive(unsigned long when, void *_t)
+static void tcp_send_keepalive(uint64_t when, void *_t)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)_t;
   IGNORE_PARAMETER(when);
@@ -2020,26 +2001,6 @@
   }
 }
 
-void zombie_timer(unsigned long time, void *param)
-{
-	struct tcp_port_pair * ports = (struct tcp_port_pair *)param;
-	IGNORE_PARAMETER(time);
-	if(ports)
-	{
-		struct pico_socket_tcp * t = (struct pico_socket_tcp *)pico_sockets_find(ports->local,ports->remote);
-		if(t)
-		{
-			(t->sock).state &= 0x00FFU;
-			(t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED;
-			(t->sock).state &= 0xFF00U;
-			(t->sock).state |= PICO_SOCKET_STATE_CLOSED;
-			tcp_dbg("Deleting zombie socket %p\n",param);
-			pico_socket_del(&t->sock);
-		}
-		pico_free(ports);
-	}
-}
-
 int pico_tcp_output(struct pico_socket *s, int loop_score)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
@@ -2054,8 +2015,8 @@
     hdr = (struct pico_tcp_hdr *)f->transport_hdr;
     f->timestamp = pico_tick;
     tcp_add_options(t, f, hdr->flags, tcp_options_size(t, hdr->flags));
-    if (seq_compare(SEQN(f) + f->payload_len, SEQN(una) + (t->recv_wnd << t->recv_wnd_scale)) > 0) {
-      t->cwnd = t->in_flight;
+    if (seq_compare((SEQN(f) + f->payload_len), (SEQN(una) + (uint32_t)(t->recv_wnd << t->recv_wnd_scale))) > 0) {
+      t->cwnd = (uint16_t)t->in_flight;
       if (t->cwnd < 1)
         t->cwnd = 1;
       if (t->x_mode != PICO_TCP_WINDOW_FULL) {
@@ -2109,17 +2070,12 @@
       s->state &= 0x00FFU;
       s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1;
     } else if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) {
-    	struct tcp_port_pair *pair = (struct tcp_port_pair *)pico_zalloc(sizeof(struct tcp_port_pair));
-    	pair->local = s->local_port;
-    	pair->remote = s->remote_port;
       /* send fin if queue empty and in state shut local (write) */
       tcp_send_fin(t);
       /* change tcp state to LAST_ACK */
       s->state &= 0x00FFU;
       s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK;
       tcp_dbg("TCP> STATE: LAST_ACK.\n");
-      // start zombie timer
-      pico_timer_add(PICO_TCP_ZOMBIE_TO,&zombie_timer,(void *)pair);
     }
   }
   return loop_score;
@@ -2131,8 +2087,8 @@
   struct pico_frame *f_temp,*f_new;
   struct pico_socket *s = (struct pico_socket *) &t->sock;
   struct pico_tcp_hdr *hdr;
-  int total_len = 0, total_payload_len = 0;
-  int off = 0, test = 0;
+  uint16_t total_len = 0, total_payload_len = 0;
+  uint16_t off = 0, test = 0;
 
   off = pico_tcp_overhead(s);
 
@@ -2149,7 +2105,7 @@
       break;
   }
   /* alloc new frame with payload size = off + total_len */
-  f_new = pico_socket_frame_alloc(s, off + total_len);
+  f_new = pico_socket_frame_alloc(s, (uint16_t)(off + total_len));
   if (!f_new) {
     pico_err = PICO_ERR_ENOMEM;
     return f_new;
@@ -2176,7 +2132,7 @@
     f_temp = first_segment(&t->tcpq_hold);
   }
 
-  hdr->len = (f_new->payload - f_new->transport_hdr) << 2 | t->jumbo;
+  hdr->len = (uint8_t)((f_new->payload - f_new->transport_hdr) << 2 | t->jumbo);
 
   tcp_dbg_nagle("NAGLE make - joined %d segments, len %d bytes\n",test,total_payload_len);
 
@@ -2185,21 +2141,21 @@
 
 /* original behavior kept when Nagle disabled;
    Nagle algorithm added here, keeping hold frame queue instead of eg linked list of data */
-int pico_tcp_push(struct pico_protocol *self, struct pico_frame *f)
+int32_t pico_tcp_push(struct pico_protocol *self, struct pico_frame *f)
 {
   struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
   struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock;
   struct pico_frame *f_new;
-  int total_len = 0;
+  uint32_t total_len = 0;
   IGNORE_PARAMETER(self);
   pico_err = PICO_ERR_NOERR;
   hdr->trans.sport = t->sock.local_port;
   hdr->trans.dport = t->sock.remote_port;
   hdr->seq = long_be(t->snd_last + 1);
-  hdr->len = (f->payload - f->transport_hdr) << 2 | t->jumbo;
+  hdr->len = (uint8_t)((f->payload - f->transport_hdr) << 2 | t->jumbo);
 
   if ((uint32_t)f->payload_len > (uint32_t)(t->tcpq_out.max_size - t->tcpq_out.size))
-    t->sock.ev_pending &= (~PICO_SOCK_EV_WR);
+    t->sock.ev_pending &= (uint16_t)(~PICO_SOCK_EV_WR);
 
   /***************************************************************************/
 
@@ -2283,6 +2239,8 @@
 void pico_tcp_cleanup_queues(struct pico_socket *sck)
 {
   struct pico_socket_tcp * tcp = (struct pico_socket_tcp *)sck;
+  if(tcp->retrans_tmr)
+	  pico_timer_cancel(tcp->retrans_tmr);
   tcp_discard_all_segments(&tcp->tcpq_in);
   tcp_discard_all_segments(&tcp->tcpq_out);
   tcp_discard_all_segments(&tcp->tcpq_hold);