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.

Files at this revision

API Documentation at this revision

Comitter:
tass
Date:
Mon Sep 02 08:02:21 2013 +0000
Parent:
50:8c79c30b48e3
Child:
53:f3ea2e39a7b2
Commit message:
Updated from masterbranch

Changed in this revision

include/arch/pico_mbed.h Show annotated file Show diff for this revision Revisions of this file
include/heap.h Show annotated file Show diff for this revision Revisions of this file
include/pico_config.h Show annotated file Show diff for this revision Revisions of this file
include/pico_constants.h Show annotated file Show diff for this revision Revisions of this file
include/pico_protocol.h Show annotated file Show diff for this revision Revisions of this file
include/pico_stack.h Show annotated file Show diff for this revision Revisions of this file
include/pico_tree.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_dev_loop.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_dhcp_client.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_dhcp_client.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_dhcp_common.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_dhcp_common.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_dhcp_server.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_dhcp_server.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_dns_client.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_http_client.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_http_client.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_http_server.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_http_server.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_http_util.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_http_util.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_icmp4.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_igmp.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_ipfilter.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_ipv4.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_nat.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_nat.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_simple_http.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_tcp.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_udp.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_zmq.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_zmq.h Show annotated file Show diff for this revision Revisions of this file
stack/pico_arp.c Show annotated file Show diff for this revision Revisions of this file
stack/pico_device.c Show annotated file Show diff for this revision Revisions of this file
stack/pico_frame.c Show annotated file Show diff for this revision Revisions of this file
stack/pico_protocol.c Show annotated file Show diff for this revision Revisions of this file
stack/pico_socket.c Show annotated file Show diff for this revision Revisions of this file
stack/pico_stack.c Show annotated file Show diff for this revision Revisions of this file
stack/pico_tree.c Show annotated file Show diff for this revision Revisions of this file
--- a/include/arch/pico_mbed.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/include/arch/pico_mbed.h	Mon Sep 02 08:02:21 2013 +0000
@@ -10,7 +10,6 @@
 
 #ifndef PICO_SUPPORT_MBED
 #define PICO_SUPPORT_MBED
-#include <stdio.h>
 
 //#include "mbed.h"
 //#include "serial_api.h"
@@ -26,33 +25,6 @@
 #define pico_zalloc(x) calloc(x, 1)
 #define pico_free(x) free(x)
 
-#ifdef MEMORY_MEASURE // in case, comment out the two defines above me.
-extern uint32_t max_mem;
-extern uint32_t cur_mem;
-
-static inline void * pico_zalloc(int x)
-{
-    uint32_t *ptr;
-    if ((cur_mem + x )> (10 * 1024))
-        return NULL;
-        
-    ptr = (uint32_t *)calloc(x + 4, 1);
-    *ptr = (uint32_t)x;
-    cur_mem += x;
-    if (cur_mem > max_mem) {
-        max_mem = cur_mem;
-        printf("max mem: %lu\n", max_mem);
-    }
-    return (void*)(ptr + 1);
-}
-
-static inline void pico_free(void *x)
-{
-    uint32_t *ptr = (uint32_t*)(((uint8_t *)x) - 4);
-    cur_mem -= *ptr;
-    free(ptr);
-}
-#endif
 
 #define PICO_SUPPORT_MUTEX
 extern void *pico_mutex_init(void);
--- a/include/heap.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/include/heap.h	Mon Sep 02 08:02:21 2013 +0000
@@ -6,16 +6,16 @@
 
 #define DECLARE_HEAP(type, orderby) \
 struct heap_##type {   \
-  uint32_t size;       \
-  uint32_t n;       \
-  type *top;        \
+  uint32_t size;   	\
+  uint32_t n;   	\
+  type *top;    	\
 }; \
 typedef struct heap_##type heap_##type; \
 static inline int heap_insert(struct heap_##type *heap, type *el) \
 { \
   int i; \
   type * newTop; \
-  if (++heap->n >= heap->size) {                                                \
+  if (++heap->n >= heap->size) {    											\
     newTop = pico_zalloc((heap->n + 1) * sizeof(type)); \
     if(!newTop) \
       return -1; \
@@ -23,59 +23,59 @@
       memcpy(newTop,heap->top,heap->n*sizeof(type)); \
       pico_free(heap->top); \
     } \
-    heap->top = newTop;                \
-    heap->size++;                                                                \
-  }                                                                              \
-  if (heap->n == 1) {                                                          \
-    memcpy(&heap->top[1], el, sizeof(type));                                    \
-    return 0;                                                                    \
-  }                                                                              \
-  for (i = heap->n; ((i > 1) && (heap->top[i / 2].orderby > el->orderby)); i /= 2) {          \
-    memcpy(&heap->top[i], &heap->top[i / 2], sizeof(type));                        \
-  }              \
-  memcpy(&heap->top[i], el, sizeof(type));                                      \
-  return 0;                                                                       \
+    heap->top = newTop;				\
+    heap->size++;																\
+  }  																			\
+  if (heap->n == 1) {  														\
+    memcpy(&heap->top[1], el, sizeof(type));									\
+    return 0;																	\
+  }  																			\
+  for (i = heap->n; ((i > 1) && (heap->top[i / 2].orderby > el->orderby)); i /= 2) {  		\
+    memcpy(&heap->top[i], &heap->top[i / 2], sizeof(type));						\
+  }  			\
+  memcpy(&heap->top[i], el, sizeof(type));  									\
+  return 0;   																	\
 } \
 static inline int heap_peek(struct heap_##type *heap, type *first) \
 { \
-  type *last;              \
-  int i, child;          \
-  if(heap->n == 0) {      \
-    return -1;             \
-  }                      \
-  memcpy(first, &heap->top[1], sizeof(type));      \
-  last = &heap->top[heap->n--];                  \
-  for(i = 1; (i * 2) <= heap->n; i = child) {      \
-    child = 2 * i;                                \
-    if ((child != heap->n) &&                     \
-        (heap->top[child + 1]).orderby             \
-        < (heap->top[child]).orderby)            \
-        child++;                                \
-    if (last->orderby >                         \
-        heap->top[child].orderby)                \
-        memcpy(&heap->top[i], &heap->top[child],\
-                sizeof(type));                    \
-    else                                        \
-        break;                                    \
-  }                                              \
-  memcpy(&heap->top[i], last, sizeof(type));      \
-  return 0;                                      \
+  type *last;  			\
+  uint32_t i, child;  		\
+  if(heap->n == 0) {  	\
+    return -1; 			\
+  }  					\
+  memcpy(first, &heap->top[1], sizeof(type));  	\
+  last = &heap->top[heap->n--];  				\
+  for(i = 1; (i * 2) <= heap->n; i = child) {  	\
+    child = 2 * i;								\
+    if ((child != heap->n) && 					\
+    	(heap->top[child + 1]).orderby 			\
+    	< (heap->top[child]).orderby)			\
+    	child++;								\
+    if (last->orderby > 						\
+    	heap->top[child].orderby)				\
+    	memcpy(&heap->top[i], &heap->top[child],\
+    			sizeof(type));					\
+    else										\
+    	break;									\
+  }  											\
+  memcpy(&heap->top[i], last, sizeof(type));  	\
+  return 0;  									\
 } \
 static inline type *heap_first(heap_##type *heap)  \
 { \
-  if (heap->n == 0)      \
-    return NULL;        \
+  if (heap->n == 0)  	\
+    return NULL;		\
   return &heap->top[1];  \
 } \
 static inline heap_##type *heap_init(void) \
 { \
   heap_##type *p = (heap_##type *)pico_zalloc(sizeof(heap_##type));  \
-  return p;      \
+  return p;  	\
 } \
 static inline void heap_destroy(heap_##type *h) \
 { \
   pico_free(h->top);   \
-  pico_free(h);       \
+  pico_free(h);   	\
 } \
 
 
--- a/include/pico_config.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/include/pico_config.h	Mon Sep 02 08:02:21 2013 +0000
@@ -10,7 +10,7 @@
 #include <string.h>
 #include "pico_constants.h"
 
-
+#define IGNORE_PARAMETER(x) ((void)x)
 #define MBED
 //#define PICO_SUPPORT_CRC
 #define PICO_SUPPORT_DEVLOOP
--- a/include/pico_constants.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/include/pico_constants.h	Mon Sep 02 08:02:21 2013 +0000
@@ -106,7 +106,7 @@
 extern const uint8_t PICO_IPV6_ANY[PICO_SIZE_IP6];
 #endif
 
-static inline uint32_t pico_hash(char *name)
+static inline uint32_t pico_hash(const char *name)
 {
   unsigned long hash = 5381;
   int c;
--- a/include/pico_protocol.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/include/pico_protocol.h	Mon Sep 02 08:02:21 2013 +0000
@@ -72,16 +72,16 @@
 #define MAX_PROTOCOL_NAME 16
 
 struct pico_protocol {
-  char name[MAX_PROTOCOL_NAME];
+  const char name[MAX_PROTOCOL_NAME];
   uint32_t hash;
-  enum pico_layer layer;
-  int proto_number;
-  struct pico_queue *q_in;
-  struct pico_queue *q_out;
-  struct pico_frame *(*alloc)(struct pico_protocol *self, int size); /* Frame allocation. */
-  int (*push) (struct pico_protocol *self, struct pico_frame *p);    /* Push function, for active outgoing pkts from above */
-  int (*process_out)(struct pico_protocol *self, struct pico_frame *p); /* Send loop. */
-  int (*process_in)(struct pico_protocol *self, struct pico_frame *p); /* Recv loop. */
+  const enum pico_layer layer;
+  const int proto_number;
+  struct pico_queue * const q_in;
+  struct pico_queue * const q_out;
+  struct pico_frame *(* const alloc)(struct pico_protocol *self, int size); /* Frame allocation. */
+  int (* const push) (struct pico_protocol *self, struct pico_frame *p);    /* Push function, for active outgoing pkts from above */
+  int (* const process_out)(struct pico_protocol *self, struct pico_frame *p); /* Send loop. */
+  int (* const process_in)(struct pico_protocol *self, struct pico_frame *p); /* Recv loop. */
 };
 
 int pico_protocols_loop(int loop_score);
--- a/include/pico_stack.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/include/pico_stack.h	Mon Sep 02 08:02:21 2013 +0000
@@ -10,6 +10,9 @@
 
 #define PICO_MAX_TIMERS 20
 
+#define PICO_ETH_MTU 1514
+#define PICO_IP_MTU 1500
+
 /* ===== RECEIVING FUNCTIONS (from dev up to socket) ===== */
 
 /* TRANSPORT LEVEL */
--- a/include/pico_tree.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/include/pico_tree.h	Mon Sep 02 08:02:21 2013 +0000
@@ -13,11 +13,11 @@
 
 // This is used to declare a new tree, leaf root by default
 #define PICO_TREE_DECLARE(name,compareFunction) \
-    struct pico_tree name =\
-    { \
-        &LEAF, \
-        compareFunction \
-    }
+	struct pico_tree name =\
+	{ \
+		&LEAF, \
+		compareFunction \
+	}
 
 struct pico_tree_node
 {
@@ -30,9 +30,9 @@
 
 struct pico_tree
 {
-    struct pico_tree_node * root; // root of the tree
+	struct pico_tree_node * root; // root of the tree
 
-    // this function directly provides the keys as parameters not the nodes.
+	// this function directly provides the keys as parameters not the nodes.
   int (*compare)(void* keyA, void* keyB);
 };
 
@@ -43,8 +43,8 @@
 void * pico_tree_insert(struct pico_tree * tree, void * key);
 void * pico_tree_delete(struct pico_tree * tree, void * key);
 void * pico_tree_findKey(struct pico_tree * tree, void * key);
-void     pico_tree_drop(struct pico_tree * tree);
-int     pico_tree_empty(struct pico_tree * tree);
+void 	pico_tree_drop(struct pico_tree * tree);
+int 	pico_tree_empty(struct pico_tree * tree);
 struct pico_tree_node * pico_tree_findNode(struct pico_tree * tree, void * key);
 
 void * pico_tree_first(struct pico_tree * tree);
@@ -62,23 +62,23 @@
  */
 
 #define pico_tree_foreach(idx,tree) \
-        for ((idx) = pico_tree_firstNode((tree)->root); \
-             (idx) != &LEAF; \
-             (idx) = pico_tree_next(idx))
+		for ((idx) = pico_tree_firstNode((tree)->root); \
+		     (idx) != &LEAF; \
+		     (idx) = pico_tree_next(idx))
 
 #define pico_tree_foreach_reverse(idx,tree) \
-        for ((idx) = pico_tree_lastNode((tree)->root); \
-             (idx) != &LEAF; \
-             (idx) = pico_tree_prev(idx))
+		for ((idx) = pico_tree_lastNode((tree)->root); \
+		     (idx) != &LEAF; \
+		     (idx) = pico_tree_prev(idx))
 
 #define pico_tree_foreach_safe(idx,tree,idx2) \
-        for ((idx) = pico_tree_firstNode((tree)->root);    \
-             ((idx) != &LEAF) && ((idx2) = pico_tree_next(idx), 1); \
-              (idx) = (idx2))
+		for ((idx) = pico_tree_firstNode((tree)->root);	\
+		     ((idx) != &LEAF) && ((idx2) = pico_tree_next(idx), 1); \
+		      (idx) = (idx2))
 
 #define pico_tree_foreach_reverse_safe(idx,tree,idx2) \
-        for ((idx) = pico_tree_lastNode((tree)->root); \
-                ((idx) != &LEAF) && ((idx2) = pico_tree_prev(idx), 1); \
-                 (idx) = (idx2))
+		for ((idx) = pico_tree_lastNode((tree)->root); \
+				((idx) != &LEAF) && ((idx2) = pico_tree_prev(idx), 1); \
+				 (idx) = (idx2))
 
 #endif
--- a/modules/pico_dev_loop.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_dev_loop.c	Mon Sep 02 08:02:21 2013 +0000
@@ -18,7 +18,8 @@
 
 static int pico_loop_send(struct pico_device *dev, void *buf, int len)
 {
-  if (len > LOOP_MTU)
+	IGNORE_PARAMETER(dev);
+	if (len > LOOP_MTU)
     return 0;
 
   if (l_bufsize == 0) {
@@ -46,6 +47,7 @@
 
 void pico_loop_destroy(struct pico_device *dev)
 {
+	IGNORE_PARAMETER(dev);
 }
 
 struct pico_device *pico_loop_create(void)
--- a/modules/pico_dhcp_client.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_dhcp_client.c	Mon Sep 02 08:02:21 2013 +0000
@@ -2,730 +2,918 @@
 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
 See LICENSE and COPYING for usage.
 
-Authors: Frederik Van Slycken, Kristof Roelants
+Authors: Kristof Roelants, Frederik Van Slycken 
 *********************************************************************/
 
+
 #include "pico_dhcp_client.h"
 #include "pico_stack.h"
 #include "pico_config.h"
 #include "pico_device.h"
 #include "pico_ipv4.h"
 #include "pico_socket.h"
+#include "pico_eth.h"
 
 #ifdef PICO_SUPPORT_DHCPC
+#define dhcpc_dbg(...) do{}while(0)
+//#define dhcpc_dbg dbg
 
-/***********
- * structs *
- ***********/
+/* timer values */
+#define DHCP_CLIENT_REINIT             3000 /* msec */
+#define DHCP_CLIENT_RETRANS            4 /* sec */
+#define DHCP_CLIENT_RETRIES            3
+
+#define DHCP_CLIENT_TIMER_STOPPED      0
+#define DHCP_CLIENT_TIMER_STARTED      1
+
+/* custom statuses */
+#define DHCP_CLIENT_STATUS_INIT        0
+#define DHCP_CLIENT_STATUS_SOCKET      1
+#define DHCP_CLIENT_STATUS_BOUND       2
+#define DHCP_CLIENT_STATUS_LINKED      3
+#define DHCP_CLIENT_STATUS_TRANSMITTED 4
+#define DHCP_CLIENT_STATUS_INITIALIZED 5
 
-static uint8_t dhcp_client_mutex = 1; /* to serialize client negotations if multiple devices */
+/* maximum size of a DHCP message */
+#define DHCP_CLIENT_MAXMSGZISE         PICO_IP_MTU
+
+/* serialize client negotiations if multiple devices */
+/* NOTE: ONLY initialization is serialized! */
+static uint8_t pico_dhcp_client_mutex = 1; 
 
-struct dhcp_timer_param{
-  uint16_t type;
-  struct pico_dhcp_client_cookie* cli;
-  int valid;
+enum dhcp_client_state {
+  DHCP_CLIENT_STATE_INIT_REBOOT = 0,
+  DHCP_CLIENT_STATE_REBOOTING,
+  DHCP_CLIENT_STATE_INIT,
+  DHCP_CLIENT_STATE_SELECTING,
+  DHCP_CLIENT_STATE_REQUESTING,
+  DHCP_CLIENT_STATE_BOUND,
+  DHCP_CLIENT_STATE_RENEWING,
+  DHCP_CLIENT_STATE_REBINDING
+};
+
+struct dhcp_client_timer
+{
+  uint8_t state;
+  uint32_t time;
 };
 
 struct pico_dhcp_client_cookie
 {
+  uint8_t status;
+  uint8_t event;
+  uint8_t retry;
   uint32_t xid;
-  uint32_t *xid_user;
+  uint32_t *uid;
+  enum dhcp_client_state state;
+  void (*cb)(void* dhcpc, int code);
+  unsigned long init_timestamp;
+  struct pico_socket *s;
   struct pico_ip4 address;
   struct pico_ip4 netmask;
   struct pico_ip4 gateway;
   struct pico_ip4 nameserver;
   struct pico_ip4 server_id;
-  uint32_t lease_time;
-  uint32_t T1;
-  uint32_t T2;
-  struct pico_socket* socket;
-  int connected;
-  struct pico_device* device;
-  unsigned long start_time;
-  int attempt;
-  enum dhcp_negotiation_state state;
-  void (*cb)(void* cli, int code);
-  struct dhcp_timer_param* timer_param_1;
-  struct dhcp_timer_param* timer_param_2;
-  struct dhcp_timer_param* timer_param_lease;
-  struct dhcp_timer_param* timer_param_retransmit;
-  int link_added;
+  struct pico_device *dev;
+  struct dhcp_client_timer init_timer;
+  struct dhcp_client_timer requesting_timer;
+  struct dhcp_client_timer renewing_timer;
+  struct dhcp_client_timer rebinding_timer;
+  struct dhcp_client_timer T1_timer;
+  struct dhcp_client_timer T2_timer;
+  struct dhcp_client_timer lease_timer;
 };
 
+static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc);
+static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+static int pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type);
+static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s);
+static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+
 static int dhcp_cookies_cmp(void *ka, void *kb)
 {
   struct pico_dhcp_client_cookie *a = ka, *b = kb;
-  if (a->xid < b->xid)
-    return -1; 
-  else if (a->xid > b->xid)
-    return 1;
-  else
+  if (a->xid == b->xid)
     return 0;
+  return (a->xid < b->xid) ? -1 : 1;
 } 
 PICO_TREE_DECLARE(DHCPCookies, dhcp_cookies_cmp);
 
-/*************************
- * function declarations *
- *************************/
-static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len);
-static void pico_dhcp_reinitiate_negotiation(unsigned long now, void *arg);
+static struct pico_dhcp_client_cookie *pico_dhcp_client_add_cookie(uint32_t xid, struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid)
+{
+  struct pico_dhcp_client_cookie *dhcpc = NULL, *found = NULL, test = {0};
+  
+  test.xid = xid;
+  found = pico_tree_findKey(&DHCPCookies, &test);
+  if (found) {
+    pico_err = PICO_ERR_EAGAIN;
+    return NULL;
+  }
+
+  dhcpc = pico_zalloc(sizeof(struct pico_dhcp_client_cookie));
+  if (!dhcpc) {
+    pico_err = PICO_ERR_ENOMEM;
+    return NULL;
+  }
+
+  dhcpc->state = DHCP_CLIENT_STATE_INIT;
+  dhcpc->status = DHCP_CLIENT_STATUS_INIT;
+  dhcpc->xid = xid;
+  dhcpc->uid = uid;
+  *(dhcpc->uid) = 0;
+  dhcpc->cb = cb;
+  dhcpc->dev = dev;
+
+  pico_tree_insert(&DHCPCookies, dhcpc);
+  return dhcpc;
+}
+
+static int pico_dhcp_client_del_cookie(uint32_t xid)
+{
+  struct pico_dhcp_client_cookie test = {0}, *found = NULL;
+
+  test.xid = xid;
+  found = pico_tree_findKey(&DHCPCookies, &test);
+  if (!found)
+    return -1;
+
+  pico_socket_close(found->s);
+  pico_tree_delete(&DHCPCookies, found);
+  pico_free(found);
+  return 0;
+}
+
+static struct pico_dhcp_client_cookie *pico_dhcp_client_find_cookie(uint32_t xid)
+{
+  struct pico_dhcp_client_cookie test = {0}, *found = NULL;
+
+  test.xid = xid;
+  found = pico_tree_findKey(&DHCPCookies, &test);
+  if (found)
+    return found;
+  else
+    return NULL;
+}
+
+static void pico_dhcp_client_init_timer(unsigned long now, void *arg)
+{
+  struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
+
+  if (dhcpc->init_timer.state == DHCP_CLIENT_TIMER_STOPPED)
+    return;
 
-//cb
-static void pico_dhcp_wakeup(uint16_t ev, struct pico_socket *s);
-static void dhcp_timer_cb(unsigned long tick, void* param);
+  if (++dhcpc->retry >= DHCP_CLIENT_RETRIES) {
+    pico_err = PICO_ERR_EAGAIN;
+    dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
+    pico_dhcp_client_del_cookie(dhcpc->xid);
+    pico_dhcp_client_mutex++;
+    return;
+  }
+
+  /* init_timer is restarted in retransmit function, 
+   * otherwise an old init_timer would go on indefinitely */
+  dhcpc->event = PICO_DHCP_EVENT_RETRANSMIT;
+  pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
+  return;
+}
+
+static void pico_dhcp_client_requesting_timer(unsigned long now, void *arg)
+{
+  struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
+
+  if (dhcpc->requesting_timer.state == DHCP_CLIENT_TIMER_STOPPED)
+    return;
+
+  if (++dhcpc->retry > DHCP_CLIENT_RETRIES) {
+    pico_dhcp_client_mutex++;
+    reset(dhcpc, NULL);
+    return;
+  }
+
+  /* requesting_timer is restarted in retransmit function, 
+   * otherwise an old requesting_timer would go on indefinitely */
+  dhcpc->event = PICO_DHCP_EVENT_RETRANSMIT;
+  pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
+  return;
+}
 
-//util
-static void pico_dhcp_retry(struct pico_dhcp_client_cookie *client);
-static int dhclient_send(struct pico_dhcp_client_cookie *cli, uint8_t msg_type);
-static int pico_dhcp_verify_and_identify_type(uint8_t* data, int len, struct pico_dhcp_client_cookie *cli);
-static int init_cookie(struct pico_dhcp_client_cookie* cli);
-static struct pico_dhcp_client_cookie* get_cookie_by_xid(uint32_t xid);
-static uint32_t get_xid(uint8_t* data);
+static void pico_dhcp_client_renewing_timer(unsigned long now, void *arg)
+{
+  struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
+
+  if (dhcpc->renewing_timer.state == DHCP_CLIENT_TIMER_STOPPED)
+    return;
+
+  /* renewing_timer is restarted in retransmit function, 
+   * otherwise an old renewing_timer would go on indefinitely */
+  dhcpc->retry++;
+  dhcpc->event = PICO_DHCP_EVENT_RETRANSMIT;
+  pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
+  return;
+}
+
+static void pico_dhcp_client_rebinding_timer(unsigned long now, void *arg)
+{
+  struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
+
+  if (dhcpc->rebinding_timer.state == DHCP_CLIENT_TIMER_STOPPED)
+    return;
+
+  /* rebinding_timer is restarted in retransmit function, 
+   * otherwise an old rebinding_timer would go on indefinitely */
+  dhcpc->retry++;
+  dhcpc->event = PICO_DHCP_EVENT_RETRANSMIT;
+  pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
+  return;
+}
+
+static void pico_dhcp_client_T1_timer(unsigned long now, void *arg)
+{
+  struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
+
+  if (dhcpc->T1_timer.state == DHCP_CLIENT_TIMER_STOPPED)
+    return;
 
-//fsm functions
-static int recv_offer(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-static int recv_ack(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-static int renew(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-static int reset(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-static int retransmit(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
+  /* T1 state is set to stopped in renew function, 
+   * otherwise an old T1 could stop a valid T1 */
+  dhcpc->event = PICO_DHCP_EVENT_T1;
+  pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
+  return;
+}
+
+static void pico_dhcp_client_T2_timer(unsigned long now, void *arg)
+{
+  struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
+
+  if (dhcpc->T2_timer.state == DHCP_CLIENT_TIMER_STOPPED)
+    return;
+
+  /* T2 state is set to stopped in rebind function, 
+   * otherwise an old T2 could stop a valid T2. 
+   * Likewise for renewing_timer */
+  dhcpc->event = PICO_DHCP_EVENT_T2;
+  pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
+  return;
+}
+
+static void pico_dhcp_client_lease_timer(unsigned long now, void *arg)
+{
+  struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
+
+  if (dhcpc->lease_timer.state == DHCP_CLIENT_TIMER_STOPPED)
+    return;
+
+  /* lease state is set to stopped in reset function, 
+   * otherwise an old lease could stop a valid lease. 
+   * Likewise for rebinding_timer */
+  dhcpc->event = PICO_DHCP_EVENT_LEASE;
+  pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
+  return;
+}
+
+static void pico_dhcp_client_reinit(unsigned long now, void *arg)
+{
+  struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
+
+  if (++dhcpc->retry > DHCP_CLIENT_RETRIES) {
+    pico_err = PICO_ERR_EAGAIN;
+    dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
+    pico_dhcp_client_del_cookie(dhcpc->xid);
+    return;
+  }
+  pico_dhcp_client_init(dhcpc);
+  return;
+}
+
+static void pico_dhcp_client_stop_timers(struct pico_dhcp_client_cookie *dhcpc)
+{
+  dhcpc->retry = 0;
+  dhcpc->init_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->requesting_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->renewing_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->rebinding_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->T1_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->T2_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->lease_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+
+  return;
+}
+
+static void pico_dhcp_client_start_init_timer(struct pico_dhcp_client_cookie *dhcpc)
+{
+  uint32_t time = 0;
 
-//fsm implementation
-static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len);
+  /* timer value is doubled with every retry (exponential backoff) */
+  dhcpc->init_timer.state = DHCP_CLIENT_TIMER_STARTED;
+  dhcpc->init_timer.time = DHCP_CLIENT_RETRANS;
+  time = dhcpc->init_timer.time << dhcpc->retry;
+  pico_timer_add(time * 1000, pico_dhcp_client_init_timer, dhcpc);
+
+  return;
+}
+
+static void pico_dhcp_client_start_requesting_timer(struct pico_dhcp_client_cookie *dhcpc)
+{
+  uint32_t time = 0;
+
+  /* timer value is doubled with every retry (exponential backoff) */
+  dhcpc->init_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->requesting_timer.state = DHCP_CLIENT_TIMER_STARTED;
+  dhcpc->requesting_timer.time = DHCP_CLIENT_RETRANS;
+  time = dhcpc->requesting_timer.time << dhcpc->retry;
+  pico_timer_add(time * 1000, pico_dhcp_client_requesting_timer, dhcpc);
+
+  return;
+}
+
+static void pico_dhcp_client_start_renewing_timer(struct pico_dhcp_client_cookie *dhcpc)
+{
+  uint32_t halftime = 0;
+
+  /* wait one-half of the remaining time until T2, down to a minimum of 60 seconds */
+  /* (dhcpc->retry + 1): initial -> divide by 2, 1st retry -> divide by 4, 2nd retry -> divide by 8, etc */
+  dhcpc->T1_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->renewing_timer.state = DHCP_CLIENT_TIMER_STARTED;
+  halftime = dhcpc->renewing_timer.time >> (dhcpc->retry + 1);
+  if (halftime < 60)
+    halftime = 60;
+  pico_timer_add(halftime * 1000, pico_dhcp_client_renewing_timer, dhcpc);
+
+  return;
+}
 
-/***************
- * entry point *
- ***************/
+static void pico_dhcp_client_start_rebinding_timer(struct pico_dhcp_client_cookie *dhcpc)
+{
+  uint32_t halftime = 0;
+
+  /* wait one-half of the remaining time until T2, down to a minimum of 60 seconds */
+  /* (dhcpc->retry + 1): initial -> divide by 2, 1st retry -> divide by 4, 2nd retry -> divide by 8, etc */
+  dhcpc->T2_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->renewing_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->rebinding_timer.state = DHCP_CLIENT_TIMER_STARTED;
+  halftime = dhcpc->rebinding_timer.time >> (dhcpc->retry + 1);
+  if (halftime < 60)
+    halftime = 60;
+  pico_timer_add(halftime * 1000, pico_dhcp_client_rebinding_timer, dhcpc);
+
+  return;
+}
 
-static uint32_t pico_dhcp_execute_init(struct pico_dhcp_client_cookie *cli)
+static void pico_dhcp_client_start_reacquisition_timers(struct pico_dhcp_client_cookie *dhcpc)
 {
-  if (!dhcp_client_mutex) {
-    pico_timer_add(3000, pico_dhcp_reinitiate_negotiation, cli);
+  dhcpc->requesting_timer.state = DHCP_CLIENT_TIMER_STOPPED;
+  dhcpc->T1_timer.state = DHCP_CLIENT_TIMER_STARTED;
+  dhcpc->T2_timer.state = DHCP_CLIENT_TIMER_STARTED;
+  dhcpc->lease_timer.state = DHCP_CLIENT_TIMER_STARTED;
+  pico_timer_add(dhcpc->T1_timer.time * 1000, pico_dhcp_client_T1_timer, dhcpc);
+  pico_timer_add(dhcpc->T2_timer.time * 1000, pico_dhcp_client_T2_timer, dhcpc);
+  pico_timer_add(dhcpc->lease_timer.time * 1000, pico_dhcp_client_lease_timer, dhcpc);
+
+  return;
+}
+
+static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc)
+{
+  uint16_t port = PICO_DHCP_CLIENT_PORT;
+  struct pico_ip4 inaddr_any = {0}, netmask = {0};
+
+  /* serialize client negotations if multiple devices */
+  /* NOTE: ONLY initialization is serialized! */
+  if (!pico_dhcp_client_mutex) {
+    pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
     return 0;
   }
-  dhcp_client_mutex--;
+  pico_dhcp_client_mutex--;
+
+  switch (dhcpc->status)
+  {
+    case DHCP_CLIENT_STATUS_INIT:
+      dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup);
+      if (!dhcpc->s) {
+        pico_dhcp_client_mutex++;
+        pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
+        break;
+      }
+      dhcpc->s->dev = dhcpc->dev;
+      dhcpc->status = DHCP_CLIENT_STATUS_SOCKET;
+      /* fallthrough */
+
+    case DHCP_CLIENT_STATUS_SOCKET:
+      if (pico_socket_bind(dhcpc->s, &inaddr_any, &port) < 0) {
+        pico_dhcp_client_mutex++;
+        pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
+        break;
+      }
+      dhcpc->status = DHCP_CLIENT_STATUS_BOUND;
+      /* fallthrough */
+
+    case DHCP_CLIENT_STATUS_BOUND:
+      /* adding a link with address 0.0.0.0 and netmask 0.0.0.0, 
+       * automatically adds a route for a global broadcast */
+      if (pico_ipv4_link_add(dhcpc->dev, inaddr_any, netmask) < 0) {
+        pico_dhcp_client_mutex++;
+        pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
+        break;
+      }
+      dhcpc->status = DHCP_CLIENT_STATUS_LINKED;
+      /* fallthrough */
+
+    case DHCP_CLIENT_STATUS_LINKED:
+      if (pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER) < 0) {
+        pico_dhcp_client_mutex++;
+        pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
+        break;
+      }
+      dhcpc->status = DHCP_CLIENT_STATUS_TRANSMITTED;
+      /* fallthrough */
+
+    case DHCP_CLIENT_STATUS_TRANSMITTED:
+      dhcpc->retry = 0;
+      dhcpc->init_timestamp = PICO_TIME_MS();
+      pico_dhcp_client_start_init_timer(dhcpc);
+      break;
+
+    default:
+      return -1;
+  }
+  return 0;
+}
+
+int pico_dhcp_initiate_negotiation(struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid)
+{
+  uint8_t retry = 32;
+  uint32_t xid = 0;
+  struct pico_dhcp_client_cookie *dhcpc = NULL;
+
+  if (!dev || !cb || !uid) {
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+  }
+  if (!dev->eth) {
+    pico_err = PICO_ERR_EOPNOTSUPP;
+    return -1;
+  }
+
+  /* attempt to generate a correct xid, else fail */
+  do {
+    xid = pico_rand();
+  } while (!xid && --retry);
+
+  if (!xid) {
+    pico_err = PICO_ERR_EAGAIN;
+    return -1;
+  }
+
+  dhcpc = pico_dhcp_client_add_cookie(xid, dev, cb, uid);
+  if (!dhcpc)
+    return -1;
+
+  dhcpc_dbg("DHCP client: cookie with xid %u\n", dhcpc->xid);
+  return pico_dhcp_client_init(dhcpc);
+}
 
-  if (init_cookie(cli) < 0)
+static void pico_dhcp_client_recv_params(struct pico_dhcp_client_cookie *dhcpc, struct pico_dhcp_opt *opt)
+{
+  do {
+    switch (opt->code)
+    {
+      case PICO_DHCP_OPT_PAD:
+        break;
+
+      case PICO_DHCP_OPT_END:
+        break;
+
+      case PICO_DHCP_OPT_MSGTYPE:
+        dhcpc->event = opt->ext.msg_type.type;
+        dhcpc_dbg("DHCP client: message type %u\n", dhcpc->event);
+        break;
+
+      case PICO_DHCP_OPT_LEASETIME:
+        dhcpc->lease_timer.time = long_be(opt->ext.lease_time.time);
+        dhcpc_dbg("DHCP client: lease time %u\n", dhcpc->lease_timer.time);
+        break;
+
+      case PICO_DHCP_OPT_RENEWALTIME:
+        dhcpc->T1_timer.time = long_be(opt->ext.renewal_time.time);
+        dhcpc_dbg("DHCP client: renewal time %u\n", dhcpc->T1_timer.time);
+        break;
+
+      case PICO_DHCP_OPT_REBINDINGTIME:
+        dhcpc->T2_timer.time = long_be(opt->ext.rebinding_time.time);
+        dhcpc_dbg("DHCP client: rebinding time %u\n", dhcpc->T2_timer.time);
+        break;
+
+      case PICO_DHCP_OPT_ROUTER:
+        dhcpc->gateway = opt->ext.router.ip;
+        dhcpc_dbg("DHCP client: router %08X\n", dhcpc->gateway.addr);
+        break;
+
+      case PICO_DHCP_OPT_DNS:
+        dhcpc->nameserver = opt->ext.dns.ip;
+        dhcpc_dbg("DHCP client: dns %08X\n", dhcpc->nameserver.addr);
+        break;
+
+      case PICO_DHCP_OPT_NETMASK:
+        dhcpc->netmask = opt->ext.netmask.ip;
+        dhcpc_dbg("DHCP client: netmask %08X\n", dhcpc->netmask.addr);
+        break;
+
+      case PICO_DHCP_OPT_SERVERID:
+        dhcpc->server_id = opt->ext.server_id.ip;
+        dhcpc_dbg("DHCP client: server ID %08X\n", dhcpc->server_id.addr);
+        break;
+
+      case PICO_DHCP_OPT_OPTOVERLOAD:
+        dhcpc_dbg("DHCP client: WARNING option overload present (not processed)");
+        break;
+
+      default:
+        dhcpc_dbg("DHCP client: WARNING unsupported option %u\n", opt->code);
+        break;
+    }
+  } while (pico_dhcp_next_option(&opt));
+
+  /* default values for T1 and T2 when not provided */
+  if (!dhcpc->T1_timer.time)
+    dhcpc->T1_timer.time = dhcpc->lease_timer.time >> 1;
+  if (!dhcpc->T2_timer.time)
+    dhcpc->T2_timer.time = (dhcpc->lease_timer.time * 875) / 1000;
+
+  return;
+}
+
+static int recv_offer(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+  struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)hdr->options;
+
+  pico_dhcp_client_recv_params(dhcpc, opt);
+  if ((dhcpc->event != PICO_DHCP_MSG_OFFER) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_timer.time)
+    return -1;
+  dhcpc->address.addr = hdr->yiaddr;
+
+  /* we skip state SELECTING, process first offer received */
+  dhcpc->state = DHCP_CLIENT_STATE_REQUESTING;
+  dhcpc->retry = 0;
+  pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+  pico_dhcp_client_start_requesting_timer(dhcpc);
+  return 0;
+}
+
+static int recv_ack(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+  struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)hdr->options;
+  struct pico_ip4 address = {0}, netmask = {0}, inaddr_any = {0}, bcast = { .addr = 0xFFFFFFFF };
+
+  pico_dhcp_client_recv_params(dhcpc, opt);
+  if ((dhcpc->event != PICO_DHCP_MSG_ACK) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_timer.time)
     return -1;
 
-  dbg("DHCPC: cookie with xid %u\n", cli->xid);
-  
-  if (pico_tree_insert(&DHCPCookies, cli)) {
-    pico_err = PICO_ERR_EAGAIN;
-    if(cli->cb != NULL) {
-      cli->cb(cli, PICO_DHCP_ERROR);
-    }
-    pico_free(cli);
-    return -1; /* Element key already exists */
+  /* close the socket used for address (re)acquisition */
+  pico_socket_close(dhcpc->s);
+  /* delete the link with address 0.0.0.0, add new link with acquired address */
+  if (dhcpc->status == DHCP_CLIENT_STATUS_TRANSMITTED) {
+    pico_ipv4_link_del(dhcpc->dev, address);
+    pico_ipv4_link_add(dhcpc->dev, dhcpc->address, dhcpc->netmask);
+    dhcpc->status = DHCP_CLIENT_STATUS_INITIALIZED;
+  }
+  /* delete the default route for our global broadcast messages, otherwise another interface can not rebind */
+  if (dhcpc->state == DHCP_CLIENT_STATE_REBINDING)
+    pico_ipv4_route_del(bcast, netmask, inaddr_any, 1, pico_ipv4_link_get(&dhcpc->address));
+
+  dbg("DHCP client: renewal time (T1) %u\n", dhcpc->T1_timer.time);
+  dbg("DHCP client: rebinding time (T2) %u\n", dhcpc->T2_timer.time);
+  dbg("DHCP client: lease time %u\n", dhcpc->lease_timer.time);
+
+  dhcpc->retry = 0;
+  dhcpc->renewing_timer.time = dhcpc->T2_timer.time - dhcpc->T1_timer.time;
+  dhcpc->rebinding_timer.time = dhcpc->lease_timer.time - dhcpc->T2_timer.time;
+  pico_dhcp_client_start_reacquisition_timers(dhcpc);
+
+  pico_dhcp_client_mutex++;
+  *(dhcpc->uid) = dhcpc->xid;
+  dhcpc->cb(dhcpc, PICO_DHCP_SUCCESS);
+  dhcpc->state = DHCP_CLIENT_STATE_BOUND;
+  return 0;
+}
+
+static int renew(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+  uint16_t port = PICO_DHCP_CLIENT_PORT;
+
+  dhcpc->state = DHCP_CLIENT_STATE_RENEWING;
+  dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup);
+  if (!dhcpc->s) {
+    dhcpc_dbg("DHCP client ERROR: failure opening socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
+    dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
+    return -1;
+  }
+  if (pico_socket_bind(dhcpc->s, &dhcpc->address, &port) != 0) {
+    dhcpc_dbg("DHCP client ERROR: failure binding socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
+    pico_socket_close(dhcpc->s);
+    dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
+    return -1;
   }
 
-  if (dhclient_send(cli, PICO_DHCP_MSG_DISCOVER) < 0)
+  dhcpc->retry = 0;
+  pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+  pico_dhcp_client_start_renewing_timer(dhcpc);
+
+  return 0;
+}
+
+static int rebind(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+  struct pico_ip4 bcast = { .addr = 0xFFFFFFFF }, netmask = {0}, inaddr_any = {0};
+
+  dhcpc->state = DHCP_CLIENT_STATE_REBINDING;
+  dhcpc->retry = 0;
+  /* we need a default route for our global broadcast messages, otherwise they get dropped. */
+  pico_ipv4_route_add(bcast, netmask, inaddr_any, 1, pico_ipv4_link_get(&dhcpc->address));
+  pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+  pico_dhcp_client_start_rebinding_timer(dhcpc);
+
+  return 0;
+}
+
+static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+  struct pico_ip4 address = {0}, netmask = {0}, inaddr_any = {0}, bcast = { .addr = 0xFFFFFFFF };
+
+  if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING)
+    address.addr = PICO_IP4_ANY;
+  else
+    address.addr = dhcpc->address.addr;
+
+  /* delete the default route for our global broadcast messages, otherwise another interface can not rebind */
+  if (dhcpc->state == DHCP_CLIENT_STATE_REBINDING)
+    pico_ipv4_route_del(bcast, netmask, inaddr_any, 1, pico_ipv4_link_get(&dhcpc->address));
+
+  /* close the socket used for address (re)acquisition */
+  pico_socket_close(dhcpc->s);
+  /* delete the link with the currently in use address */
+  pico_ipv4_link_del(dhcpc->dev, address);
+
+  dhcpc->cb(dhcpc, PICO_DHCP_RESET);
+  dhcpc->state = DHCP_CLIENT_STATE_INIT;
+  dhcpc->status = DHCP_CLIENT_STATUS_INIT;
+  pico_dhcp_client_stop_timers(dhcpc);
+  pico_dhcp_client_init(dhcpc);
+  return 0;
+}
+
+static int retransmit(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+  switch (dhcpc->state)
+  {
+    case DHCP_CLIENT_STATE_INIT:
+      pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
+      pico_dhcp_client_start_init_timer(dhcpc);
+      break;
+
+    case DHCP_CLIENT_STATE_REQUESTING:
+      pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+      pico_dhcp_client_start_requesting_timer(dhcpc);
+      break;
+
+    case DHCP_CLIENT_STATE_RENEWING:
+      pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+      pico_dhcp_client_start_renewing_timer(dhcpc);
+      break;
+
+    case DHCP_CLIENT_STATE_REBINDING:
+      pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
+      pico_dhcp_client_start_rebinding_timer(dhcpc);
+      break;
+
+    default:
+      dhcpc_dbg("DHCP client WARNING: retransmit in incorrect state (%u)!\n", dhcpc->state);
+      return -1;
+  }
+  return 0;
+}
+
+struct dhcp_action_entry {
+  int (*offer)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+  int (*ack)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+  int (*nak)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+  int (*timer1)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+  int (*timer2)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+  int (*timer_lease)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+  int (*timer_retransmit)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+};
+
+static struct dhcp_action_entry dhcp_fsm[] = 
+{ /* event                |offer      |ack      |nak    |T1    |T2     |lease  |retransmit */
+/* state init-reboot */ { NULL,       NULL,     NULL,   NULL,  NULL,   NULL,  NULL       },
+/* state rebooting   */ { NULL,       NULL,     NULL,   NULL,  NULL,   NULL,  NULL       },
+/* state init        */ { recv_offer, NULL,     NULL,   NULL,  NULL,   NULL,  retransmit },
+/* state selecting   */ { NULL,       NULL,     NULL,   NULL,  NULL,   NULL,  NULL       },
+/* state requesting  */ { NULL,       recv_ack, reset,  NULL,  NULL,   NULL,  retransmit },
+/* state bound       */ { NULL,       NULL,     NULL,   renew, NULL,   NULL,  NULL       },
+/* state renewing    */ { NULL,       recv_ack, reset,  NULL,  rebind, NULL,  retransmit },
+/* state rebinding   */ { NULL,       recv_ack, reset,  NULL,  NULL,   reset, retransmit },
+};
+
+/* TIMERS REMARK:
+ * In state bound we have T1, T2 and the lease timer running. If T1 goes off, we attempt to renew.
+ * If the renew succeeds a new T1, T2 and lease timer is started. The former T2 and lease timer is
+ * still running though. This poses no concerns as the T2 and lease event in state bound have a NULL 
+ * pointer in the fsm. If the former T2 or lease timer goes off, nothing happens. Same situation 
+ * applies for T2 and a succesfull rebind. */
+
+static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+  switch (event) 
+  {
+    case PICO_DHCP_MSG_OFFER:
+      dhcpc_dbg("DHCP client: received OFFER\n");
+      if (dhcp_fsm[dhcpc->state].offer)
+        dhcp_fsm[dhcpc->state].offer(dhcpc, buf);
+      break;
+
+    case PICO_DHCP_MSG_ACK:
+      dhcpc_dbg("DHCP client: received ACK\n");
+      if (dhcp_fsm[dhcpc->state].ack)
+        dhcp_fsm[dhcpc->state].ack(dhcpc, buf);
+      break;
+
+    case PICO_DHCP_MSG_NAK:
+      dhcpc_dbg("DHCP client: received NAK\n");
+      if (dhcp_fsm[dhcpc->state].nak)
+        dhcp_fsm[dhcpc->state].nak(dhcpc, buf);
+      break;
+
+    case PICO_DHCP_EVENT_T1:
+      dhcpc_dbg("DHCP client: received T1 timeout\n");
+      if (dhcp_fsm[dhcpc->state].timer1)
+        dhcp_fsm[dhcpc->state].timer1(dhcpc, NULL);
+      break;
+
+    case PICO_DHCP_EVENT_T2:
+      dhcpc_dbg("DHCP client: received T2 timeout\n");
+      if (dhcp_fsm[dhcpc->state].timer2)
+        dhcp_fsm[dhcpc->state].timer2(dhcpc, NULL);
+      break;
+
+    case PICO_DHCP_EVENT_LEASE:
+      dhcpc_dbg("DHCP client: received LEASE timeout\n");
+      if (dhcp_fsm[dhcpc->state].timer_lease)
+        dhcp_fsm[dhcpc->state].timer_lease(dhcpc, NULL);
+      break;
+
+    case PICO_DHCP_EVENT_RETRANSMIT:
+      dhcpc_dbg("DHCP client: received RETRANSMIT timeout\n");
+      if (dhcp_fsm[dhcpc->state].timer_retransmit)
+        dhcp_fsm[dhcpc->state].timer_retransmit(dhcpc, NULL);
+      break;
+
+    default:
+      dhcpc_dbg("DHCP client WARNING: unrecognized event (%u)!\n", dhcpc->event);
+      return;
+  }
+  return;
+}
+
+static int pico_dhcp_client_opt_parse(void *ptr, int len)
+{
+  int optlen = len - sizeof(struct pico_dhcp_hdr);
+  struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)ptr;
+  struct pico_dhcp_opt *opt = NULL;
+
+  if (hdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE)
+    return -1;
+  if (!pico_dhcp_are_options_valid(hdr->options, optlen))
+    return -1;
+
+  opt = (struct pico_dhcp_opt *)hdr->options;
+  do {
+    if (opt->code == PICO_DHCP_OPT_MSGTYPE)
+      return opt->ext.msg_type.type;
+  } while (pico_dhcp_next_option(&opt));
+
+  return -1;
+}
+
+static int pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type)
+{
+  int r = 0, optlen = 0, offset = 0;
+  struct pico_ip4 destination = { .addr = 0xFFFFFFFF};
+  struct pico_dhcp_hdr *hdr = NULL;
+
+  switch (msg_type)
+  {
+    case PICO_DHCP_MSG_DISCOVER:
+      dhcpc_dbg("DHCP client: sent DHCPDISCOVER\n");
+      optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_END;
+      hdr = pico_zalloc(sizeof(struct pico_dhcp_hdr) + optlen);
+      /* specific options */
+      offset += pico_dhcp_opt_maxmsgsize(&hdr->options[offset], DHCP_CLIENT_MAXMSGZISE);
+      break;
+
+    case PICO_DHCP_MSG_REQUEST:
+      dhcpc_dbg("DHCP client: sent DHCPREQUEST\n");
+      optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_REQIP + PICO_DHCP_OPTLEN_SERVERID 
+              + PICO_DHCP_OPTLEN_END;
+      hdr = pico_zalloc(sizeof(struct pico_dhcp_hdr) + optlen);
+      /* specific options */
+      offset += pico_dhcp_opt_maxmsgsize(&hdr->options[offset], DHCP_CLIENT_MAXMSGZISE);
+      if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING) {
+        offset += pico_dhcp_opt_reqip(&hdr->options[offset], &dhcpc->address);
+        offset += pico_dhcp_opt_serverid(&hdr->options[offset], &dhcpc->server_id);
+      }
+      break;
+
+    default:
+      return -1;
+  }
+
+  /* common options */
+  offset += pico_dhcp_opt_msgtype(&hdr->options[offset], msg_type);
+  offset += pico_dhcp_opt_paramlist(&hdr->options[offset]);
+  offset += pico_dhcp_opt_end(&hdr->options[offset]);
+
+  switch (dhcpc->state)
+  {
+    case DHCP_CLIENT_STATE_BOUND:
+      destination.addr = dhcpc->server_id.addr;
+      hdr->ciaddr = dhcpc->address.addr;
+      break;
+
+    case DHCP_CLIENT_STATE_RENEWING:
+      destination.addr = dhcpc->server_id.addr;
+      hdr->ciaddr = dhcpc->address.addr;
+      break;
+
+    case DHCP_CLIENT_STATE_REBINDING:
+      hdr->ciaddr = dhcpc->address.addr;
+      break;
+
+    default:
+      /* do nothing */
+      break;
+  }
+
+  /* header information */
+  hdr->op = PICO_DHCP_OP_REQUEST;
+  hdr->htype = PICO_DHCP_HTYPE_ETH;
+  hdr->hlen = PICO_SIZE_ETH;
+  hdr->xid = dhcpc->xid;
+  hdr->flags = short_be(PICO_DHCP_FLAG_BROADCAST);
+  hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
+  /* copy client hardware address */
+  memcpy(hdr->hwaddr, &dhcpc->dev->eth->mac, PICO_SIZE_ETH);
+
+  r = pico_socket_sendto(dhcpc->s, hdr, sizeof(struct pico_dhcp_hdr) + optlen, &destination, PICO_DHCPD_PORT);
+  pico_free(hdr);
+  if (r < 0)
     return -1;
 
   return 0;
 }
 
-/* returns a pointer to the client cookie. The user should pass this pointer every time he calls a dhcp-function. This is so that we can (one day) support dhcp on multiple interfaces */
-int pico_dhcp_initiate_negotiation(struct pico_device *device, void (*callback)(void *cli, int code), uint32_t *xid)
-{
-  struct pico_dhcp_client_cookie *cli;
-  
-  if(!device || !callback || !xid){
-    pico_err = PICO_ERR_EINVAL;
-    return -1;
-  }
-  cli = pico_zalloc(sizeof(struct pico_dhcp_client_cookie));
-  if(!cli){
-    pico_err = PICO_ERR_ENOMEM;
-    return -1;
-  }
-
-  cli->device = device;
-  cli->cb = callback;
-  cli->xid_user = xid;
-  *(cli->xid_user) = 0;
-
-  return pico_dhcp_execute_init(cli);
-}
-
-static void pico_dhcp_reinitiate_negotiation(unsigned long now, void *arg)
-{
-  struct pico_dhcp_client_cookie *cli = (struct pico_dhcp_client_cookie *) arg;
-
-  pico_dhcp_execute_init(cli);
-
-  return;
-}
-
-/********************
- * access functions *
- ********************/
-
-struct pico_ip4 pico_dhcp_get_address(void* cli)
-{
-  return ((struct pico_dhcp_client_cookie*)cli)->address;
-}
-
-struct pico_ip4 pico_dhcp_get_gateway(void* cli)
-{
-  return ((struct pico_dhcp_client_cookie*)cli)->gateway;
-}
-
-struct pico_ip4 pico_dhcp_get_nameserver(void* cli)
-{
-  return ((struct pico_dhcp_client_cookie*)cli)->nameserver;
-}
-
-/*************
- * callbacks *
- *************/
-
-static void pico_dhcp_wakeup(uint16_t ev, struct pico_socket *s)
-{
-  uint8_t buf[DHCPC_DATAGRAM_SIZE];
-  int r=0;
-  uint32_t peer;
-  uint16_t port;
-  int type;
-
-  struct pico_dhcp_client_cookie *cli;
-  dbg("DHCPC: called dhcp_wakeup\n");
-  if (ev == PICO_SOCK_EV_RD) {
-    do {
-      r = pico_socket_recvfrom(s, buf, DHCPC_DATAGRAM_SIZE, &peer, &port);
-      cli = get_cookie_by_xid(get_xid(buf));
-      if(cli == NULL)
-        return;
-      if (r > 0 && port == PICO_DHCPD_PORT) {
-        type = pico_dhcp_verify_and_identify_type(buf, r, cli);
-        pico_dhcp_state_machine(type, cli, buf, r);
-      }
-    } while(r>0);
-  }
-}
-
-static void dhcp_timer_cb(unsigned long tick, void* param)
-{
-  struct dhcp_timer_param* param2 = (struct dhcp_timer_param*) param;
-  if(param2->valid == 1){
-    //dbg("called timer cb on active timer type %d\n",param2->type);
-    pico_dhcp_state_machine(param2->type, param2->cli, NULL, 0);
-  }
-  if(param2->cli->timer_param_1 == param){
-    param2->cli->timer_param_1 = NULL;
-  }
-  if(param2->cli->timer_param_2 == param){
-    param2->cli->timer_param_2 = NULL;
-  }
-  if(param2->cli->timer_param_lease == param){
-    param2->cli->timer_param_lease = NULL;
-  }
-  if(param2->cli->timer_param_retransmit == param){
-    param2->cli->timer_param_retransmit = NULL;
-  }
-
-  pico_free(param);
-
-}
-/*****************
- * fsm functions *
- *****************/
-
-static int recv_offer(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
+static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s)
 {
-  struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data;
-  uint8_t *nextopt, opt_data[20], opt_type;
-  int opt_len = 20;
-  uint8_t msg_type = 0xFF;
-  int T1_set = 0;
-  int T2_set = 0;
-
-  cli->address.addr = dhdr->yiaddr;
-
-  opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt);
-  while (opt_type != PICO_DHCPOPT_END) {
-    if (opt_type == PICO_DHCPOPT_MSGTYPE)
-      msg_type = opt_data[0];
-    if ((opt_type == PICO_DHCPOPT_LEASETIME) && (opt_len == 4)){
-      memcpy(&cli->lease_time, opt_data, 4);
-      cli->lease_time = long_be(cli->lease_time);
-    }
-    if ((opt_type == PICO_DHCPOPT_RENEWALTIME) && (opt_len == 4)){
-      memcpy(&cli->T1, opt_data, 4);
-      cli->T1 = long_be(cli->T1);
-      T1_set =1;
-    }
-    if ((opt_type == PICO_DHCPOPT_REBINDINGTIME) && (opt_len == 4)){
-      memcpy(&cli->T2, opt_data, 4);
-      cli->T2 = long_be(cli->T2);
-      T2_set =1;
-    }
-    if ((opt_type == PICO_DHCPOPT_ROUTER) && (opt_len == 4)) //XXX assuming only one router will be advertised...
-      memcpy(&cli->gateway.addr, opt_data, 4);
-    if ((opt_type == PICO_DHCPOPT_DNS) && (opt_len == 4))
-      memcpy(&cli->nameserver.addr, opt_data, 4);
-    if ((opt_type == PICO_DHCPOPT_NETMASK) && (opt_len == 4))
-      memcpy(&cli->netmask.addr, opt_data, 4);
-    if ((opt_type == PICO_DHCPOPT_SERVERID) && (opt_len == 4))
-      memcpy(&cli->server_id.addr, opt_data, 4);
-    if (opt_type == PICO_DHCPOPT_OPTIONOVERLOAD)
-      dbg("DHCPC: WARNING: option overload present (not processed)");
-
-    opt_len = 20;
-    opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt);
-  }
-
-  /* default values for T1 and T2 if necessary */
-  if(T1_set != 1)
-    cli->T1 = cli->lease_time >> 1;
-  if(T2_set != 1)
-    cli->T2 = (cli->lease_time * 875) / 1000;
-
-
-
-  if ((msg_type != PICO_DHCP_MSG_OFFER) || !cli->lease_time || !cli->netmask.addr || !cli->server_id.addr )
-    return 0;
-
-
-  dhclient_send(cli, PICO_DHCP_MSG_REQUEST);
-  cli->state = DHCPSTATE_REQUEST;
-  return 1;
-}
-
-static int recv_ack(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
-{
-  struct pico_ip4 address = {0};
-
-  if(cli->link_added == 0){
-    /* close the socket bound on address 0.0.0.0 */
-    pico_socket_close(cli->socket);
-    cli->socket = NULL;
-    pico_ipv4_link_del(cli->device, address);
-    pico_ipv4_link_add(cli->device, cli->address, cli->netmask);
-    cli->link_added = 1;
-  }
-  cli->state = DHCPSTATE_BOUND;
-
-  dbg("DHCPC: T1: %d\n",cli->T1);
-  dbg("DHCPC: T2: %d\n",cli->T2);
-  dbg("DHCPC: lease time: %d\n",cli->lease_time);
-
-  if(cli->timer_param_1)
-    cli->timer_param_1->valid = 0;
-  if(cli->timer_param_2)
-    cli->timer_param_2->valid = 0;
-  if(cli->timer_param_lease)
-    cli->timer_param_lease->valid = 0;
-  if(cli->timer_param_retransmit)
-    cli->timer_param_retransmit->valid = 0;
-
-
-  cli->timer_param_1 = pico_zalloc(sizeof(struct dhcp_timer_param));
-  if(!cli->timer_param_1){
-    if(cli->cb != NULL){
-      pico_err = PICO_ERR_ENOMEM;
-      cli->cb(cli, PICO_DHCP_ERROR);
-    }
-    return 0;
-  }
-  cli->timer_param_2 = pico_zalloc(sizeof(struct dhcp_timer_param));
-  if(!cli->timer_param_2){
-    if(cli->cb != NULL){
-      pico_err = PICO_ERR_ENOMEM;
-      cli->cb(cli, PICO_DHCP_ERROR);
-    }
-    return 0;
-  }
-  cli->timer_param_lease = pico_zalloc(sizeof(struct dhcp_timer_param));
-  if(!cli->timer_param_lease){
-    if(cli->cb != NULL){
-      pico_err = PICO_ERR_ENOMEM;
-      cli->cb(cli, PICO_DHCP_ERROR);
-    }
-    return 0;
-  }
-  cli->timer_param_1->valid = 1;
-  cli->timer_param_2->valid = 1;
-  cli->timer_param_lease->valid = 1;
-
-  cli->timer_param_1->cli = cli;
-  cli->timer_param_2->cli = cli;
-  cli->timer_param_lease->cli = cli;
-
-  cli->timer_param_1->type = PICO_DHCP_EVENT_T1;
-  cli->timer_param_2->type = PICO_DHCP_EVENT_T2;
-  cli->timer_param_lease->type = PICO_DHCP_EVENT_LEASE;
-  //add timer
-  pico_timer_add(cli->T1*1000, dhcp_timer_cb, cli->timer_param_1);
-  pico_timer_add(cli->T2*1000, dhcp_timer_cb, cli->timer_param_2);
-  pico_timer_add(cli->lease_time*1000, dhcp_timer_cb, cli->timer_param_lease);
-
-  *(cli->xid_user) = cli->xid;
-  if(cli->cb != NULL)
-    cli->cb(cli, PICO_DHCP_SUCCESS);
-  else
-    dbg("DHCPC: no callback\n");
-
-  dhcp_client_mutex++;
-  cli->state = DHCPSTATE_BOUND;
-  return 0;
-}
-
-static int renew(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
-{
-  uint16_t port = PICO_DHCP_CLIENT_PORT;
-
-  /* open and bind to currently acquired address */
-  if (!cli->socket){
-    cli->socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_wakeup);
-    if (!cli->socket) {
-      dbg("DHCPC: error opening socket on renew: %s\n", strerror(pico_err));
-      if(cli->cb != NULL)
-        cli->cb(cli, PICO_DHCP_ERROR);
-      return -1;
-    }
-    if (pico_socket_bind(cli->socket, &cli->address, &port) != 0){
-      dbg("DHCPC: error binding socket on renew: %s\n", strerror(pico_err));
-      pico_socket_close(cli->socket);
-      if(cli->cb != NULL)
-        cli->cb(cli, PICO_DHCP_ERROR);
-      return -1;
-    }
-  }
-  cli->state = DHCPSTATE_RENEWING;
-  dhclient_send(cli, PICO_DHCP_MSG_REQUEST);
-
-  return 0;
-}
-
-static int reset(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
-{
-  if(cli->cb != NULL)
-    cli->cb(cli, PICO_DHCP_RESET);
-  //reset pretty much everything
-
-  if(cli->timer_param_1)
-    cli->timer_param_1->valid = 0;
-  if(cli->timer_param_2)
-    cli->timer_param_2->valid = 0;
-  if(cli->timer_param_lease)
-    cli->timer_param_lease->valid = 0;
-  if(cli->timer_param_retransmit)
-    cli->timer_param_retransmit->valid = 0;
-
-  pico_socket_close(cli->socket);
-  pico_ipv4_link_del(cli->device, cli->address);
-
-  //initiate negotiations again
-  init_cookie(cli);
-  pico_dhcp_retry(cli);
-  dhclient_send(cli, PICO_DHCP_MSG_DISCOVER);
+  uint8_t buf[DHCP_CLIENT_MAXMSGZISE] = {0};
+  int r = 0;
+  struct pico_dhcp_hdr *hdr = NULL;
+  struct pico_dhcp_client_cookie *dhcpc = NULL;
 
-  return 0;
-
-}
-
-static int retransmit(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
-{
-  pico_dhcp_retry(cli);
-
-  if(cli->state == DHCPSTATE_DISCOVER)
-    dhclient_send(cli, PICO_DHCP_MSG_DISCOVER);
-  else if(cli->state == DHCPSTATE_RENEWING)
-    dhclient_send(cli, PICO_DHCP_MSG_REQUEST);
-  else
-    dbg("DHCPC: WARNING: should not get here in state %d!\n", cli->state);
-
-  return 0;
-
-}
-
-/**********************
- * fsm implementation *
- **********************/
-
-struct dhcp_action_entry {
-  uint16_t tcpstate;
-  int (*offer)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-  int (*ack)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-  int (*nak)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-  int (*timer1)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-  int (*timer_lease)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-  int (*timer_retransmit)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
-};
-
-static struct dhcp_action_entry dhcp_fsm[] = {
-    /* State             offer       ack       nak     timer1  timer_lease timer_retransmit*/
-  { DHCPSTATE_DISCOVER,  recv_offer, NULL,     NULL,   NULL,   reset,      retransmit},
-  { DHCPSTATE_OFFER,     NULL,       NULL,     NULL,   NULL,   reset,      NULL},
-  { DHCPSTATE_REQUEST,   NULL,       recv_ack, reset,  NULL,   reset,      retransmit},
-  { DHCPSTATE_BOUND,     NULL,       NULL,     reset,  renew,  reset,      NULL},
-  { DHCPSTATE_RENEWING,  NULL,       recv_ack, reset,  NULL,   reset,      retransmit},
-};
-
-
-static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len)
-{
-  dbg("DHCPC: received incoming event of type %d\n", type);
-  switch(type){
-    case PICO_DHCP_MSG_OFFER:
-      if(dhcp_fsm[cli->state].offer != NULL)
-        dhcp_fsm[cli->state].offer(cli, data, len);
-      break;
-    case PICO_DHCP_MSG_ACK:
-      if(dhcp_fsm[cli->state].ack != NULL){
-        dhcp_fsm[cli->state].ack(cli, data, len);
-      }
-      break;
-    case PICO_DHCP_MSG_NAK:
-      if(dhcp_fsm[cli->state].nak!= NULL){
-        dhcp_fsm[cli->state].nak(cli, data, len);
-      }
-      break;
-    case PICO_DHCP_EVENT_T1:
-      if(dhcp_fsm[cli->state].timer1!= NULL){
-        dhcp_fsm[cli->state].timer1(cli, NULL, 0);
-      }
-      break;
-    case PICO_DHCP_EVENT_LEASE:
-      if(dhcp_fsm[cli->state].timer_lease!= NULL){
-        dhcp_fsm[cli->state].timer_lease(cli, NULL, 0);
-      }
-      break;
-    case PICO_DHCP_EVENT_RETRANSMIT:
-      if(dhcp_fsm[cli->state].timer_retransmit!= NULL){
-        dhcp_fsm[cli->state].timer_retransmit(cli, NULL, 0);
-      }
-      break;
-    default:
-      dbg("DHCPC: event not supported yet!!\n");
-      break;
-  }
-}
-
-
-/*********************
- * utility functions *
- *********************/
-
-static void pico_dhcp_retry(struct pico_dhcp_client_cookie *cli)
-{
-  const int MAX_RETRY = 3;
-  uint32_t new_xid;
-  if (++cli->attempt > MAX_RETRY) {
-    cli->start_time = pico_tick;
-    cli->attempt = 0;
-     new_xid = pico_rand();
-    while(get_cookie_by_xid(new_xid) != NULL){
-      new_xid = pico_rand();
-    }
-    cli->xid = new_xid;
-    cli->state = DHCPSTATE_DISCOVER;
-  }
-}
-
-static int dhclient_send(struct pico_dhcp_client_cookie *cli, uint8_t msg_type)
-{
-  uint8_t buf_out[DHCPC_DATAGRAM_SIZE] = {0};
-  struct pico_dhcphdr *dh_out = (struct pico_dhcphdr *) buf_out;
-  int sent = 0;
-  int i = 0;
-  struct pico_ip4 destination;
-  uint16_t port = PICO_DHCPD_PORT;
-  if(cli->state == DHCPSTATE_BOUND || cli->state == DHCPSTATE_RENEWING){
-    destination.addr = cli->server_id.addr;
-  }else{
-    destination.addr = long_be(0xFFFFFFFF);
-  }
-
-  if(cli->device->eth == NULL){
-    pico_err = PICO_ERR_EOPNOTSUPP;
-    if(cli->cb != NULL){
-      cli->cb(cli, PICO_DHCP_ERROR);
-    }
-    return -1;
-  }
-  memcpy(dh_out->hwaddr, &cli->device->eth->mac, PICO_HLEN_ETHER);
-  dh_out->op = PICO_DHCP_OP_REQUEST;
-  dh_out->htype = PICO_HTYPE_ETHER;
-  dh_out->hlen = PICO_HLEN_ETHER;
-  dh_out->xid = cli->xid;
-  dh_out->secs = (msg_type == PICO_DHCP_MSG_REQUEST)?0:short_be((pico_tick - cli->start_time)/1000);
-  dh_out->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
-  if (cli->state == DHCPSTATE_RENEWING)
-    dh_out->ciaddr = cli->address.addr;
-
-  /* Option: msg type, len 1 */
-  dh_out->options[i++] = PICO_DHCPOPT_MSGTYPE;
-  dh_out->options[i++] = 1;
-  dh_out->options[i++] = msg_type;
+  if (ev != PICO_SOCK_EV_RD)
+    return;
+  r = pico_socket_recvfrom(s, buf, DHCP_CLIENT_MAXMSGZISE, NULL, NULL);
+  if (r < 0)
+    return;
 
-  if (( msg_type == PICO_DHCP_MSG_REQUEST) && ( cli->state != DHCPSTATE_RENEWING )) {
-    dh_out->options[i++] = PICO_DHCPOPT_REQIP;
-    dh_out->options[i++] = 4;
-    dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF000000) >> 24;
-    dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF0000) >> 16;
-    dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF00) >> 8;
-    dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF);
-    dh_out->options[i++] = PICO_DHCPOPT_SERVERID;
-    dh_out->options[i++] = 4;
-    dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF000000) >> 24;
-    dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF0000) >> 16;
-    dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF00) >> 8;
-    dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF);
-  }
-
-  /* Option: req list, len 4 */
-  dh_out->options[i++] = PICO_DHCPOPT_PARMLIST;
-  dh_out->options[i++] = 7;
-  dh_out->options[i++] = PICO_DHCPOPT_NETMASK;
-  dh_out->options[i++] = PICO_DHCPOPT_BCAST;
-  dh_out->options[i++] = PICO_DHCPOPT_TIME;
-  dh_out->options[i++] = PICO_DHCPOPT_ROUTER;
-  dh_out->options[i++] = PICO_DHCPOPT_HOSTNAME;
-  dh_out->options[i++] = PICO_DHCPOPT_RENEWALTIME;
-  dh_out->options[i++] = PICO_DHCPOPT_REBINDINGTIME;
-
-  /* Option : max message size */
-  if( msg_type == PICO_DHCP_MSG_REQUEST || msg_type == PICO_DHCP_MSG_DISCOVER){
-    uint16_t dds = DHCPC_DATAGRAM_SIZE;
-    dh_out->options[i++] = PICO_DHCPOPT_MAXMSGSIZE;
-    dh_out->options[i++] = 2;
-    dh_out->options[i++] = (dds & 0xFF00) >> 8;
-    dh_out->options[i++] = (dds & 0xFF);
-  }
-
-
-
-  dh_out->options[i] = PICO_DHCPOPT_END;
-  sent = pico_socket_sendto(cli->socket, buf_out, DHCPC_DATAGRAM_SIZE, &destination, port);
-  if (sent < 0) {
-    dbg("DHCPC: sendto failed: %s\n", strerror(pico_err));
-    if(cli->cb != NULL)
-      cli->cb(cli, PICO_DHCP_ERROR);
-  }
-
-
-  //resend-timer :
-  if(cli->timer_param_retransmit != NULL)
-    cli->timer_param_retransmit->valid=0;
-
-  cli->timer_param_retransmit = pico_zalloc(sizeof(struct dhcp_timer_param));
-  if(!cli->timer_param_retransmit){
-    if(cli->cb != NULL)
-      pico_err = PICO_ERR_ENOMEM;
-      cli->cb(cli, PICO_DHCP_ERROR);
-    return -1;
-  }
-  cli->timer_param_retransmit->valid = 1;
-  cli->timer_param_retransmit->cli = cli;
-  cli->timer_param_retransmit->type = PICO_DHCP_EVENT_RETRANSMIT;
-  pico_timer_add(4000, dhcp_timer_cb, cli->timer_param_retransmit);
-
-  return 0;
-}
-
-//identifies type & does some preprocessing : checking if everything is valid
-static int pico_dhcp_verify_and_identify_type(uint8_t* data, int len, struct pico_dhcp_client_cookie *cli)
-{
-  struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data;
-  uint8_t *nextopt, opt_data[20], opt_type;
-  int opt_len = 20;
-
-  if (dhdr->xid != cli->xid)
-    return 0;
-
-  if (!is_options_valid(dhdr->options, len - sizeof(struct pico_dhcphdr)))
-    return 0;
-
-  if( dhdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE)
-    return 0;
-
-  opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt);
-  while (opt_type != PICO_DHCPOPT_END) {
-    /* parse interesting options here */
-    if (opt_type == PICO_DHCPOPT_MSGTYPE) {
-      return *opt_data;
-    }
-    opt_len = 20;
-    opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt);
-  }
-  return 0;
-
-}
-
-static int init_cookie(struct pico_dhcp_client_cookie* cli)
-{
-  uint8_t n = 3;
-  uint16_t port = PICO_DHCP_CLIENT_PORT;
-  struct pico_ip4 address, netmask;
-
-  address.addr = long_be(0x00000000);
-  netmask.addr = long_be(0x00000000);
-
-  cli->state = DHCPSTATE_DISCOVER;
-  cli->start_time = pico_tick;
-  cli->attempt = 0;
-
-  cli->socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_wakeup);
-  if (!cli->socket) {
-    dbg("DHCPC: error opening socket: %s\n", strerror(pico_err));
-    if(cli->cb != NULL)
-      cli->cb(cli, PICO_DHCP_ERROR);
-    return -1;
-  }
-  if (pico_socket_bind(cli->socket, &address, &port) != 0){
-    dbg("DHCPC: error binding socket: %s\n", strerror(pico_err));
-    pico_socket_close(cli->socket);
-    if(cli->cb != NULL)
-      cli->cb(cli, PICO_DHCP_ERROR);
-    return -1;
-  }
-  cli->socket->dev = cli->device;
-
-  if(pico_ipv4_link_add(cli->device, address, netmask) != 0){
-    dbg("DHCPC: error adding link: %s\n", strerror(pico_err));
-    if(cli->cb != NULL)
-      cli->cb(cli, PICO_DHCP_ERROR);
-    return -1;
-  }
-
-  /* attempt to generate a correct xid 3 times, then fail */
-  do {
-    cli->xid = pico_rand();
-  } while (!cli->xid && --n);
-  if (!cli->xid) {
-    if(cli->cb != NULL)
-      cli->cb(cli, PICO_DHCP_ERROR);
-    return -1;
-  }
-
-  return 0;
-}
-
-static struct pico_dhcp_client_cookie *get_cookie_by_xid(uint32_t xid)
-{
-  struct pico_dhcp_client_cookie test = { }, *cookie = NULL;
-
-  if (!xid)
-    return NULL;
-
-  test.xid = xid;
-  cookie = pico_tree_findKey(&DHCPCookies, &test);
-  if (!cookie)
-    return NULL;
-  else
-    return cookie;
+  /* If the 'xid' of an arriving message does not match the 'xid' 
+   * of the most recent transmitted message, the message must be 
+   * silently discarded. */
+  hdr = (struct pico_dhcp_hdr *)buf;
+  dhcpc = pico_dhcp_client_find_cookie(hdr->xid);
+  if (!dhcpc)
+    return;
+  dhcpc->event = pico_dhcp_client_opt_parse(buf, r);
+  pico_dhcp_state_machine(dhcpc->event, dhcpc, buf);
 }
 
 void *pico_dhcp_get_identifier(uint32_t xid)
 {
-  return (void *) get_cookie_by_xid(xid);
+  return (void *)pico_dhcp_client_find_cookie(xid);
+}
+
+struct pico_ip4 pico_dhcp_get_address(void* dhcpc)
+{
+  return ((struct pico_dhcp_client_cookie*)dhcpc)->address;
 }
 
-static uint32_t get_xid(uint8_t* data)
+struct pico_ip4 pico_dhcp_get_gateway(void* dhcpc)
 {
-  struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data;
-  return dhdr->xid;
+  return ((struct pico_dhcp_client_cookie*)dhcpc)->gateway;
 }
 
+struct pico_ip4 pico_dhcp_get_nameserver(void* dhcpc)
+{
+  return ((struct pico_dhcp_client_cookie*)dhcpc)->nameserver;
+}
 #endif
--- a/modules/pico_dhcp_client.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_dhcp_client.h	Mon Sep 02 08:02:21 2013 +0000
@@ -7,13 +7,10 @@
 *********************************************************************/
 #ifndef _INCLUDE_PICO_DHCP_CLIENT
 #define _INCLUDE_PICO_DHCP_CLIENT
-
-
 #include "pico_dhcp_common.h"
 #include "pico_addressing.h"
 #include "pico_protocol.h"
 
-
 int pico_dhcp_initiate_negotiation(struct pico_device *device, void (*callback)(void* cli, int code), uint32_t *xid);
 void pico_dhcp_process_incoming_message(uint8_t *data, int len);
 void *pico_dhcp_get_identifier(uint32_t xid);
@@ -26,11 +23,4 @@
 #define PICO_DHCP_ERROR   1
 #define PICO_DHCP_RESET   2
 
-/* DHCP EVENT TYPE 
- * these come after the message types, used for the state machine*/
-#define PICO_DHCP_EVENT_T1                   9
-#define PICO_DHCP_EVENT_T2                   10
-#define PICO_DHCP_EVENT_LEASE                11
-#define PICO_DHCP_EVENT_RETRANSMIT           12
-
 #endif
--- a/modules/pico_dhcp_common.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_dhcp_common.c	Mon Sep 02 08:02:21 2013 +0000
@@ -12,56 +12,174 @@
 #include "pico_dhcp_common.h"
 
 #if defined (PICO_SUPPORT_DHCPC) || defined (PICO_SUPPORT_DHCPD)
-//this function should only be used after you checked if the options are valid! otherwise it could read from bad memory!
-uint8_t dhcp_get_next_option(uint8_t *begin, uint8_t *data, int *len, uint8_t **nextopt)
+/* pico_dhcp_are_options_valid needs to be called first to prevent illegal memory access */
+/* The argument pointer is moved forward to the next option */
+struct pico_dhcp_opt *pico_dhcp_next_option(struct pico_dhcp_opt **ptr)
 {
-    uint8_t *p;
-    uint8_t type;
-    uint8_t opt_len;
+  uint8_t **p = (uint8_t **)ptr;
+  struct pico_dhcp_opt *opt = *ptr;
+
+	if (opt->code == PICO_DHCP_OPT_END)
+    return NULL;
+  if (opt->code == PICO_DHCP_OPT_PAD) {
+    *p += 1; 
+		return *ptr;
+  }
+
+  *p += (opt->len + 2); /* (len + 2) to account for code and len octet */
+  return *ptr;
+}
 
-    if (!begin)
-        p = *nextopt;
-    else
-        p = begin;
+int pico_dhcp_are_options_valid(void *ptr, int len)
+{
+	uint8_t optlen = 0, *p = ptr;
+
+	while (len > 0) {
+    switch (*p)
+    {
+      case PICO_DHCP_OPT_END:
+        return 1;
+
+      case PICO_DHCP_OPT_PAD:
+        p++;
+        len--;
+        break;
 
-    type = *p;
-    *nextopt = ++p;
-    if ((type == PICO_DHCPOPT_END) || (type == PICO_DHCPOPT_PAD)) {
-        memset(data, 0, *len);
-        len = 0;
-        return type;
+      default:
+        p++; /* move pointer from code octet to len octet */
+        if ((--len <= 0) || (len - (*p + 1) < 0)) /* (*p + 1) to account for len octet */
+          return 0;
+        optlen = *p;
+        p += optlen + 1;
+        len -= optlen;
+        break;
     }
-    opt_len = *p;
-    p++;
-    if (*len > opt_len)
-        *len = opt_len;
-    memcpy(data, p, *len);
-    *nextopt = p + opt_len;
-    return type;
+	}
+	return 0;
+}
+
+int pico_dhcp_opt_netmask(void *ptr, struct pico_ip4 *ip)
+{
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: netmask */
+  opt->code = PICO_DHCP_OPT_NETMASK;
+  opt->len = PICO_DHCP_OPTLEN_NETMASK - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.netmask.ip = *ip;
+  return PICO_DHCP_OPTLEN_NETMASK;
+}
+
+int pico_dhcp_opt_router(void *ptr, struct pico_ip4 *ip)
+{
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: router */
+  opt->code = PICO_DHCP_OPT_ROUTER;
+  opt->len = PICO_DHCP_OPTLEN_ROUTER - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.router.ip = *ip;
+  return PICO_DHCP_OPTLEN_ROUTER;
+}
+
+int pico_dhcp_opt_dns(void *ptr, struct pico_ip4 *ip)
+{
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: dns */
+  opt->code = PICO_DHCP_OPT_DNS;
+  opt->len = PICO_DHCP_OPTLEN_DNS - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.dns.ip = *ip;
+  return PICO_DHCP_OPTLEN_DNS;
 }
 
-int is_options_valid(uint8_t *opt_buffer, int len)
+int pico_dhcp_opt_broadcast(void *ptr, struct pico_ip4 *ip)
+{
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: broadcast */
+  opt->code = PICO_DHCP_OPT_BROADCAST;
+  opt->len = PICO_DHCP_OPTLEN_BROADCAST - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.broadcast.ip = *ip;
+  return PICO_DHCP_OPTLEN_BROADCAST;
+}
+
+int pico_dhcp_opt_reqip(void *ptr, struct pico_ip4 *ip)
+{
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: request IP address */
+  opt->code = PICO_DHCP_OPT_REQIP;
+  opt->len = PICO_DHCP_OPTLEN_REQIP - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.req_ip.ip = *ip;
+  return PICO_DHCP_OPTLEN_REQIP;
+}
+
+int pico_dhcp_opt_leasetime(void *ptr, uint32_t time)
+{
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: lease time */
+  opt->code = PICO_DHCP_OPT_LEASETIME;
+  opt->len = PICO_DHCP_OPTLEN_LEASETIME - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.lease_time.time = time;
+  return PICO_DHCP_OPTLEN_LEASETIME;
+}
+
+int pico_dhcp_opt_msgtype(void *ptr, uint8_t type)
 {
-    uint8_t *p = opt_buffer;
-    while (len > 0) {
-        if (*p == PICO_DHCPOPT_END)
-            return 1;
-        else if (*p == PICO_DHCPOPT_PAD) {
-            p++;
-            len--;
-        } else {
-            uint8_t opt_len;
-            p++;
-            len--;
-            if(len > 0) {
-                opt_len = *p;
-                p += opt_len + 1;
-                len -= opt_len;
-            }else
-                return 0;
-        }
-    }
-    return 0;
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: message type */
+  opt->code = PICO_DHCP_OPT_MSGTYPE;
+  opt->len = PICO_DHCP_OPTLEN_MSGTYPE - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.msg_type.type = type;
+  return PICO_DHCP_OPTLEN_MSGTYPE;
+}
+
+int pico_dhcp_opt_serverid(void *ptr, struct pico_ip4 *ip)
+{
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: server identifier */
+  opt->code = PICO_DHCP_OPT_SERVERID;
+  opt->len = PICO_DHCP_OPTLEN_SERVERID - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.server_id.ip = *ip;
+  return PICO_DHCP_OPTLEN_SERVERID;
+}
+
+int pico_dhcp_opt_paramlist(void *ptr)
+{
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: parameter list */
+  opt->code = PICO_DHCP_OPT_PARAMLIST;
+  opt->len = PICO_DHCP_OPTLEN_PARAMLIST - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.param_list.code[0] = PICO_DHCP_OPT_NETMASK;
+  opt->ext.param_list.code[1] = PICO_DHCP_OPT_TIME;
+  opt->ext.param_list.code[2] = PICO_DHCP_OPT_ROUTER;
+  opt->ext.param_list.code[3] = PICO_DHCP_OPT_HOSTNAME;
+  opt->ext.param_list.code[4] = PICO_DHCP_OPT_RENEWALTIME;
+  opt->ext.param_list.code[5] = PICO_DHCP_OPT_REBINDINGTIME;
+  return PICO_DHCP_OPTLEN_PARAMLIST;
+}
+
+int pico_dhcp_opt_maxmsgsize(void *ptr, uint16_t size)
+{
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+  /* option: maximum message size */
+  opt->code = PICO_DHCP_OPT_MAXMSGSIZE;
+  opt->len = PICO_DHCP_OPTLEN_MAXMSGSIZE - PICO_DHCP_OPTLEN_HDR;
+  opt->ext.max_msg_size.size = short_be(size);
+  return PICO_DHCP_OPTLEN_MAXMSGSIZE;
+}
+
+int pico_dhcp_opt_end(void *ptr)
+{
+  uint8_t *opt = (uint8_t *)ptr;
+
+  /* option: end of options */
+  *opt = PICO_DHCP_OPT_END;
+  return PICO_DHCP_OPTLEN_END;
 }
 
 #endif
--- a/modules/pico_dhcp_common.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_dhcp_common.h	Mon Sep 02 08:02:21 2013 +0000
@@ -7,96 +7,177 @@
 *********************************************************************/
 #ifndef _INCLUDE_PICO_DHCP_COMMON
 #define _INCLUDE_PICO_DHCP_COMMON
-
-
-#include <stdint.h>
-
-//minimum size is 576, cfr RFC
-#define DHCPC_DATAGRAM_SIZE 576
-#define DHCPD_DATAGRAM_SIZE 576
-
+#include "pico_addressing.h"
 
 #define PICO_DHCPD_PORT (short_be(67))
 #define PICO_DHCP_CLIENT_PORT (short_be(68))
-
-#define PICO_DHCP_OP_REQUEST 1
-#define PICO_DHCP_OP_REPLY   2
+#define PICO_DHCPD_MAGIC_COOKIE (long_be(0x63825363))
+#define PICO_DHCP_HTYPE_ETH 1
 
-#define PICO_HTYPE_ETHER 1
-#define PICO_HLEN_ETHER  6
-
-#define PICO_DHCPD_MAGIC_COOKIE (long_be(0x63825363))
+/* flags */
+#define PICO_DHCP_FLAG_BROADCAST        0x8000
 
-/* DHCP OPTIONS, RFC2132 */
-#define PICO_DHCPOPT_PAD                     0x00
-#define PICO_DHCPOPT_NETMASK                 0x01
-#define PICO_DHCPOPT_TIME                    0x02
-#define PICO_DHCPOPT_ROUTER                  0x03
-#define PICO_DHCPOPT_DNS                     0x06
-#define PICO_DHCPOPT_HOSTNAME                0x0c
-#define PICO_DHCPOPT_DOMAINNAME              0x0f
-#define PICO_DHCPOPT_MTU                     0x1a
-#define PICO_DHCPOPT_BCAST                   0x1c
-#define PICO_DHCPOPT_NETBIOSNS               0x2c
-#define PICO_DHCPOPT_NETBIOSSCOPE            0x2f
+/* options */
+#define PICO_DHCP_OPT_PAD               0x00
+#define PICO_DHCP_OPT_NETMASK           0x01
+#define PICO_DHCP_OPT_TIME              0x02
+#define PICO_DHCP_OPT_ROUTER            0x03
+#define PICO_DHCP_OPT_DNS               0x06
+#define PICO_DHCP_OPT_HOSTNAME          0x0c
+#define PICO_DHCP_OPT_DOMAINNAME        0x0f
+#define PICO_DHCP_OPT_MTU               0x1a
+#define PICO_DHCP_OPT_BROADCAST         0x1c
+#define PICO_DHCP_OPT_NETBIOSNS         0x2c
+#define PICO_DHCP_OPT_NETBIOSSCOPE      0x2f
+#define PICO_DHCP_OPT_REQIP             0x32
+#define PICO_DHCP_OPT_LEASETIME         0x33
+#define PICO_DHCP_OPT_OPTOVERLOAD       0x34
+#define PICO_DHCP_OPT_MSGTYPE           0x35
+#define PICO_DHCP_OPT_SERVERID          0x36
+#define PICO_DHCP_OPT_PARAMLIST         0x37
+#define PICO_DHCP_OPT_MESSAGE           0x38
+#define PICO_DHCP_OPT_MAXMSGSIZE        0x39
+#define PICO_DHCP_OPT_RENEWALTIME       0x3a
+#define PICO_DHCP_OPT_REBINDINGTIME     0x3b
+#define PICO_DHCP_OPT_VENDORID          0x3c
+#define PICO_DHCP_OPT_CLIENTID          0x3d
+#define PICO_DHCP_OPT_DOMAINSEARCH      0x77
+#define PICO_DHCP_OPT_STATICROUTE       0x79
+#define PICO_DHCP_OPT_END               0xFF
 
-#define PICO_DHCPOPT_REQIP                   0x32
-#define PICO_DHCPOPT_LEASETIME               0x33
-#define PICO_DHCPOPT_OPTIONOVERLOAD          0x34
-#define PICO_DHCPOPT_MSGTYPE                 0x35
-#define PICO_DHCPOPT_SERVERID                0x36
-#define PICO_DHCPOPT_PARMLIST                0x37
-#define PICO_DHCPOPT_MAXMSGSIZE              0x39
-#define PICO_DHCPOPT_RENEWALTIME             0x3a
-#define PICO_DHCPOPT_REBINDINGTIME           0x3b
-#define PICO_DHCPOPT_DOMAINSEARCH            0x77
-#define PICO_DHCPOPT_STATICROUTE             0x79
-#define PICO_DHCPOPT_END                     0xFF
+/* options len */
+#define PICO_DHCP_OPTLEN_HDR            2 /* account for code and len field */
+#define PICO_DHCP_OPTLEN_NETMASK        6
+#define PICO_DHCP_OPTLEN_ROUTER         6
+#define PICO_DHCP_OPTLEN_DNS            6
+#define PICO_DHCP_OPTLEN_BROADCAST      6
+#define PICO_DHCP_OPTLEN_REQIP          6
+#define PICO_DHCP_OPTLEN_LEASETIME      6
+#define PICO_DHCP_OPTLEN_OPTOVERLOAD    3
+#define PICO_DHCP_OPTLEN_MSGTYPE        3
+#define PICO_DHCP_OPTLEN_SERVERID       6
+#define PICO_DHCP_OPTLEN_PARAMLIST      8 /* PicoTCP specific */
+#define PICO_DHCP_OPTLEN_MAXMSGSIZE     4
+#define PICO_DHCP_OPTLEN_RENEWALTIME    6
+#define PICO_DHCP_OPTLEN_REBINDINGTIME  6
+#define PICO_DHCP_OPTLEN_END            1
+
+/* op codes */
+#define PICO_DHCP_OP_REQUEST            1
+#define PICO_DHCP_OP_REPLY              2
 
-/* DHCP MESSAGE TYPE */
-#define PICO_DHCP_MSG_DISCOVER               1
-#define PICO_DHCP_MSG_OFFER                  2
-#define PICO_DHCP_MSG_REQUEST                3
-#define PICO_DHCP_MSG_DECLINE                4
-#define PICO_DHCP_MSG_ACK                    5
-#define PICO_DHCP_MSG_NAK                    6
-#define PICO_DHCP_MSG_RELEASE                7
-#define PICO_DHCP_MSG_INFORM                 8
+/* rfc message types */
+#define PICO_DHCP_MSG_DISCOVER          1
+#define PICO_DHCP_MSG_OFFER             2
+#define PICO_DHCP_MSG_REQUEST           3
+#define PICO_DHCP_MSG_DECLINE           4
+#define PICO_DHCP_MSG_ACK               5
+#define PICO_DHCP_MSG_NAK               6
+#define PICO_DHCP_MSG_RELEASE           7
+#define PICO_DHCP_MSG_INFORM            8
+
+/* custom message types */
+#define PICO_DHCP_EVENT_T1              9
+#define PICO_DHCP_EVENT_T2              10
+#define PICO_DHCP_EVENT_LEASE           11
+#define PICO_DHCP_EVENT_RETRANSMIT      12
 
-
-enum dhcp_negotiation_state {
-        DHCPSTATE_DISCOVER = 0,
-        DHCPSTATE_OFFER,
-        DHCPSTATE_REQUEST,
-        DHCPSTATE_BOUND,
-        DHCPSTATE_RENEWING
+struct __attribute__((packed)) pico_dhcp_hdr
+{
+	uint8_t op;
+	uint8_t htype;
+	uint8_t hlen;
+	uint8_t hops; //zero
+	uint32_t xid; //store this in the request
+	uint16_t secs; // ignore
+	uint16_t flags;
+	uint32_t ciaddr; // client address - if asking for renewal
+	uint32_t yiaddr; // your address (client)
+	uint32_t siaddr; // dhcp offered address
+	uint32_t giaddr; // relay agent, bootp.
+	uint8_t hwaddr[6];
+	uint8_t hwaddr_padding[10];
+	char    hostname[64];
+	char    bootp_filename[128];
+	uint32_t dhcp_magic;
+	uint8_t options[0];
 };
 
-
-struct __attribute__((packed)) pico_dhcphdr
+struct __attribute__((packed)) pico_dhcp_opt
 {
-    uint8_t op;
-    uint8_t htype;
-    uint8_t hlen;
-    uint8_t hops; //zero
-    uint32_t xid; //store this in the request
-    uint16_t secs; // ignore
-    uint16_t flags;
-    uint32_t ciaddr; // client address - if asking for renewal
-    uint32_t yiaddr; // your address (client)
-    uint32_t siaddr; // dhcp offered address
-    uint32_t giaddr; // relay agent, bootp.
-    uint8_t hwaddr[6];
-    uint8_t hwaddr_padding[10];
-    char    hostname[64];
-    char    bootp_filename[128];
-    uint32_t dhcp_magic;
-    uint8_t options[0];
+  uint8_t code;
+  uint8_t len;
+  union {
+    struct {
+      struct pico_ip4 ip;
+    } netmask;
+    struct {
+      struct pico_ip4 ip;
+    } router;
+    struct {
+      struct pico_ip4 ip;
+    } dns;
+    struct {
+      struct pico_ip4 ip;
+    } broadcast;
+    struct {
+      struct pico_ip4 ip;
+    } req_ip;
+    struct {
+      uint32_t time;
+    } lease_time;
+    struct {
+      uint8_t value;
+    } opt_overload;
+    struct {
+      char name[0];
+    } tftp_server;
+    struct {
+      char name[0];
+    } bootfile;
+    struct {
+      uint8_t type;
+    } msg_type;
+    struct {
+      struct pico_ip4 ip;
+    } server_id;
+    struct {
+      uint8_t code[0];
+    } param_list;
+    struct {
+      char error[0];
+    } message;
+    struct {
+      uint16_t size;
+    } max_msg_size;
+    struct {
+      uint32_t time;
+    } renewal_time;
+    struct {
+      uint32_t time;
+    } rebinding_time;
+    struct {
+      uint8_t id[0];
+    } vendor_id;
+    struct {
+      uint8_t id[0];
+    } client_id;
+  } ext;
 };
 
-
-//common functions for client and server
+uint8_t dhcp_get_next_option(uint8_t *begin, uint8_t *data, int *len, uint8_t **nextopt);
+struct pico_dhcp_opt *pico_dhcp_next_option(struct pico_dhcp_opt **ptr);
+int pico_dhcp_are_options_valid(void *ptr, int len); 
 
-uint8_t dhcp_get_next_option(uint8_t *begin, uint8_t *data, int *len, uint8_t **nextopt);
-int is_options_valid(uint8_t *opt_buffer, int len); 
+int pico_dhcp_opt_netmask(void *ptr, struct pico_ip4 *ip);
+int pico_dhcp_opt_router(void *ptr, struct pico_ip4 *ip);
+int pico_dhcp_opt_dns(void *ptr, struct pico_ip4 *ip);
+int pico_dhcp_opt_broadcast(void *ptr, struct pico_ip4 *ip);
+int pico_dhcp_opt_reqip(void *ptr, struct pico_ip4 *ip);
+int pico_dhcp_opt_leasetime(void *ptr, uint32_t time);
+int pico_dhcp_opt_msgtype(void *ptr, uint8_t type);
+int pico_dhcp_opt_serverid(void *ptr, struct pico_ip4 *ip);
+int pico_dhcp_opt_paramlist(void *ptr);
+int pico_dhcp_opt_maxmsgsize(void *ptr, uint16_t size);
+int pico_dhcp_opt_end(void *ptr);
 #endif
--- a/modules/pico_dhcp_server.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_dhcp_server.c	Mon Sep 02 08:02:21 2013 +0000
@@ -7,332 +7,310 @@
 *********************************************************************/
 
 #ifdef PICO_SUPPORT_DHCPD
-
 #include "pico_dhcp_server.h"
-#include "pico_stack.h"
 #include "pico_config.h"
 #include "pico_addressing.h"
 #include "pico_socket.h"
+#include "pico_udp.h"
+#include "pico_stack.h"
 #include "pico_arp.h"
-#include <stdlib.h>
+
+#define dhcps_dbg(...) do{}while(0)
+//#define dhcps_dbg dbg
+
+/* default configurations */ 
+#define DHCP_SERVER_OPENDNS    long_be(0xd043dede) /* OpenDNS DNS server 208.67.222.222 */
+#define DHCP_SERVER_POOL_START long_be(0x00000064)
+#define DHCP_SERVER_POOL_END   long_be(0x000000fe)
+#define DHCP_SERVER_LEASE_TIME long_be(0x00000078)
+
+/* maximum size of a DHCP message */
+#define DHCP_SERVER_MAXMSGSIZE (PICO_IP_MTU - sizeof(struct pico_ipv4_hdr) - sizeof(struct pico_udp_hdr))
+
+#define ip_inrange(x) ((long_be(x) >= long_be(dhcpn->dhcps->pool_start)) && (long_be(x) <= long_be(dhcpn->dhcps->pool_end)))
 
-# define dhcpd_dbg(...) do{}while(0)
-//# define dhcpd_dbg dbg
+enum dhcp_server_state {
+  PICO_DHCP_STATE_DISCOVER = 0,
+  PICO_DHCP_STATE_OFFER,
+  PICO_DHCP_STATE_REQUEST,
+  PICO_DHCP_STATE_BOUND,
+  PICO_DHCP_STATE_RENEWING
+};
 
-#define dhcpd_make_offer(x) dhcpd_make_reply(x, PICO_DHCP_MSG_OFFER)
-#define dhcpd_make_ack(x) dhcpd_make_reply(x, PICO_DHCP_MSG_ACK)
-#define ip_inrange(x) ((long_be(x) >= long_be(dn->settings->pool_start)) && (long_be(x) <= long_be(dn->settings->pool_end)))
+struct pico_dhcp_server_negotiation {
+  uint32_t xid;
+  enum dhcp_server_state state;
+  struct pico_dhcp_server_setting *dhcps;
+  struct pico_ip4 ciaddr;
+  struct pico_eth hwaddr;
+};
+
+static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s);
 
 static int dhcp_settings_cmp(void *ka, void *kb)
 {
-  struct pico_dhcpd_settings *a = ka, *b = kb;
-  if (a->dev < b->dev)
-    return -1; 
-  else if (a->dev > b->dev)
-    return 1;
-  else
+  struct pico_dhcp_server_setting *a = ka, *b = kb;
+  if (a->dev == b->dev)
     return 0;
+  return (a->dev < b->dev) ? -1 : 1;
 } 
 PICO_TREE_DECLARE(DHCPSettings, dhcp_settings_cmp);
 
 static int dhcp_negotiations_cmp(void *ka, void *kb)
 {
-  struct pico_dhcp_negotiation *a = ka, *b = kb;
-  if (a->xid < b->xid)
-    return -1; 
-  else if (a->xid > b->xid)
-    return 1;
-  else
+  struct pico_dhcp_server_negotiation *a = ka, *b = kb;
+  if (a->xid == b->xid)
     return 0;
+  return (a->xid < b->xid) ? -1 : 1;
 } 
 PICO_TREE_DECLARE(DHCPNegotiations, dhcp_negotiations_cmp);
 
-static struct pico_dhcp_negotiation *get_negotiation_by_xid(uint32_t xid)
+static struct pico_dhcp_server_setting *pico_dhcp_server_add_setting(struct pico_dhcp_server_setting *setting)
 {
-  struct pico_dhcp_negotiation test = { }, *neg = NULL;
+  uint16_t port = PICO_DHCPD_PORT;
+  struct pico_dhcp_server_setting *dhcps = NULL, *found = NULL, test = {0};
+  struct pico_ipv4_link *link = NULL;
+  
+  link = pico_ipv4_link_get(&setting->server_ip);
+  if (!link) {
+    pico_err = PICO_ERR_EINVAL;
+    return NULL;
+  }
+  test.dev = setting->dev;
+  found = pico_tree_findKey(&DHCPSettings, &test);
+  if (found) {
+    pico_err = PICO_ERR_EINVAL;
+    return NULL;
+  }
+  dhcps = pico_zalloc(sizeof(struct pico_dhcp_server_setting));
+  if (!dhcps) {
+    pico_err = PICO_ERR_ENOMEM;
+    return NULL;
+  }
 
-  test.xid = xid;
-  neg = pico_tree_findKey(&DHCPNegotiations, &test);
-  if (!neg)
+  dhcps->lease_time = setting->lease_time;
+  dhcps->pool_start = setting->pool_start;
+  dhcps->pool_next = setting->pool_next;
+  dhcps->pool_end = setting->pool_end;
+  dhcps->dev = link->dev;
+  dhcps->server_ip = link->address;
+  dhcps->netmask = link->netmask;
+
+  /* default values if not provided */
+  if (!dhcps->pool_start)
+    dhcps->pool_start = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_START;
+  if (!dhcps->pool_end)
+    dhcps->pool_end = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_END;
+  if (!dhcps->lease_time)
+    dhcps->lease_time = DHCP_SERVER_LEASE_TIME;
+  dhcps->pool_next = dhcps->pool_start;
+
+  dhcps->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup);
+  if (!dhcps->s) {
+    dhcps_dbg("DHCP server ERROR: failure opening socket (%s)\n", strerror(pico_err));
+    pico_free(dhcps);
     return NULL;
-  else
-    return neg;
+  }
+  if (pico_socket_bind(dhcps->s, &dhcps->server_ip, &port) < 0) {
+    dhcps_dbg("DHCP server ERROR: failure binding socket (%s)\n", strerror(pico_err));
+    pico_free(dhcps);
+    return NULL;
+  }
+  
+  pico_tree_insert(&DHCPSettings, dhcps);
+  return dhcps;
 }
 
-static void dhcpd_make_reply(struct pico_dhcp_negotiation *dn, uint8_t reply_type)
+static struct pico_dhcp_server_negotiation *pico_dhcp_server_find_negotiation(uint32_t xid)
 {
-  uint8_t buf_out[DHCPD_DATAGRAM_SIZE] = {0};
-  struct pico_dhcphdr *dh_out = (struct pico_dhcphdr *) buf_out;
-  struct pico_ip4 destination = { };
-  uint32_t bcast = dn->settings->my_ip.addr | ~(dn->settings->netmask.addr);
-  uint32_t dns_server = OPENDNS;
-  uint16_t port = PICO_DHCP_CLIENT_PORT;
-  int sent = 0;
-
-  memcpy(dh_out->hwaddr, dn->eth.addr, PICO_HLEN_ETHER);
-  dh_out->op = PICO_DHCP_OP_REPLY;
-  dh_out->htype = PICO_HTYPE_ETHER;
-  dh_out->hlen = PICO_HLEN_ETHER;
-  dh_out->xid = dn->xid;
-  dh_out->yiaddr = dn->ipv4.addr;
-  dh_out->siaddr = dn->settings->my_ip.addr;
-  dh_out->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
-
-  /* Option: msg type, len 1 */
-  dh_out->options[0] = PICO_DHCPOPT_MSGTYPE;
-  dh_out->options[1] = 1;
-  dh_out->options[2] = reply_type;
-
-  /* Option: server id, len 4 */
-  dh_out->options[3] = PICO_DHCPOPT_SERVERID;
-  dh_out->options[4] = 4;
-  memcpy(dh_out->options + 5, &dn->settings->my_ip.addr, 4);
+  struct pico_dhcp_server_negotiation test = {0}, *found = NULL;
 
-  /* Option: Lease time, len 4 */
-  dh_out->options[9] = PICO_DHCPOPT_LEASETIME;
-  dh_out->options[10] = 4;
-  memcpy(dh_out->options + 11, &dn->settings->lease_time, 4);
-
-  /* Option: Netmask, len 4 */
-  dh_out->options[15] = PICO_DHCPOPT_NETMASK;
-  dh_out->options[16] = 4;
-  memcpy(dh_out->options + 17, &dn->settings->netmask.addr, 4);
-
-  /* Option: Router, len 4 */
-  dh_out->options[21] = PICO_DHCPOPT_ROUTER;
-  dh_out->options[22] = 4;
-  memcpy(dh_out->options + 23, &dn->settings->my_ip.addr, 4);
-
-  /* Option: Broadcast, len 4 */
-  dh_out->options[27] = PICO_DHCPOPT_BCAST;
-  dh_out->options[28] = 4;
-  memcpy(dh_out->options + 29, &bcast, 4);
-
-  /* Option: DNS, len 4 */
-  dh_out->options[33] = PICO_DHCPOPT_DNS;
-  dh_out->options[34] = 4;
-  memcpy(dh_out->options + 35, &dns_server, 4);
-
-  dh_out->options[40] = PICO_DHCPOPT_END;
-
-  destination.addr = dh_out->yiaddr;
-
-  sent = pico_socket_sendto(dn->settings->s, buf_out, DHCPD_DATAGRAM_SIZE, &destination, port);
-  if (sent < 0) {
-    dhcpd_dbg("DHCPD: sendto failed with code %d!\n", pico_err);
-  }
+  test.xid = xid;
+  found = pico_tree_findKey(&DHCPNegotiations, &test);
+  if (found)
+    return found;
+  else
+    return NULL;
 }
 
-static void dhcp_recv(struct pico_socket *s, uint8_t *buffer, int len)
+static struct pico_dhcp_server_negotiation *pico_dhcp_server_add_negotiation(struct pico_device *dev, struct pico_dhcp_hdr *hdr)
 {
-  struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) buffer;
-  struct pico_dhcp_negotiation *dn = get_negotiation_by_xid(dhdr->xid);
-  struct pico_ip4* ipv4 = NULL;
-  struct pico_dhcpd_settings test, *settings = NULL;
-  uint8_t *nextopt, opt_data[20], opt_type;
-  int opt_len = 20;
-  uint8_t msg_type;
-  uint32_t msg_reqIP = 0;
-  uint32_t msg_servID = 0;
+  struct pico_dhcp_server_negotiation *dhcpn = NULL;
+  struct pico_dhcp_server_setting test = {0};
+  struct pico_ip4 *ciaddr = NULL;
+
+  if (pico_dhcp_server_find_negotiation(hdr->xid))
+    return NULL;
+
+  dhcpn = pico_zalloc(sizeof(struct pico_dhcp_server_negotiation));
+  if (!dhcpn) {
+    pico_err = PICO_ERR_ENOMEM;
+    return NULL;
+  }
 
-  if (!is_options_valid(dhdr->options, len - sizeof(struct pico_dhcphdr))) {
-    dhcpd_dbg("DHCPD WARNING: invalid options in dhcp message\n");
-    return;
+  dhcpn->xid = hdr->xid;
+  dhcpn->state = PICO_DHCP_STATE_DISCOVER;
+  memcpy(dhcpn->hwaddr.addr, hdr->hwaddr, PICO_SIZE_ETH);
+
+  test.dev = dev;
+  dhcpn->dhcps = pico_tree_findKey(&DHCPSettings, &test);
+  if (!dhcpn->dhcps) {
+    dhcps_dbg("DHCP server WARNING: received DHCP message on unconfigured link %s\n", dev->name);
+    pico_free(dhcpn);
+    return NULL;
+  }
+
+  ciaddr = pico_arp_reverse_lookup(&dhcpn->hwaddr);
+  if (!ciaddr) {
+    dhcpn->ciaddr.addr = dhcpn->dhcps->pool_next;
+    dhcpn->dhcps->pool_next = long_be(long_be(dhcpn->dhcps->pool_next) + 1);
+    pico_arp_create_entry(dhcpn->hwaddr.addr, dhcpn->ciaddr, dhcpn->dhcps->dev);
+  } else {
+    dhcpn->ciaddr = *ciaddr;
   }
 
-  if (!dn) {
-    dn = pico_zalloc(sizeof(struct pico_dhcp_negotiation));
-    if (!dn) {
-      pico_err = PICO_ERR_ENOMEM;
-      return;
-    }
-    dn->xid = dhdr->xid;
-    dn->state = DHCPSTATE_DISCOVER;
-    memcpy(dn->eth.addr, dhdr->hwaddr, PICO_HLEN_ETHER);
+  pico_tree_insert(&DHCPNegotiations, dhcpn);
+  return dhcpn; 
+}
+
+static void dhcpd_make_reply(struct pico_dhcp_server_negotiation *dhcpn, uint8_t msg_type)
+{
+  int r = 0, optlen = 0, offset = 0;
+  struct pico_ip4 broadcast = {0}, dns = {0}, destination = { .addr = 0xFFFFFFFF};
+  struct pico_dhcp_hdr *hdr = NULL;
+
+  dns.addr = DHCP_SERVER_OPENDNS;
+  broadcast.addr = dhcpn->dhcps->server_ip.addr | ~(dhcpn->dhcps->netmask.addr);
+
+  optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_SERVERID + PICO_DHCP_OPTLEN_LEASETIME + PICO_DHCP_OPTLEN_NETMASK + PICO_DHCP_OPTLEN_ROUTER 
+          + PICO_DHCP_OPTLEN_BROADCAST + PICO_DHCP_OPTLEN_DNS + PICO_DHCP_OPTLEN_END;
+  hdr = pico_zalloc(sizeof(struct pico_dhcp_hdr) + optlen);
+
+  hdr->op = PICO_DHCP_OP_REPLY;
+  hdr->htype = PICO_DHCP_HTYPE_ETH;
+  hdr->hlen = PICO_SIZE_ETH;
+  hdr->xid = dhcpn->xid;
+  hdr->yiaddr = dhcpn->ciaddr.addr;
+  hdr->siaddr = dhcpn->dhcps->server_ip.addr;
+  hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
+  memcpy(hdr->hwaddr, dhcpn->hwaddr.addr, PICO_SIZE_ETH);
 
-    test.dev = pico_ipv4_link_find(&s->local_addr.ip4);
-    settings = pico_tree_findKey(&DHCPSettings, &test);
-    if (settings) {
-      dn->settings = settings;
-    } else {
-      dhcpd_dbg("DHCPD WARNING: received DHCP message on unconfigured link %s\n", test.dev->name);
-      pico_free(dn);
-      return;
-    }
+  /* options */
+  offset += pico_dhcp_opt_msgtype(&hdr->options[offset], msg_type);
+  offset += pico_dhcp_opt_serverid(&hdr->options[offset], &dhcpn->dhcps->server_ip);
+  offset += pico_dhcp_opt_leasetime(&hdr->options[offset], dhcpn->dhcps->lease_time);
+  offset += pico_dhcp_opt_netmask(&hdr->options[offset], &dhcpn->dhcps->netmask);
+  offset += pico_dhcp_opt_router(&hdr->options[offset], &dhcpn->dhcps->server_ip);
+  offset += pico_dhcp_opt_broadcast(&hdr->options[offset], &broadcast);
+  offset += pico_dhcp_opt_dns(&hdr->options[offset], &dns);
+  offset += pico_dhcp_opt_end(&hdr->options[offset]);
+
+  destination.addr = hdr->yiaddr;
+  r = pico_socket_sendto(dhcpn->dhcps->s, hdr, sizeof(struct pico_dhcp_hdr) + optlen, &destination, PICO_DHCP_CLIENT_PORT);
+  if (r < 0)
+    dhcps_dbg("DHCP server WARNING: failure sending: %s!\n", strerror(pico_err));
 
-    ipv4 = pico_arp_reverse_lookup(&dn->eth);
-    if (!ipv4) {
-      dn->ipv4.addr = settings->pool_next;
-      pico_arp_create_entry(dn->eth.addr, dn->ipv4, settings->dev);
-      settings->pool_next = long_be(long_be(settings->pool_next) + 1);
-    } else {
-      dn->ipv4.addr = ipv4->addr;
-    }
+  return;
+}
 
-    if (pico_tree_insert(&DHCPNegotiations, dn)) {
-      dhcpd_dbg("DHCPD WARNING: tried creating new negotation for existing xid %u\n", dn->xid);
-      pico_free(dn);
-      return; /* Element key already exists */
-    }
-  }
- 
-  if (!ip_inrange(dn->ipv4.addr))
+static void pico_dhcp_server_recv(struct pico_socket *s, uint8_t *buf, int len)
+{
+  uint8_t msgtype = 0;
+  int optlen = len - sizeof(struct pico_dhcp_hdr);
+  struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
+  struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)hdr->options;
+  struct pico_dhcp_server_negotiation *dhcpn = NULL;
+  struct pico_ip4 reqip = {0}, server_id = {0};
+  struct pico_device *dev = NULL;
+
+  if (!pico_dhcp_are_options_valid(hdr->options, optlen))
     return;
 
-  opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt);
-  while (opt_type != PICO_DHCPOPT_END) {
-    /* parse interesting options here */
-      //dhcpd_dbg("DHCPD sever: opt_type %x,  opt_data[0]%d\n", opt_type, opt_data[0]);
-    switch(opt_type){
-      case PICO_DHCPOPT_MSGTYPE:
-        msg_type = opt_data[0];
+  dev = pico_ipv4_link_find(&s->local_addr.ip4);
+  dhcpn = pico_dhcp_server_find_negotiation(hdr->xid);
+  if (!dhcpn)
+    dhcpn = pico_dhcp_server_add_negotiation(dev, hdr);
+ 
+  if (!ip_inrange(dhcpn->ciaddr.addr))
+    return;
+
+  do {
+    switch (opt->code)
+    {
+      case PICO_DHCP_OPT_PAD:
+        break;
+
+      case PICO_DHCP_OPT_END:
         break;
-      case PICO_DHCPOPT_REQIP:
-        //dhcpd_dbg("DHCPD sever: opt_type %x,  opt_len%d\n", opt_type, opt_len);
-        if( opt_len == 4)
-        {
-          msg_reqIP =  ( opt_data[0] << 24 );
-          msg_reqIP |= ( opt_data[1] << 16 );
-          msg_reqIP |= ( opt_data[2] << 8  );
-          msg_reqIP |= ( opt_data[3]       );
-         //dhcpd_dbg("DHCPD sever: msg_reqIP %x, opt_data[0] %x,[1] %x,[2] %x,[3] %x\n", msg_reqIP, opt_data[0],opt_data[1],opt_data[2],opt_data[3]);
-        };
+
+      case PICO_DHCP_OPT_MSGTYPE:
+        msgtype = opt->ext.msg_type.type;
+        dhcps_dbg("DHCP server: message type %u\n", msgtype);
         break;
-      case PICO_DHCPOPT_SERVERID:
-        //dhcpd_dbg("DHCPD sever: opt_type %x,  opt_len%d\n", opt_type, opt_len);
-        if( opt_len == 4)
-        {
-          msg_servID =  ( opt_data[0] << 24 );
-          msg_servID |= ( opt_data[1] << 16 );
-          msg_servID |= ( opt_data[2] << 8  );
-          msg_servID |= ( opt_data[3]       );
-          //dhcpd_dbg("DHCPD sever: msg_servID %x, opt_data[0] %x,[1] %x,[2] %x,[3] %x\n", msg_servID, opt_data[0],opt_data[1],opt_data[2],opt_data[3]);
-        };
+
+      case PICO_DHCP_OPT_REQIP:
+        reqip = opt->ext.req_ip.ip;
+        dhcps_dbg("DHCP server: requested IP %08X\n", reqip.addr);
+        break;
+
+      case PICO_DHCP_OPT_SERVERID:
+        server_id = opt->ext.server_id.ip;
+        dhcps_dbg("DHCP server: server ID %08X\n", server_id.addr);
         break;        
+
       default:
+        dhcps_dbg("DHCP server WARNING: unsupported option %u\n", opt->code);
         break;
     }
-        
-    opt_len = 20;
-    opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt);
-  }
-    
-  //dhcpd_dbg("DHCPD sever: msg_type %d, dn->state %d\n", msg_type, dn->state);
-  //dhcpd_dbg("DHCPD sever: msg_reqIP %x, dn->msg_servID %x\n", msg_reqIP, msg_servID);
-  //dhcpd_dbg("DHCPD sever: dhdr->ciaddr %x, dhdr->yiaddr %x, dn->ipv4.addr %x\n", dhdr->ciaddr,dhdr->yiaddr,dn->ipv4.addr);
+  } while (pico_dhcp_next_option(&opt));
+
+  switch (msgtype)
+  {
+    case PICO_DHCP_MSG_DISCOVER:
+      dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_OFFER);
+      dhcpn->state = PICO_DHCP_STATE_OFFER;
+      break;
 
-  if (msg_type == PICO_DHCP_MSG_DISCOVER)
-  {
-    dhcpd_make_offer(dn);
-    dn->state = DHCPSTATE_OFFER;
-    return;
+    case PICO_DHCP_MSG_REQUEST:
+      if ((dhcpn->state == PICO_DHCP_STATE_BOUND) && (!reqip.addr) && (!server_id.addr) && (hdr->ciaddr == dhcpn->ciaddr.addr))
+        dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK);
+      if (dhcpn->state == PICO_DHCP_STATE_OFFER) {
+        dhcpn->state = PICO_DHCP_STATE_BOUND;
+        dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK);
+      }
+      break;
+
+    default:
+      dhcps_dbg("DHCP server WARNING: unsupported message type %u\n", msgtype);
+      break;
   }
-  else if ((msg_type == PICO_DHCP_MSG_REQUEST)&&( dn->state == DHCPSTATE_OFFER))
-  {
-    dhcpd_make_ack(dn);
-    dn->state = DHCPSTATE_BOUND;
-    return;
-  }
-  else if ((msg_type == PICO_DHCP_MSG_REQUEST)&&( dn->state == DHCPSTATE_BOUND))
-  {
-    if( ( msg_servID == 0 )
-      &&( msg_reqIP == 0 )
-      &&( dhdr->ciaddr == dn->ipv4.addr)
-      )
-    { 
-      dhcpd_make_ack(dn);
-      return;
-    }
-  }  
+  return;
 }
 
 static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s)
 {
-  uint8_t buf[DHCPD_DATAGRAM_SIZE] = { };
+  uint8_t buf[DHCP_SERVER_MAXMSGSIZE] = {0};
   int r = 0;
-  uint32_t peer = 0;
-  uint16_t port = 0;
 
-  dhcpd_dbg("DHCPD: called dhcpd_wakeup\n");
-  if (ev == PICO_SOCK_EV_RD) {
-    do {
-      r = pico_socket_recvfrom(s, buf, DHCPD_DATAGRAM_SIZE, &peer, &port);
-      if (r > 0 && port == PICO_DHCP_CLIENT_PORT) {
-        dhcp_recv(s, buf, r);
-      }
-    } while(r>0);
-  }
+  if (ev != PICO_SOCK_EV_RD)
+    return;
+  r = pico_socket_recvfrom(s, buf, DHCP_SERVER_MAXMSGSIZE, NULL, NULL);
+  if (r < 0)
+    return;
+
+  pico_dhcp_server_recv(s, buf, r);
+  return;
 }
 
-int pico_dhcp_server_initiate(struct pico_dhcpd_settings *setting)
+int pico_dhcp_server_initiate(struct pico_dhcp_server_setting *setting)
 {
-  struct pico_dhcpd_settings *settings = NULL;
-  struct pico_ipv4_link *link = NULL;
-  uint16_t port = PICO_DHCPD_PORT;
-
-  if (!setting) {
+  if (!setting || !setting->server_ip.addr) {
     pico_err = PICO_ERR_EINVAL;
     return -1;
   }
 
-  if (!setting->my_ip.addr) {
-    pico_err = PICO_ERR_EINVAL;
-    dhcpd_dbg("DHCPD: IP address of interface was not supplied\n");
-    return -1;
-  }
-
-  link = pico_ipv4_link_get(&setting->my_ip);
-  if (!link) {
-    pico_err = PICO_ERR_EINVAL;
-    dhcpd_dbg("DHCPD: no link with IP %X found\n", setting->my_ip.addr);
-    return -1;
-  }
-
-  settings = pico_zalloc(sizeof(struct pico_dhcpd_settings));
-  if (!settings) {
-    pico_err = PICO_ERR_ENOMEM;
+  if (pico_dhcp_server_add_setting(setting) == NULL)
     return -1;
-  }
-  memcpy(settings, setting, sizeof(struct pico_dhcpd_settings));
-
-  settings->dev = link->dev;
-  dhcpd_dbg("DHCPD: configuring DHCP server for link %s\n", link->dev->name);
-  settings->my_ip.addr = link->address.addr;
-  dhcpd_dbg("DHCPD: using server addr %X\n", long_be(settings->my_ip.addr));
-  settings->netmask.addr = link->netmask.addr;
-  dhcpd_dbg("DHCPD: using netmask %X\n", long_be(settings->netmask.addr));
-
-  /* default values if not provided */
-  if (settings->pool_start == 0)
-    settings->pool_start = (settings->my_ip.addr & settings->netmask.addr) | POOL_START;
-  dhcpd_dbg("DHCPD: using pool_start %X\n", long_be(settings->pool_start));
-  if (settings->pool_end == 0)
-    settings->pool_end = (settings->my_ip.addr & settings->netmask.addr) | POOL_END;
-  dhcpd_dbg("DHCPD: using pool_end %x\n", long_be(settings->pool_end));
-  if (settings->lease_time == 0)
-    settings->lease_time = LEASE_TIME;
-  dhcpd_dbg("DHCPD: using lease time %x\n", long_be(settings->lease_time));
-  settings->pool_next = settings->pool_start;
-
-  settings->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup);
-  if (!settings->s) {
-    dhcpd_dbg("DHCP: could not open client socket\n");
-    pico_free(settings);
-    return -1;
-  }
-  if (pico_socket_bind(settings->s, &settings->my_ip, &port) != 0) {
-    dhcpd_dbg("DHCP: could not bind server socket (%s)\n", strerror(pico_err));
-    pico_free(settings);
-    return -1;
-  }
-  
-  if (pico_tree_insert(&DHCPSettings, settings)) {
-    dhcpd_dbg("DHCPD ERROR: link %s already configured\n", link->dev->name);
-    pico_err = PICO_ERR_EINVAL;
-    pico_free(settings);
-    return -1; /* Element key already exists */
-  }
-  dhcpd_dbg("DHCPD: configured DHCP server for link %s\n", link->dev->name);
 
   return 0;
 }
--- a/modules/pico_dhcp_server.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_dhcp_server.h	Mon Sep 02 08:02:21 2013 +0000
@@ -9,35 +9,20 @@
 #include "pico_dhcp_common.h"
 #include "pico_addressing.h"
 
-/* default configuration */ 
-#define OPENDNS (long_be(0xd043dede)) /* OpenDNS DNS server 208.67.222.222 */
-#define POOL_START long_be(0x00000064)
-#define POOL_END long_be(0x000000fe)
-#define LEASE_TIME long_be(0x00000078)
-
-struct pico_dhcpd_settings
+struct pico_dhcp_server_setting
 {
-  struct pico_device *dev;
-  struct pico_socket *s;
-  struct pico_ip4 my_ip;
-  struct pico_ip4 netmask;
   uint32_t pool_start;
   uint32_t pool_next;
   uint32_t pool_end;
   uint32_t lease_time;
+  struct pico_device *dev;
+  struct pico_socket *s;
+  struct pico_ip4 server_ip;
+  struct pico_ip4 netmask;
   uint8_t flags; /* unused atm */
 };
 
-struct pico_dhcp_negotiation {
-  struct pico_dhcpd_settings *settings;
-  struct pico_ip4 ipv4;
-  struct pico_eth eth;
-  enum dhcp_negotiation_state state;
-  uint32_t xid;
-  uint32_t assigned_address;
-};
-
-/* required settings field: IP address of the interface to serve, only IPs of this network will be served. */
-int pico_dhcp_server_initiate(struct pico_dhcpd_settings *setting);
+/* required field: IP address of the interface to serve, only IPs of this network will be served. */
+int pico_dhcp_server_initiate(struct pico_dhcp_server_setting *dhcps);
 
 #endif /* _INCLUDE_PICO_DHCP_SERVER */
--- a/modules/pico_dns_client.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_dns_client.c	Mon Sep 02 08:02:21 2013 +0000
@@ -26,10 +26,8 @@
 #define PICO_DNS_CLIENT_RETRANS 4000
 #define PICO_DNS_CLIENT_MAX_RETRANS 3
 
-/* Default nameservers */
+/* Default nameservers + port */
 #define PICO_DNS_NS_GOOGLE "8.8.8.8"
-
-/* Nameserver port */
 #define PICO_DNS_NS_PORT 53
 
 /* FLAG values */
@@ -64,78 +62,648 @@
 #define PICO_DNS_LABEL 0
 #define PICO_DNS_POINTER 3
 
+/* Label len */
+#define PICO_DNS_LABEL_INITIAL 1
+#define PICO_DNS_LABEL_ROOT 1
+
 /* TTL values */
 #define PICO_DNS_MAX_TTL 604800 /* one week */
 
-/* Header flags */
-#define FLAG_QR(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 15)) | (x << 15)) 
-#define FLAG_OPCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF << 11)) | (x << 11)) 
-#define FLAG_AA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 10)) | (x << 10)) 
-#define FLAG_TC(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 9)) | (x << 9)) 
-#define FLAG_RD(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 8)) | (x << 8)) 
-#define FLAG_RA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 7)) | (x << 7)) 
-#define FLAG_Z(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x7 << 4)) | (x << 4)) 
-#define FLAG_RCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF)) | x) 
+/* Len of an IPv4 address string */
+#define PICO_DNS_IPV4_ADDR_LEN 16
+
+static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
+static void pico_dns_client_retransmission(unsigned long now, void *arg);
 
-#define GET_FLAG_QR(hdr) ((((hdr)->flags) & (1 << 15)) != 0) 
-#define GET_FLAG_OPCODE(hdr) ((((hdr)->flags) & (0xF << 11)) >> 11) 
-#define GET_FLAG_AA(hdr) ((((hdr)->flags) & (1 << 10)) != 0) 
-#define GET_FLAG_TC(hdr) ((((hdr)->flags) & (1 << 9)) != 0) 
-#define GET_FLAG_RD(hdr) ((((hdr)->flags) & (1 << 8)) != 0) 
-#define GET_FLAG_RA(hdr) ((((hdr)->flags) & (1 << 7)) != 0) 
-#define GET_FLAG_Z(hdr) ((((hdr)->flags) & (0x7 << 4)) >> 4) 
-#define GET_FLAG_RCODE(hdr) (((hdr)->flags) & (0x0F)) 
+/* RFC 1035 section 4. MESSAGES */
+struct __attribute__((packed)) pico_dns_name
+{
+  char name[0];
+};
 
-/* RFC 1025 section 4. MESSAGES */
-struct __attribute__((packed)) dns_message_hdr
+/* prefix = header + name pointer
+ * flags splitted in 2x uint8 due to endianness */
+struct __attribute__((packed)) pico_dns_prefix
 {
   uint16_t id;
-  uint16_t flags;
+  uint8_t rd:1; /* recursion desired  */
+  uint8_t tc:1; /* truncation  */
+  uint8_t aa:1; /* authoritative answer  */
+  uint8_t opcode:4; /* opcode  */
+  uint8_t qr:1; /* query  */
+  uint8_t rcode:4; /* response code */
+  uint8_t z:3; /* zero */
+  uint8_t ra:1; /* recursion available  */
   uint16_t qdcount;
   uint16_t ancount;
   uint16_t nscount;
   uint16_t arcount;
+  struct pico_dns_name domain;
 };
 
-struct __attribute__((packed)) dns_query_suffix
+struct __attribute__((packed)) pico_dns_query_suffix
 {
-  /* NAME - domain name to which this resource record pertains */
   uint16_t qtype;
   uint16_t qclass;
 };
 
-struct __attribute__((packed)) dns_answer_suffix
+struct __attribute__((packed)) pico_dns_answer_suffix
 {
-  /* NAME - domain name to which this resource record pertains */
   uint16_t qtype;
   uint16_t qclass;
   uint32_t ttl;
   uint16_t rdlength;
-  /* RDATA - variable length string of octets that describes the resource */
+  uint8_t rdata[0];
 };
 
 struct pico_dns_ns
 {
-  struct pico_ip4 ns; /* Nameserver */
+  struct pico_ip4 ns; /* nameserver */
 };
 
 static int dns_ns_cmp(void *ka, void *kb)
 {
-    struct pico_dns_ns *a = ka, *b = kb;
-  if (a->ns.addr < b->ns.addr)
-    return -1; 
-  else if (a->ns.addr > b->ns.addr)
-    return 1;
+	struct pico_dns_ns *a = ka, *b = kb;
+  if (a->ns.addr == b->ns.addr)
+    return 0;
+  return (a->ns.addr < b->ns.addr) ? -1 : 1;
+} 
+PICO_TREE_DECLARE(NSTable, dns_ns_cmp);
+    
+struct pico_dns_query
+{
+  char *query;
+  uint16_t len;
+  uint16_t id;
+  uint16_t qtype;
+  uint16_t qclass;
+  uint8_t retrans;
+  struct pico_dns_ns q_ns;
+  struct pico_socket *s;
+  void (*callback)(char *, void *);
+  void *arg;
+};
+
+static int dns_query_cmp(void *ka, void *kb)
+{
+	struct pico_dns_query *a = ka,*b = kb;
+  if (a->id == b->id)
+    return 0;
+  return (a->id < b->id) ? -1 : 1;
+} 
+PICO_TREE_DECLARE(DNSTable, dns_query_cmp);
+
+static int pico_dns_client_del_ns(struct pico_ip4 *ns_addr)
+{
+  struct pico_dns_ns test = {{0}}, *found = NULL;
+
+  test.ns = *ns_addr;
+  found = pico_tree_findKey(&NSTable, &test);
+  if (!found)
+    return -1;
+
+  pico_tree_delete(&NSTable, found);
+  pico_free(found);
+
+  /* no NS left, add default NS */
+  if (pico_tree_empty(&NSTable))
+    pico_dns_client_init();
+
+  return 0;
+}
+
+static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr)
+{
+  struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}};
+  
+  dns = pico_zalloc(sizeof(struct pico_dns_ns));
+  if (!dns) {
+    pico_err = PICO_ERR_ENOMEM;
+    return NULL;
+  }
+  dns->ns = *ns_addr;
+
+  found = pico_tree_insert(&NSTable, dns);
+  if (found) { /* nameserver already present */
+    pico_free(dns);
+    return found;
+  }
+
+  /* default NS found, remove it */
+  pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
+  found = pico_tree_findKey(&NSTable, &test);
+  if (found && (found->ns.addr != ns_addr->addr))
+    pico_dns_client_del_ns(&found->ns);
+
+  return dns;
+}
+
+static struct pico_dns_ns pico_dns_client_next_ns(struct pico_ip4 *ns_addr)
+{
+  struct pico_dns_ns dns = {{0}}, *nxtdns = NULL;
+  struct pico_tree_node *node = NULL, *nxtnode = NULL;
+
+  dns.ns = *ns_addr;
+  node = pico_tree_findNode(&NSTable, &dns);
+  if (!node)
+    return dns; /* keep using current NS */
+
+  nxtnode = pico_tree_next(node);
+  nxtdns = nxtnode->keyValue;
+  if (!nxtdns)
+    nxtdns = (struct pico_dns_ns *)pico_tree_first(&NSTable);
+  return *nxtdns;
+}
+
+static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_prefix *hdr, uint16_t len, struct pico_dns_query_suffix *suffix, 
+                                                        void (*callback)(char *, void *), void *arg)
+{
+  struct pico_dns_query *q = NULL, *found = NULL;
+
+  q = pico_zalloc(sizeof(struct pico_dns_query));
+  if (!q)
+    return NULL;
+
+  q->query = (char *)hdr;
+  q->len = len;
+  q->id = short_be(hdr->id);
+  q->qtype = short_be(suffix->qtype);
+  q->qclass = short_be(suffix->qclass);
+  q->retrans = 1;
+  q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
+  q->callback = callback;
+  q->arg = arg;
+  q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
+  if (!q->s) {
+    pico_free(q);
+    return NULL;
+  }
+
+  found = pico_tree_insert(&DNSTable, q);
+  if (found) {
+    pico_err = PICO_ERR_EAGAIN;
+    pico_socket_close(q->s);
+    pico_free(q);
+    return NULL;
+  }
+
+  return q;
+}
+
+static int pico_dns_client_del_query(uint16_t id)
+{
+  struct pico_dns_query test = {0}, *found = NULL;
+
+  test.id = id;
+  found = pico_tree_findKey(&NSTable, &test);
+  if (!found)
+    return -1;
+
+  pico_free(found->query);
+  pico_socket_close(found->s);
+  pico_tree_delete(&DNSTable, found);
+  pico_free(found);
+  return 0;
+}
+
+static struct pico_dns_query *pico_dns_client_find_query(uint16_t id)
+{
+  struct pico_dns_query test = {0}, *found = NULL;
+
+  test.id = id;
+  found = pico_tree_findKey(&DNSTable, &test);
+  if (found)
+    return found;
   else
+    return NULL;
+}
+
+/* determine len of string */
+static uint16_t pico_dns_client_strlen(const char *url)
+{
+  char p = 0;
+  uint16_t len = 0;
+
+  if (!url)
     return 0;
-} 
-    
-PICO_TREE_DECLARE(NSTable,dns_ns_cmp);
+
+  while ((p = *url++) != 0) {
+    len++;
+  }
+  return len;
+}
+
+/* seek end of string */
+static char *pico_dns_client_seek(char *ptr)
+{
+  char p = 0;
+
+  if (!ptr)
+    return NULL;
+
+  while ((p = *ptr++) != 0);
+  return ptr++;
+}
+
+/* mirror ip address numbers
+ * f.e. 192.168.0.1 => 1.0.168.192 */
+static int pico_dns_client_mirror(char *ptr)
+{
+  const unsigned char *addr = NULL;
+  char *m = ptr;
+  uint32_t ip = 0;
+  int i = 0;
+
+  if (pico_string_to_ipv4(ptr, &ip) < 0)
+    return -1;
+
+  ptr = m;
+  addr = (unsigned char *)&ip;
+  for (i = 3; i >= 0; i--) {
+    if (addr[i] > 99) {
+      *ptr++ = '0' + (addr[i] / 100);
+      *ptr++ = '0' + ((addr[i] % 100) / 10);
+      *ptr++ = '0' + ((addr[i] % 100) % 10);
+    } else if(addr[i] > 9) {
+      *ptr++ = '0' + (addr[i] / 10);
+      *ptr++ = '0' + (addr[i] % 10);
+    } else {
+      *ptr++ = '0' + addr[i];
+    }
+    if(i > 0)
+      *ptr++ = '.';
+  }
+  *ptr = '\0';
+
+  return 0;
+}
+
+static struct pico_dns_query *pico_dns_client_idcheck(uint16_t id)
+{
+  struct pico_dns_query test = {0};
+
+  test.id = id;
+  return pico_tree_findKey(&DNSTable, &test);
+}
+
+static int pico_dns_client_query_prefix(struct pico_dns_prefix *pre)
+{
+  uint16_t id = 0;
+  uint8_t retry = 32;
+
+  do {
+    id = (uint16_t)(pico_rand() & 0xFFFFU);
+    dns_dbg("DNS: generated id %u\n", id);
+  } while (retry-- && pico_dns_client_idcheck(id));
+  if (!retry)
+    return -1;
+
+  pre->id = short_be(id);
+  pre->qr = PICO_DNS_QR_QUERY; 
+  pre->opcode = PICO_DNS_OPCODE_QUERY; 
+  pre->aa = PICO_DNS_AA_NO_AUTHORITY; 
+  pre->tc = PICO_DNS_TC_NO_TRUNCATION; 
+  pre->rd = PICO_DNS_RD_IS_DESIRED; 
+  pre->ra = PICO_DNS_RA_NO_SUPPORT; 
+  pre->z = 0; 
+  pre->rcode = PICO_DNS_RCODE_NO_ERROR; 
+  pre->qdcount = short_be(1);
+  pre->ancount = short_be(0);
+  pre->nscount = short_be(0);
+  pre->arcount = short_be(0);
+
+  return 0;
+}
+
+static int pico_dns_client_query_suffix(struct pico_dns_query_suffix *suf, uint16_t type, uint16_t class)
+{
+  suf->qtype = short_be(type);
+  suf->qclass = short_be(class);
+  return 0;
+}
+
+/* replace '.' in the domain name by the label length 
+ * f.e. www.google.be => 3www6google2be0 */
+static int pico_dns_client_query_domain(char *ptr)
+{
+  char p = 0, *label = NULL;
+  uint8_t len = 0;
+
+  if (!ptr)
+    return -1;
+
+  label = ptr++;
+  while ((p = *ptr++) != 0){
+    if (p == '.') {
+      *label = len;
+      label = ptr - 1;
+      len = 0;
+    } else {
+      len++;
+    }
+  }
+  *label = len;
+  return 0;
+}
+
+/* replace the label length in the domain name by '.' 
+ * f.e. 3www6google2be0 => .www.google.be */
+static int pico_dns_client_answer_domain(char *ptr)
+{
+  char p = 0, *label = NULL;
+
+  if (!ptr)
+    return -1;
+
+  label = ptr;
+  while ((p = *ptr++) != 0){
+    ptr += p;
+    *label = '.';
+    label = ptr;
+  }
+  return 0;
+}
+
+static int pico_dns_client_check_prefix(struct pico_dns_prefix *pre)
+{
+  if (pre->qr != PICO_DNS_QR_RESPONSE || pre->opcode != PICO_DNS_OPCODE_QUERY || pre->rcode != PICO_DNS_RCODE_NO_ERROR) {
+    dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", pre->opcode, pre->tc, pre->rcode);
+    return -1;
+  }
+  if (short_be(pre->ancount) < 1) {
+    dns_dbg("DNS ERROR: ancount < 1\n");
+    return -1;
+  }
+  return 0;
+}
+
+static int pico_dns_client_check_qsuffix(struct pico_dns_query_suffix *suf, struct pico_dns_query *q)
+{
+  if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) {
+    dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass));
+    return -1;
+  }
+  return 0;
+}
+
+static int pico_dns_client_check_asuffix(struct pico_dns_answer_suffix *suf, struct pico_dns_query *q)
+{
+  if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) {
+    dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass));
+    return -1;
+  }
+  if (long_be(suf->ttl) > PICO_DNS_MAX_TTL) {
+    dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(suf->ttl), PICO_DNS_MAX_TTL);
+    return -1;
+  }
+  return 0;
+}
+
+static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_prefix *pre, struct pico_dns_query *q)
+{
+  struct pico_dns_answer_suffix *asuffix = NULL;
+  uint16_t comp = 0, compression = 0;
+  uint16_t i = 0;
+  char *psuffix = suf;
+
+  while (i++ < short_be(pre->ancount)) {
+    comp = short_from(psuffix);
+    compression = short_be(comp);
+    switch (compression >> 14)
+    {
+      case PICO_DNS_POINTER:
+        while (compression >> 14 == PICO_DNS_POINTER) {
+          dns_dbg("DNS: pointer\n");
+          psuffix += sizeof(uint16_t);
+          comp = short_from(psuffix);
+          compression = short_be(comp);
+        }
+        break;
+
+      case PICO_DNS_LABEL:
+        dns_dbg("DNS: label\n");
+        psuffix = pico_dns_client_seek(psuffix);
+        break;
+
+      default:
+        dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression);
+        return NULL;
+    }
+
+    asuffix = (struct pico_dns_answer_suffix *)psuffix;
+    if (pico_dns_client_check_asuffix(asuffix, q) < 0) {
+      psuffix += (sizeof(struct pico_dns_answer_suffix) + short_be(asuffix->rdlength));
+      continue;
+    }
+    return psuffix;
+  }
+  return NULL;
+}
+
+static int pico_dns_client_send(struct pico_dns_query *q)
+{
+  dns_dbg("DNS: sending query to %08X\n", q->q_ns.ns.addr);
+  if (!q->s)
+    return -1;
+  if (pico_socket_connect(q->s, &q->q_ns.ns, short_be(PICO_DNS_NS_PORT)) < 0)
+    return -1;
+
+  pico_socket_send(q->s, q->query, q->len);
+  pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, q);
+
+  return 0;
+}
+
+static void pico_dns_client_retransmission(unsigned long now, void *arg)
+{
+  struct pico_dns_query *q = (struct pico_dns_query *)arg;
+  IGNORE_PARAMETER(now);
+  /* dns query successful? */
+  if (!q->retrans) {
+    pico_dns_client_del_query(q->id);
+    return;
+  }
+
+  if (q->retrans++ <= PICO_DNS_CLIENT_MAX_RETRANS) {
+    q->q_ns = pico_dns_client_next_ns(&q->q_ns.ns); 
+    pico_dns_client_send(q);
+  } else {
+    pico_err = PICO_ERR_EIO;
+    q->callback(NULL, q->arg);
+    pico_dns_client_del_query(q->id);
+  }
+}
+
+static int pico_dns_client_user_callback(struct pico_dns_answer_suffix *asuffix, struct pico_dns_query *q)
+{
+  uint32_t ip = 0;
+  char *str = NULL;
+  
+  switch (q->qtype)
+  {
+    case PICO_DNS_TYPE_A:
+      ip = long_from(asuffix->rdata);
+      str = pico_zalloc(PICO_DNS_IPV4_ADDR_LEN);
+      pico_ipv4_to_string(str, ip);
+      break;
+
+    case PICO_DNS_TYPE_PTR:
+      pico_dns_client_answer_domain((char *)asuffix->rdata);
+      str = pico_zalloc(asuffix->rdlength - PICO_DNS_LABEL_INITIAL);
+      memcpy(str, asuffix->rdata + PICO_DNS_LABEL_INITIAL, short_be(asuffix->rdlength) - PICO_DNS_LABEL_INITIAL);
+      break;
+
+    default:
+      dns_dbg("DNS ERROR: incorrect qtype (%u)\n", q->qtype);
+      break;
+  }
+
+  if (q->retrans) {
+    q->callback(str, q->arg);
+    q->retrans = 0;
+  }
+  return 0;
+}
+
+static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s)
+{
+  struct pico_dns_prefix *prefix = NULL;
+  struct pico_dns_name *domain = NULL;
+  struct pico_dns_query_suffix *qsuffix = NULL;
+  struct pico_dns_answer_suffix *asuffix = NULL;
+  struct pico_dns_query *q = NULL;
+  char *p_asuffix = NULL;
+  char msg[PICO_DNS_MAX_RESPONSE_LEN] = {0};
+
+  if (ev == PICO_SOCK_EV_ERR) {
+    dns_dbg("DNS: socket error received\n");
+    return;
+  }
+
+  if (ev & PICO_SOCK_EV_RD) {
+    if (pico_socket_read(s, msg, PICO_DNS_MAX_RESPONSE_LEN) <= 0)
+      return;
+  }
+
+  prefix = (struct pico_dns_prefix *)msg;
+  domain = &prefix->domain;
+  qsuffix = (struct pico_dns_query_suffix *)pico_dns_client_seek(domain->name);
+  /* valid asuffix is determined dynamically later on */
+
+  if (pico_dns_client_check_prefix(prefix) < 0)
+    return;
+  q = pico_dns_client_find_query(short_be(prefix->id));
+  if (!q)
+    return;
+  if (pico_dns_client_check_qsuffix(qsuffix, q) < 0)
+    return;
+
+  p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_query_suffix);
+  p_asuffix = pico_dns_client_seek_suffix(p_asuffix, prefix, q);
+  if (!p_asuffix)
+    return;
+
+  asuffix = (struct pico_dns_answer_suffix *)p_asuffix;
+  pico_dns_client_user_callback(asuffix, q);
+
+  return;
+}
+
+int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
+{
+  char *msg = NULL;
+  struct pico_dns_prefix *prefix = NULL;
+  struct pico_dns_name *domain = NULL;
+  struct pico_dns_query_suffix *qsuffix = NULL;
+  struct pico_dns_query *q = NULL;
+  uint16_t len = 0, lblen = 0, strlen = 0;
+
+  if (!url || !callback) {
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+  }
+
+  strlen = pico_dns_client_strlen(url);
+  lblen = PICO_DNS_LABEL_INITIAL + strlen + PICO_DNS_LABEL_ROOT;
+  len = sizeof(struct pico_dns_prefix) + lblen + sizeof(struct pico_dns_query_suffix);
+  msg = pico_zalloc(len);
+  if (!msg) {
+    pico_err = PICO_ERR_ENOMEM;
+    return -1;
+  }
+  prefix = (struct pico_dns_prefix *)msg;
+  domain = &prefix->domain;
+  qsuffix = (struct pico_dns_query_suffix *)(domain->name + lblen);
+  memcpy(domain->name + PICO_DNS_LABEL_INITIAL, url, strlen);
+
+  /* assemble dns message */
+  pico_dns_client_query_prefix(prefix);
+  pico_dns_client_query_domain(domain->name);
+  pico_dns_client_query_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN);
+
+  q = pico_dns_client_add_query(prefix, len, qsuffix, callback, arg);
+  if (!q) {
+    pico_free(msg);
+    return -1;
+  }
+  if (pico_dns_client_send(q) < 0) {
+    pico_dns_client_del_query(q->id); /* frees msg */
+    return -1;
+  }
+
+  return 0;
+}
+
+int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
+{
+  char *inaddr_arpa = ".in-addr.arpa", *msg = NULL;
+  struct pico_dns_prefix *prefix = NULL;
+  struct pico_dns_name *domain = NULL;
+  struct pico_dns_query_suffix *qsuffix = NULL;
+  struct pico_dns_query *q = NULL;
+  uint16_t len = 0, lblen = 0, strlen = 0, arpalen = 0;
+
+  if (!ip || !callback) {
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+  }
+
+  strlen = pico_dns_client_strlen(ip);
+  arpalen = pico_dns_client_strlen(inaddr_arpa);
+  lblen = PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT;
+  len = sizeof(struct pico_dns_prefix) + lblen + sizeof(struct pico_dns_query_suffix);
+  msg = pico_zalloc(len);
+  if (!msg) {
+    pico_err = PICO_ERR_ENOMEM;
+    return -1;
+  }
+  prefix = (struct pico_dns_prefix *)msg;
+  domain = &prefix->domain;
+  qsuffix = (struct pico_dns_query_suffix *)(prefix->domain.name + lblen);
+  memcpy(domain->name + PICO_DNS_LABEL_INITIAL, ip, strlen);
+  pico_dns_client_mirror(domain->name + PICO_DNS_LABEL_INITIAL);
+  memcpy(domain->name + PICO_DNS_LABEL_INITIAL + strlen, inaddr_arpa, arpalen);
+
+  /* assemble dns message */
+  pico_dns_client_query_prefix(prefix);
+  pico_dns_client_query_domain(domain->name);
+  pico_dns_client_query_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN);
+
+  q = pico_dns_client_add_query(prefix, len, qsuffix, callback, arg);
+  if (!q) {
+    pico_free(msg);
+    return -1;
+  }
+  if (pico_dns_client_send(q) < 0) {
+    pico_dns_client_del_query(q->id); /* frees msg */
+    return -1;
+  }
+
+  return 0;
+}
 
 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
 {
-  struct pico_dns_ns test, *key = NULL;
-
   if (!ns) {
     pico_err = PICO_ERR_EINVAL;
     return -1;
@@ -144,60 +712,15 @@
   switch (flag)
   {
     case PICO_DNS_NS_ADD:
-      key = pico_zalloc(sizeof(struct pico_dns_ns));
-      if (!key) {
-        pico_err = PICO_ERR_ENOMEM;
+      if (!pico_dns_client_add_ns(ns))
         return -1;
-      }
-      key->ns = *ns;
-
-      if(pico_tree_insert(&NSTable,key)){
-        dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr);
-        pico_err = PICO_ERR_EINVAL;
-        pico_free(key);
-        return -1; /* Element key already exists */
-      }
-      dns_dbg("DNS: nameserver %08X added\n", ns->addr);
-      /* If default NS found, remove it */
-      pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
-      if (ns->addr != test.ns.addr) {
-
-          key = pico_tree_findKey(&NSTable,&test);
-        if (key) {
-            if(pico_tree_delete(&NSTable,key)) {
-            dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr);
-            pico_free(key);
-          } else {
-            pico_err = PICO_ERR_EAGAIN;
-            return -1;
-          }
-        }
-      }
       break;
 
     case PICO_DNS_NS_DEL:
-      test.ns = *ns;
-
-      key = pico_tree_findKey(&NSTable,&test);
-      if (!key) {
-        dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr);
+      if (pico_dns_client_del_ns(ns) < 0) {
         pico_err = PICO_ERR_EINVAL;
         return -1;
       }
-      /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
-
-            if(pico_tree_delete(&NSTable,key)) {
-        dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr);
-        pico_free(key);
-      } else {
-        pico_err = PICO_ERR_EAGAIN;
-        return -1;
-      }
-      /* If no NS left, add default NS */
-      if(pico_tree_first(&NSTable) == NULL){
-        dns_dbg("DNS: add default nameserver\n");
-        return pico_dns_client_init();
-      }
       break;
 
     default:
@@ -209,559 +732,12 @@
 
 int pico_dns_client_init()
 {
-  struct pico_ip4 default_ns;
-  if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) != 0) {
-    pico_err = PICO_ERR_EINVAL;
+  struct pico_ip4 default_ns = {0};
+
+  if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) < 0)
     return -1;
-  }
+
   return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD);
 }
 
-struct pico_dns_key
-{
-  char *q_hdr;
-  uint16_t len;
-  uint16_t id;
-  uint16_t qtype;
-  uint16_t qclass;
-  uint8_t retrans;
-  struct pico_dns_ns q_ns;
-  struct pico_socket *s;
-  void (*callback)(char *, void *);
-  void *arg;
-};
-
-static int dns_cmp(void *ka, void *kb)
-{
-    struct pico_dns_key *a = ka,*b = kb;
-  if (a->id < b->id)
-    return -1; 
-  else if (a->id > b->id)
-    return 1;
-  else
-    return 0;
-} 
-    
-PICO_TREE_DECLARE(DNSTable,dns_cmp);
-
-static int pico_dns_client_strlen(const char *url)
-{
-  uint16_t len = 0;
-  int p;
-
-  if (!url)
-    return -1;
-
-  while ((p = *url++) != 0) {
-    len++;
-  }
-  return len;
-}
-
-/* Replace '.' by the label length */
-static int pico_dns_client_label(char *ptr)
-{
-  char *l;
-  uint8_t lbl_len = 0;
-  int p;
-
-  if (!ptr)
-    return -1;
-
-  l = ptr++;
-  while ((p = *ptr++) != 0){
-    if (p == '.') {
-      *l = lbl_len;
-      l = ptr - 1;
-      lbl_len = 0;
-    } else {
-      lbl_len++;
-    }
-  }
-  *l = lbl_len;
-  return 0;
-}
-
-/* Replace the label length by '.' */
-static int pico_dns_client_reverse_label(char *ptr)
-{
-  char *l;
-  int p;
-
-  if(!ptr)
-    return -1;
-
-  l = ptr;
-  while ((p = *ptr++) != 0){
-    ptr += p;
-    *l = '.';
-    l = ptr;
-  }
-  return 0;
-}
-
-/* Seek the end of a string */
-static char *pico_dns_client_seek(char *ptr)
-{
-  int p;
-
-  if (!ptr)
-    return NULL;
-
-  while ((p = *ptr++) != 0);
-
-  return ptr++;
-}
-
-static inline void pico_dns_client_construct_hdr(struct dns_message_hdr *hdr, uint16_t id)
-{
-  hdr->id = short_be(id);
-  FLAG_QR(hdr, PICO_DNS_QR_QUERY); 
-  FLAG_OPCODE(hdr, PICO_DNS_OPCODE_QUERY); 
-  FLAG_AA(hdr, PICO_DNS_AA_NO_AUTHORITY); 
-  FLAG_TC(hdr, PICO_DNS_TC_NO_TRUNCATION); 
-  FLAG_RD(hdr, PICO_DNS_RD_IS_DESIRED); 
-  FLAG_RA(hdr, PICO_DNS_RA_NO_SUPPORT); 
-  FLAG_Z(hdr, 0); 
-  FLAG_RCODE(hdr, PICO_DNS_RCODE_NO_ERROR); 
-  hdr->flags = short_be(hdr->flags);
-  hdr->qdcount = short_be(1);
-  hdr->ancount = short_be(0);
-  hdr->nscount = short_be(0);
-  hdr->arcount = short_be(0);
-}
-
-static inline void pico_dns_client_hdr_ntoh(struct dns_message_hdr *hdr)
-{
-  hdr->id = short_be(hdr->id);
-  hdr->flags = short_be(hdr->flags);
-  hdr->qdcount = short_be(hdr->qdcount);
-  hdr->ancount = short_be(hdr->ancount);
-  hdr->nscount = short_be(hdr->nscount);
-  hdr->arcount = short_be(hdr->arcount);
-}
-
-
-static int pico_dns_client_mirror(char *ptr)
-{
-  unsigned char buf[4] = {0};
-  char *m;
-  int cnt = 0;
-  int p, i;
-
-  if (!ptr)
-    return -1;
-
-  m = ptr;
-  while ((p = *ptr++) != 0)
-  {
-    if (pico_is_digit(p)) {
-      buf[cnt] = (10 * buf[cnt]) + (p - '0');
-    } else if (p == '.') {
-        cnt++;
-    } else {
-      return -1;
-    }
-  }
-
-  /* Handle short notation */
-  if(cnt == 1){
-    buf[3] = buf[1];
-    buf[1] = 0;
-    buf[2] = 0;
-  }else if (cnt == 2){
-    buf[3] = buf[2];
-    buf[2] = 0;
-  }else if(cnt != 3){
-    /* String could not be parsed, return error */
-    return -1;
-  }
-
-  ptr = m;
-  for(i = 3; i >= 0; i--)
-  {
-    if(buf[i] > 99){
-      *ptr++ = '0' + (buf[i] / 100);
-      *ptr++ = '0' + ((buf[i] % 100) / 10);
-      *ptr++ = '0' + ((buf[i] % 100) % 10);
-    }else if(buf[i] > 9){
-      *ptr++ = '0' + (buf[i] / 10);
-      *ptr++ = '0' + (buf[i] % 10);
-    }else{
-      *ptr++ = '0' + buf[i];
-    }
-    if(i > 0)
-      *ptr++ = '.';
-  }
-
-  return 0;
-}
-
-static struct pico_dns_key *pico_dns_client_idcheck(uint16_t id)
-{
-  struct pico_dns_key test;
-
-  test.id = id;
-  return pico_tree_findKey(&DNSTable,&test);
-}
-
-static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
-
-static int pico_dns_client_send(struct pico_dns_key *key)
-{
-  struct pico_socket *s;
-  int w = 0;
-
-  dns_dbg("DNS: sending query to %08X\n", key->q_ns.ns.addr);
-  s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
-  if (!s)
-    return -1; 
-  key->s = s;
-  if (pico_socket_connect(s, &key->q_ns.ns, short_be(PICO_DNS_NS_PORT)) != 0)
-    return -1;
-  w = pico_socket_send(s, key->q_hdr, key->len);
-  if (w <= 0)
-    return -1;
-
-  return 0;
-}
-
-static void pico_dns_client_retransmission(unsigned long now, void *arg)
-{
-  struct pico_dns_key *key = (struct pico_dns_key *)arg;
-  struct pico_dns_ns *q_ns = NULL;
-
-  if (!key->retrans) {
-    dns_dbg("DNS: no retransmission!\n");
-    pico_free(key->q_hdr);
-
-    if(pico_tree_delete(&DNSTable,key))
-      pico_free(key);
-  }
-  else if (key->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) {
-    key->retrans++;
-    dns_dbg("DNS: retransmission! (%u attempts)\n", key->retrans);
-        // ugly hack
-    q_ns = pico_tree_next(pico_tree_findNode(&NSTable,&key->q_ns))->keyValue;
-    if (q_ns)
-      key->q_ns = *q_ns; 
-    else
-        key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
-    pico_dns_client_send(key);
-    pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
-  } else {
-    dns_dbg("DNS ERROR: no reply from nameservers! (%u attempts)\n", key->retrans);
-    pico_socket_close(key->s);
-    pico_err = PICO_ERR_EIO;
-    key->callback(NULL, key->arg);
-    pico_free(key->q_hdr);
-    /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
-
-    if(pico_tree_delete(&DNSTable,key))
-      pico_free(key);
-  }
-}
-
-static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s)
-{
-  char *q_qname, *q_suf, *a_hdr, *a_qname, *a_suf, *a_rdata;
-  struct dns_message_hdr *hdr;
-  struct dns_query_suffix query_suf;
-  struct dns_answer_suffix answer_suf;
-  struct pico_dns_key test, *key;
-  char *answer;
-  char dns_answer[PICO_DNS_MAX_RESPONSE_LEN] = {0};
-  uint8_t valid_suffix = 0;
-  uint16_t compression = 0;
-  int i = 0, r = 0;
-
-  if (ev & PICO_SOCK_EV_RD) {
-    r = pico_socket_read(s, dns_answer, PICO_DNS_MAX_RESPONSE_LEN);
-    pico_socket_close(s);
-    if (r == PICO_DNS_MAX_RESPONSE_LEN || r < (int)sizeof(struct dns_message_hdr)) {
-      dns_dbg("DNS ERROR: received incorrect number(%d) of bytes\n", r);
-      return;
-    }
-
-    /* Check header validity */
-    a_hdr = dns_answer;
-    hdr = (struct dns_message_hdr *) a_hdr;
-    pico_dns_client_hdr_ntoh(hdr);
-    if (GET_FLAG_QR(hdr) != PICO_DNS_QR_RESPONSE || GET_FLAG_OPCODE(hdr) != PICO_DNS_OPCODE_QUERY 
-        || GET_FLAG_TC(hdr) == PICO_DNS_TC_IS_TRUNCATED || GET_FLAG_RCODE(hdr) != PICO_DNS_RCODE_NO_ERROR) {
-      dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", GET_FLAG_OPCODE(hdr), GET_FLAG_TC(hdr), GET_FLAG_RCODE(hdr));
-      return;
-    }
-
-    if (hdr->ancount < 1 || r < (int)(sizeof(struct dns_message_hdr) + hdr->qdcount * sizeof(struct dns_query_suffix)
-            + hdr->ancount * sizeof(struct dns_answer_suffix))) {
-      dns_dbg("DNS ERROR: ancount < 1 OR received number(%d) of bytes too low\n", r);
-      return;
-    }
-
-    /* Find DNS key */
-    test.id = hdr->id;
-
-    key = pico_tree_findKey(&DNSTable,&test);
-    if (!key) {
-      dns_dbg("DNS WARNING: key with id %u not found\n", hdr->id);
-      return;
-    }
-    key->retrans = 0;
-
-    /* Check query suffix validity */
-    q_qname = a_hdr + sizeof(struct dns_message_hdr);
-    q_suf = pico_dns_client_seek(q_qname);
-    query_suf = *(struct dns_query_suffix *) q_suf;
-    if (short_be(query_suf.qtype) != key->qtype || short_be(query_suf.qclass) != key->qclass) {
-      dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(query_suf.qtype), short_be(query_suf.qclass));
-      return;
-    }
-
-    /* Seek answer suffix */
-    a_qname = q_suf + sizeof(struct dns_query_suffix);
-    a_suf = a_qname;
-    while(i++ < hdr->ancount) {
-      uint16_t comp_h = short_from(a_suf);
-      compression = short_be(comp_h);
-      switch (compression >> 14)
-      {
-        case PICO_DNS_POINTER:
-          while (compression >> 14 == PICO_DNS_POINTER) {
-            dns_dbg("DNS: pointer\n");
-            a_suf += sizeof(uint16_t);
-            comp_h = short_from(a_suf);
-            compression = short_be(comp_h);
-          }
-          break;
-
-        case PICO_DNS_LABEL:
-          dns_dbg("DNS: label\n");
-          a_suf = pico_dns_client_seek(a_qname);
-          break;
-
-        default:
-          dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression);
-          return;
-      }
-
-      /* Check answer suffix validity */
-      answer_suf = *(struct dns_answer_suffix *)a_suf;
-      if (short_be(answer_suf.qtype) != key->qtype || short_be(answer_suf.qclass) != key->qclass) {
-        dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(answer_suf.qtype), short_be(answer_suf.qclass));
-        a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
-        continue;
-      }
-
-      if (short_be(answer_suf.ttl) > PICO_DNS_MAX_TTL) {
-        dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(answer_suf.ttl), PICO_DNS_MAX_TTL);
-        a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
-        continue;
-      }
-
-      valid_suffix = 1;
-      break;
-    }
-
-    if (!valid_suffix) {
-       dns_dbg("DNS ERROR: invalid dns answer suffix\n");
-       return;
-    }
-
-    a_rdata = a_suf + sizeof(struct dns_answer_suffix);
-    if (key->qtype == PICO_DNS_TYPE_A) {
-      uint32_t ip_h = long_from(a_rdata);
-      dns_dbg("DNS: length %u | ip %08X\n", short_be(answer_suf.rdlength), long_be(ip_h));
-      answer = pico_zalloc(16);
-      pico_ipv4_to_string(answer, ip_h);
-      key->callback(answer, key->arg);
-    } else if (key->qtype == PICO_DNS_TYPE_PTR) {
-      pico_dns_client_reverse_label((char *) a_rdata);
-      dns_dbg("DNS: length %u | name %s\n", short_be(answer_suf.rdlength), (char *)a_rdata + 1);
-      answer = pico_zalloc(answer_suf.rdlength - 1);
-      memcpy(answer, (char *)a_rdata + 1, short_be(answer_suf.rdlength) - 1);
-      key->callback(answer, key->arg);
-    } else {
-      dns_dbg("DNS ERROR: incorrect qtype (%u)\n", key->qtype);
-      return;
-    }
-  }
-
-  if (ev == PICO_SOCK_EV_ERR) {
-    dns_dbg("DNS: socket error received\n");
-  }
-}
-
-int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
-{
-  char *q_hdr, *q_qname, *q_suf;
-  struct dns_message_hdr *hdr;
-  struct dns_query_suffix query_suf;
-  struct pico_dns_key *key;
-  uint16_t url_len = 0;
-  uint16_t id = 0;
-
-  if (!url || !callback) {
-    dns_dbg("DNS ERROR: NULL parameters\n");
-    pico_err = PICO_ERR_EINVAL;
-    return -1;
-  }
-
-  url_len = pico_dns_client_strlen(url);
-  /* 2 extra bytes for url_len to account for 2 extra label length octets */
-  q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix));
-  if (!q_hdr) {
-    pico_err = PICO_ERR_ENOMEM;
-    return -1;
-  }
-  q_qname = q_hdr + sizeof(struct dns_message_hdr);
-  q_suf = q_qname + (1 + url_len + 1);
-
-  /* Construct query header */
-  hdr = (struct dns_message_hdr *) q_hdr;
-  do {
-    id = (uint16_t) (pico_rand() & 0xFFFFU);
-    dns_dbg("DNS: generated id %u\n", id);
-  } while (pico_dns_client_idcheck(id));
-  pico_dns_client_construct_hdr(hdr, id);
-  /* Add and manipulate domain name */
-  memcpy(q_qname + 1, url, url_len + 1);
-  pico_dns_client_label(q_qname);
-  /* Add type and class of query */
-  query_suf.qtype = short_be(PICO_DNS_TYPE_A);
-  query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
-  memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
-  /* Create RB entry */
-  key = pico_zalloc(sizeof(struct pico_dns_key));
-  if (!key) {
-    pico_free(q_hdr);
-    pico_err = PICO_ERR_ENOMEM;
-    return -1;
-  }
-  key->q_hdr = q_hdr;
-  key->len = sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix);
-  key->id = id;
-  key->qtype = PICO_DNS_TYPE_A;
-  key->qclass = PICO_DNS_CLASS_IN;
-  key->retrans = 1;
-
-  key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
-  key->s = NULL;
-  key->callback = callback;
-  key->arg = arg;
-  /* Send query */
-  if (pico_dns_client_send(key) < 0) {
-    pico_free(q_hdr);
-    if (key->s)
-      pico_socket_close(key->s);
-    pico_free(key);
-    pico_err = PICO_ERR_EAGAIN;
-    return -1;
-  }
-  /* Insert RB entry */
-
-  if(pico_tree_insert(&DNSTable,key)) {
-    pico_free(q_hdr);
-    pico_free(key);
-    pico_err = PICO_ERR_EAGAIN;
-    return -1; /* Element key already exists */
-  }
-
-  pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
-  return 0;
-}
-
-int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
-{
-  char *q_hdr, *q_qname, *q_suf;
-  struct dns_message_hdr *hdr;
-  struct dns_query_suffix query_suf;
-  struct pico_dns_key *key;
-  uint16_t ip_len = 0;
-  uint16_t arpa_len = 0;
-  uint16_t id = 0;
-
-  if (!ip || !callback) {
-    dns_dbg("DNS ERROR: NULL parameters\n");
-    pico_err = PICO_ERR_EINVAL;
-    return -1;
-  }
-
-  ip_len = pico_dns_client_strlen(ip);
-  arpa_len = pico_dns_client_strlen(".in-addr.arpa");
-  /* 2 extra bytes for ip_len and arpa_len to account for 2 extra length octets */
-  q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix));
-  if (!q_hdr) {
-    pico_err = PICO_ERR_ENOMEM;
-    return -1;
-  }
-  q_qname = q_hdr + sizeof(struct dns_message_hdr);
-  q_suf = q_qname + (1 + ip_len + arpa_len + 1);
-
-  /* Construct query header */
-  hdr = (struct dns_message_hdr *)q_hdr;
-  do {
-    id = (uint16_t) (pico_rand() & 0xFFFFU);
-    dns_dbg("DNS: generated id %u\n", id);
-  } while (pico_dns_client_idcheck(id));
-  pico_dns_client_construct_hdr(hdr, id);
-  /* Add and manipulate domain name */
-  memcpy(q_qname + 1, ip, ip_len + 1);
-  pico_dns_client_mirror(q_qname + 1);
-  memcpy(q_qname + 1 + ip_len, ".in-addr.arpa", arpa_len);
-  pico_dns_client_label(q_qname);
-  /* Add type and class of query */
-  query_suf.qtype = short_be(PICO_DNS_TYPE_PTR);
-  query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
-  memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
-  /* Create RB entry */
-  key = pico_zalloc(sizeof(struct pico_dns_key));
-  if (!key) {
-    pico_free(q_hdr);
-    pico_err = PICO_ERR_ENOMEM;
-    return -1;
-  }
-  key->q_hdr = q_hdr;
-  key->len = sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix);
-  key->id = id;
-  key->qtype = PICO_DNS_TYPE_PTR;
-  key->qclass = PICO_DNS_CLASS_IN;
-  key->retrans = 1;
-  key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
-  key->s = NULL;
-  key->callback = callback;
-  key->arg = arg;
-  /* Send query */
-  if (pico_dns_client_send(key) < 0) {
-    pico_free(q_hdr);
-    if (key->s)
-      pico_socket_close(key->s);
-    pico_free(key);
-    pico_err = PICO_ERR_EAGAIN;
-    return -1;
-  }
-  /* Insert RB entry */
-
-  if(pico_tree_insert(&DNSTable,key)) {
-    pico_free(q_hdr);
-    pico_free(key);
-    pico_err = PICO_ERR_EAGAIN;
-    return -1; /* Element key already exists */
-  }
-
-  pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
-  return 0;
-}
-
-#ifdef PICO_DNS_CLIENT_MAIN
-int main(int argc, char *argv[])
-{
-  dns_dbg(">>>>> DNS GET ADDR\n");
-  pico_dns_client_getaddr("www.google.be");
-  dns_dbg(">>>>> DNS GET NAME\n");
-  pico_dns_client_getname("173.194.67.94");
-
-  return 0;
-}
-#endif /* PICO_DNS_CLIENT_MAIN */
 #endif /* PICO_SUPPORT_DNS_CLIENT */
--- a/modules/pico_http_client.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_http_client.c	Mon Sep 02 08:02:21 2013 +0000
@@ -31,45 +31,45 @@
 
 #define HTTP_GET_BASIC_SIZE   63u
 #define HTTP_HEADER_LINE_SIZE 50u
-#define RESPONSE_INDEX                9u
+#define RESPONSE_INDEX				9u
 
-#define HTTP_CHUNK_ERROR    0xFFFFFFFFu
+#define HTTP_CHUNK_ERROR	0xFFFFFFFFu
 
 #ifdef dbg
-    #undef dbg
-    #define dbg(...) do{}while(0);
+	#undef dbg
+	#define dbg(...) do{}while(0);
 #endif
 
-#define consumeChar(c)                             (pico_socket_read(client->sck,&c,1u))
-#define isLocation(line)                         (memcmp(line,"Location",8u) == 0)
-#define isContentLength(line)             (memcmp(line,"Content-Length",14u) == 0u)
-#define isTransferEncoding(line)        (memcmp(line,"Transfer-Encoding",17u) == 0u)
-#define isChunked(line)                            (memcmp(line," chunked",8u) == 0u)
-#define isNotHTTPv1(line)                        (memcmp(line,"HTTP/1.",7u))
+#define consumeChar(c) 							(pico_socket_read(client->sck,&c,1u))
+#define isLocation(line) 						(memcmp(line,"Location",8u) == 0)
+#define isContentLength(line) 			(memcmp(line,"Content-Length",14u) == 0u)
+#define isTransferEncoding(line)		(memcmp(line,"Transfer-Encoding",17u) == 0u)
+#define isChunked(line)							(memcmp(line," chunked",8u) == 0u)
+#define isNotHTTPv1(line)						(memcmp(line,"HTTP/1.",7u))
 #define is_hex_digit(x) ( ('0' <= x && x <= '9') || ('a' <= x && x <= 'f') )
 #define hex_digit_to_dec(x) ( ('0' <= x && x <= '9') ? x-'0' : ( ('a' <= x && x <= 'f') ? x-'a' + 10 : -1) )
 
 struct pico_http_client
 {
-    uint16_t connectionID;
-    uint8_t state;
-    struct pico_socket * sck;
-    void (*wakeup)(uint16_t ev, uint16_t conn);
-    struct pico_ip4 ip;
-    struct pico_http_uri * uriKey;
-    struct pico_http_header * header;
+	uint16_t connectionID;
+	uint8_t state;
+	struct pico_socket * sck;
+	void (*wakeup)(uint16_t ev, uint16_t conn);
+	struct pico_ip4 ip;
+	struct pico_http_uri * uriKey;
+	struct pico_http_header * header;
 };
 
 // HTTP Client internal states
 #define HTTP_READING_HEADER      0
-#define HTTP_READING_BODY                 1
+#define HTTP_READING_BODY				 1
 #define HTTP_READING_CHUNK_VALUE 2
 #define HTTP_READING_CHUNK_TRAIL 3
 
 
 static int compareClients(void * ka, void * kb)
 {
-    return ((struct pico_http_client *)ka)->connectionID - ((struct pico_http_client *)kb)->connectionID;
+	return ((struct pico_http_client *)ka)->connectionID - ((struct pico_http_client *)kb)->connectionID;
 }
 
 PICO_TREE_DECLARE(pico_client_list,compareClients);
@@ -81,120 +81,120 @@
 void tcpCallback(uint16_t ev, struct pico_socket *s)
 {
 
-    struct pico_http_client * client = NULL;
-    struct pico_tree_node * index;
+	struct pico_http_client * client = NULL;
+	struct pico_tree_node * index;
 
-    // find httpClient
-    pico_tree_foreach(index,&pico_client_list)
-    {
-        if( ((struct pico_http_client *)index->keyValue)->sck == s )
-        {
-            client = (struct pico_http_client *)index->keyValue;
-            break;
-        }
-    }
+	// find httpClient
+	pico_tree_foreach(index,&pico_client_list)
+	{
+		if( ((struct pico_http_client *)index->keyValue)->sck == s )
+		{
+			client = (struct pico_http_client *)index->keyValue;
+			break;
+		}
+	}
 
-    if(!client)
-    {
-        dbg("Client not found...Something went wrong !\n");
-        return;
-    }
+	if(!client)
+	{
+		dbg("Client not found...Something went wrong !\n");
+		return;
+	}
 
-    if(ev & PICO_SOCK_EV_CONN)
-        client->wakeup(EV_HTTP_CON,client->connectionID);
+	if(ev & PICO_SOCK_EV_CONN)
+		client->wakeup(EV_HTTP_CON,client->connectionID);
 
-    if(ev & PICO_SOCK_EV_RD)
-    {
+	if(ev & PICO_SOCK_EV_RD)
+	{
 
-        // read the header, if not read
-        if(client->state == HTTP_READING_HEADER)
-        {
-            // wait for header
-            client->header = pico_zalloc(sizeof(struct pico_http_header));
-            if(!client->header)
-            {
-                pico_err = PICO_ERR_ENOMEM;
-                return;
-            }
+		// read the header, if not read
+		if(client->state == HTTP_READING_HEADER)
+		{
+			// wait for header
+			client->header = pico_zalloc(sizeof(struct pico_http_header));
+			if(!client->header)
+			{
+				pico_err = PICO_ERR_ENOMEM;
+				return;
+			}
 
-            // wait for header
-            if(parseHeaderFromServer(client,client->header) < 0)
-            {
-                client->wakeup(EV_HTTP_ERROR,client->connectionID);
-            }
-            else
-            {
-                // call wakeup
-                if(client->header->responseCode != HTTP_CONTINUE)
-                {
-                    client->wakeup(
-                            client->header->responseCode == HTTP_OK ?
-                            EV_HTTP_REQ | EV_HTTP_BODY : // data comes for sure only when 200 is received
-                            EV_HTTP_REQ
-                            ,client->connectionID);
-                }
-            }
-        }
-        else
-        {
-            // just let the user know that data has arrived, if chunked data comes, will be treated in the
-            // read api.
-            client->wakeup(EV_HTTP_BODY,client->connectionID);
-        }
-    }
+			// wait for header
+			if(parseHeaderFromServer(client,client->header) < 0)
+			{
+				client->wakeup(EV_HTTP_ERROR,client->connectionID);
+			}
+			else
+			{
+				// call wakeup
+				if(client->header->responseCode != HTTP_CONTINUE)
+				{
+					client->wakeup(
+							client->header->responseCode == HTTP_OK ?
+							EV_HTTP_REQ | EV_HTTP_BODY : // data comes for sure only when 200 is received
+							EV_HTTP_REQ
+							,client->connectionID);
+				}
+			}
+		}
+		else
+		{
+			// just let the user know that data has arrived, if chunked data comes, will be treated in the
+			// read api.
+			client->wakeup(EV_HTTP_BODY,client->connectionID);
+		}
+	}
 
-    if(ev & PICO_SOCK_EV_ERR)
-    {
-        client->wakeup(EV_HTTP_ERROR,client->connectionID);
-    }
+	if(ev & PICO_SOCK_EV_ERR)
+	{
+		client->wakeup(EV_HTTP_ERROR,client->connectionID);
+	}
 
-    if( (ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN) )
-    {
-        client->wakeup(EV_HTTP_CLOSE,client->connectionID);
-    }
+	if( (ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN) )
+	{
+		client->wakeup(EV_HTTP_CLOSE,client->connectionID);
+	}
 
 }
 
 // used for getting a response from DNS servers
 static void dnsCallback(char *ip, void * ptr)
 {
-    struct pico_http_client * client = (struct pico_http_client *)ptr;
+	struct pico_http_client * client = (struct pico_http_client *)ptr;
 
-    if(!client)
-    {
-        dbg("Who made the request ?!\n");
-        return;
-    }
+	if(!client)
+	{
+		dbg("Who made the request ?!\n");
+		return;
+	}
 
-    if(ip)
-    {
-        client->wakeup(EV_HTTP_DNS,client->connectionID);
+	if(ip)
+	{
+		client->wakeup(EV_HTTP_DNS,client->connectionID);
 
-        // add the ip address to the client, and start a tcp connection socket
-        pico_string_to_ipv4(ip,&client->ip.addr);
-        pico_free(ip);
-        client->sck = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &tcpCallback);
-        if(!client->sck)
-        {
-            client->wakeup(EV_HTTP_ERROR,client->connectionID);
-            return;
-        }
+		// add the ip address to the client, and start a tcp connection socket
+		pico_string_to_ipv4(ip,&client->ip.addr);
+		pico_free(ip);
+		client->sck = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &tcpCallback);
+		if(!client->sck)
+		{
+			client->wakeup(EV_HTTP_ERROR,client->connectionID);
+			return;
+		}
 
-        if(pico_socket_connect(client->sck,&client->ip,short_be(client->uriKey->port)) < 0)
-        {
-            client->wakeup(EV_HTTP_ERROR,client->connectionID);
-            return;
-        }
+		if(pico_socket_connect(client->sck,&client->ip,short_be(client->uriKey->port)) < 0)
+		{
+			client->wakeup(EV_HTTP_ERROR,client->connectionID);
+			return;
+		}
 
-    }
-    else
-    {
-        // wakeup client and let know error occured
-        client->wakeup(EV_HTTP_ERROR,client->connectionID);
+	}
+	else
+	{
+		// wakeup client and let know error occured
+		client->wakeup(EV_HTTP_ERROR,client->connectionID);
 
-        // close the client (free used heap)
-        pico_http_client_close(client->connectionID);
-    }
+		// close the client (free used heap)
+		pico_http_client_close(client->connectionID);
+	}
 }
 
 /*
@@ -208,51 +208,51 @@
  */
 int pico_http_client_open(char * uri, void (*wakeup)(uint16_t ev, uint16_t conn))
 {
-    struct pico_http_client * client;
+	struct pico_http_client * client;
 
-    if(!wakeup)
-    {
-        pico_err = PICO_ERR_EINVAL;
-        return HTTP_RETURN_ERROR;
-    }
+	if(!wakeup)
+	{
+		pico_err = PICO_ERR_EINVAL;
+		return HTTP_RETURN_ERROR;
+	}
 
-    client = pico_zalloc(sizeof(struct pico_http_client));
-    if(!client)
-    {
-        // memory error
-        pico_err = PICO_ERR_ENOMEM;
-        return HTTP_RETURN_ERROR;
-    }
+	client = pico_zalloc(sizeof(struct pico_http_client));
+	if(!client)
+	{
+		// memory error
+		pico_err = PICO_ERR_ENOMEM;
+		return HTTP_RETURN_ERROR;
+	}
 
-    client->wakeup = wakeup;
-    client->connectionID = (uint16_t)pico_rand() & 0x7FFFu; // negative values mean error, still not good generation
+	client->wakeup = wakeup;
+	client->connectionID = (uint16_t)pico_rand() & 0x7FFFu; // negative values mean error, still not good generation
 
-    client->uriKey = pico_zalloc(sizeof(struct pico_http_uri));
+	client->uriKey = pico_zalloc(sizeof(struct pico_http_uri));
 
-    if(!client->uriKey)
-    {
-        pico_err = PICO_ERR_ENOMEM;
-        pico_free(client);
-        return HTTP_RETURN_ERROR;
-    }
+	if(!client->uriKey)
+	{
+		pico_err = PICO_ERR_ENOMEM;
+		pico_free(client);
+		return HTTP_RETURN_ERROR;
+	}
 
-    pico_processURI(uri,client->uriKey);
+	pico_processURI(uri,client->uriKey);
 
-    if(pico_tree_insert(&pico_client_list,client))
-    {
-        // already in
-        pico_err = PICO_ERR_EEXIST;
-        pico_free(client->uriKey);
-        pico_free(client);
-        return HTTP_RETURN_ERROR;
-    }
+	if(pico_tree_insert(&pico_client_list,client))
+	{
+		// already in
+		pico_err = PICO_ERR_EEXIST;
+		pico_free(client->uriKey);
+		pico_free(client);
+		return HTTP_RETURN_ERROR;
+	}
 
-    // dns query
-    dbg("Querying : %s \n",client->uriKey->host);
-    pico_dns_client_getaddr(client->uriKey->host, dnsCallback,client);
+	// dns query
+	dbg("Querying : %s \n",client->uriKey->host);
+	pico_dns_client_getaddr(client->uriKey->host, dnsCallback,client);
 
-    // return the connection ID
-    return client->connectionID;
+	// return the connection ID
+	return client->connectionID;
 }
 
 /*
@@ -268,34 +268,34 @@
  */
 int pico_http_client_sendHeader(uint16_t conn, char * header, int hdr)
 {
-    struct pico_http_client search = {.connectionID = conn};
-    struct pico_http_client * http = pico_tree_findKey(&pico_client_list,&search);
-    int length ;
-    if(!http)
-    {
-        dbg("Client not found !\n");
-        return HTTP_RETURN_ERROR;
-    }
+	struct pico_http_client search = {.connectionID = conn};
+	struct pico_http_client * http = pico_tree_findKey(&pico_client_list,&search);
+	int length ;
+	if(!http)
+	{
+		dbg("Client not found !\n");
+		return HTTP_RETURN_ERROR;
+	}
 
-    // the api gives the possibility to the user to build the GET header
-    // based on the uri passed when opening the client, less headache for the user
-    if(hdr == HTTP_HEADER_DEFAULT)
-    {
-        header = pico_http_client_buildHeader(http->uriKey);
+	// the api gives the possibility to the user to build the GET header
+	// based on the uri passed when opening the client, less headache for the user
+	if(hdr == HTTP_HEADER_DEFAULT)
+	{
+		header = pico_http_client_buildHeader(http->uriKey);
 
-        if(!header)
-        {
-            pico_err = PICO_ERR_ENOMEM;
-            return HTTP_RETURN_ERROR;
-        }
-    }
+		if(!header)
+		{
+			pico_err = PICO_ERR_ENOMEM;
+			return HTTP_RETURN_ERROR;
+		}
+	}
 
-    length = pico_socket_write(http->sck,(void *)header,strlen(header)+1);
+	length = pico_socket_write(http->sck,(void *)header,strlen(header)+1);
 
-    if(hdr == HTTP_HEADER_DEFAULT)
-        pico_free(header);
+	if(hdr == HTTP_HEADER_DEFAULT)
+		pico_free(header);
 
-    return length;
+	return length;
 }
 
 /*
@@ -308,90 +308,90 @@
  */
 int pico_http_client_readData(uint16_t conn, char * data, uint16_t size)
 {
-    struct pico_http_client dummy = {.connectionID = conn};
-    struct pico_http_client * client = pico_tree_findKey(&pico_client_list,&dummy);
+	struct pico_http_client dummy = {.connectionID = conn};
+	struct pico_http_client * client = pico_tree_findKey(&pico_client_list,&dummy);
 
-    if(!client)
-    {
-        dbg("Wrong connection id !\n");
-        pico_err = PICO_ERR_EINVAL;
-        return HTTP_RETURN_ERROR;
-    }
+	if(!client)
+	{
+		dbg("Wrong connection id !\n");
+		pico_err = PICO_ERR_EINVAL;
+		return HTTP_RETURN_ERROR;
+	}
 
-    // for the moment just read the data, do not care if it's chunked or not
-    if(client->header->transferCoding == HTTP_TRANSFER_FULL)
-        return pico_socket_read(client->sck,(void *)data,size);
-    else
-    {
-        int lenRead = 0;
+	// for the moment just read the data, do not care if it's chunked or not
+	if(client->header->transferCoding == HTTP_TRANSFER_FULL)
+		return pico_socket_read(client->sck,(void *)data,size);
+	else
+	{
+		int lenRead = 0;
 
-        // read the chunk line
-        if(readChunkLine(client) == HTTP_RETURN_ERROR)
-        {
-            dbg("Probably the chunk is malformed or parsed wrong...\n");
-            client->wakeup(EV_HTTP_ERROR,client->connectionID);
-            return HTTP_RETURN_ERROR;
-        }
+		// read the chunk line
+		if(readChunkLine(client) == HTTP_RETURN_ERROR)
+		{
+			dbg("Probably the chunk is malformed or parsed wrong...\n");
+			client->wakeup(EV_HTTP_ERROR,client->connectionID);
+			return HTTP_RETURN_ERROR;
+		}
 
-        // nothing to read, no use to try
-        if(client->state != HTTP_READING_BODY)
-        {
-            pico_err = PICO_ERR_EAGAIN;
-            return HTTP_RETURN_OK;
-        }
+		// nothing to read, no use to try
+		if(client->state != HTTP_READING_BODY)
+		{
+			pico_err = PICO_ERR_EAGAIN;
+			return HTTP_RETURN_OK;
+		}
 
-        // check if we need more than one chunk
-        if(size >= client->header->contentLengthOrChunk)
-        {
-            // read the rest of the chunk, if chunk is done, proceed to the next chunk
-            while(lenRead <= size)
-            {
-                int tmpLenRead = 0;
+		// check if we need more than one chunk
+		if(size >= client->header->contentLengthOrChunk)
+		{
+			// read the rest of the chunk, if chunk is done, proceed to the next chunk
+			while(lenRead <= size)
+			{
+				int tmpLenRead = 0;
 
-                if(client->state == HTTP_READING_BODY)
-                {
+				if(client->state == HTTP_READING_BODY)
+				{
 
-                    // if needed truncate the data
-                    tmpLenRead = pico_socket_read(client->sck,data + lenRead,
-                    client->header->contentLengthOrChunk < size-lenRead ? client->header->contentLengthOrChunk : size-lenRead);
+					// if needed truncate the data
+					tmpLenRead = pico_socket_read(client->sck,data + lenRead,
+					client->header->contentLengthOrChunk < (uint32_t)(size-lenRead) ? client->header->contentLengthOrChunk : (uint32_t)(size-lenRead));
 
-                    if(tmpLenRead > 0)
-                    {
-                        client->header->contentLengthOrChunk -= tmpLenRead;
-                    }
-                    else if(tmpLenRead < 0)
-                    {
-                        // error on reading
-                        dbg(">>> Error returned pico_socket_read\n");
-                        pico_err = PICO_ERR_EBUSY;
-                        // return how much data was read until now
-                        return lenRead;
-                    }
-                }
+					if(tmpLenRead > 0)
+					{
+						client->header->contentLengthOrChunk -= tmpLenRead;
+					}
+					else if(tmpLenRead < 0)
+					{
+						// error on reading
+						dbg(">>> Error returned pico_socket_read\n");
+						pico_err = PICO_ERR_EBUSY;
+						// return how much data was read until now
+						return lenRead;
+					}
+				}
 
-                lenRead += tmpLenRead;
-                if(readChunkLine(client) == HTTP_RETURN_ERROR)
-                {
-                    dbg("Probably the chunk is malformed or parsed wrong...\n");
-                    client->wakeup(EV_HTTP_ERROR,client->connectionID);
-                    return HTTP_RETURN_ERROR;
-                }
+				lenRead += tmpLenRead;
+				if(readChunkLine(client) == HTTP_RETURN_ERROR)
+				{
+					dbg("Probably the chunk is malformed or parsed wrong...\n");
+					client->wakeup(EV_HTTP_ERROR,client->connectionID);
+					return HTTP_RETURN_ERROR;
+				}
 
-                if(client->state != HTTP_READING_BODY || !tmpLenRead)  break;
+				if(client->state != HTTP_READING_BODY || !tmpLenRead)  break;
 
-            }
-        }
-        else
-        {
-            // read the data from the chunk
-            lenRead = pico_socket_read(client->sck,(void *)data,size);
+			}
+		}
+		else
+		{
+			// read the data from the chunk
+			lenRead = pico_socket_read(client->sck,(void *)data,size);
 
-            if(lenRead)
-                client->header->contentLengthOrChunk -= lenRead;
-        }
+			if(lenRead)
+				client->header->contentLengthOrChunk -= lenRead;
+		}
 
-        return lenRead;
-    }
+		return lenRead;
+	}
 }
 
 /*
@@ -401,20 +401,20 @@
  */
 struct pico_http_header * pico_http_client_readHeader(uint16_t conn)
 {
-    struct pico_http_client dummy = {.connectionID = conn};
-    struct pico_http_client * client = pico_tree_findKey(&pico_client_list,&dummy);
+	struct pico_http_client dummy = {.connectionID = conn};
+	struct pico_http_client * client = pico_tree_findKey(&pico_client_list,&dummy);
 
-    if(client)
-    {
-        return client->header;
-    }
-    else
-    {
-        // not found
-        dbg("Wrong connection id !\n");
-        pico_err = PICO_ERR_EINVAL;
-        return NULL;
-    }
+	if(client)
+	{
+		return client->header;
+	}
+	else
+	{
+		// not found
+		dbg("Wrong connection id !\n");
+		pico_err = PICO_ERR_EINVAL;
+		return NULL;
+	}
 }
 
 /*
@@ -424,18 +424,18 @@
  */
 struct pico_http_uri * pico_http_client_readUriData(uint16_t conn)
 {
-    struct pico_http_client dummy = {.connectionID = conn};
-    struct pico_http_client * client = pico_tree_findKey(&pico_client_list,&dummy);
-    //
-    if(client)
-        return client->uriKey;
-    else
-    {
-        // not found
-        dbg("Wrong connection id !\n");
-        pico_err = PICO_ERR_EINVAL;
-        return NULL;
-    }
+	struct pico_http_client dummy = {.connectionID = conn};
+	struct pico_http_client * client = pico_tree_findKey(&pico_client_list,&dummy);
+	//
+	if(client)
+		return client->uriKey;
+	else
+	{
+		// not found
+		dbg("Wrong connection id !\n");
+		pico_err = PICO_ERR_EINVAL;
+		return NULL;
+	}
 }
 
 /*
@@ -445,44 +445,44 @@
  */
 int pico_http_client_close(uint16_t conn)
 {
-    struct pico_http_client * toBeRemoved = NULL;
-    struct pico_http_client dummy = {};
-    dummy.connectionID = conn;
+	struct pico_http_client * toBeRemoved = NULL;
+	struct pico_http_client dummy = {0};
+	dummy.connectionID = conn;
 
-    dbg("Closing the client...\n");
-    toBeRemoved = pico_tree_delete(&pico_client_list,&dummy);
-    if(!toBeRemoved)
-    {
-        dbg("Warning ! Element not found ...");
-        return HTTP_RETURN_ERROR;
-    }
+	dbg("Closing the client...\n");
+	toBeRemoved = pico_tree_delete(&pico_client_list,&dummy);
+	if(!toBeRemoved)
+	{
+		dbg("Warning ! Element not found ...");
+		return HTTP_RETURN_ERROR;
+	}
 
-    // close socket
-    if(toBeRemoved->sck)
-    pico_socket_close(toBeRemoved->sck);
+	// close socket
+	if(toBeRemoved->sck)
+	pico_socket_close(toBeRemoved->sck);
 
 
-    if(toBeRemoved->header)
-    {
-        // free space used
-            if(toBeRemoved->header->location)
-                pico_free(toBeRemoved->header->location);
+	if(toBeRemoved->header)
+	{
+		// free space used
+			if(toBeRemoved->header->location)
+				pico_free(toBeRemoved->header->location);
 
-        pico_free(toBeRemoved->header);
-    }
+		pico_free(toBeRemoved->header);
+	}
 
-    if(toBeRemoved->uriKey)
-    {
-        if(toBeRemoved->uriKey->host)
-            pico_free(toBeRemoved->uriKey->host);
+	if(toBeRemoved->uriKey)
+	{
+		if(toBeRemoved->uriKey->host)
+			pico_free(toBeRemoved->uriKey->host);
 
-        if(toBeRemoved->uriKey->resource)
-            pico_free(toBeRemoved->uriKey->resource);
-        pico_free(toBeRemoved->uriKey);
-    }
-    pico_free(toBeRemoved);
+		if(toBeRemoved->uriKey->resource)
+			pico_free(toBeRemoved->uriKey->resource);
+		pico_free(toBeRemoved->uriKey);
+	}
+	pico_free(toBeRemoved);
 
-    return 0;
+	return 0;
 }
 
 /*
@@ -492,210 +492,210 @@
  */
 char * pico_http_client_buildHeader(const struct pico_http_uri * uriData)
 {
-    char * header;
-    char port[6u]; // 6 = max length of a uint16 + \0
+	char * header;
+	char port[6u]; // 6 = max length of a uint16 + \0
 
-    uint16_t headerSize = HTTP_GET_BASIC_SIZE;
+	uint16_t headerSize = HTTP_GET_BASIC_SIZE;
 
-    if(!uriData->host || !uriData->resource || !uriData->port)
-    {
-        pico_err = PICO_ERR_EINVAL;
-        return NULL;
-    }
+	if(!uriData->host || !uriData->resource || !uriData->port)
+	{
+		pico_err = PICO_ERR_EINVAL;
+		return NULL;
+	}
 
-    //
-    headerSize += strlen(uriData->host) + strlen(uriData->resource) + pico_itoa(uriData->port,port) + 4u; // 3 = size(CRLF + \0)
-    header = pico_zalloc(headerSize);
+	//
+	headerSize += strlen(uriData->host) + strlen(uriData->resource) + pico_itoa(uriData->port,port) + 4u; // 3 = size(CRLF + \0)
+	header = pico_zalloc(headerSize);
 
-    if(!header)
-    {
-        // not enought memory
-        pico_err = PICO_ERR_ENOMEM;
-        return NULL;
-    }
+	if(!header)
+	{
+		// not enought memory
+		pico_err = PICO_ERR_ENOMEM;
+		return NULL;
+	}
 
-    // build the actual header
-    strcpy(header,"GET ");
-    strcat(header,uriData->resource);
-    strcat(header," HTTP/1.1\r\n");
-    strcat(header,"Host: ");
-    strcat(header,uriData->host);
-    strcat(header,":");
-    strcat(header,port);
-    strcat(header,"\r\n");
-    strcat(header,"User-Agent: picoTCP\r\nConnection: close\r\n\r\n"); //?
+	// build the actual header
+	strcpy(header,"GET ");
+	strcat(header,uriData->resource);
+	strcat(header," HTTP/1.1\r\n");
+	strcat(header,"Host: ");
+	strcat(header,uriData->host);
+	strcat(header,":");
+	strcat(header,port);
+	strcat(header,"\r\n");
+	strcat(header,"User-Agent: picoTCP\r\nConnection: close\r\n\r\n"); //?
 
-    return header;
+	return header;
 }
 
 int parseHeaderFromServer(struct pico_http_client * client, struct pico_http_header * header)
 {
-    char line[HTTP_HEADER_LINE_SIZE];
-    char c;
-    int index = 0;
+	char line[HTTP_HEADER_LINE_SIZE];
+	char c;
+	uint32_t index = 0;
 
-    // read the first line of the header
-    while(consumeChar(c)>0 && c!='\r')
-    {
-        if(index < HTTP_HEADER_LINE_SIZE) // truncate if too long
-            line[index++] = c;
-    }
+	// read the first line of the header
+	while(consumeChar(c)>0 && c!='\r')
+	{
+		if(index < HTTP_HEADER_LINE_SIZE) // truncate if too long
+			line[index++] = c;
+	}
 
-    consumeChar(c); // consume \n
+	consumeChar(c); // consume \n
 
-    // check the integrity of the response
-    // make sure we have enough characters to include the response code
-    // make sure the server response starts with HTTP/1.
-    if(index < RESPONSE_INDEX+2 || isNotHTTPv1(line))
-    {
-        // wrong format of the the response
-        pico_err = PICO_ERR_EINVAL;
-        return HTTP_RETURN_ERROR;
-    }
+	// check the integrity of the response
+	// make sure we have enough characters to include the response code
+	// make sure the server response starts with HTTP/1.
+	if(index < RESPONSE_INDEX+2 || isNotHTTPv1(line))
+	{
+		// wrong format of the the response
+		pico_err = PICO_ERR_EINVAL;
+		return HTTP_RETURN_ERROR;
+	}
 
-    // extract response code
-    header->responseCode = (line[RESPONSE_INDEX] - '0') * 100u +
-                                                 (line[RESPONSE_INDEX+1] - '0') * 10u +
-                                                 (line[RESPONSE_INDEX+2] - '0');
+	// extract response code
+	header->responseCode = (line[RESPONSE_INDEX] - '0') * 100u +
+												 (line[RESPONSE_INDEX+1] - '0') * 10u +
+												 (line[RESPONSE_INDEX+2] - '0');
 
 
-    if(header->responseCode/100u > 5u)
-    {
-        // invalid response type
-        header->responseCode = 0;
-        return HTTP_RETURN_ERROR;
-    }
+	if(header->responseCode/100u > 5u)
+	{
+		// invalid response type
+		header->responseCode = 0;
+		return HTTP_RETURN_ERROR;
+	}
 
-    dbg("Server response : %d \n",header->responseCode);
+	dbg("Server response : %d \n",header->responseCode);
 
-    // parse the rest of the header
-    while(consumeChar(c)>0)
-    {
-        if(c==':')
-        {
-            // check for interesting fields
+	// parse the rest of the header
+	while(consumeChar(c)>0)
+	{
+		if(c==':')
+		{
+			// check for interesting fields
 
-            // Location:
-            if(isLocation(line))
-            {
-                index = 0;
-                while(consumeChar(c)>0 && c!='\r')
-                {
-                    line[index++] = c;
-                }
+			// Location:
+			if(isLocation(line))
+			{
+				index = 0;
+				while(consumeChar(c)>0 && c!='\r')
+				{
+					line[index++] = c;
+				}
 
-                // allocate space for the field
-                header->location = pico_zalloc(index+1u);
-                if(!header->location)
-                {
-                    pico_err = PICO_ERR_ENOMEM;
-                    return HTTP_RETURN_ERROR;
-                }
+				// allocate space for the field
+				header->location = pico_zalloc(index+1u);
+				if(!header->location)
+				{
+					pico_err = PICO_ERR_ENOMEM;
+					return HTTP_RETURN_ERROR;
+				}
 
-                memcpy(header->location,line,index);
+				memcpy(header->location,line,index);
 
-            }// Content-Length:
-            else if(isContentLength(line))
-            {
-                header->contentLengthOrChunk = 0u;
-                header->transferCoding = HTTP_TRANSFER_FULL;
-                // consume the first space
-                consumeChar(c);
-                while(consumeChar(c)>0 && c!='\r')
-                {
-                    header->contentLengthOrChunk = header->contentLengthOrChunk*10u + (c-'0');
-                }
+			}// Content-Length:
+			else if(isContentLength(line))
+			{
+				header->contentLengthOrChunk = 0u;
+				header->transferCoding = HTTP_TRANSFER_FULL;
+				// consume the first space
+				consumeChar(c);
+				while(consumeChar(c)>0 && c!='\r')
+				{
+					header->contentLengthOrChunk = header->contentLengthOrChunk*10u + (c-'0');
+				}
 
-            }// Transfer-Encoding: chunked
-            else if(isTransferEncoding(line))
-            {
-                index = 0;
-                while(consumeChar(c)>0 && c!='\r')
-                {
-                    line[index++] = c;
-                }
+			}// Transfer-Encoding: chunked
+			else if(isTransferEncoding(line))
+			{
+				index = 0;
+				while(consumeChar(c)>0 && c!='\r')
+				{
+					line[index++] = c;
+				}
 
-                if(isChunked(line))
-                {
-                    header->contentLengthOrChunk = 0u;
-                    header->transferCoding = HTTP_TRANSFER_CHUNKED;
-                }
+				if(isChunked(line))
+				{
+					header->contentLengthOrChunk = 0u;
+					header->transferCoding = HTTP_TRANSFER_CHUNKED;
+				}
 
-            }// just ignore the line
-            else
-            {
-                while(consumeChar(c)>0 && c!='\r');
-            }
+			}// just ignore the line
+			else
+			{
+				while(consumeChar(c)>0 && c!='\r');
+			}
 
-            // consume the next one
-            consumeChar(c);
-            // reset the index
-            index = 0u;
-        }
-        else if(c=='\r' && !index)
-        {
-                // consume the \n
-                consumeChar(c);
-                break;
-        }
-        else
-        {
-            line[index++] = c;
-        }
-    }
+			// consume the next one
+			consumeChar(c);
+			// reset the index
+			index = 0u;
+		}
+		else if(c=='\r' && !index)
+		{
+				// consume the \n
+				consumeChar(c);
+				break;
+		}
+		else
+		{
+			line[index++] = c;
+		}
+	}
 
-    if(header->transferCoding == HTTP_TRANSFER_CHUNKED)
-    {
-        // read the first chunk
-        header->contentLengthOrChunk = 0;
+	if(header->transferCoding == HTTP_TRANSFER_CHUNKED)
+	{
+		// read the first chunk
+		header->contentLengthOrChunk = 0;
 
-        client->state = HTTP_READING_CHUNK_VALUE;
-        readChunkLine(client);
+		client->state = HTTP_READING_CHUNK_VALUE;
+		readChunkLine(client);
 
-    }
-    else
-        client->state = HTTP_READING_BODY;
+	}
+	else
+		client->state = HTTP_READING_BODY;
 
-    dbg("End of header\n");
-    return HTTP_RETURN_OK;
+	dbg("End of header\n");
+	return HTTP_RETURN_OK;
 
 }
 
 // an async read of the chunk part, since in theory a chunk can be split in 2 packets
 int readChunkLine(struct pico_http_client * client)
 {
-    char c = 0;
+	char c = 0;
 
-    if(client->header->contentLengthOrChunk==0 && client->state == HTTP_READING_BODY)
-    {
-        client->state = HTTP_READING_CHUNK_VALUE;
-    }
+	if(client->header->contentLengthOrChunk==0 && client->state == HTTP_READING_BODY)
+	{
+		client->state = HTTP_READING_CHUNK_VALUE;
+	}
 
-    if(client->state == HTTP_READING_CHUNK_VALUE)
-    {
-        while(consumeChar(c)>0 && c!='\r' && c!=';')
-        {
-            if(is_hex_digit(c))
-                client->header->contentLengthOrChunk = (client->header->contentLengthOrChunk << 4u) + hex_digit_to_dec(c);
-            else
-            {
-                pico_err = PICO_ERR_EINVAL;
-                // something went wrong
-                return HTTP_RETURN_ERROR;
-            }
-        }
+	if(client->state == HTTP_READING_CHUNK_VALUE)
+	{
+		while(consumeChar(c)>0 && c!='\r' && c!=';')
+		{
+			if(is_hex_digit(c))
+				client->header->contentLengthOrChunk = (client->header->contentLengthOrChunk << 4u) + hex_digit_to_dec(c);
+			else
+			{
+				pico_err = PICO_ERR_EINVAL;
+				// something went wrong
+				return HTTP_RETURN_ERROR;
+			}
+		}
 
-        if(c=='\r' || c==';') client->state = HTTP_READING_CHUNK_TRAIL;
-    }
+		if(c=='\r' || c==';') client->state = HTTP_READING_CHUNK_TRAIL;
+	}
 
-    if(client->state == HTTP_READING_CHUNK_TRAIL)
-    {
+	if(client->state == HTTP_READING_CHUNK_TRAIL)
+	{
 
-        while(consumeChar(c)>0 && c!='\n');
+		while(consumeChar(c)>0 && c!='\n');
 
-        if(c=='\n') client->state = HTTP_READING_BODY;
-    }
+		if(c=='\n') client->state = HTTP_READING_BODY;
+	}
 
-    return HTTP_RETURN_OK;
+	return HTTP_RETURN_OK;
 }
 #endif
--- a/modules/pico_http_client.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_http_client.h	Mon Sep 02 08:02:21 2013 +0000
@@ -15,13 +15,13 @@
  * Transfer encodings
  */
 #define HTTP_TRANSFER_CHUNKED  1u
-#define HTTP_TRANSFER_FULL         0u
+#define HTTP_TRANSFER_FULL		 0u
 
 /*
  * Parameters for the send header function
  */
-#define HTTP_HEADER_RAW                    0u
-#define HTTP_HEADER_DEFAULT            1u
+#define HTTP_HEADER_RAW					0u
+#define HTTP_HEADER_DEFAULT			1u
 
 /*
  * Data types
@@ -29,10 +29,10 @@
 
 struct pico_http_header
 {
-    uint16_t responseCode;                     // http response
-    char * location;                                     // if redirect is reported
-    uint32_t contentLengthOrChunk;    // size of the message
-    uint8_t transferCoding;                   // chunked or full
+	uint16_t responseCode;     				// http response
+	char * location;					 				// if redirect is reported
+	uint32_t contentLengthOrChunk;    // size of the message
+	uint8_t transferCoding;   				// chunked or full
 
 };
 
--- a/modules/pico_http_server.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_http_server.c	Mon Sep 02 08:02:21 2013 +0000
@@ -13,30 +13,30 @@
 
 #ifdef PICO_SUPPORT_HTTP_SERVER
 
-#define BACKLOG                              10
+#define BACKLOG 						 	10
 
-#define HTTP_SERVER_CLOSED         0
-#define HTTP_SERVER_LISTEN         1
+#define HTTP_SERVER_CLOSED	 	0
+#define HTTP_SERVER_LISTEN	 	1
 
-#define HTTP_HEADER_MAX_LINE     256u
+#define HTTP_HEADER_MAX_LINE 	256u
 
 #define consumeChar(c) (pico_socket_read(client->sck,&c,1u))
 
-static char returnOkHeader[] =
+static const char returnOkHeader[] =
 "HTTP/1.1 200 OK\r\n\
 Host: localhost\r\n\
 Transfer-Encoding: chunked\r\n\
 Connection: close\r\n\
 \r\n";
 
-static char returnFailHeader[] =
+static const char returnFailHeader[] =
 "HTTP/1.1 404 Not Found\r\n\
 Host: localhost\r\n\
 Connection: close\r\n\
 \r\n\
 <html><body>The resource you requested cannot be found !</body></html>";
 
-static char errorHeader[] =
+static const char errorHeader[] =
 "HTTP/1.1 400 Bad Request\r\n\
 Host: localhost\r\n\
 Connection: close\r\n\
@@ -45,35 +45,35 @@
 
 struct httpServer
 {
-    uint16_t state;
-    struct pico_socket * sck;
-    uint16_t port;
-    void (*wakeup)(uint16_t ev, uint16_t param);
-    uint8_t accepted;
+	uint16_t state;
+	struct pico_socket * sck;
+	uint16_t port;
+	void (*wakeup)(uint16_t ev, uint16_t param);
+	uint8_t accepted;
 };
 
 struct httpClient
 {
-    uint16_t connectionID;
-    struct pico_socket * sck;
-    void * buffer;
-    uint16_t bufferSize;
-    uint16_t bufferSent;
-    char * resource;
-    uint16_t state;
+	uint16_t connectionID;
+	struct pico_socket * sck;
+	void * buffer;
+	uint16_t bufferSize;
+	uint16_t bufferSent;
+	char * resource;
+	uint16_t state;
 };
 
 /* Local states for clients */
-#define HTTP_WAIT_HDR                0
-#define HTTP_WAIT_EOF_HDR        1
-#define HTTP_EOF_HDR                2
+#define HTTP_WAIT_HDR				0
+#define HTTP_WAIT_EOF_HDR		1
+#define HTTP_EOF_HDR				2
 #define HTTP_WAIT_RESPONSE  3
-#define HTTP_WAIT_DATA            4
-#define HTTP_SENDING_DATA        5
-#define HTTP_ERROR                    6
-#define HTTP_CLOSED                    7
+#define HTTP_WAIT_DATA			4
+#define HTTP_SENDING_DATA		5
+#define HTTP_ERROR					6
+#define HTTP_CLOSED					7
 
-static struct httpServer server = {};
+static struct httpServer server = {0};
 
 /*
  * Private functions
@@ -86,76 +86,76 @@
 
 static int compareClients(void * ka, void * kb)
 {
-    return ((struct httpClient *)ka)->connectionID - ((struct httpClient *)kb)->connectionID;
+	return ((struct httpClient *)ka)->connectionID - ((struct httpClient *)kb)->connectionID;
 }
 
 PICO_TREE_DECLARE(pico_http_clients,compareClients);
 
 void httpServerCbk(uint16_t ev, struct pico_socket *s)
 {
-    struct pico_tree_node * index;
-    struct httpClient * client = NULL;
+	struct pico_tree_node * index;
+	struct httpClient * client = NULL;
   uint8_t serverEvent = FALSE;
 
   // determine the client for the socket
   if( s == server.sck)
   {
-        serverEvent = TRUE;
+		serverEvent = TRUE;
   }
   else
   {
-        pico_tree_foreach(index,&pico_http_clients)
-        {
-            client = index->keyValue;
-            if(client->sck == s) break;
-            client = NULL;
-        }
+		pico_tree_foreach(index,&pico_http_clients)
+		{
+			client = index->keyValue;
+			if(client->sck == s) break;
+			client = NULL;
+		}
   }
 
-    if(!client && !serverEvent)
-    {
-        return;
-    }
+	if(!client && !serverEvent)
+	{
+		return;
+	}
 
-    if (ev & PICO_SOCK_EV_RD)
-    {
+	if (ev & PICO_SOCK_EV_RD)
+	{
 
-        if(readData(client) == HTTP_RETURN_ERROR)
-        {
-            // send out error
-            client->state = HTTP_ERROR;
-            pico_socket_write(client->sck,errorHeader,sizeof(errorHeader)-1);
-            server.wakeup(EV_HTTP_ERROR,client->connectionID);
-        }
-    }
+		if(readData(client) == HTTP_RETURN_ERROR)
+		{
+			// send out error
+			client->state = HTTP_ERROR;
+			pico_socket_write(client->sck,(char *)errorHeader,sizeof(errorHeader)-1);
+			server.wakeup(EV_HTTP_ERROR,client->connectionID);
+		}
+	}
 
-    if(ev & PICO_SOCK_EV_WR)
-    {
-        if(client->state == HTTP_SENDING_DATA)
-        {
-            sendData(client);
-        }
-    }
+	if(ev & PICO_SOCK_EV_WR)
+	{
+		if(client->state == HTTP_SENDING_DATA)
+		{
+			sendData(client);
+		}
+	}
 
-    if(ev & PICO_SOCK_EV_CONN)
-    {
-        server.accepted = FALSE;
-        server.wakeup(EV_HTTP_CON,HTTP_SERVER_ID);
-        if(!server.accepted)
-        {
-            pico_socket_close(s); // reject socket
-        }
-    }
+	if(ev & PICO_SOCK_EV_CONN)
+	{
+		server.accepted = FALSE;
+		server.wakeup(EV_HTTP_CON,HTTP_SERVER_ID);
+		if(!server.accepted)
+		{
+			pico_socket_close(s); // reject socket
+		}
+	}
 
-    if( (ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN) )
-    {
-        server.wakeup(EV_HTTP_CLOSE,(serverEvent ? HTTP_SERVER_ID : client->connectionID));
-    }
+	if( (ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN) )
+	{
+		server.wakeup(EV_HTTP_CLOSE,(serverEvent ? HTTP_SERVER_ID : client->connectionID));
+	}
 
-    if(ev & PICO_SOCK_EV_ERR)
-    {
-        server.wakeup(EV_HTTP_ERROR,(serverEvent ? HTTP_SERVER_ID : client->connectionID));
-    }
+	if(ev & PICO_SOCK_EV_ERR)
+	{
+		server.wakeup(EV_HTTP_ERROR,(serverEvent ? HTTP_SERVER_ID : client->connectionID));
+	}
 }
 
 /*
@@ -164,38 +164,38 @@
  */
 int pico_http_server_start(uint16_t port, void (*wakeup)(uint16_t ev, uint16_t conn))
 {
-    struct pico_ip4 anything = {};
+	struct pico_ip4 anything = {0};
 
-    server.port = port ? short_be(port) : short_be(80u);
+	server.port = port ? short_be(port) : short_be(80u);
 
-    if(!wakeup)
-    {
-        pico_err = PICO_ERR_EINVAL;
-        return HTTP_RETURN_ERROR;
-    }
+	if(!wakeup)
+	{
+		pico_err = PICO_ERR_EINVAL;
+		return HTTP_RETURN_ERROR;
+	}
 
-    server.sck = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &httpServerCbk);
+	server.sck = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &httpServerCbk);
 
-    if(!server.sck)
-    {
-        pico_err = PICO_ERR_EFAULT;
-        return HTTP_RETURN_ERROR;
-    }
+	if(!server.sck)
+	{
+		pico_err = PICO_ERR_EFAULT;
+		return HTTP_RETURN_ERROR;
+	}
 
-    if(pico_socket_bind(server.sck , &anything, &server.port)!=0)
-    {
-        pico_err = PICO_ERR_EADDRNOTAVAIL;
-        return HTTP_RETURN_ERROR;
-    }
+	if(pico_socket_bind(server.sck , &anything, &server.port)!=0)
+	{
+		pico_err = PICO_ERR_EADDRNOTAVAIL;
+		return HTTP_RETURN_ERROR;
+	}
 
-    if (pico_socket_listen(server.sck, BACKLOG) != 0)
-    {
-        pico_err = PICO_ERR_EADDRINUSE;
-        return HTTP_RETURN_ERROR;
-    }
-    server.wakeup = wakeup;
-    server.state = HTTP_SERVER_LISTEN;
-    return HTTP_RETURN_OK;
+	if (pico_socket_listen(server.sck, BACKLOG) != 0)
+	{
+		pico_err = PICO_ERR_EADDRINUSE;
+		return HTTP_RETURN_ERROR;
+	}
+	server.wakeup = wakeup;
+	server.state = HTTP_SERVER_LISTEN;
+	return HTTP_RETURN_OK;
 }
 
 /*
@@ -215,32 +215,32 @@
   client = pico_zalloc(sizeof(struct httpClient));
   if(!client)
   {
-        pico_err = PICO_ERR_ENOMEM;
-      return HTTP_RETURN_ERROR;
+		pico_err = PICO_ERR_ENOMEM;
+  	return HTTP_RETURN_ERROR;
   }
 
-    client->sck = pico_socket_accept(server.sck,&orig,&port);
+	client->sck = pico_socket_accept(server.sck,&orig,&port);
 
-    if(!client->sck)
-    {
-        pico_err = PICO_ERR_ENOMEM;
-        pico_free(client);
-        return HTTP_RETURN_ERROR;
-    }
+	if(!client->sck)
+	{
+		pico_err = PICO_ERR_ENOMEM;
+		pico_free(client);
+		return HTTP_RETURN_ERROR;
+	}
 
-    server.accepted = TRUE;
-    // buffer used for async sending
-    client->state = HTTP_WAIT_HDR;
-    client->buffer = NULL;
-    client->bufferSize = 0;
-    client->connectionID = pico_rand() & 0x7FFF;
+	server.accepted = TRUE;
+	// buffer used for async sending
+	client->state = HTTP_WAIT_HDR;
+	client->buffer = NULL;
+	client->bufferSize = 0;
+	client->connectionID = pico_rand() & 0x7FFF;
 
-    //add element to the tree, if duplicate because the rand
-    //regenerate
-    while(pico_tree_insert(&pico_http_clients,client)!=NULL)
-        client->connectionID = pico_rand() & 0x7FFF;
+	//add element to the tree, if duplicate because the rand
+	//regenerate
+	while(pico_tree_insert(&pico_http_clients,client)!=NULL)
+		client->connectionID = pico_rand() & 0x7FFF;
 
-    return client->connectionID;
+	return client->connectionID;
 }
 
 /*
@@ -250,12 +250,12 @@
  */
 char * pico_http_getResource(uint16_t conn)
 {
-    struct httpClient * client = findClient(conn);
+	struct httpClient * client = findClient(conn);
 
-    if(!client)
-        return NULL;
-    else
-        return client->resource;
+	if(!client)
+		return NULL;
+	else
+		return client->resource;
 }
 
 /*
@@ -275,37 +275,37 @@
  */
 int pico_http_respond(uint16_t conn, uint16_t code)
 {
-    struct httpClient * client = findClient(conn);
+	struct httpClient * client = findClient(conn);
 
-    if(!client)
-    {
-        dbg("Client not found !\n");
-        return HTTP_RETURN_ERROR;
-    }
+	if(!client)
+	{
+		dbg("Client not found !\n");
+		return HTTP_RETURN_ERROR;
+	}
 
-    if(client->state == HTTP_WAIT_RESPONSE)
-    {
-        if(code == HTTP_RESOURCE_FOUND)
-        {
-            client->state = HTTP_WAIT_DATA;
-            return pico_socket_write(client->sck,returnOkHeader,sizeof(returnOkHeader)-1);//remove \0
-        }
-        else
-        {
-            int length;
+	if(client->state == HTTP_WAIT_RESPONSE)
+	{
+		if(code == HTTP_RESOURCE_FOUND)
+		{
+			client->state = HTTP_WAIT_DATA;
+			return pico_socket_write(client->sck,(char *)returnOkHeader,sizeof(returnOkHeader)-1);//remove \0
+		}
+		else
+		{
+			int length;
 
-            length = pico_socket_write(client->sck,returnFailHeader,sizeof(returnFailHeader)-1);//remove \0
-            pico_socket_close(client->sck);
-            client->state = HTTP_CLOSED;
-            return length;
+			length = pico_socket_write(client->sck,(char *)returnFailHeader,sizeof(returnFailHeader)-1);//remove \0
+			pico_socket_close(client->sck);
+			client->state = HTTP_CLOSED;
+			return length;
 
-        }
-    }
-    else
-    {
-        dbg("Bad state for the client \n");
-        return HTTP_RETURN_ERROR;
-    }
+		}
+	}
+	else
+	{
+		dbg("Bad state for the client \n");
+		return HTTP_RETURN_ERROR;
+	}
 
 }
 
@@ -326,71 +326,71 @@
 int pico_http_submitData(uint16_t conn, void * buffer, int len)
 {
 
-    struct httpClient * client = findClient(conn);
-    char chunkStr[10];
-    int chunkCount;
+	struct httpClient * client = findClient(conn);
+	char chunkStr[10];
+	int chunkCount;
 
-    if(client->state != HTTP_WAIT_DATA)
-    {
-        dbg("Client is in a different state than accepted\n");
-        return HTTP_RETURN_ERROR;
-    }
+	if(client->state != HTTP_WAIT_DATA)
+	{
+		dbg("Client is in a different state than accepted\n");
+		return HTTP_RETURN_ERROR;
+	}
 
-    if(client->buffer)
-    {
-        dbg("Already a buffer submited\n");
-        return HTTP_RETURN_ERROR;
-    }
+	if(client->buffer)
+	{
+		dbg("Already a buffer submited\n");
+		return HTTP_RETURN_ERROR;
+	}
 
-    if(!client)
-    {
-        dbg("Wrong connection ID\n");
-        return HTTP_RETURN_ERROR;
-    }
+	if(!client)
+	{
+		dbg("Wrong connection ID\n");
+		return HTTP_RETURN_ERROR;
+	}
 
-    if(!buffer)
-    {
-        len = 0;
-    }
+	if(!buffer)
+	{
+		len = 0;
+	}
 
-    if(len > 0)
-    {
-        client->buffer = pico_zalloc(len);
-        if(!client->buffer)
-        {
-            pico_err = PICO_ERR_ENOMEM;
-            return HTTP_RETURN_ERROR;
-        }
-        // taking over the buffer
-        memcpy(client->buffer,buffer,len);
-    }
-    else
-        client->buffer = NULL;
+	if(len > 0)
+	{
+		client->buffer = pico_zalloc(len);
+		if(!client->buffer)
+		{
+			pico_err = PICO_ERR_ENOMEM;
+			return HTTP_RETURN_ERROR;
+		}
+		// taking over the buffer
+		memcpy(client->buffer,buffer,len);
+	}
+	else
+		client->buffer = NULL;
 
 
-    client->bufferSize = len;
-    client->bufferSent = 0;
+	client->bufferSize = len;
+	client->bufferSent = 0;
 
-    // create the chunk size and send it
-    if(len > 0)
-    {
-        client->state = HTTP_SENDING_DATA;
-        chunkCount = pico_itoaHex(client->bufferSize,chunkStr);
-        chunkStr[chunkCount++] = '\r';
-        chunkStr[chunkCount++] = '\n';
-        pico_socket_write(client->sck,chunkStr,chunkCount);
-    }
-    else if(len == 0)
-    {
-        dbg("->\n");
-        // end of transmision
-        pico_socket_write(client->sck,"0\r\n\r\n",5u);
-        // nothing left, close the client
-        pico_socket_close(client->sck);
-        client->state = HTTP_CLOSED;
-    }
+	// create the chunk size and send it
+	if(len > 0)
+	{
+		client->state = HTTP_SENDING_DATA;
+		chunkCount = pico_itoaHex(client->bufferSize,chunkStr);
+		chunkStr[chunkCount++] = '\r';
+		chunkStr[chunkCount++] = '\n';
+		pico_socket_write(client->sck,chunkStr,chunkCount);
+	}
+	else if(len == 0)
+	{
+		dbg("->\n");
+		// end of transmision
+		pico_socket_write(client->sck,"0\r\n\r\n",5u);
+		// nothing left, close the client
+		pico_socket_close(client->sck);
+		client->state = HTTP_CLOSED;
+	}
 
-    return HTTP_RETURN_OK;
+	return HTTP_RETURN_OK;
 }
 
 /*
@@ -400,18 +400,18 @@
 
 int pico_http_getProgress(uint16_t conn, uint16_t * sent, uint16_t *total)
 {
-    struct httpClient * client = findClient(conn);
+	struct httpClient * client = findClient(conn);
 
-    if(!client)
-    {
-        dbg("Wrong connection id !\n");
-        return HTTP_RETURN_ERROR;
-    }
+	if(!client)
+	{
+		dbg("Wrong connection id !\n");
+		return HTTP_RETURN_ERROR;
+	}
 
-    *sent = client->bufferSent;
-    *total = client->bufferSize;
+	*sent = client->bufferSent;
+	*total = client->bufferSize;
 
-    return HTTP_RETURN_OK;
+	return HTTP_RETURN_OK;
 }
 
 /*
@@ -420,217 +420,217 @@
  */
 int pico_http_close(uint16_t conn)
 {
-    // close the server
-    if(conn == HTTP_SERVER_ID)
-    {
-        if(server.state == HTTP_SERVER_LISTEN)
-        {
-            struct pico_tree_node * index, * tmp;
-            // close the server
-            pico_socket_close(server.sck);
-            server.sck = NULL;
+	// close the server
+	if(conn == HTTP_SERVER_ID)
+	{
+		if(server.state == HTTP_SERVER_LISTEN)
+		{
+			struct pico_tree_node * index, * tmp;
+			// close the server
+			pico_socket_close(server.sck);
+			server.sck = NULL;
 
-            // destroy the tree
-            pico_tree_foreach_safe(index,&pico_http_clients,tmp)
-            {
-                struct httpClient * client = index->keyValue;
+			// destroy the tree
+			pico_tree_foreach_safe(index,&pico_http_clients,tmp)
+			{
+				struct httpClient * client = index->keyValue;
 
-                if(client->resource)
-                    pico_free(client->resource);
+				if(client->resource)
+					pico_free(client->resource);
 
-                pico_socket_close(client->sck);
-                pico_tree_delete(&pico_http_clients,client);
-            }
+				pico_socket_close(client->sck);
+				pico_tree_delete(&pico_http_clients,client);
+			}
 
-            server.state = HTTP_SERVER_CLOSED;
-            return HTTP_RETURN_OK;
-        }
-        else // nothing to close
-            return HTTP_RETURN_ERROR;
-    } // close a connection in this case
-    else
-    {
+			server.state = HTTP_SERVER_CLOSED;
+			return HTTP_RETURN_OK;
+		}
+		else // nothing to close
+			return HTTP_RETURN_ERROR;
+	} // close a connection in this case
+	else
+	{
 
-        struct httpClient * client = findClient(conn);
+		struct httpClient * client = findClient(conn);
 
-        if(!client)
-        {
-            dbg("Client not found..\n");
-            return HTTP_RETURN_ERROR;
-        }
+		if(!client)
+		{
+			dbg("Client not found..\n");
+			return HTTP_RETURN_ERROR;
+		}
 
-        pico_tree_delete(&pico_http_clients,client);
+		pico_tree_delete(&pico_http_clients,client);
 
-        if(client->resource)
-            pico_free(client->resource);
+		if(client->resource)
+			pico_free(client->resource);
 
-        if(client->buffer)
-            pico_free(client->buffer);
+		if(client->buffer)
+			pico_free(client->buffer);
 
-        if(client->state != HTTP_CLOSED || !client->sck)
-            pico_socket_close(client->sck);
+		if(client->state != HTTP_CLOSED || !client->sck)
+			pico_socket_close(client->sck);
 
-        pico_free(client);
-        return HTTP_RETURN_OK;
-    }
+		pico_free(client);
+		return HTTP_RETURN_OK;
+	}
 }
 
 // check the integrity of the request
 int parseRequest(struct httpClient * client)
 {
-    char c;
-    //read first line
-    consumeChar(c);
-    if(c == 'G')
-    { // possible GET
+	char c;
+	//read first line
+	consumeChar(c);
+	if(c == 'G')
+	{ // possible GET
 
-        char line[HTTP_HEADER_MAX_LINE];
-        int index = 0;
+		char line[HTTP_HEADER_MAX_LINE];
+		uint32_t index = 0;
 
-        line[index] = c;
+		line[index] = c;
 
-        // consume the full line
-        while(consumeChar(c)>0) // read char by char only the first line
-        {
-            line[++index] = c;
-            if(c == '\n')
-                break;
+		// consume the full line
+		while(consumeChar(c)>0) // read char by char only the first line
+		{
+			line[++index] = c;
+			if(c == '\n')
+				break;
 
-                if(index >= HTTP_HEADER_MAX_LINE)
-            {
-                dbg("Size exceeded \n");
-                return HTTP_RETURN_ERROR;
-            }
-        }
+			if(index >= HTTP_HEADER_MAX_LINE)
+			{
+				dbg("Size exceeded \n");
+				return HTTP_RETURN_ERROR;
+			}
+		}
 
-        // extract the function and the resource
-        if(memcmp(line,"GET",3u) || line[3u]!=' ' || index < 10u || line[index] !='\n')
-        {
-            dbg("Wrong command or wrong ending\n");
-            return HTTP_RETURN_ERROR;
-        }
+		// extract the function and the resource
+		if(memcmp(line,"GET",3u) || line[3u]!=' ' || index < 10u || line[index] !='\n')
+		{
+			dbg("Wrong command or wrong ending\n");
+			return HTTP_RETURN_ERROR;
+		}
 
-        // start reading the resource
-        index = 4u; // go after ' '
-        while(line[index]!=' ')
-        {
-            if(line[index]=='\n') // no terminator ' '
-            {
-                dbg("No terminator...\n");
-                return HTTP_RETURN_ERROR;
-            }
+		// start reading the resource
+		index = 4u; // go after ' '
+		while(line[index]!=' ')
+		{
+			if(line[index]=='\n') // no terminator ' '
+			{
+				dbg("No terminator...\n");
+				return HTTP_RETURN_ERROR;
+			}
 
-            index++;
-        }
+			index++;
+		}
 
-        client->resource = pico_zalloc(index - 3u);// allocate without the GET in front + 1 which is \0
+		client->resource = pico_zalloc(index - 3u);// allocate without the GET in front + 1 which is \0
 
-        if(!client)
-        {
-            pico_err = PICO_ERR_ENOMEM;
-            return HTTP_RETURN_ERROR;
-        }
+		if(!client)
+		{
+			pico_err = PICO_ERR_ENOMEM;
+			return HTTP_RETURN_ERROR;
+		}
 
-        // copy the resource
-        memcpy(client->resource,line+4u,index-4u);// copy without the \0 which was already set by pico_zalloc
+		// copy the resource
+		memcpy(client->resource,line+4u,index-4u);// copy without the \0 which was already set by pico_zalloc
 
-        client->state = HTTP_WAIT_EOF_HDR;
-        return HTTP_RETURN_OK;
+		client->state = HTTP_WAIT_EOF_HDR;
+		return HTTP_RETURN_OK;
 
-    }
+	}
 
-    return HTTP_RETURN_ERROR;
+	return HTTP_RETURN_ERROR;
 }
 
 
 
 int readRemainingHeader(struct httpClient * client)
 {
-    char line[100];
-    int count = 0;
-    int len;
+	char line[100];
+	int count = 0;
+	int len;
 
-    while( (len = pico_socket_read(client->sck,line,100u)) > 0)
-    {
-        char c;
-        int index = 0;
-        // parse the response
-        while(index < len)
-        {
-            c = line[index++];
-            if(c!='\r' && c!='\n')
-                count++;
-            if(c=='\n')
-            {
-                if(!count)
-                {
-                    client->state = HTTP_EOF_HDR;
-                    dbg("End of header !\n");
-                    break;
-                }
-                count = 0;
+	while( (len = pico_socket_read(client->sck,line,100u)) > 0)
+	{
+		char c;
+		int index = 0;
+		// parse the response
+		while(index < len)
+		{
+			c = line[index++];
+			if(c!='\r' && c!='\n')
+				count++;
+			if(c=='\n')
+			{
+				if(!count)
+				{
+					client->state = HTTP_EOF_HDR;
+					dbg("End of header !\n");
+					break;
+				}
+				count = 0;
 
-            }
-        }
-    }
+			}
+		}
+	}
 
-    return HTTP_RETURN_OK;
+	return HTTP_RETURN_OK;
 }
 
 void sendData(struct httpClient * client)
 {
-    int length;
-    while( client->bufferSent < client->bufferSize &&
-    (length = pico_socket_write(client->sck,client->buffer+client->bufferSent,client->bufferSize-client->bufferSent)) > 0 )
-    {
-        client->bufferSent += length;
-        server.wakeup(EV_HTTP_PROGRESS,client->connectionID);
-    }
+	int length;
+	while( client->bufferSent < client->bufferSize &&
+	(length = pico_socket_write(client->sck,client->buffer+client->bufferSent,client->bufferSize-client->bufferSent)) > 0 )
+	{
+		client->bufferSent += length;
+		server.wakeup(EV_HTTP_PROGRESS,client->connectionID);
+	}
 
-    if(client->bufferSent == client->bufferSize && client->bufferSize)
-    {
-        //send chunk trail
-        if(pico_socket_write(client->sck,"\r\n",2) > 0)
-        {
-            client->state = HTTP_WAIT_DATA;
-            //free the buffer
-            pico_free(client->buffer);
-            client->buffer = NULL;
-            server.wakeup(EV_HTTP_SENT,client->connectionID);
-        }
-    }
+	if(client->bufferSent == client->bufferSize && client->bufferSize)
+	{
+		//send chunk trail
+		if(pico_socket_write(client->sck,"\r\n",2) > 0)
+		{
+			client->state = HTTP_WAIT_DATA;
+			//free the buffer
+			pico_free(client->buffer);
+			client->buffer = NULL;
+			server.wakeup(EV_HTTP_SENT,client->connectionID);
+		}
+	}
 
 }
 
 int readData(struct httpClient * client)
 {
-    if(client->state == HTTP_WAIT_HDR)
-    {
-        if(parseRequest(client)<0 || readRemainingHeader(client)<0)
-        {
-            return HTTP_RETURN_ERROR;
-        }
-    } // continue with this in case the header comes line by line not a big chunk
-    else if(client->state == HTTP_WAIT_EOF_HDR)
-    {
-        if(readRemainingHeader(client)<0 )
-            return HTTP_RETURN_ERROR;
-    }
+	if(client->state == HTTP_WAIT_HDR)
+	{
+		if(parseRequest(client)<0 || readRemainingHeader(client)<0)
+		{
+			return HTTP_RETURN_ERROR;
+		}
+	} // continue with this in case the header comes line by line not a big chunk
+	else if(client->state == HTTP_WAIT_EOF_HDR)
+	{
+		if(readRemainingHeader(client)<0 )
+			return HTTP_RETURN_ERROR;
+	}
 
-    if(client->state == HTTP_EOF_HDR)
-    {
-        client->state = HTTP_WAIT_RESPONSE;
-        pico_socket_shutdown(client->sck,PICO_SHUT_RD);
-        server.wakeup(EV_HTTP_REQ,client->connectionID);
-    }
+	if(client->state == HTTP_EOF_HDR)
+	{
+		client->state = HTTP_WAIT_RESPONSE;
+		pico_socket_shutdown(client->sck,PICO_SHUT_RD);
+		server.wakeup(EV_HTTP_REQ,client->connectionID);
+	}
 
-    return HTTP_RETURN_OK;
+	return HTTP_RETURN_OK;
 }
 
 struct httpClient * findClient(uint16_t conn)
 {
-    struct httpClient dummy = {.connectionID = conn};
+	struct httpClient dummy = {.connectionID = conn};
 
-    return pico_tree_findKey(&pico_http_clients,&dummy);
+	return pico_tree_findKey(&pico_http_clients,&dummy);
 }
 #endif
--- a/modules/pico_http_server.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_http_server.h	Mon Sep 02 08:02:21 2013 +0000
@@ -12,11 +12,11 @@
 #include "pico_http_util.h"
 
 // Response codes
-#define HTTP_RESOURCE_FOUND                0
-#define HTTP_RESOURCE_NOT_FOUND        1
+#define HTTP_RESOURCE_FOUND				0
+#define HTTP_RESOURCE_NOT_FOUND		1
 
 // Generic id for the server
-#define HTTP_SERVER_ID                    0
+#define HTTP_SERVER_ID					0
 
 /*
  * Server functions
@@ -28,13 +28,13 @@
  * Client functions
  */
 char * pico_http_getResource(uint16_t conn);
-int      pico_http_getProgress(uint16_t conn, uint16_t * sent, uint16_t *total);
+int 	 pico_http_getProgress(uint16_t conn, uint16_t * sent, uint16_t *total);
 
 /*
  * Handshake and data functions
  */
-int      pico_http_respond(uint16_t conn, uint16_t code);
-int      pico_http_submitData(uint16_t conn, void * buffer, int len);
-int      pico_http_close(uint16_t conn);
+int 	 pico_http_respond(uint16_t conn, uint16_t code);
+int 	 pico_http_submitData(uint16_t conn, void * buffer, int len);
+int 	 pico_http_close(uint16_t conn);
 
 #endif /* PICO_HTTP_SERVER_H_ */
--- a/modules/pico_http_util.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_http_util.c	Mon Sep 02 08:02:21 2013 +0000
@@ -11,176 +11,176 @@
 #include "pico_protocol.h"
 #include "pico_http_util.h"
 
-#define TRUE    1
+#define TRUE	1
 #define FALSE 0
 
-#define HTTP_PROTO_TOK        "http://"
-#define HTTP_PROTO_LEN        7u
+#define HTTP_PROTO_TOK		"http://"
+#define HTTP_PROTO_LEN		7u
 
 #if defined PICO_SUPPORT_HTTP_CLIENT || defined PICO_SUPPORT_HTTP_SERVER
 
 int pico_itoaHex(uint16_t port, char * ptr)
 {
-    int size = 0;
-    int index;
+	int size = 0;
+	int index;
 
-    // transform to from number to string [ in backwards ]
-    while(port)
-    {
-        ptr[size] = ((port & 0xF) < 10) ? ((port & 0xF) + '0') : ((port & 0xF) - 10 + 'a');
-        port = port>>4u; //divide by 16
-        size++;
-    }
+	// transform to from number to string [ in backwards ]
+	while(port)
+	{
+		ptr[size] = ((port & 0xF) < 10) ? ((port & 0xF) + '0') : ((port & 0xF) - 10 + 'a');
+		port = port>>4u; //divide by 16
+		size++;
+	}
 
-    // invert positions
-    for(index=0 ;index < size>>1u ;index++)
-    {
-        char c = ptr[index];
-        ptr[index] = ptr[size-index-1];
-        ptr[size-index-1] = c;
-    }
-    ptr[size] = '\0';
-    return size;
+	// invert positions
+	for(index=0 ;index < size>>1u ;index++)
+	{
+		char c = ptr[index];
+		ptr[index] = ptr[size-index-1];
+		ptr[size-index-1] = c;
+	}
+	ptr[size] = '\0';
+	return size;
 }
 
 int pico_itoa(uint16_t port, char * ptr)
 {
-    int size = 0;
-    int index;
+	int size = 0;
+	int index;
 
-    // transform to from number to string [ in backwards ]
-    while(port)
-    {
-        ptr[size] = port%10 + '0';
-        port = port/10;
-        size++;
-    }
+	// transform to from number to string [ in backwards ]
+	while(port)
+	{
+		ptr[size] = port%10 + '0';
+		port = port/10;
+		size++;
+	}
 
-    // invert positions
-    for(index=0 ;index < size>>1u ;index++)
-    {
-        char c = ptr[index];
-        ptr[index] = ptr[size-index-1];
-        ptr[size-index-1] = c;
-    }
-    ptr[size] = '\0';
-    return size;
+	// invert positions
+	for(index=0 ;index < size>>1u ;index++)
+	{
+		char c = ptr[index];
+		ptr[index] = ptr[size-index-1];
+		ptr[size-index-1] = c;
+	}
+	ptr[size] = '\0';
+	return size;
 }
 
 
 int pico_processURI(const char * uri, struct pico_http_uri * urikey)
 {
 
-    uint16_t lastIndex = 0, index;
+	uint16_t lastIndex = 0, index;
 
-    if(!uri || !urikey || uri[0] == '/')
-    {
-        pico_err = PICO_ERR_EINVAL;
-        goto error;
-    }
+	if(!uri || !urikey || uri[0] == '/')
+	{
+		pico_err = PICO_ERR_EINVAL;
+		goto error;
+	}
 
-    // detect protocol => search for  "://"
-    if(memcmp(uri,HTTP_PROTO_TOK,HTTP_PROTO_LEN) == 0) // could be optimized
-    { // protocol identified, it is http
-        urikey->protoHttp = TRUE;
-        lastIndex = HTTP_PROTO_LEN;
-    }
-    else
-    {
-        if(strstr(uri,"://")) // different protocol specified
-        {
-            urikey->protoHttp = FALSE;
-            goto error;
-        }
-        // no protocol specified, assuming by default it's http
-        urikey->protoHttp = TRUE;
-    }
+	// detect protocol => search for  "://"
+	if(memcmp(uri,HTTP_PROTO_TOK,HTTP_PROTO_LEN) == 0) // could be optimized
+	{ // protocol identified, it is http
+		urikey->protoHttp = TRUE;
+		lastIndex = HTTP_PROTO_LEN;
+	}
+	else
+	{
+		if(strstr(uri,"://")) // different protocol specified
+		{
+			urikey->protoHttp = FALSE;
+			goto error;
+		}
+		// no protocol specified, assuming by default it's http
+		urikey->protoHttp = TRUE;
+	}
 
-    // detect hostname
-    index = lastIndex;
-    while(uri[index] && uri[index]!='/' && uri[index]!=':') index++;
+	// detect hostname
+	index = lastIndex;
+	while(uri[index] && uri[index]!='/' && uri[index]!=':') index++;
 
-    if(index == lastIndex)
-    {
-        // wrong format
-        urikey->host = urikey->resource = NULL;
-        urikey->port = urikey->protoHttp = 0u;
+	if(index == lastIndex)
+	{
+		// wrong format
+		urikey->host = urikey->resource = NULL;
+		urikey->port = urikey->protoHttp = 0u;
 
-        goto error;
-    }
-    else
-    {
-        // extract host
-        urikey->host = (char *)pico_zalloc(index-lastIndex+1);
+		goto error;
+	}
+	else
+	{
+		// extract host
+		urikey->host = (char *)pico_zalloc(index-lastIndex+1);
 
-        if(!urikey->host)
-        {
-            // no memory
-            goto error;
-        }
-        memcpy(urikey->host,uri+lastIndex,index-lastIndex);
-    }
+		if(!urikey->host)
+		{
+			// no memory
+			goto error;
+		}
+		memcpy(urikey->host,uri+lastIndex,index-lastIndex);
+	}
 
-    if(!uri[index])
-    {
-        // nothing specified
-        urikey->port = 80u;
-        urikey->resource = pico_zalloc(2u);
-        urikey->resource[0] = '/';
-        return HTTP_RETURN_OK;
-    }
-    else if(uri[index] == '/')
-    {
-        urikey->port = 80u;
-    }
-    else if(uri[index] == ':')
-    {
-        urikey->port = 0u;
-        index++;
-        while(uri[index] && uri[index]!='/')
-        {
-            // should check if every component is a digit
-            urikey->port = urikey->port*10 + (uri[index] - '0');
-            index++;
-        }
-    }
+	if(!uri[index])
+	{
+		// nothing specified
+		urikey->port = 80u;
+		urikey->resource = pico_zalloc(2u);
+		urikey->resource[0] = '/';
+		return HTTP_RETURN_OK;
+	}
+	else if(uri[index] == '/')
+	{
+		urikey->port = 80u;
+	}
+	else if(uri[index] == ':')
+	{
+		urikey->port = 0u;
+		index++;
+		while(uri[index] && uri[index]!='/')
+		{
+			// should check if every component is a digit
+			urikey->port = urikey->port*10 + (uri[index] - '0');
+			index++;
+		}
+	}
 
   // extract resource
-    if(!uri[index])
-    {
-        urikey->resource = pico_zalloc(2u);
-        urikey->resource[0] = '/';
-    }
-    else
-    {
-        lastIndex = index;
-        while(uri[index] && uri[index]!='?' && uri[index]!='&' && uri[index]!='#') index++;
-        urikey->resource = (char *)pico_zalloc(index-lastIndex+1);
+	if(!uri[index])
+	{
+		urikey->resource = pico_zalloc(2u);
+		urikey->resource[0] = '/';
+	}
+	else
+	{
+		lastIndex = index;
+		while(uri[index] && uri[index]!='?' && uri[index]!='&' && uri[index]!='#') index++;
+		urikey->resource = (char *)pico_zalloc(index-lastIndex+1);
 
-        if(!urikey->resource)
-        {
-            // no memory
-            pico_err = PICO_ERR_ENOMEM;
-            goto error;
-        }
+		if(!urikey->resource)
+		{
+			// no memory
+			pico_err = PICO_ERR_ENOMEM;
+			goto error;
+		}
 
-        memcpy(urikey->resource,uri+lastIndex,index-lastIndex);
-    }
+		memcpy(urikey->resource,uri+lastIndex,index-lastIndex);
+	}
 
-    return HTTP_RETURN_OK;
+	return HTTP_RETURN_OK;
 
-    error :
-    if(urikey->resource)
-    {
-        pico_free(urikey->resource);
-        urikey->resource = NULL;
-    }
-    if(urikey->host)
-    {
-        pico_free(urikey->host);
-        urikey->host = NULL;
-    }
+	error :
+	if(urikey->resource)
+	{
+		pico_free(urikey->resource);
+		urikey->resource = NULL;
+	}
+	if(urikey->host)
+	{
+		pico_free(urikey->host);
+		urikey->host = NULL;
+	}
 
-    return HTTP_RETURN_ERROR;
+	return HTTP_RETURN_ERROR;
 }
 #endif
--- a/modules/pico_http_util.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_http_util.h	Mon Sep 02 08:02:21 2013 +0000
@@ -9,104 +9,104 @@
 #define PICO_HTTP_UTIL_H_
 
 /* Informational reponses */
-#define HTTP_CONTINUE                         100u
+#define HTTP_CONTINUE 						100u
 #define HTTP_SWITCHING_PROTOCOLS  101u
-#define HTTP_PROCESSING                      102u
+#define HTTP_PROCESSING					  102u
 
 /* Success */
-#define HTTP_OK                                        200u
-#define HTTP_CREATED                            201u
-#define HTTP_ACCEPTED                            202u
-#define HTTP_NON_AUTH_INFO                203u
-#define HTTP_NO_CONTENT                        204u
-#define HTTP_RESET_CONTENT                205u
-#define HTTP_PARTIAL_CONTENT            206u
-#define HTTP_MULTI_STATUS                    207u
-#define HTTP_ALREADY_REPORTED            208u
-#define HTTP_LOW_SPACE                        250u
-#define HTTP_IM_SPACE                            226u
+#define HTTP_OK										200u
+#define HTTP_CREATED							201u
+#define HTTP_ACCEPTED							202u
+#define HTTP_NON_AUTH_INFO				203u
+#define HTTP_NO_CONTENT						204u
+#define HTTP_RESET_CONTENT				205u
+#define HTTP_PARTIAL_CONTENT			206u
+#define HTTP_MULTI_STATUS					207u
+#define HTTP_ALREADY_REPORTED			208u
+#define HTTP_LOW_SPACE						250u
+#define HTTP_IM_SPACE							226u
 
 /* Redirection */
-#define HTTP_MULTI_CHOICE                    300u
-#define HTTP_MOVED_PERMANENT            301u
-#define HTTP_FOUND                                302u
-#define HTTP_SEE_OTHER                        303u
-#define HTTP_NOT_MODIFIED                    304u
-#define HTTP_USE_PROXY                        305u
-#define HTTP_SWITCH_PROXY                    306u
-#define HTTP_TEMP_REDIRECT                307u
-#define HTTP_PERM_REDIRECT                308u
+#define HTTP_MULTI_CHOICE					300u
+#define HTTP_MOVED_PERMANENT			301u
+#define HTTP_FOUND								302u
+#define HTTP_SEE_OTHER						303u
+#define HTTP_NOT_MODIFIED					304u
+#define HTTP_USE_PROXY						305u
+#define HTTP_SWITCH_PROXY					306u
+#define HTTP_TEMP_REDIRECT				307u
+#define HTTP_PERM_REDIRECT				308u
 
 /* Client error */
-#define HTTP_BAD_REQUEST                    400u
-#define HTTP_UNAUTH                                401u
-#define HTTP_PAYMENT_REQ                    402u
-#define HTTP_FORBIDDEN                        403u
-#define HTTP_NOT_FOUND                        404u
-#define HTTP_METH_NOT_ALLOWED            405u
-#define HTTP_NOT_ACCEPTABLE                406u
-#define HTTP_PROXY_AUTH_REQ                407u
-#define HTTP_REQ_TIMEOUT                    408u
-#define HTTP_CONFLICT                            409u
-#define HTTP_GONE                                    410u
-#define HTTP_LEN_REQ                            411u
-#define HTTP_PRECONDITION_FAIL        412u
-#define HTTP_REQ_ENT_LARGE                413u
-#define HTTP_URI_TOO_LONG                    414u
-#define HTTP_UNSUPORTED_MEDIA            415u
-#define HTTP_REQ_RANGE_NOK                416u
-#define HTTP_EXPECT_FAILED                417u
-#define HTTP_TEAPOT                                418u
-#define HTTP_UNPROC_ENTITY                422u
-#define HTTP_LOCKED                                423u
-#define HTTP_METHOD_FAIL                    424u
-#define HTTP_UNORDERED                        425u
-#define HTTP_UPGRADE_REQ                    426u
-#define HTTP_PRECOND_REQ                    428u
-#define HTTP_TOO_MANY_REQ                    429u
-#define HTTP_HEDER_FIELD_LARGE        431u
+#define HTTP_BAD_REQUEST					400u
+#define HTTP_UNAUTH								401u
+#define HTTP_PAYMENT_REQ					402u
+#define HTTP_FORBIDDEN						403u
+#define HTTP_NOT_FOUND						404u
+#define HTTP_METH_NOT_ALLOWED			405u
+#define HTTP_NOT_ACCEPTABLE				406u
+#define HTTP_PROXY_AUTH_REQ				407u
+#define HTTP_REQ_TIMEOUT					408u
+#define HTTP_CONFLICT							409u
+#define HTTP_GONE									410u
+#define HTTP_LEN_REQ							411u
+#define HTTP_PRECONDITION_FAIL		412u
+#define HTTP_REQ_ENT_LARGE				413u
+#define HTTP_URI_TOO_LONG					414u
+#define HTTP_UNSUPORTED_MEDIA			415u
+#define HTTP_REQ_RANGE_NOK				416u
+#define HTTP_EXPECT_FAILED				417u
+#define HTTP_TEAPOT								418u
+#define HTTP_UNPROC_ENTITY				422u
+#define HTTP_LOCKED								423u
+#define HTTP_METHOD_FAIL					424u
+#define HTTP_UNORDERED						425u
+#define HTTP_UPGRADE_REQ					426u
+#define HTTP_PRECOND_REQ					428u
+#define HTTP_TOO_MANY_REQ					429u
+#define HTTP_HEDER_FIELD_LARGE		431u
 
 /* Server error */
-#define HTTP_INTERNAL_SERVER_ERR    500u
-#define HTTP_NOT_IMPLEMENTED            501u
-#define HTTP_BAD_GATEWAY                    502u
-#define HTTP_SERVICE_UNAVAILABLE    503u
-#define HTTP_GATEWAY_TIMEOUT            504u
-#define HTTP_NOT_SUPPORTED                505u
-#define HTTP_SERV_LOW_STORAGE            507u
-#define HTTP_LOOP_DETECTED                508u
-#define HTTP_NOT_EXTENDED                    510u
-#define HTTP_NETWORK_AUTH                    511u
-#define HTTP_PERMISSION_DENIED        550u
+#define HTTP_INTERNAL_SERVER_ERR	500u
+#define HTTP_NOT_IMPLEMENTED			501u
+#define HTTP_BAD_GATEWAY					502u
+#define HTTP_SERVICE_UNAVAILABLE	503u
+#define HTTP_GATEWAY_TIMEOUT			504u
+#define HTTP_NOT_SUPPORTED				505u
+#define HTTP_SERV_LOW_STORAGE			507u
+#define HTTP_LOOP_DETECTED				508u
+#define HTTP_NOT_EXTENDED					510u
+#define HTTP_NETWORK_AUTH					511u
+#define HTTP_PERMISSION_DENIED		550u
 
 /* Returns used  */
 #define HTTP_RETURN_ERROR    -1
-#define HTTP_RETURN_OK                0
+#define HTTP_RETURN_OK				0
 
 /* List of events - shared between client and server */
-#define EV_HTTP_CON            1u
+#define EV_HTTP_CON		    1u
 #define EV_HTTP_REQ       2u
 #define EV_HTTP_PROGRESS  4u
-#define EV_HTTP_SENT          8u
+#define EV_HTTP_SENT		  8u
 #define EV_HTTP_CLOSE     16u
 #define EV_HTTP_ERROR     32u
-#define EV_HTTP_BODY            64u
-#define EV_HTTP_DNS                128u
+#define EV_HTTP_BODY			64u
+#define EV_HTTP_DNS				128u
 
 #ifndef TRUE
-    #define TRUE    1
+	#define TRUE	1
 #endif
 
 #ifndef FALSE
-    #define FALSE 0
+	#define FALSE 0
 #endif
 
 struct pico_http_uri
 {
-    uint8_t protoHttp; // is the protocol Http ?
-    char * host;             // hostname
-    uint16_t port;         // port if specified
-    char * resource;     // resource , ignoring the other possible parameters
+	uint8_t protoHttp; // is the protocol Http ?
+	char * host;			 // hostname
+	uint16_t port;		 // port if specified
+	char * resource;	 // resource , ignoring the other possible parameters
 };
 
 // used for chunks
--- a/modules/pico_icmp4.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_icmp4.c	Mon Sep 02 08:02:21 2013 +0000
@@ -17,8 +17,8 @@
 #include "pico_tree.h"
 
 /* Queues */
-static struct pico_queue icmp_in = {};
-static struct pico_queue icmp_out = {};
+static struct pico_queue icmp_in = {0};
+static struct pico_queue icmp_out = {0};
 
 
 /* Functions */
@@ -41,7 +41,9 @@
 
 static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *f)
 {
-  struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
+	struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
+	IGNORE_PARAMETER(self);
+
   if (hdr->type == PICO_ICMP_ECHO) {
     hdr->type = PICO_ICMP_ECHOREPLY;
     /* outgoing frames require a f->len without the ethernet header len */
@@ -65,7 +67,9 @@
 
 static int pico_icmp4_process_out(struct pico_protocol *self, struct pico_frame *f)
 {
-  dbg("Called %s\n", __FUNCTION__);
+	IGNORE_PARAMETER(self);
+	IGNORE_PARAMETER(f);
+	dbg("Called %s\n", __FUNCTION__);
   return 0;
 }
 
@@ -163,7 +167,7 @@
 
 static int cookie_compare(void *ka, void *kb)
 {
-    struct pico_icmp4_ping_cookie *a = ka, *b = kb;
+	struct pico_icmp4_ping_cookie *a = ka, *b = kb;
   if (a->id < b->id)
     return -1;
   if (a->id > b->id)
@@ -197,6 +201,8 @@
 static void ping_timeout(unsigned long now, void *arg)
 {
   struct pico_icmp4_ping_cookie *cookie = (struct pico_icmp4_ping_cookie *)arg;
+  IGNORE_PARAMETER(now);
+
   if(pico_tree_findKey(&Pings,cookie)){
     if (cookie->err == PICO_PING_ERR_PENDING) {
       struct pico_icmp4_stats stats;
@@ -227,8 +233,9 @@
 static void next_ping(unsigned long now, void *arg)
 {
   struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg;
+  IGNORE_PARAMETER(now);
 
-    if(pico_tree_findKey(&Pings,cookie)){
+	if(pico_tree_findKey(&Pings,cookie)){
     if (cookie->seq < cookie->count) {
       newcookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie));
       if (!newcookie)
@@ -236,7 +243,7 @@
       memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie));
       newcookie->seq++;
 
-        pico_tree_insert(&Pings,newcookie);
+	    pico_tree_insert(&Pings,newcookie);
       send_ping(newcookie);
     }
   }
@@ -260,8 +267,8 @@
     stats.time = pico_tick - cookie->timestamp;
     stats.err = cookie->err;
     stats.ttl = ((struct pico_ipv4_hdr *)f->net_hdr)->ttl;
-        if(cookie->cb != NULL)
-        cookie->cb(&stats);
+		if(cookie->cb != NULL)
+    	cookie->cb(&stats);
   } else {
     dbg("Reply for seq=%d, not found.\n", test.seq);
   }
--- a/modules/pico_igmp.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_igmp.c	Mon Sep 02 08:02:21 2013 +0000
@@ -138,8 +138,8 @@
 };
 
 /* queues */
-static struct pico_queue igmp_in = {};
-static struct pico_queue igmp_out = {};
+static struct pico_queue igmp_in = {0};
+static struct pico_queue igmp_out = {0};
 
 /* finite state machine caller */
 static int pico_igmp_process_event(struct igmp_parameters *p);
@@ -216,6 +216,7 @@
 {
   struct igmp_timer *t = NULL, *timer = NULL, test = {0};
 
+  IGNORE_PARAMETER(now);
   t = (struct igmp_timer *)arg;
   test.type = t->type;
   test.mcast_link = t->mcast_link;
@@ -481,7 +482,8 @@
 static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f)
 {
   struct igmp_parameters *p = NULL;
- 
+  IGNORE_PARAMETER(self);
+
   if (!pico_igmp_is_checksum_valid(f))
     goto out;
   if (pico_igmp_compatibility_mode(f) < 0)
@@ -499,7 +501,9 @@
 
 static int pico_igmp_process_out(struct pico_protocol *self, struct pico_frame *f) {
   /* packets are directly transferred to the IP layer by calling pico_ipv4_frame_push */
-  return 0;
+	IGNORE_PARAMETER(self);
+	IGNORE_PARAMETER(f);
+	return 0;
 }
 
 /* Interface: protocol definition */
--- a/modules/pico_ipfilter.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_ipfilter.c	Mon Sep 02 08:02:21 2013 +0000
@@ -44,16 +44,23 @@
 
 /*======================== FUNCTION PNTRS ==========================*/
 
-static int fp_accept(struct filter_node *filter, struct pico_frame *f) {return 0;}
+static int fp_accept(struct filter_node *filter, struct pico_frame *f) {
+	IGNORE_PARAMETER(filter);
+	IGNORE_PARAMETER(f);
+	return 0;
+}
 
 static int fp_priority(struct filter_node *filter, struct pico_frame *f) {
 
   //TODO do priority-stuff
+	IGNORE_PARAMETER(filter);
+	IGNORE_PARAMETER(f);
   return 0;
 }
 
 static int fp_reject(struct filter_node *filter, struct pico_frame *f) {
 // TODO check first if sender is pico itself or not
+	IGNORE_PARAMETER(filter);
   ipf_dbg("ipfilter> #reject\n");
   pico_icmp4_packet_filtered(f);
   pico_frame_discard(f);
@@ -61,7 +68,7 @@
 }
 
 static int fp_drop(struct filter_node *filter, struct pico_frame *f) {
-
+	IGNORE_PARAMETER(filter);
   ipf_dbg("ipfilter> # drop\n");
   pico_frame_discard(f);
   return 1;
@@ -81,7 +88,7 @@
     pico_err = PICO_ERR_EINVAL;
     return -1;
   }
-  if (action > 3 || action < 0) {
+  if (action > 3) {
     pico_err = PICO_ERR_EINVAL;
     return -1;
   }
--- a/modules/pico_ipv4.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_ipv4.c	Mon Sep 02 08:02:21 2013 +0000
@@ -33,8 +33,8 @@
 #endif
 
 /* Queues */
-static struct pico_queue in = {};
-static struct pico_queue out = {};
+static struct pico_queue in = {0};
+static struct pico_queue out = {0};
 
 /* Functions */
 static int ipv4_route_compare(void *ka, void * kb);
@@ -125,7 +125,7 @@
    * */
 
   for(i = 0; i < 32; i++){
-    if((mask_swap << i) & (1 << 31)){
+    if((mask_swap << i) & 0x80000000){
       if(end) {
         pico_err = PICO_ERR_EINVAL;
         return -1;
@@ -414,6 +414,7 @@
 #else
 static inline int pico_ipv4_crc_check(struct pico_frame *f)
 {
+	IGNORE_PARAMETER(f);
   return 1;
 }
 #endif /* PICO_SUPPORT_CRC */
@@ -505,17 +506,16 @@
     }
 #endif
   } else if (pico_ipv4_link_find(&hdr->dst)) {
-   if (pico_ipv4_nat_isenabled_in(f) == 0) {  /* if NAT enabled (dst port registerd), do NAT */
-      if(pico_ipv4_nat(f, hdr->dst) != 0) {
-        return -1;
-      }
-      pico_ipv4_forward(f); /* Local packet became forward packet after NAT */
-    } else {                              /* no NAT so enqueue to next layer */
+    if (pico_ipv4_nat_inbound(f, &hdr->dst) == 0)
+      pico_enqueue(pico_proto_ipv4.q_in, f); /* dst changed, reprocess */
+    else 
       pico_transport_receive(f, hdr->proto);
-    }
   } else if (pico_tree_findKey(&Tree_dev_link, &test)){
 #ifdef PICO_SUPPORT_UDP
     //address of this device is apparently 0.0.0.0; might be a DHCP packet
+    /* XXX KRO: is obsolete. Broadcast flag is set on outgoing DHCP messages.
+     * incomming DHCP messages are to be broadcasted. Our current DHCP server
+     * implementation does not take this flag into account yet though ... */
     pico_enqueue(pico_proto_udp.q_in, f);
 #endif
   } else {
@@ -526,7 +526,7 @@
       pico_frame_discard(f);
     } else if (pico_ipv4_forward(f) != 0) {
         /* Packet is not local. Try to forward. */
-        pico_frame_discard(f);
+        pico_ipv4_forward(f);
     }
   }
   return 0;
@@ -537,7 +537,8 @@
 
 static int pico_ipv4_process_out(struct pico_protocol *self, struct pico_frame *f)
 {
-  f->start = (uint8_t*) f->net_hdr;
+	IGNORE_PARAMETER(self);
+	f->start = (uint8_t*) f->net_hdr;
   #ifdef PICO_SUPPORT_IPFILTER
   if (ipfilter(f)) {
     /*pico_frame is discarded as result of the filtering*/
@@ -550,8 +551,10 @@
 
 static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, int size)
 {
-  struct pico_frame *f =  pico_frame_alloc(size + PICO_SIZE_IP4HDR + PICO_SIZE_ETHHDR);
-  if (!f)
+	struct pico_frame *f =  pico_frame_alloc(size + PICO_SIZE_IP4HDR + PICO_SIZE_ETHHDR);
+	IGNORE_PARAMETER(self);
+
+	if (!f)
     return NULL;
   f->datalink_hdr = f->buffer;
   f->net_hdr = f->buffer + PICO_SIZE_ETHHDR;
@@ -899,7 +902,6 @@
             }
             ip_mcast_dbg("MCAST: IP %08X NOT in included interface source list\n", hdr->src.addr);
             return -1;
-            break;
 
           case PICO_IP_MULTICAST_EXCLUDE:
             pico_tree_foreach(index2, &g->MCASTSources)
@@ -911,11 +913,9 @@
             }
             ip_mcast_dbg("MCAST: IP %08X NOT in excluded interface source list\n", hdr->src.addr);
             return 0;
-            break;
 
           default:
             return -1;
-            break;
         }
       } else {
         ip_mcast_dbg("MCAST: IP %08X is group member of different link %s\n", hdr->dst.addr, link->dev->name);
@@ -1071,8 +1071,10 @@
 
 static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f)
 {
-  struct pico_ip4 *dst;
+	struct pico_ip4 *dst;
   struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info;
+  IGNORE_PARAMETER(self);
+
   if (!f->sock) {
     pico_frame_discard(f);
     return -1;
@@ -1153,8 +1155,10 @@
 
 int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link)
 {
-  struct pico_ipv4_route test, *found;
-  if (!link) {
+	struct pico_ipv4_route test, *found;
+	IGNORE_PARAMETER(gateway);
+
+	if (!link) {
     pico_err = PICO_ERR_EINVAL;
     return -1;
   }
@@ -1366,13 +1370,12 @@
     return -1;
   }
 
-  //dbg("IP> FORWARDING.\n");
   rt = route_find(&hdr->dst);
   if (!rt) {
     pico_notify_dest_unreachable(f);
     return -1;
   }
-  //dbg("ROUTE: valid..\n");
+
   f->dev = rt->link->dev;
   hdr->ttl-=1;
   if (hdr->ttl < 1) {
@@ -1381,11 +1384,8 @@
   }
   hdr->crc++;
 
-  /* check if NAT enbled on link and do NAT if so */
-  if (pico_ipv4_nat_isenabled_out(rt->link) == 0)
-    pico_ipv4_nat(f, rt->link->address);
+  pico_ipv4_nat_outbound(f, &rt->link->address);
 
-  //dbg("Routing towards %s\n", f->dev->name);
   f->start = f->net_hdr;
   if(f->dev->eth != NULL)
     f->len -= PICO_SIZE_ETHHDR;
--- a/modules/pico_nat.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_nat.c	Mon Sep 02 08:02:21 2013 +0000
@@ -16,593 +16,459 @@
 #include "pico_addressing.h"
 #include "pico_nat.h"
 
-
 #ifdef PICO_SUPPORT_IPV4
 #ifdef PICO_SUPPORT_NAT
 
 #define nat_dbg(...) do{}while(0)
 //#define nat_dbg dbg
-#define NAT_TCP_TIMEWAIT 240000 /* 4mins (in msec) */
-//#define NAT_TCP_TIMEWAIT 10000 /* 10 sec (in msec)  - for testing purposes only*/
-
+#define PICO_NAT_TIMEWAIT  240000 /* msec (4 mins) */
 
-struct pico_nat_key {
-  struct pico_ip4 pub_addr;
-  uint16_t pub_port;
-  struct pico_ip4 priv_addr;
-  uint16_t priv_port;
+#define PICO_NAT_INBOUND   0
+#define PICO_NAT_OUTBOUND  1
+
+struct pico_nat_tuple {
   uint8_t proto;
-  /*
-  del_flags:
-              1                   0 
-    5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-   |F|B|S|R|P|~| CONNECTION ACTIVE |
-   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-  F: FIN from Forwarding packet
-  B: FIN from Backwarding packet
-  S: SYN 
-  R: RST  
-  P: Persistant
-         
-  */
-  uint16_t del_flags;
-  /* Connector for trees */
+  uint16_t conn_active:11;
+  uint16_t portforward:1;
+  uint16_t rst:1;
+  uint16_t syn:1;
+  uint16_t fin_in:1;
+  uint16_t fin_out:1;
+  uint16_t src_port;
+  uint16_t dst_port;
+  uint16_t nat_port;
+  struct pico_ip4 src_addr;
+  struct pico_ip4 dst_addr;
+  struct pico_ip4 nat_addr;
 };
 
-static struct pico_ipv4_link pub_link;
-static uint8_t enable_nat_flag = 0;
+static struct pico_ipv4_link *nat_link = NULL;
 
-static int nat_cmp_backward(void * ka, void * kb)
+static int nat_cmp_inbound(void * ka, void * kb)
 {
-    struct pico_nat_key *a = ka, *b = kb;
-  if (a->pub_port < b->pub_port) {
+	struct pico_nat_tuple *a = ka, *b = kb;
+
+  if (a->nat_port < b->nat_port)
     return -1;
-  }
-  else if (a->pub_port > b->pub_port) {
+  if (a->nat_port > b->nat_port)
     return 1;
-  }
-  else {
-    if (a->proto < b->proto) {
-      return -1;
-    }
-    else if (a->proto > b->proto) {
+  if (a->proto < b->proto)
+    return -1;
+  if (a->proto > b->proto)
       return 1;
-    }
-    else {
-      /* a and b are identical */
-      return 0;
-    }
-  }
+  return 0; /* identical */
 }
 
-static int nat_cmp_forward(void * ka, void * kb)
+static int nat_cmp_outbound(void * ka, void * kb)
 {
-    struct pico_nat_key *a =ka, *b = kb;
-  if (a->priv_addr.addr < b->priv_addr.addr) {
+	struct pico_nat_tuple *a =ka, *b = kb;
+
+  if (a->src_addr.addr < b->src_addr.addr)
     return -1;
-  }
-  else if (a->priv_addr.addr > b->priv_addr.addr) {
+  if (a->src_addr.addr > b->src_addr.addr)
     return 1;
-  }
-  else {
-    if (a->priv_port < b->priv_port) {
-      return -1;
-    }
-    else if (a->priv_port > b->priv_port) {
-      return 1;
-    }
-    else {
-      if (a->proto < b->proto) {
-        return -1;
-      }
-      else if (a->proto > b->proto) {
-        return 1;
-      }
-      else {
-        /* a and b are identical */
-        return 0;
-      }
-    }
-  }
+  if (a->src_port < b->src_port)
+    return -1;
+  if (a->src_port > b->src_port)
+    return 1;
+  if (a->proto < b->proto)
+    return -1;
+  if (a->proto > b->proto)
+    return 1;
+  return 0; /* identical */
 }
 
-PICO_TREE_DECLARE(KEYTable_forward,nat_cmp_forward);
-PICO_TREE_DECLARE(KEYTable_backward,nat_cmp_backward);
+PICO_TREE_DECLARE(NATOutbound, nat_cmp_outbound);
+PICO_TREE_DECLARE(NATInbound, nat_cmp_inbound);
+
+void pico_ipv4_nat_print_table(void)
+{
+  struct pico_nat_tuple __attribute__((unused)) *t = NULL;
+  struct pico_tree_node *index = NULL;
+
+  nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+  nat_dbg("+                                                        NAT table                                                       +\n");
+  nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
+  nat_dbg("+ src_addr | src_port | dst_addr | dst_port | nat_addr | nat_port | proto | conn active | FIN1 | FIN2 | SYN | RST | FORW +\n");
+  nat_dbg("+------------------------------------------------------------------------------------------------------------------------+\n");
+
+  pico_tree_foreach(index, &NATOutbound)
+  {
+  	t = index->keyValue;
+    nat_dbg("+ %08X |  %05u   | %08X |  %05u   | %08X |  %05u   |  %03u  |     %03u     |   %u  |   %u  |  %u  |  %u  |   %u  +\n", 
+           long_be(t->src_addr.addr), t->src_port, long_be(t->dst_addr.addr), t->dst_port, long_be(t->nat_addr.addr), t->nat_port, 
+           t->proto, t->conn_active, t->fin_in, t->fin_out, t->syn, t->rst, t->portforward);
+  }
+  nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+}
 
 /* 
   2 options: 
-    find on proto and pub_port 
-    find on priv_addr, priv_port and proto 
+    find on nat_port and proto
+    find on src_addr, src_port and proto 
   zero the unused parameters 
 */
-static struct pico_nat_key *pico_ipv4_nat_find_key(uint16_t pub_port, struct pico_ip4 *priv_addr, uint16_t priv_port, uint8_t proto)
+static struct pico_nat_tuple *pico_ipv4_nat_find_tuple(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
 {
-  struct pico_nat_key test;
-  test.pub_port = pub_port;
-  test.priv_port = priv_port;
+  struct pico_nat_tuple *found = NULL, test = {0};
+
+  test.nat_port = nat_port;
+  test.src_port = src_port;
   test.proto = proto;
-  if (priv_addr)
-    test.priv_addr = *priv_addr;
-  else
-    test.priv_addr.addr = 0;
+  if (src_addr)
+    test.src_addr = *src_addr;
 
-  /* returns NULL if test can not be found */ 
-  if (!pub_port)
-      return pico_tree_findKey(&KEYTable_forward,&test);
+  if (nat_port)
+  	found = pico_tree_findKey(&NATInbound, &test);
   else
-      return pico_tree_findKey(&KEYTable_backward, &test);
+  	found = pico_tree_findKey(&NATOutbound, &test);
+
+  if (found)
+    return found;
+  else
+    return NULL;
 }
 
-int pico_ipv4_nat_find(uint16_t pub_port, struct pico_ip4 *priv_addr, uint16_t priv_port, uint8_t proto)
+int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
 {
-  struct pico_nat_key *k = NULL;
+  struct pico_nat_tuple *t = NULL;
 
-  k = pico_ipv4_nat_find_key(pub_port, priv_addr, priv_port, proto); 
-  if (k)
+  t = pico_ipv4_nat_find_tuple(nat_port, src_addr, src_port, proto); 
+  if (t)
+    return 1;
+  else
     return 0;
-  else
-    return -1;
 }
 
-int pico_ipv4_nat_snif_forward(struct pico_nat_key *nk, struct pico_frame *f)
+static struct pico_nat_tuple *pico_ipv4_nat_add(struct pico_ip4 dst_addr, uint16_t dst_port, struct pico_ip4 src_addr, uint16_t src_port, 
+                                                struct pico_ip4 nat_addr, uint16_t nat_port, uint8_t proto)
 {
-  uint8_t proto;
-  struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
-  struct pico_tcp_hdr *tcp_hdr;
- 
-  if (!ipv4_hdr)
-    return -1;
-  proto = ipv4_hdr->proto;
+  struct pico_nat_tuple *t = pico_zalloc(sizeof(struct pico_nat_tuple));
+  if (!t) {
+    pico_err = PICO_ERR_ENOMEM;
+    return NULL;
+  }
 
-  if (proto == PICO_PROTO_TCP) {
-    tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-    if (!tcp_hdr)
-      return -1;
-    if (tcp_hdr->flags & PICO_TCP_FIN) {
-      nk->del_flags |= PICO_DEL_FLAGS_FIN_FORWARD; //FIN from forwarding packet
-    }
-    if (tcp_hdr->flags & PICO_TCP_SYN) {
-      nk->del_flags |= PICO_DEL_FLAGS_SYN; 
-    }
-    if (tcp_hdr->flags & PICO_TCP_RST) {
-      nk->del_flags |= PICO_DEL_FLAGS_RST;
-    }
-  } else if (proto == PICO_PROTO_UDP) {
-    /* set conn active to 1 */
-    nk->del_flags &= 0xFE00; 
-    nk->del_flags++;
-  } 
-  return 0; 
+  t->dst_addr = dst_addr;
+  t->dst_port = dst_port;
+  t->src_addr = src_addr;
+  t->src_port = src_port;
+  t->nat_addr = nat_addr;
+  t->nat_port = nat_port;
+  t->proto = proto;
+  t->conn_active = 1;
+  t->portforward = 0;
+  t->rst = 0;
+  t->syn = 0;
+  t->fin_in = 0;
+  t->fin_out = 0;
+
+  if (pico_tree_insert(&NATOutbound, t)) {
+    pico_free(t);
+    return NULL;
+  }
+  if (pico_tree_insert(&NATInbound, t)) {
+    pico_tree_delete(&NATOutbound, t);
+    pico_free(t);
+    return NULL;
+  }
+
+  return t;
 }
 
-
-int pico_ipv4_nat_snif_backward(struct pico_nat_key *nk, struct pico_frame *f)
+static int pico_ipv4_nat_del(uint16_t nat_port, uint8_t proto)
 {
-  uint8_t proto;
-  struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
-  struct pico_tcp_hdr *tcp_hdr;
-
-  if (!ipv4_hdr)
-    return -1;
-  proto = ipv4_hdr->proto;
-
-  if (proto == PICO_PROTO_TCP) {
-    tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-    if (!tcp_hdr)
-      return -1;
-    if (tcp_hdr->flags & PICO_TCP_FIN) {
-      nk->del_flags |= PICO_DEL_FLAGS_FIN_BACKWARD; //FIN from backwarding packet
-    }
-    if (tcp_hdr->flags & PICO_TCP_SYN) {
-      nk->del_flags |= PICO_DEL_FLAGS_SYN;
-    }
-    if (tcp_hdr->flags & PICO_TCP_RST) {
-      nk->del_flags |= PICO_DEL_FLAGS_RST;
-    }
-  } else if (proto == PICO_PROTO_UDP) {
-    /* set conn active to 1 */
-    nk->del_flags &= 0xFE00; 
-    nk->del_flags++;
+  struct pico_nat_tuple *t = NULL;
+  t = pico_ipv4_nat_find_tuple(nat_port, NULL, 0, proto);
+  if (t) {
+    pico_tree_delete(&NATOutbound, t);
+    pico_tree_delete(&NATInbound, t);
+    pico_free(t);
   }
   return 0;
 }
 
-void pico_ipv4_nat_table_cleanup(unsigned long now, void *_unused)
+static struct pico_nat_tuple *pico_ipv4_nat_generate_tuple(struct pico_frame *f)
 {
-  struct pico_tree_node * idx, * safe;
-  struct pico_nat_key *k = NULL;
-    nat_dbg("NAT: before table cleanup:\n");
+  struct pico_trans *trans = NULL;
+  struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
+  uint16_t nport = 0;
+  uint8_t retry = 32;
+
+  /* generate NAT port */
+  do {
+    uint32_t rand = pico_rand();
+    nport = (uint16_t) (rand & 0xFFFFU);
+    nport = (uint16_t)(nport % (65535 - 1024)) + 1024U;
+		nport = short_be(nport);
+
+    if (pico_is_port_free(net->proto, nport, NULL, &pico_proto_ipv4))
+      break;
+  } while (--retry);
+
+  if (!retry)
+    return NULL;
+    
+  switch (net->proto) {
+    case PICO_PROTO_TCP:
+    {
+      struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
+      trans = &tcp->trans; 
+      break;
+    }
+    case PICO_PROTO_UDP:
+    {
+      struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
+      trans = &udp->trans;
+      break;
+    }
+    case PICO_PROTO_ICMP4:
+      /* XXX: implement */
+      break;
+
+    default:
+      return NULL;
+  }
+
+  return pico_ipv4_nat_add(net->dst, trans->dport, net->src, trans->sport, nat_link->address, nport, net->proto);
+  // XXX return pico_ipv4_nat_add(nat_link->address, port, net->src, trans->sport, net->proto);
+}
+
+static int pico_ipv4_nat_snif_session(struct pico_nat_tuple *t, struct pico_frame *f, uint8_t direction)
+{
+  struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr;
+ 
+  switch (net->proto) {
+    case PICO_PROTO_TCP:
+    {
+      struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
+      if (tcp->flags & PICO_TCP_SYN)
+        t->syn = 1;
+      if (tcp->flags & PICO_TCP_RST)
+        t->rst = 1;
+      if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_INBOUND))
+          t->fin_in = 1;
+      if ((tcp->flags & PICO_TCP_FIN) && (direction == PICO_NAT_OUTBOUND))
+          t->fin_out = 1;
+      break;
+    }
+
+    case PICO_PROTO_UDP:
+      t->conn_active = 1;
+      break;
+
+    case PICO_PROTO_ICMP4:
+      /* XXX: implement */
+      break;
+
+    default:
+      return -1;
+  }
+
+  return 0;
+}
+
+static void pico_ipv4_nat_table_cleanup(unsigned long now, void *_unused)
+{
+  struct pico_tree_node *index = NULL, *_tmp = NULL;
+  struct pico_nat_tuple *t = NULL;
+  IGNORE_PARAMETER(now);
+  IGNORE_PARAMETER(_unused);
+	nat_dbg("NAT: before table cleanup:\n");
   pico_ipv4_nat_print_table();
 
-  //struct pico_nat_key *tmp;
-  pico_tree_foreach_reverse_safe(idx,&KEYTable_forward,safe){
-      k = idx->keyValue;
-    switch (k->proto)
+  pico_tree_foreach_reverse_safe(index, &NATOutbound, _tmp)
+  {
+  	t = index->keyValue;
+    switch (t->proto)
     {
       case PICO_PROTO_TCP:
-        if ((k->del_flags & 0x0800) >> 11) {
-          /* entry is persistant */
+        if (t->portforward)
           break;
-        }
-        else if ((k->del_flags & 0x01FF) == 0) {
-          /* conn active is zero, delete entry */
-          pico_ipv4_nat_del(k->pub_port, k->proto);
-        }
-        else if ((k->del_flags & 0x1000) >> 12) {
-          /* RST flag set, set conn active to zero */
-          k->del_flags &= 0xFE00;
-        }
-        else if (((k->del_flags & 0x8000) >> 15) && ((k->del_flags & 0x4000) >> 14)) {
-          /* FIN1 and FIN2 set, set conn active to zero */
-          k->del_flags &= 0xFE00; 
-        }
-        else if ((k->del_flags & 0x01FF) > 360) {
-          /* conn is active for 24 hours, delete entry */
-          pico_ipv4_nat_del(k->pub_port, k->proto);
-        }
-        else {
-          k->del_flags++;
-        } 
+        else if (t->conn_active == 0 || t->conn_active > 360) /* conn active for > 24 hours */
+          pico_ipv4_nat_del(t->nat_port, t->proto);
+        else if (t->rst || (t->fin_in && t->fin_out))
+          t->conn_active = 0;
+        else
+          t->conn_active++;
         break;
 
       case PICO_PROTO_UDP:
-        if ((k->del_flags & 0x0800) >> 11) {
-          /* entry is persistant */
+        if (t->portforward)
           break;
-        }
-        else if ((k->del_flags & 0x01FF) > 1) {
-          /* Delete entry when it has existed NAT_TCP_TIMEWAIT */
-          pico_ipv4_nat_del(k->pub_port, k->proto);
-        }
-        else {
-          k->del_flags++;
-        }
+        else if (t->conn_active > 1)
+          pico_ipv4_nat_del(t->nat_port, t->proto);
+        else
+          t->conn_active++;
         break;
 
+      case PICO_PROTO_ICMP4:
+        if (t->conn_active > 1)
+          pico_ipv4_nat_del(t->nat_port, t->proto);
+        else
+          t->conn_active++;
+
       default:
-        /* Unknown protocol in NAT table, delete when it has existed NAT_TCP_TIMEWAIT */
-        if ((k->del_flags & 0x01FF) > 1) {
-          pico_ipv4_nat_del(k->pub_port, k->proto);
-        }
-        else {
-          k->del_flags++;
-        }
+        /* unknown protocol in NAT table, delete when it has existed NAT_TIMEWAIT */
+        if (t->conn_active > 1)
+          pico_ipv4_nat_del(t->nat_port, t->proto);
+        else
+          t->conn_active++;
     }
   }
 
   nat_dbg("NAT: after table cleanup:\n");
   pico_ipv4_nat_print_table();
-  pico_timer_add(NAT_TCP_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
-}
-
-int pico_ipv4_nat_add(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto)
-{
-  struct pico_nat_key *key = pico_zalloc(sizeof(struct pico_nat_key));
-  if (!key) {
-    pico_err = PICO_ERR_ENOMEM;
-    return -1;
-  }
-
-  key->pub_addr = pub_addr;
-  key->pub_port = pub_port;
-  key->priv_addr = priv_addr;
-  key->priv_port = priv_port;
-  key->proto = proto;
-  key->del_flags = 0x0001; /* set conn active to 1, other flags to 0 */
-
-  /* RB_INSERT returns NULL when element added, pointer to the element if already in tree */
-  if(!pico_tree_insert(&KEYTable_forward, key) && !pico_tree_insert(&KEYTable_backward, key)){
-    return 0; /* New element added */
-  }
-  else {
-    pico_free(key);
-    pico_err = PICO_ERR_EINVAL;
-    return -1; /* Element key already exists */
-  }
+  pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
 }
 
-
-int pico_ipv4_nat_del(uint16_t pub_port, uint8_t proto)
+int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag)
 {
-  struct pico_nat_key *key = NULL;
-  key = pico_ipv4_nat_find_key(pub_port, NULL, 0, proto);
-  if (!key) {
-    nat_dbg("NAT: key to delete not found: proto %u | pub_port %u\n", proto, pub_port);
-    return -1;
-  }
-  else {
-    nat_dbg("NAT: key to delete found: proto %u | pub_port %u\n", proto, pub_port);  
-    /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
-    if(pico_tree_delete(&KEYTable_forward, key) && pico_tree_delete(&KEYTable_backward, key))
-          pico_free(key);
-    else
-      return -1; /* Error on removing element, do not free! */
-  }
-  return 0;
-}
+  struct pico_nat_tuple *t = NULL;
+  struct pico_ip4 any_addr = {0};
+  uint16_t any_port = 0;
 
-int pico_ipv4_port_forward(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto, uint8_t persistant)
-{
-  struct pico_nat_key *key = NULL;
-
-  switch (persistant)
+  switch (flag)
   {
-    case PICO_IPV4_FORWARD_ADD:
-      if (pico_ipv4_nat_add(pub_addr, pub_port, priv_addr, priv_port, proto) != 0)
-        return -1;  /* pico_err set in nat_add */
-      key = pico_ipv4_nat_find_key(pub_port, &priv_addr, priv_port, proto);
-      if (!key) {
+    case PICO_NAT_PORT_FORWARD_ADD:
+      t = pico_ipv4_nat_add(any_addr, any_port, src_addr, src_port, nat_addr, nat_port, proto);
+      if (!t) {
         pico_err = PICO_ERR_EAGAIN;
         return -1;
       }
-      key->del_flags = (key->del_flags & ~(0x1 << 11)) | (persistant << 11);
+      t->portforward = 1;
       break;
 
-    case PICO_IPV4_FORWARD_DEL:
-      return pico_ipv4_nat_del(pub_port, proto);
+    case PICO_NAT_PORT_FORWARD_DEL:
+      return pico_ipv4_nat_del(nat_port, proto);
 
     default:
       pico_err = PICO_ERR_EINVAL;
       return -1;
   }
+
   pico_ipv4_nat_print_table();
   return 0;
 }
 
-
-void pico_ipv4_nat_print_table(void)
-{
-  struct pico_nat_key __attribute__((unused)) *k = NULL ;
-  struct pico_tree_node * index;
-  uint16_t i = 0;
-
-  nat_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
-  nat_dbg("+                                                       NAT table                                                       +\n");
-  nat_dbg("+-----------------------------------------------------------------------------------------------------------------------+\n");
-  nat_dbg("+  pointer   | private_addr | private_port | proto | pub_addr | pub_port | conn active | FIN1 | FIN2 | SYN | RST | PERS +\n");
-  nat_dbg("+-----------------------------------------------------------------------------------------------------------------------+\n");
-
-  pico_tree_foreach(index,&KEYTable_forward){
-      k = index->keyValue;
-    nat_dbg("+ %10p |   %08X   |    %05u     |  %04u | %08X |  %05u   |     %03u     |   %u  |   %u  |  %u  |  %u  |   %u  +\n", 
-           k, k->priv_addr.addr, k->priv_port, k->proto, k->pub_addr.addr, k->pub_port, (k->del_flags)&0x01FF, ((k->del_flags)&0x8000)>>15, 
-           ((k->del_flags)&0x4000)>>14, ((k->del_flags)&0x2000)>>13, ((k->del_flags)&0x1000)>>12, ((k->del_flags)&0x0800)>>11);
-    i++;
-  }
-  nat_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
-}
-
-int pico_ipv4_nat_generate_key(struct pico_nat_key* nk, struct pico_frame* f, struct pico_ip4 pub_addr)
+int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr)
 {
-  uint16_t pub_port = 0;
-  uint8_t proto;
-  struct pico_tcp_hdr *tcp_hdr = NULL;  /* forced to use pico_trans */
-  struct pico_udp_hdr *udp_hdr = NULL;  /* forced to use pico_trans */
-  struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
-  if (!ipv4_hdr)
+  struct pico_nat_tuple *tuple = NULL;
+  struct pico_trans *trans = NULL; 
+  struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr; 
+
+  if (!pico_ipv4_nat_is_enabled(link_addr))
     return -1;
-  proto = ipv4_hdr->proto;
-  do {
-    /* 1. generate valid new NAT port entry */
-    uint32_t rand = pico_rand();
-    pub_port = (uint16_t) (rand & 0xFFFFU);
-    pub_port = (uint16_t)(pub_port % (65535 - 1024)) + 1024U;
-        pub_port = short_be(pub_port);
 
-    /* 2. check if already in table, if no exit */
-    nat_dbg("NAT: check if generated port %u is free\n", short_be(pub_port));
-    if (pico_is_port_free(proto, pub_port, NULL, &pico_proto_ipv4))
+  switch (net->proto) {
+    case PICO_PROTO_TCP:
+    {
+      struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
+      trans = &tcp->trans;
+      tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
+      if (!tuple)
+        return -1;
+      /* replace dst IP and dst PORT */
+      net->dst = tuple->src_addr;
+      trans->dport = tuple->src_port;
+      /* recalculate CRC */
+      tcp->crc = 0;
+      tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
       break;
-  
-  } while (1);
-  nat_dbg("NAT: port %u is free\n", short_be(pub_port));
-    
-  if (proto == PICO_PROTO_TCP) {  
-    tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-    if (!tcp_hdr)
-      return -1;
-    nk->priv_port = tcp_hdr->trans.sport; 
-  } else if (proto == PICO_PROTO_UDP) {
-    udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
-    if (!udp_hdr)
-      return -1;
-    nk->priv_port = udp_hdr->trans.sport; 
-  } else if (proto == PICO_PROTO_ICMP4) {
-    nk->priv_port = (uint16_t)(ipv4_hdr->src.addr & 0x00FF); 
-    pub_port = (uint16_t)(ipv4_hdr->dst.addr & 0x00FF);
-    if (!pico_is_port_free(proto, pub_port, NULL, &pico_proto_ipv4))
+    }
+    case PICO_PROTO_UDP:
+    {
+      struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
+      trans = &udp->trans;
+      tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
+      if (!tuple)
+        return -1;
+      /* replace dst IP and dst PORT */
+      net->dst = tuple->src_addr;
+      trans->dport = tuple->src_port;
+      /* recalculate CRC */
+      udp->crc = 0;
+      udp->crc = short_be(pico_udp_checksum_ipv4(f));
+      break;
+    }
+    case PICO_PROTO_ICMP4:
+      /* XXX reimplement */
+      break;
+
+    default:
+      nat_dbg("NAT ERROR: inbound NAT on erroneous protocol\n");
       return -1;
   }
 
-  nk->pub_addr = pub_addr; /* get public ip address from device */
-  nk->pub_port = pub_port;
-  nk->priv_addr = ipv4_hdr->src;
-  nk->proto = ipv4_hdr->proto;
-  nk->del_flags = 0x0001; /* set conn active to 1 */
-  if (pico_ipv4_nat_add(nk->pub_addr, nk->pub_port, nk->priv_addr, nk->priv_port, nk->proto) < 0) {
-    return -1;
-  } else {
-    return 0;
-  }
-}
-
-
-static int pico_nat_tcp_checksum(struct pico_frame *f)
-{
-  struct pico_tcp_hdr *trans_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-  struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr;
-
-  struct tcp_pseudo_hdr_ipv4 pseudo;
-  if (!trans_hdr || !net_hdr)
-    return -1;
-
-  pseudo.src.addr = net_hdr->src.addr;
-  pseudo.dst.addr = net_hdr->dst.addr;
-  pseudo.res = 0;
-  pseudo.proto = PICO_PROTO_TCP;
-  pseudo.tcp_len = short_be(f->transport_len);
-
-  trans_hdr->crc = 0;
-  trans_hdr->crc = pico_dualbuffer_checksum(&pseudo, sizeof(struct tcp_pseudo_hdr_ipv4), trans_hdr, f->transport_len);
-  trans_hdr->crc = short_be(trans_hdr->crc);
-  return 0;
-}
-
+  pico_ipv4_nat_snif_session(tuple, f, PICO_NAT_INBOUND);
+  net->crc = 0;
+  net->crc = short_be(pico_checksum(net, f->net_len));
 
-int pico_ipv4_nat_translate(struct pico_nat_key* nk, struct pico_frame* f)
-{
-  uint8_t proto;
-  struct pico_tcp_hdr *tcp_hdr = NULL;  /* forced to use pico_trans */
-  struct pico_udp_hdr *udp_hdr = NULL;  /* forced to use pico_trans */
-
-  struct pico_ipv4_hdr* ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
-  if (!ipv4_hdr)
-    return -1;
-  proto = ipv4_hdr->proto;
-  
-  if (proto == PICO_PROTO_TCP) {
-    tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-    if (!tcp_hdr)
-      return -1;
-    tcp_hdr->trans.sport = nk->pub_port;
-  } else if (proto == PICO_PROTO_UDP) {  
-    udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
-    if (!udp_hdr)
-      return -1;
-    udp_hdr->trans.sport = nk->pub_port;
-  }
-
-  //if(f->proto == PICO_PROTO_ICMP){
-  //} XXX no action
-
-  ipv4_hdr->src = nk->pub_addr;
-
-  if (proto == PICO_PROTO_TCP) {
-    pico_nat_tcp_checksum(f);
-  } else if (proto == PICO_PROTO_UDP){
-    udp_hdr->crc = 0;
-    udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f));
-  }
-
-  // pico_ipv4_checksum(f);
-  ipv4_hdr->crc = 0;
-  ipv4_hdr->crc = short_be(pico_checksum(ipv4_hdr, f->net_len));
+  nat_dbg("NAT: inbound translation {dst.addr, dport}: {%08X,%u} -> {%08X,%u}\n", 
+            tuple->nat_addr.addr, short_be(tuple->nat_port), tuple->src_addr.addr, short_be(tuple->src_port));
 
   return 0;
 }
 
-
-int pico_ipv4_nat_port_forward(struct pico_frame* f)
+int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr)
 {
-  struct pico_nat_key *nk = NULL;
-  struct pico_tcp_hdr *tcp_hdr = NULL;
-  struct pico_udp_hdr *udp_hdr = NULL; 
-  struct pico_icmp4_hdr *icmp_hdr = NULL;
-  struct pico_ipv4_hdr* ipv4_hdr;
-  uint16_t pub_port = 0; 
-  uint8_t proto;
+  struct pico_nat_tuple *tuple = NULL;
+  struct pico_trans *trans = NULL; 
+  struct pico_ipv4_hdr *net = (struct pico_ipv4_hdr *)f->net_hdr; 
+
+  if (!pico_ipv4_nat_is_enabled(link_addr))
+    return -1;
 
-  ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr;
-  if (!ipv4_hdr)
-    return -1; 
-  proto = ipv4_hdr->proto; 
-  
-  if (proto == PICO_PROTO_TCP) {
-    tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-    if (!tcp_hdr)
-      return -1;
-    pub_port = tcp_hdr->trans.dport;  
-  } else if (proto == PICO_PROTO_UDP) {  
-    udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
-    if (!udp_hdr)
+  switch (net->proto) {
+    case PICO_PROTO_TCP:
+    {
+      struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
+      trans = &tcp->trans;
+      tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
+      if (!tuple)
+        tuple = pico_ipv4_nat_generate_tuple(f);
+      /* replace src IP and src PORT */
+      net->src = tuple->nat_addr;
+      trans->sport = tuple->nat_port;
+      /* recalculate CRC */
+      tcp->crc = 0;
+      tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
+      break;
+    }
+    case PICO_PROTO_UDP:
+    {
+      struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
+      trans = &udp->trans;
+      tuple = pico_ipv4_nat_find_tuple(0, &net->src, trans->sport, net->proto);
+      if (!tuple)
+        tuple = pico_ipv4_nat_generate_tuple(f);
+      /* replace src IP and src PORT */
+      net->src = tuple->nat_addr;
+      trans->sport = tuple->nat_port;
+      /* recalculate CRC */
+      udp->crc = 0;
+      udp->crc = short_be(pico_udp_checksum_ipv4(f));
+      break;
+    }
+    case PICO_PROTO_ICMP4:
+      /* XXX reimplement */
+      break;
+
+    default:
+      nat_dbg("NAT ERROR: outbound NAT on erroneous protocol\n");
       return -1;
-    pub_port = udp_hdr->trans.dport;
-  } else if (proto == PICO_PROTO_ICMP4) {
-    icmp_hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
-    if (!icmp_hdr)
-      return -1;
-    /* XXX PRELIMINARY ONLY LAST 16 BITS OF IP */
-    pub_port = (uint16_t)(ipv4_hdr->src.addr & 0x00FF);
-  }
-
-  nk = pico_ipv4_nat_find_key(pub_port, 0, 0, proto);
-
-  if (!nk) {
-    nat_dbg("\nNAT: ERROR key not found in table\n");
-    return -1;
-  } else {
-    pico_ipv4_nat_snif_forward(nk,f);
-    ipv4_hdr->dst.addr = nk->priv_addr.addr;
-
-    if (proto == PICO_PROTO_TCP) {
-       tcp_hdr->trans.dport = nk->priv_port;
-       pico_nat_tcp_checksum(f);
-    } else if (proto == PICO_PROTO_UDP) {
-      udp_hdr->trans.dport = nk->priv_port;
-      udp_hdr->crc = 0;
-      udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f));
-    }
   }
 
-  ipv4_hdr->crc = 0;
-  ipv4_hdr->crc = short_be(pico_checksum(ipv4_hdr, f->net_len));
- 
-  return 0; 
-}
-
-
-
-int pico_ipv4_nat(struct pico_frame *f, struct pico_ip4 pub_addr)
-{
-  /*do nat---------*/
-  struct pico_nat_key *nk = NULL;
-  struct pico_nat_key key;
-  struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr; 
-  struct pico_tcp_hdr *tcp_hdr = NULL;  
-  struct pico_udp_hdr *udp_hdr = NULL;  
-  int ret;
-  uint8_t proto = net_hdr->proto;
-  uint16_t priv_port = 0;
-  struct pico_ip4 priv_addr= net_hdr->src;
-
-  nk= &key;
+  pico_ipv4_nat_snif_session(tuple, f, PICO_NAT_OUTBOUND);
+  net->crc = 0;
+  net->crc = short_be(pico_checksum(net, f->net_len));
 
-  /* TODO DELME check if IN */
-  if (pub_addr.addr == net_hdr->dst.addr) {
-    nat_dbg("NAT: backward translation {dst.addr, dport}: {%08X,%u} ->", net_hdr->dst.addr, ((struct pico_trans *)f->transport_hdr)->dport);
-    ret = pico_ipv4_nat_port_forward(f);  /* our IN definition */
-    nat_dbg(" {%08X,%u}\n", net_hdr->dst.addr, short_be(((struct pico_trans *)f->transport_hdr)->dport));
-  } else {
-    if (net_hdr->proto == PICO_PROTO_TCP) {
-      tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-      priv_port = tcp_hdr->trans.sport;
-    } else if (net_hdr->proto == PICO_PROTO_UDP) {
-      udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
-      priv_port = udp_hdr->trans.sport;
-    } else if (net_hdr->proto == PICO_PROTO_ICMP4) {
-      //udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
-      priv_port = (uint16_t)(net_hdr->src.addr & 0x00FF);
-    }
+  nat_dbg("NAT: outbound translation {src.addr, sport}: {%08X,%u} -> {%08X,%u}\n", 
+            tuple->src_addr.addr, short_be(tuple->src_port), tuple->nat_addr.addr, short_be(tuple->nat_port));
 
-    ret = pico_ipv4_nat_find(0, &priv_addr, priv_port, proto);
-    if (ret >= 0) {
-      // Key is available in table
-      nk = pico_ipv4_nat_find_key(0, &priv_addr, priv_port, proto);
-    } else {
-      nat_dbg("NAT: key not found in NAT table -> generate key\n");
-      pico_ipv4_nat_generate_key(nk, f, pub_addr);
-    }
-    pico_ipv4_nat_snif_backward(nk,f);
-    nat_dbg("NAT: forward translation {src.addr, sport}: {%08X,%u} ->", net_hdr->src.addr, short_be(((struct pico_trans *)f->transport_hdr)->sport));
-    pico_ipv4_nat_translate(nk, f); /* our OUT definition */
-    nat_dbg(" {%08X,%u}\n", net_hdr->src.addr, short_be(((struct pico_trans *)f->transport_hdr)->sport));
-  } 
   return 0;
 }
 
-
 int pico_ipv4_nat_enable(struct pico_ipv4_link *link)
 {
   if (link == NULL) {
@@ -610,74 +476,25 @@
     return -1;
   }
 
-  pub_link = *link;
-  pico_timer_add(NAT_TCP_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
-  enable_nat_flag = 1;
+  nat_link = link;
+  pico_timer_add(PICO_NAT_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL);
   return 0;
 }
  
 int pico_ipv4_nat_disable(void)
 {
-  pub_link.address.addr = 0;
-  enable_nat_flag = 0;   
+  nat_link = NULL;
   return 0;
 }
 
-
-int pico_ipv4_nat_isenabled_out(struct pico_ipv4_link *link)
+int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr)
 {
-  if (enable_nat_flag) {
-    // is pub_link = *link
-    if (pub_link.address.addr == link->address.addr)
-      return 0;
-    else
-      return -1;
-  } else {
-    return -1;
-  }
+  if (!nat_link)
+    return 0;
+  if (nat_link->address.addr != link_addr->addr)
+    return 0;
+  return 1;
 }
 
-
-int pico_ipv4_nat_isenabled_in(struct pico_frame *f)
-{
-  if (enable_nat_flag) {
-    struct pico_tcp_hdr *tcp_hdr = NULL;
-    struct pico_udp_hdr *udp_hdr = NULL;
-    uint16_t pub_port = 0;
-    int ret;
-    uint8_t proto;
- 
-    struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *) f->net_hdr; 
-    if (!ipv4_hdr)
-      return -1;
-    proto = ipv4_hdr->proto;    
-
-    if (proto == PICO_PROTO_TCP) {
-      tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-      if (!tcp_hdr)
-        return -1;
-      pub_port= tcp_hdr->trans.dport;
-    } else if (proto == PICO_PROTO_UDP) {
-      udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
-      if (!udp_hdr)
-        return -1;
-      pub_port= udp_hdr->trans.dport;
-    } else if (proto == PICO_PROTO_ICMP4) {
-      //icmp_hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
-      //if (!icmp_hdr)
-      //  return -1;
-      /* XXX PRELIMINARY ONLY LAST 16 BITS OF IP */
-      pub_port = (uint16_t)(ipv4_hdr->src.addr & 0x00FF);
-    }
-    ret = pico_ipv4_nat_find(pub_port, NULL, 0, proto);
-    if (ret == 0)
-      return 0;
-    else
-      return -1;
-  } else {
-    return -1;    
-  }
-}
 #endif
 #endif
-
--- a/modules/pico_nat.h	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_nat.h	Mon Sep 02 08:02:21 2013 +0000
@@ -11,40 +11,29 @@
 #define _INCLUDE_PICO_NAT
 #include "pico_frame.h"
 
-#define PICO_DEL_FLAGS_FIN_FORWARD   (0x8000)
-#define PICO_DEL_FLAGS_FIN_BACKWARD  (0x4000)
-#define PICO_DEL_FLAGS_SYN           (0x2000)
-#define PICO_DEL_FLAGS_RST           (0x1000)
-
-#define PICO_IPV4_FORWARD_DEL 0
-#define PICO_IPV4_FORWARD_ADD 1
+#define PICO_NAT_PORT_FORWARD_DEL 0
+#define PICO_NAT_PORT_FORWARD_ADD 1
 
 #ifdef PICO_SUPPORT_NAT
 void pico_ipv4_nat_print_table(void);
-int pico_ipv4_nat_add(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto);
-int pico_ipv4_nat_del(uint16_t pub_port, uint8_t proto);
-int pico_ipv4_nat_find(uint16_t pub_port, struct pico_ip4 *priv_addr, uint16_t priv_port, uint8_t proto);
-int pico_ipv4_port_forward(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto, uint8_t persistant);
+int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto);
+int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag);
 
-int pico_ipv4_nat(struct pico_frame* f, struct pico_ip4 pub_addr);
+int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr);
+int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr);
 int pico_ipv4_nat_enable(struct pico_ipv4_link *link);
-int pico_ipv4_nat_isenabled_out(struct pico_ipv4_link *link);
-int pico_ipv4_nat_isenabled_in(struct pico_frame *f);
-
+int pico_ipv4_nat_disable(void);
+int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr);
 #else
 
-static inline int pico_ipv4_nat_isenabled_out(struct pico_ipv4_link *link)
-{
-  pico_err = PICO_ERR_EPROTONOSUPPORT;
-  return -1;
-}
-static inline int pico_ipv4_nat_isenabled_in(struct pico_frame *f)
+#define pico_ipv4_nat_print_table() do{}while(0)
+static inline int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr)
 {
   pico_err = PICO_ERR_EPROTONOSUPPORT;
   return -1;
 }
 
-static inline int pico_ipv4_nat(struct pico_frame* f, struct pico_ip4 pub_addr)
+static inline int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr)
 {
   pico_err = PICO_ERR_EPROTONOSUPPORT;
   return -1;
@@ -56,28 +45,25 @@
   return -1;
 }
 
-#define pico_ipv4_nat_print_table() do{}while(0)
-
-static inline int pico_ipv4_nat_add(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto)
+static inline int pico_ipv4_nat_disable(void)
 {
   pico_err = PICO_ERR_EPROTONOSUPPORT;
   return -1;
 }
 
-static inline int pico_ipv4_nat_del(uint16_t pub_port, uint8_t proto)
+static inline int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr)
 {
   pico_err = PICO_ERR_EPROTONOSUPPORT;
   return -1;
 }
 
-
-static inline int pico_ipv4_nat_find(uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto)
+static inline int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
 {
   pico_err = PICO_ERR_EPROTONOSUPPORT;
   return -1;
 }
 
-static inline int pico_ipv4_port_forward(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto, uint8_t persistant)
+static inline int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag)
 {
   pico_err = PICO_ERR_EPROTONOSUPPORT;
   return -1;
--- a/modules/pico_simple_http.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_simple_http.c	Mon Sep 02 08:02:21 2013 +0000
@@ -14,12 +14,12 @@
 /* The HTTP Server cannot be available without TCP support */
 #if (defined PICO_SUPPORT_HTTP) && (defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_TCP)
 
-#define HTTP_LISTEN_PORT    80u
-#define HTTP_BACKLOG             5u
+#define HTTP_LISTEN_PORT	80u
+#define HTTP_BACKLOG 			5u
 #define HTTP_HEADER_SIZE  256u
 
-#define HTTP_SUCCESS            0
-#define HTTP_ERROR                -1
+#define HTTP_SUCCESS			0
+#define HTTP_ERROR				-1
 
 static struct pico_socket * httpServer = NULL;
 static char   httpResponse[] =
@@ -35,92 +35,92 @@
 
 static void httpEventCbk(uint16_t ev, struct pico_socket *self)
 {
-    static struct pico_socket * client = NULL;
-    uint32_t peer;
-    uint16_t port;
-    int r;
-    char buffer[HTTP_HEADER_SIZE];
+	static struct pico_socket * client = NULL;
+	uint32_t peer;
+	uint16_t port;
+	int r;
+	char buffer[HTTP_HEADER_SIZE];
 
-    switch(ev)
-    {
-        case PICO_SOCK_EV_CONN :
-            if(!client)
-                client = pico_socket_accept(self, &peer, &port);
-            break;
+	switch(ev)
+	{
+		case PICO_SOCK_EV_CONN :
+			if(!client)
+				client = pico_socket_accept(self, &peer, &port);
+			break;
 
-        case PICO_SOCK_EV_RD:
-            // do not check http integrity, just mark that the http header has arrived
-            // prepare to send the response
-            r = pico_socket_recvfrom(self, buffer, HTTP_HEADER_SIZE, &peer, &port);
-            if(r>0 && memcmp(buffer,"GET",3u) == 0u)
-            { // it is an http header asking for data, return data and close
-                pico_socket_write(self,httpResponse,sizeof(httpResponse));
-                pico_socket_close(self);
-            }
-            else
-            {
-                // kill the connection, invalid header
-                pico_socket_close(self);
-            }
-            break;
+		case PICO_SOCK_EV_RD:
+			// do not check http integrity, just mark that the http header has arrived
+			// prepare to send the response
+			r = pico_socket_recvfrom(self, buffer, HTTP_HEADER_SIZE, &peer, &port);
+			if(r>0 && memcmp(buffer,"GET",3u) == 0u)
+			{ // it is an http header asking for data, return data and close
+				pico_socket_write(self,httpResponse,sizeof(httpResponse));
+				pico_socket_close(self);
+			}
+			else
+			{
+				// kill the connection, invalid header
+				pico_socket_close(self);
+			}
+			break;
 
-        case PICO_SOCK_EV_ERR:
-        case PICO_SOCK_EV_CLOSE:
-            // free the used socket
-            client = NULL;
-            break;
+		case PICO_SOCK_EV_ERR:
+		case PICO_SOCK_EV_CLOSE:
+			// free the used socket
+			client = NULL;
+			break;
 
-        default :
-            break;
-    }
+		default :
+			break;
+	}
 }
 
 int pico_startHttpServer(struct pico_ip4 * address)
 {
 
-    uint16_t localHttpPort = short_be(HTTP_LISTEN_PORT);
+	uint16_t localHttpPort = short_be(HTTP_LISTEN_PORT);
 
-    if(!pico_is_port_free(localHttpPort,PICO_PROTO_TCP, address, &pico_proto_ipv4))
-    {
-        pico_err = PICO_ERR_EADDRINUSE;
-        return HTTP_ERROR;
-    }
+	if(!pico_is_port_free(localHttpPort,PICO_PROTO_TCP, address, &pico_proto_ipv4))
+	{
+		pico_err = PICO_ERR_EADDRINUSE;
+		return HTTP_ERROR;
+	}
 
-    httpServer = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, httpEventCbk);
+	httpServer = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, httpEventCbk);
 
-    if(!httpServer)
-    {
-        pico_err = PICO_ERR_ENOMEM;
-        return HTTP_ERROR;
-    }
+	if(!httpServer)
+	{
+		pico_err = PICO_ERR_ENOMEM;
+		return HTTP_ERROR;
+	}
 
-    // both functions set the pico_err themselves.
-    if(pico_socket_bind(httpServer,address,&localHttpPort))
-        return HTTP_ERROR;
+	// both functions set the pico_err themselves.
+	if(pico_socket_bind(httpServer,address,&localHttpPort))
+		return HTTP_ERROR;
 
-    if(pico_socket_listen(httpServer,HTTP_BACKLOG))
-        return HTTP_ERROR;
+	if(pico_socket_listen(httpServer,HTTP_BACKLOG))
+		return HTTP_ERROR;
 
-    return HTTP_SUCCESS;
+	return HTTP_SUCCESS;
 }
 
 int pico_stopHttpServer(void)
 {
-    if(!httpServer)
-    {
-        pico_err = PICO_ERR_EINVAL;
-        return HTTP_ERROR;
-    }
+	if(!httpServer)
+	{
+		pico_err = PICO_ERR_EINVAL;
+		return HTTP_ERROR;
+	}
 
-    if(pico_socket_close(httpServer))
-    {
-        // no need to set the error here, function already set it
-        httpServer = NULL;
-        return HTTP_ERROR;
-    }
+	if(pico_socket_close(httpServer))
+	{
+		// no need to set the error here, function already set it
+		httpServer = NULL;
+		return HTTP_ERROR;
+	}
 
-    httpServer = NULL;
-    return HTTP_SUCCESS;
+	httpServer = NULL;
+	return HTTP_SUCCESS;
 }
 
 #endif
--- a/modules/pico_tcp.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_tcp.c	Mon Sep 02 08:02:21 2013 +0000
@@ -23,8 +23,8 @@
 
 #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_IW 		 2
+#define PICO_TCP_SYN_TO	 1000
 #define PICO_TCP_ZOMBIE_TO 30000
 
 #define PICO_TCP_MAX_CONNECT_RETRIES 7
@@ -54,8 +54,8 @@
 
 struct tcp_port_pair
 {
-    uint16_t local;
-    uint16_t remote;
+	uint16_t local;
+	uint16_t remote;
 };
 
 #ifdef PICO_SUPPORT_MUTEX
@@ -107,7 +107,7 @@
 static struct pico_frame *peek_segment(struct pico_tcp_queue *tq, uint32_t seq)
 {
   struct pico_tcp_hdr H;
-  struct pico_frame f = {};
+  struct pico_frame f = {0};
   f.transport_hdr = (uint8_t *) (&H);
   H.seq = long_be(seq);
 
@@ -128,13 +128,13 @@
 
 static int pico_enqueue_segment(struct pico_tcp_queue *tq, struct pico_frame *f)
 {
-    int ret = -1;
+	int ret = -1;
   if (f->payload_len <= 0) {
     tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n");
     //abort();
     return -1;
   }
-    LOCK(Mutex);
+	LOCK(Mutex);
   if ((tq->size + f->payload_len) > tq->max_size)
   {
     ret = 0;
@@ -229,8 +229,8 @@
 };
 
 /* Queues */
-static struct pico_queue tcp_in = {};
-static struct pico_queue tcp_out = {};
+static struct pico_queue tcp_in = {0};
+static struct pico_queue tcp_out = {0};
 
 /* If Nagle enabled, this function can make 1 new segment from smaller segments in hold queue */
 static struct pico_frame * pico_hold_segment_make(struct pico_socket_tcp *t);
@@ -311,6 +311,7 @@
 {
   struct pico_tcp_hdr *hdr;
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
+  IGNORE_PARAMETER(self);
   hdr = (struct pico_tcp_hdr *)f->transport_hdr;
 
   if (f->payload_len > 0) {
@@ -476,7 +477,7 @@
   struct pico_frame *f;
   struct pico_tree_node * index, * temp;
   int cmp;
-  int count = 0;
+  uint16_t count = 0;
 
   pico_tree_foreach_safe(index,&t->tcpq_out.pool,temp){
     f = index->keyValue;
@@ -531,7 +532,7 @@
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock;
   uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR;
-  int i = 0;
+  uint32_t i = 0;
   f->timestamp = 0;
   while (i < (f->transport_len - PICO_SIZE_TCPHDR)) {
     uint8_t type =  opt[i++];
@@ -720,7 +721,7 @@
       in_frame_off = 0;
       in_frame_len = f->payload_len;
     }
-    if ((in_frame_len + tot_rd_len) > len) {
+    if ((in_frame_len + tot_rd_len) > (uint32_t)len) {
       in_frame_len = len - tot_rd_len;
     }
 
@@ -731,7 +732,7 @@
     tot_rd_len += in_frame_len;
     t->rcv_processed += in_frame_len;
 
-    if ((in_frame_len == 0) || (in_frame_len == f->payload_len)) {
+    if ((in_frame_len == 0u) || (in_frame_len == (uint32_t)f->payload_len)) {
       pico_discard_segment(&t->tcpq_in, f);
     }
   }
@@ -748,6 +749,7 @@
 static void initconn_retry(unsigned long when, void *arg)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
+  IGNORE_PARAMETER(when);
   if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_SYN_SENT) {
     if (t->backoff > PICO_TCP_MAX_CONNECT_RETRIES) {
       tcp_dbg("TCP> Connection timeout. \n");
@@ -1255,56 +1257,56 @@
   unsigned long limit = val - t->rto;
   struct pico_tcp_hdr *hdr;
   if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED
-        || (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) )
+  		|| (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) )
   {
-        tcp_dbg("\n\nTIMEOUT! backoff = %d\n", t->backoff);
-        /* was timer cancelled? */
-        if (t->timer_running == 0) {
-            add_retransmission_timer(t, 0);
-            return;
-        }
-        t->timer_running--;
+		tcp_dbg("TIMEOUT! backoff = %d\n", t->backoff);
+		/* was timer cancelled? */
+		if (t->timer_running == 0) {
+			add_retransmission_timer(t, 0);
+			return;
+		}
+		t->timer_running--;
 
-        f = first_segment(&t->tcpq_out);
-        while (f) {
-            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;
-                    tcp_dbg("Mode: Blackout.\n");
-                    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: ENQUEUE to PROTO ( retransmit )*/
-                cpy = pico_frame_copy(f);
-                if (pico_enqueue(&tcp_out, cpy) > 0) {
-                    t->backoff++;
-                    add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick);
-                    tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
-                    return;
-                } else {
-                    add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick);
-                    pico_frame_discard(cpy);
-                }
-            }
-            f = next_segment(&t->tcpq_out, f);
-        }
-        t->backoff = 0;
-        add_retransmission_timer(t, 0);
-        if (t->tcpq_out.size < t->tcpq_out.max_size)
-             t->sock.ev_pending |= PICO_SOCK_EV_WR;
-        return;
-    }
+		f = first_segment(&t->tcpq_out);
+		while (f) {
+			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;
+					tcp_dbg("Mode: Blackout.\n");
+					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: ENQUEUE to PROTO ( retransmit )*/
+				cpy = pico_frame_copy(f);
+				if (pico_enqueue(&tcp_out, cpy) > 0) {
+					t->backoff++;
+					add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick);
+					tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
+					return;
+				} else {
+					add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick);
+					pico_frame_discard(cpy);
+				}
+			}
+			f = next_segment(&t->tcpq_out, f);
+		}
+		t->backoff = 0;
+		add_retransmission_timer(t, 0);
+		if (t->tcpq_out.size < t->tcpq_out.max_size)
+			 t->sock.ev_pending |= PICO_SOCK_EV_WR;
+		return;
+	}
 }
 
 static void add_retransmission_timer(struct pico_socket_tcp *t, unsigned long next_ts)
@@ -1404,7 +1406,7 @@
     tcp_dbg("%08x %d%s\n", cur, cur_f->payload_len, info);
 
   }
-  tcp_dbg("SND_NXT is %08x, snd_LAST is %08x", nxt, t->snd_last);
+  tcp_dbg("SND_NXT is %08x, snd_LAST is %08x\n", nxt, t->snd_last);
   tcp_dbg("===================================\n");
   tcp_dbg("\n\n");
 }
@@ -1416,7 +1418,7 @@
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
   struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
   uint32_t rtt = 0;
-  int acked = 0;
+  uint16_t acked = 0;
   struct pico_frame *una = NULL;
   if ((hdr->flags & PICO_TCP_ACK) == 0)
     return -1;
@@ -1558,7 +1560,8 @@
 
 static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f)
 {
-  tcp_dbg("RECEIVED ACK IN FIN_WAIT1\nTCP> IN STATE FIN_WAIT2\n");
+  tcp_dbg("RECEIVED ACK IN FIN_WAIT1\n");
+  tcp_dbg("TCP> IN STATE FIN_WAIT2\n");
 
   /* acking part */
   tcp_ack(s,f);
@@ -1572,6 +1575,8 @@
 static void tcp_deltcb(unsigned long when, void *arg)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg;
+  IGNORE_PARAMETER(when);
+
   if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_TIME_WAIT) {
     tcp_dbg("TCP> state: time_wait, final timer expired, going to closed state\n");
     /* update state */
@@ -1628,6 +1633,7 @@
 
 static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f)
 {
+	IGNORE_PARAMETER(f);
   tcp_dbg("TCP> state: last_ack, received ack, to closed\n");
   s->state &= 0x00FFU;
   s->state |= PICO_SOCKET_STATE_TCP_CLOSED;
@@ -1770,17 +1776,17 @@
     tcp_ack(s,f);
   if (seq_compare(SEQN(f), t->rcv_nxt) == 0) {
     /* received FIN, increase ACK nr */
-    t->rcv_nxt = long_be(hdr->seq) + 1;
-        s->state &= 0x00FFU;
-        s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT;
-        /* set SHUT_REMOTE */
+  	t->rcv_nxt = long_be(hdr->seq) + 1;
+		s->state &= 0x00FFU;
+		s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT;
+		/* set SHUT_REMOTE */
     s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
       tcp_dbg("TCP> Close-wait\n");
 
     if (s->wakeup){
       if(f->payload_len>0){
-        struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
-        t->sock.ev_pending |=PICO_SOCK_EV_CLOSE;
+        struct pico_socket_tcp *_t = (struct pico_socket_tcp *)s;
+        _t->sock.ev_pending |=PICO_SOCK_EV_CLOSE;
       }else
         s->wakeup(PICO_SOCK_EV_CLOSE, s);
     }
@@ -1798,6 +1804,7 @@
 static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
+  IGNORE_PARAMETER(f);
   tcp_dbg("TCP> Received FIN in FIN_WAIT1\n");
   s->state &= 0x00FFU;
   s->state |= PICO_SOCKET_STATE_TCP_CLOSING;
@@ -1811,6 +1818,8 @@
 static int tcp_finack(struct pico_socket *s, struct pico_frame *f)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
+  IGNORE_PARAMETER(f);
+
   tcp_dbg("TCP> ENTERED finack\n");
   t->rcv_nxt++;
   /* send ACK */
@@ -1989,40 +1998,42 @@
 static void tcp_send_keepalive(unsigned long when, void *_t)
 {
   struct pico_socket_tcp *t = (struct pico_socket_tcp *)_t;
-  tcp_dbg("\n\nSending keepalive (%d), [State = %d]...\n", t->backoff,t->sock.state );
+  IGNORE_PARAMETER(when);
+  tcp_dbg("Sending keepalive (%d), [State = %d]...\n", t->backoff,t->sock.state );
   if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED) )
   {
-        tcp_send_ack(t);
+		tcp_send_ack(t);
 
-        if (t->keepalive_timer_running > 0) {
-            t->keepalive_timer_running--;
-        }
+		if (t->keepalive_timer_running > 0) {
+			t->keepalive_timer_running--;
+		}
 
-        if (t->keepalive_timer_running == 0) {
-            t->keepalive_timer_running++;
-            tcp_dbg("[Self] Adding timer(retransmit keepalive)\n");
-            pico_timer_add(t->rto << (++t->backoff), tcp_send_keepalive, t);
-        }
+		if (t->keepalive_timer_running == 0) {
+			t->keepalive_timer_running++;
+			tcp_dbg("[Self] Adding timer(retransmit keepalive)\n");
+			pico_timer_add(t->rto << (++t->backoff), tcp_send_keepalive, t);
+		}
   }
 }
 
 void zombie_timer(unsigned long time, void *param)
 {
-    struct tcp_port_pair * ports = (struct tcp_port_pair *)param;
-    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);
-    }
+	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)
@@ -2094,9 +2105,9 @@
       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;
+    	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 */
@@ -2176,13 +2187,14 @@
   struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock;
   struct pico_frame *f_new;
   int total_len = 0;
+  IGNORE_PARAMETER(self);
 
   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;
 
-  if (f->payload_len > (t->tcpq_out.max_size - t->tcpq_out.size))
+  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);
 
   /***************************************************************************/
--- a/modules/pico_udp.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/modules/pico_udp.c	Mon Sep 02 08:02:21 2013 +0000
@@ -16,8 +16,8 @@
 
 
 /* Queues */
-static struct pico_queue udp_in = {};
-static struct pico_queue udp_out = {};
+static struct pico_queue udp_in = {0};
+static struct pico_queue udp_out = {0};
 
 
 /* Functions */
@@ -50,7 +50,8 @@
 
 static int pico_udp_process_out(struct pico_protocol *self, struct pico_frame *f)
 {
-  return pico_network_send(f); 
+	IGNORE_PARAMETER(self);
+	return pico_network_send(f);
 }
 
 static int pico_udp_push(struct pico_protocol *self, struct pico_frame *f)
@@ -77,7 +78,7 @@
     return f->payload_len;
   } else {
     return 0;
-  }    
+  }	
 }
 
 /* Interface: protocol definition */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_zmq.c	Mon Sep 02 08:02:21 2013 +0000
@@ -0,0 +1,472 @@
+/*********************************************************************
+PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+See LICENSE and COPYING for usage.
+
+Authors: Daniele Lacamera
+*********************************************************************/
+
+#include "pico_stack.h"
+#include "pico_config.h"
+#include "pico_ipv4.h"
+#include "pico_socket.h"
+#include "pico_zmq.h"
+
+#define MY_VERSION 1u
+
+ 
+enum zmq_state {
+  ST_OPEN = 0,
+  ST_CONNECTED,
+  ST_SIGNATURE,
+  ST_VERSION,
+  ST_GREETING,
+  ST_RDY,
+  ST_BUSY
+};
+
+enum zmq_role {
+  ROLE_NONE = 0,
+  ROLE_PUBLISHER,
+  ROLE_SUBSCRIBER
+};
+
+struct __attribute__((packed)) zmq_msg {
+   uint8_t flags;
+    uint8_t len;
+    char    txt[0];
+};
+
+struct zmq_socket;
+
+struct zmq_connector {
+  struct pico_socket *sock;
+  enum zmq_state state;
+  ZMQ parent;
+  enum zmq_role role;
+  uint8_t bytes_received;
+  struct zmq_connector *next;
+};
+
+struct zmq_socket {
+  struct pico_socket *sock;
+  void (*ready)(ZMQ z);
+  enum zmq_state state;
+  struct zmq_connector *subs;
+  enum zmq_role role;
+};
+
+static int zmq_socket_cmp(void *ka, void *kb)
+{
+  ZMQ a = ka;
+  ZMQ b = kb;
+  if (a->sock < b->sock)
+    return -1;
+  if (b->sock < a->sock)
+    return 1;
+  return 0;
+}
+PICO_TREE_DECLARE(zmq_sockets, zmq_socket_cmp);
+
+static inline ZMQ ZMTP(struct pico_socket *s)
+{
+  struct zmq_socket tst = { .sock = s };
+  return (pico_tree_findKey(&zmq_sockets, &tst));
+}
+
+static inline struct zmq_connector *find_subscriber(struct pico_socket *s)
+{
+  ZMQ search;
+  struct pico_tree_node *idx;
+  struct zmq_connector *el;
+  pico_tree_foreach(idx, &zmq_sockets) {
+    search = idx->keyValue;
+    el = search->subs;
+    while(el) {
+      if (el->sock == s)
+        return el;
+      el = el->next;
+    }
+  }
+  return NULL;
+}
+
+
+static void zmq_connector_add(ZMQ z, struct zmq_connector *zc)
+{
+  zc->next = z->subs;
+  z->subs = zc;
+  zc->parent = z;
+  dbg("Added connector %p, sock is %p\n", zc, zc->sock);
+}
+
+static void zmq_connector_del(struct zmq_connector *zc)
+{
+  ZMQ z = zc->parent;
+  if(z) {
+    struct zmq_connector *el = z->subs, *prev = NULL;      /* el = pointer to linked list */
+    while(el) {
+      if (el == zc) {               /* did we find the connector that we want to delete? */
+        if (prev)                   /* was there a previous list item? */
+          prev->next = zc->next;    /* link the linked list again */
+        else
+          z->subs = zc->next;       /* we were at the beginning of the list */
+        break;
+      }
+      prev = el;
+      el = el->next;
+    }
+  }
+  pico_socket_close(zc->sock);
+  pico_free(zc);
+}
+
+static void zmq_check_state(ZMQ z) 
+{
+  struct zmq_connector *c = z->subs;
+  enum zmq_state default_state, option_state;
+  if ((z->state != ST_RDY) && (z->state != ST_BUSY))
+    return;
+  if (z->role == ROLE_SUBSCRIBER) {
+    default_state = ST_RDY;
+    option_state = ST_BUSY;
+  } else {
+    default_state = ST_BUSY;
+    option_state = ST_RDY;
+  }
+  z->state = default_state;
+  while(c) {
+    if (c->state == option_state) {
+      z->state = option_state;
+      return;
+    }
+    c = c->next;
+  }
+}
+
+
+static void zmq_hs_connected(struct zmq_connector *z)
+{
+  /* v2 signature */
+  uint8_t my_signature[14] =  {0xff, 0, 0, 0, 0, 0, 0, 0, 1, 0x7f, 1, 1, 0, 0};
+
+//  uint8_t my_ver[2] = {MY_VERSION, 0};
+//  uint8_t my_greeting[52] = {'N','U','L','L', 0};
+
+  pico_socket_write(z->sock, my_signature, 14);
+//  pico_socket_write(z->sock, my_ver, 2);
+
+//  if (MY_VERSION > 2)
+//    pico_socket_write(z->sock, my_greeting, 52);
+
+  z->state = ST_SIGNATURE;
+//  z->state = ST_RDY;
+}
+ 
+static void zmq_hs_signature(struct zmq_connector *zc)
+{
+  uint8_t incoming[20];
+  int ret;
+  
+  ret = pico_socket_read(zc->sock, incoming, 14);
+  if (zc->bytes_received == 0 && ret > 0 &&  incoming[0] != 0xFF) {
+    //dbg("Received invalid signature: [0]!=0xFF\n");
+    zmq_connector_del(zc);
+  }
+  zc->bytes_received += ret;
+  if (zc->bytes_received < 14) {
+    //dbg("Waiting for the rest of the sig - got %u bytes\n",zc->bytes_received);
+    return;
+  }
+
+  //dbg("Valid signature received. len = %d, first byte: %02x\n", ret, incoming[0]);
+  zc->state = ST_RDY;
+}
+ 
+static void zmq_hs_version(struct zmq_connector *zc)
+{
+  uint8_t incoming[20];
+  int ret;
+  ret = pico_socket_read(zc->sock, incoming, 2);
+  if (ret < 0) {
+    dbg("Cannot exchange valid version information. Read returned -1\n");
+    zmq_connector_del(zc);
+    return;
+  }
+  if (ret == 0)
+     return;
+/* Version check?    
+  if (incoming[0] != 3) {
+    dbg("Version %d.x not supported by this publisher\n", incoming[0]);
+    zmq_connector_del(zc);
+    return;
+  }
+  dbg("Subscriber is using version 3. Good!\n");
+*/
+  dbg("Subscriber is using version %d. Good!\n", incoming[0]);
+  if (incoming[0] == 3)
+    zc->state = ST_GREETING;
+  else
+    zc->state = ST_RDY;
+}
+ 
+static void zmq_hs_greeting(struct zmq_connector *zc)
+{
+  uint8_t incoming[64];
+  int ret;
+  ret = pico_socket_read(zc->sock, incoming, 64);
+  dbg("zmq_socket_read in greeting returned %d\n", ret);    
+  if (ret == 0)
+   return;  
+  if (ret < 0) {
+    dbg("Cannot retrieve valid greeting\n");
+    zmq_connector_del(zc);
+    return;
+  }
+  zc->state = ST_RDY;
+  zmq_check_state(zc->parent);
+  dbg("Paired. Sending Ready.\n");
+  pico_socket_write(zc->sock, "READY   ",8);
+}
+
+static void zmq_hs_rdy(struct zmq_connector *zc)
+{
+    int ret;
+    uint8_t incoming[258];
+    if (zc->role == ROLE_SUBSCRIBER)
+      return;
+    ret = pico_socket_read(zc->sock, incoming, 258);
+    dbg("Got %d bytes from subscriber whilst in rdy state.\n", ret);
+}
+
+static void zmq_hs_busy(struct zmq_connector *zc)
+{
+  int was_busy = 0;
+  if (zc->parent->state == ST_BUSY)
+    was_busy = 1;
+  zmq_check_state(zc->parent);
+  if (was_busy && (zc->parent->state == ST_RDY) && zc->parent->ready)
+    zc->parent->ready(zc->parent);
+}
+ 
+static void(*zmq_hs_cb[])(struct zmq_connector *) = {
+    NULL,
+    zmq_hs_connected,
+    zmq_hs_signature,
+    zmq_hs_version,
+    zmq_hs_greeting,
+    zmq_hs_rdy,
+    zmq_hs_busy
+};
+
+
+static void cb_tcp0mq(uint16_t ev, struct pico_socket *s)
+{
+  struct pico_ip4 orig;
+  uint16_t port;
+  char peer[30];
+  struct zmq_connector *z_a, *zc;
+  ZMQ z = ZMTP(s);
+  
+  /* Publisher. Accepting new subscribers */
+  if (z) {
+    if (ev & PICO_SOCK_EV_CONN) { 
+      z_a = pico_zalloc(sizeof(struct zmq_socket));
+      if (z_a == NULL)
+        return;
+      
+      z_a->sock = pico_socket_accept(s, &orig, &port);
+      pico_ipv4_to_string(peer, orig.addr);
+      dbg("tcp0mq> Connection requested by %s:%u.\n", peer, short_be(port));
+      if (z->state == ST_OPEN) {
+          dbg("tcp0mq> Accepted connection! New subscriber on sock %p.\n",z_a->sock);
+          zmq_connector_add(z, z_a);
+          z_a->role = ROLE_PUBLISHER;
+          z_a->state = ST_CONNECTED;
+          zmq_hs_connected(z_a);
+      } else {
+          dbg("tcp0mq> Server busy, connection rejected\n");
+          pico_socket_close(z_a->sock);
+      }
+    }
+    return;
+  }
+
+  zc = find_subscriber(s);
+  if (!zc) {
+    dbg("Cannot find subscriber with socket %p, ev = %d!\n", s, ev);
+//    pico_socket_close(s);
+    return;
+  }
+
+  if ((ev & PICO_SOCK_EV_CONN) && zc->role == ROLE_SUBSCRIBER && zc->state == ST_OPEN)
+  {
+     zc->state = ST_CONNECTED;
+     zmq_hs_connected(zc);
+  }
+
+
+  if (ev & PICO_SOCK_EV_RD) {
+    if (zmq_hs_cb[zc->state])
+      zmq_hs_cb[zc->state](zc);
+  }
+
+  if ((ev & PICO_SOCK_EV_WR) && zc->parent && (zc->parent->role == ROLE_PUBLISHER) && (zc->state == ST_BUSY)) {
+    if (zmq_hs_cb[zc->state])
+      zmq_hs_cb[zc->state](zc);
+  }
+ 
+ 
+  if (ev & PICO_SOCK_EV_FIN) {
+    dbg("tcp0mq> Connection closed.\n");
+    zmq_connector_del(zc);
+  }
+ 
+  if (ev & PICO_SOCK_EV_ERR) {
+    dbg("tcp0mq> Socket Error received: %s. Bailing out.\n", strerror(pico_err));
+    zmq_connector_del(zc);
+  }
+ 
+  if (ev & PICO_SOCK_EV_CLOSE) {
+    dbg("tcp0mq> event close\n");
+    zmq_connector_del(zc);
+  }
+ 
+}
+
+ZMQ zmq_subscriber(void (*cb)(ZMQ z))
+{
+  ZMQ z = pico_zalloc(sizeof(struct zmq_socket));
+  if (!z) {
+    pico_err = PICO_ERR_ENOMEM;
+    return NULL;
+  }
+  z->state = ST_BUSY;
+  z->ready = cb;
+  z->role = ROLE_SUBSCRIBER;
+  pico_tree_insert(&zmq_sockets, z);
+  return z;
+}
+
+int zmq_connect(ZMQ z, char *address, uint16_t port) 
+{
+  struct pico_ip4 ip;
+  struct zmq_connector *z_c;
+  if (pico_string_to_ipv4(address, &ip.addr) < 0) {
+    dbg("FIXME!! I need to synchronize with the dns client to get to my publisher :(\n");
+    return -1;
+  }
+
+  z_c = pico_zalloc(sizeof(struct zmq_connector));
+  if (!z_c)
+    return -1;
+  z_c->role = ROLE_SUBSCRIBER;
+  z_c->state = ST_OPEN;
+  z_c->sock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcp0mq);
+  if (!z_c->sock) {
+    pico_free(z_c);
+    return -1;
+  }
+  if (pico_socket_connect(z_c->sock, &ip, short_be(port)) < 0)
+    return -1;
+  zmq_connector_add(z, z_c);
+  return 0;
+}
+
+ZMQ zmq_publisher(uint16_t _port, void (*cb)(ZMQ z))
+{
+  struct pico_socket *s;
+  struct pico_ip4 inaddr_any = {0};
+  uint16_t port = short_be(_port);
+  ZMQ z = NULL;
+  s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &cb_tcp0mq);
+  if (!s)
+    return NULL;
+ 
+  dbg("zmq_publisher: BIND\n");
+  if (pico_socket_bind(s, &inaddr_any, &port)!= 0) {
+    dbg("zmq publisher: BIND failed\n");
+    return NULL;
+  }
+  if (pico_socket_listen(s, 2) != 0) {
+    dbg("zmq publisher: LISTEN failed\n");
+    return NULL;
+  }
+  dbg("zmq_publisher: Active and bound to local port %d\n", short_be(port));
+
+  z = pico_zalloc(sizeof(struct zmq_socket));
+  if (!z) {
+    pico_socket_close(s);
+    pico_err = PICO_ERR_ENOMEM;
+    return NULL;
+  }
+  z->sock = s;
+  z->state = ST_OPEN;
+  z->ready = cb;
+  z->role = ROLE_PUBLISHER;
+  z->subs = NULL;
+  pico_tree_insert(&zmq_sockets, z);
+  dbg("zmq publisher created.\n");
+  return z;
+}
+
+int zmq_send(ZMQ z, char *txt, int len)
+{
+    struct zmq_msg *msg;
+    struct zmq_connector *c = z->subs;
+    int ret = 0;
+
+    if (!c) 
+    {
+        dbg("no subscribers, bailing out\n");
+        return 0; /* Need at least one subscriber */
+    }
+    msg = pico_zalloc(len + 2);
+    msg->flags = 4;
+    msg->len = (uint8_t) len;
+    memcpy(msg->txt, txt, len);
+
+    while (c) {
+      dbg("write to %u\n",c->state);
+      if ((ST_RDY == c->state) && (pico_socket_write(c->sock, msg, len + 2) > 0))
+        ret++;
+      c = c->next;
+    }
+    pico_free(msg);
+    return ret;
+}
+
+int zmq_recv(ZMQ z, char *txt)
+{
+  int ret;
+  struct zmq_msg msg;
+  struct zmq_connector *nxt, *c = z->subs;
+  if (z->state != ST_RDY)
+    return 0;
+  while (c) {
+    nxt = c->next;
+    ret = pico_socket_read(c->sock, &msg, 2);
+    if (ret < 0) {
+      dbg("Error reading!\n");
+      zmq_connector_del(c);
+    } else if (ret < 2) {
+      c->state = ST_BUSY;
+    } else {
+      return pico_socket_read(c->sock, txt, msg.len);
+    }
+    c = nxt;
+  }
+  zmq_check_state(z);
+  return 0;
+}
+
+void zmq_close(ZMQ z)
+{
+  struct zmq_connector *nxt, *c = z->subs;
+  while(c) {
+    nxt = c->next;
+    zmq_connector_del(c);
+    c = nxt;
+  }
+  pico_socket_close(z->sock);
+  pico_free(z); 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_zmq.h	Mon Sep 02 08:02:21 2013 +0000
@@ -0,0 +1,14 @@
+#ifndef __PICO_ZMQ_H
+#define __PICO_ZMQ_H
+
+struct zmq_socket;
+typedef struct zmq_socket *ZMQ; 
+
+ZMQ zmq_publisher(uint16_t _port, void (*cb)(ZMQ z));
+ZMQ zmq_subscriber(void (*cb)(ZMQ z));
+int zmq_connect(ZMQ z, char *address, uint16_t port);
+int zmq_send(ZMQ z, char *txt, int len);
+int zmq_recv(ZMQ z, char *txt);
+void zmq_close(ZMQ z);
+
+#endif
--- a/stack/pico_arp.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/stack/pico_arp.c	Mon Sep 02 08:02:21 2013 +0000
@@ -20,9 +20,9 @@
 #define PICO_ARP_RETRY 300
 
 #ifdef DEBUG_ARP
-    #define arp_dbg dbg
+	#define arp_dbg dbg
 #else
-    #define arp_dbg(...) do{}while(0)
+	#define arp_dbg(...) do{}while(0)
 #endif
 
 static struct pico_queue pending;
@@ -31,6 +31,8 @@
 void check_pending(unsigned long now, void *_unused)
 {
   struct pico_frame *f = pico_dequeue(&pending);
+  IGNORE_PARAMETER(now);
+  IGNORE_PARAMETER(_unused);
   if (!f) {
     pending_timer_on = 0;
     return;
@@ -80,7 +82,7 @@
 
 static int arp_compare(void * ka, void * kb)
 {
-    struct pico_arp *a = ka, *b = kb;
+	struct pico_arp *a = ka, *b = kb;
   if (a->ipv4.addr < b->ipv4.addr)
     return -1;
   else if (a->ipv4.addr > b->ipv4.addr)
@@ -109,7 +111,7 @@
   struct pico_arp* search;
   struct pico_tree_node * index;
   pico_tree_foreach(index,&arp_tree){
-      search = index->keyValue;
+  	search = index->keyValue;
     if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0)
       return &search->ipv4;
   }
@@ -164,7 +166,7 @@
   struct pico_tree_node * index;
 
   pico_tree_foreach(index,&arp_tree) {
-      a = index->keyValue;
+  	a = index->keyValue;
     arp_dbg("ARP to  %08x, mac: %02x:%02x:%02x:%02x:%02x:%02x\n", a->ipv4.addr,a->eth.addr[0],a->eth.addr[1],a->eth.addr[2],a->eth.addr[3],a->eth.addr[4],a->eth.addr[5] );
   }
 }
@@ -173,6 +175,7 @@
 void arp_expire(unsigned long now, void *_stale)
 {
   struct pico_arp *stale = (struct pico_arp *) _stale;
+  IGNORE_PARAMETER(now);
   stale->arp_status = PICO_ARP_STATUS_STALE;
   arp_dbg("ARP: Setting arp_status to STALE\n");
   pico_arp_query(stale->dev, &stale->ipv4);
@@ -191,18 +194,18 @@
 
 int pico_arp_create_entry(uint8_t* hwaddr, struct pico_ip4 ipv4, struct pico_device* dev)
 {
-    struct pico_arp* arp = pico_zalloc(sizeof(struct pico_arp));
-    if(!arp){
-        pico_err = PICO_ERR_ENOMEM;
-        return -1;
-    }
-    memcpy(arp->eth.addr, hwaddr, 6);
-    arp->ipv4.addr = ipv4.addr;
-    arp->dev = dev;
+	struct pico_arp* arp = pico_zalloc(sizeof(struct pico_arp));
+	if(!arp){
+		pico_err = PICO_ERR_ENOMEM;
+		return -1;
+	}
+	memcpy(arp->eth.addr, hwaddr, 6);
+	arp->ipv4.addr = ipv4.addr;
+	arp->dev = dev;
 
-    pico_arp_add_entry(arp);
+	pico_arp_add_entry(arp);
 
-    return 0;
+	return 0;
 }
 
 int pico_arp_receive(struct pico_frame *f)
--- a/stack/pico_device.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/stack/pico_device.c	Mon Sep 02 08:02:21 2013 +0000
@@ -17,7 +17,7 @@
 
 static int pico_dev_cmp(void *ka, void *kb)
 {
-    struct pico_device *a = ka, *b = kb;
+	struct pico_device *a = ka, *b = kb;
   if (a->hash < b->hash)
     return -1;
   if (a->hash > b->hash)
@@ -29,9 +29,9 @@
 
 int pico_device_init(struct pico_device *dev, char *name, uint8_t *mac)
 {
-    int len = strlen(name);
-    if(len>MAX_DEVICE_NAME)
-        len = MAX_DEVICE_NAME;
+	int len = strlen(name);
+	if(len>MAX_DEVICE_NAME)
+		len = MAX_DEVICE_NAME;
   memcpy(dev->name, name, len);
   dev->hash = pico_hash(dev->name);
 
@@ -158,18 +158,18 @@
     next_in = in_node->keyValue;
   }
   if (next_out == NULL) {
-      out_node = pico_tree_firstNode(Device_tree.root);
+  	out_node = pico_tree_firstNode(Device_tree.root);
     next_out = out_node->keyValue;
   }
   
   if (direction == PICO_LOOP_DIR_IN)
   {
-      next_node = in_node;
+  	next_node = in_node;
     next = next_in;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-      next_node = out_node;
+  	next_node = out_node;
     next = next_out;
   }
 
@@ -185,7 +185,7 @@
 
     if (next == NULL)
     {
-        next_node = pico_tree_firstNode(Device_tree.root);
+    	next_node = pico_tree_firstNode(Device_tree.root);
       next = next_node->keyValue;
     }
     if (next == start)
@@ -194,12 +194,12 @@
 
   if (direction == PICO_LOOP_DIR_IN)
   {
-      in_node = next_node;
+  	in_node = next_node;
     next_in = next;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-      out_node = next_node;
+  	out_node = next_node;
     next_out = next;
   }
 
@@ -211,7 +211,7 @@
   struct pico_device *dev;
   struct pico_tree_node * index;
   pico_tree_foreach(index, &Device_tree){
-      dev = index->keyValue;
+  	dev = index->keyValue;
     if(strcmp(name, dev->name) == 0)
       return dev;
   }
@@ -220,27 +220,27 @@
 
 int pico_device_broadcast(struct pico_frame * f)
 {
-    struct pico_tree_node * index;
-    int ret = -1;
+	struct pico_tree_node * index;
+	int ret = -1;
 
-    pico_tree_foreach(index,&Device_tree)
-    {
-        struct pico_device * dev = index->keyValue;
-        if(dev != f->dev)
-        {
-            struct pico_frame * copy = pico_frame_copy(f);
+	pico_tree_foreach(index,&Device_tree)
+	{
+		struct pico_device * dev = index->keyValue;
+		if(dev != f->dev)
+		{
+			struct pico_frame * copy = pico_frame_copy(f);
 
-            if(!copy)
-                return -1;
-            copy->dev = dev;
-            copy->dev->send(copy->dev, copy->start, copy->len);
-            pico_frame_discard(copy);
-        }
-        else
-        {
-            ret = f->dev->send(f->dev, f->start, f->len);
-        }
-    }
+			if(!copy)
+				return -1;
+			copy->dev = dev;
+			copy->dev->send(copy->dev, copy->start, copy->len);
+			pico_frame_discard(copy);
+		}
+		else
+		{
+			ret = f->dev->send(f->dev, f->start, f->len);
+		}
+	}
 
-    return ret;
+	return ret;
 }
--- a/stack/pico_frame.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/stack/pico_frame.c	Mon Sep 02 08:02:21 2013 +0000
@@ -103,7 +103,7 @@
   new->usage_count = uc;
 
   /* Update in-buffer pointers with offset */
-  addr_diff = (int)new->buffer - (int)f->buffer;
+  addr_diff = (int)(new->buffer - f->buffer);
   new->net_hdr += addr_diff;
   new->transport_hdr += addr_diff;
   new->app_hdr += addr_diff;
--- a/stack/pico_protocol.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/stack/pico_protocol.c	Mon Sep 02 08:02:21 2013 +0000
@@ -13,7 +13,7 @@
 
 static int pico_proto_cmp(void *ka, void *kb)
 {
-    struct pico_protocol *a = ka, *b=kb;
+	struct pico_protocol *a = ka, *b=kb;
   if (a->hash < b->hash)
     return -1;
   if (a->hash > b->hash)
@@ -67,7 +67,7 @@
   static struct pico_tree_node * next_node, * in_node, * out_node;
 
   if (next_in == NULL) {
-      in_node = pico_tree_firstNode(Datalink_proto_tree.root);
+  	in_node = pico_tree_firstNode(Datalink_proto_tree.root);
     if (in_node)
       next_in = in_node->keyValue;
   }
@@ -79,12 +79,12 @@
   
   if (direction == PICO_LOOP_DIR_IN)
   {
-      next_node = in_node;
+  	next_node = in_node;
     next = next_in;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-      next_node = out_node;
+  	next_node = out_node;
     next = next_out;
   }
 
@@ -101,8 +101,8 @@
 
     if (next == NULL)
     {
-        next_node = pico_tree_firstNode(Datalink_proto_tree.root);
-        next = next_node->keyValue;
+    	next_node = pico_tree_firstNode(Datalink_proto_tree.root);
+    	next = next_node->keyValue;
     }
     if (next == start)
       break;
@@ -110,12 +110,12 @@
 
   if (direction == PICO_LOOP_DIR_IN)
   {
-      in_node = next_node;
+  	in_node = next_node;
     next_in = next;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-      out_node = next_node;
+  	out_node = next_node;
     next_out = next;
   }
 
@@ -137,18 +137,18 @@
       next_in = in_node->keyValue;
   }
   if (next_out == NULL) {
-      out_node = pico_tree_firstNode(Network_proto_tree.root);
+  	out_node = pico_tree_firstNode(Network_proto_tree.root);
     if (out_node)
-        next_out = out_node->keyValue;
+  	  next_out = out_node->keyValue;
   }
   if (direction == PICO_LOOP_DIR_IN)
   {
-      next_node = in_node;
+  	next_node = in_node;
     next = next_in;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-      next_node = out_node;
+  	next_node = out_node;
     next = next_out;
   }
 
@@ -164,8 +164,8 @@
 
     if (next == NULL)
     {
-        next_node = pico_tree_firstNode(Network_proto_tree.root);
-        next = next_node->keyValue;
+    	next_node = pico_tree_firstNode(Network_proto_tree.root);
+    	next = next_node->keyValue;
     }
     if (next == start)
       break;
@@ -173,12 +173,12 @@
 
   if (direction == PICO_LOOP_DIR_IN)
   {
-      in_node = next_node;
+  	in_node = next_node;
     next_in = next;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-      out_node = next_node;
+  	out_node = next_node;
     next_out = next;
   }
 
@@ -194,24 +194,24 @@
   static struct pico_tree_node * next_node, * in_node, * out_node;
 
   if (next_in == NULL) {
-      in_node = pico_tree_firstNode(Transport_proto_tree.root);
+  	in_node = pico_tree_firstNode(Transport_proto_tree.root);
     if (in_node)
-        next_in = in_node->keyValue;
+    	next_in = in_node->keyValue;
   }
   if (next_out == NULL) {
-      out_node = pico_tree_firstNode(Transport_proto_tree.root);
+  	out_node = pico_tree_firstNode(Transport_proto_tree.root);
     if (out_node)
-        next_out = out_node->keyValue;
+  	  next_out = out_node->keyValue;
   }
   
   if (direction == PICO_LOOP_DIR_IN)
   {
-      next_node = in_node;
+  	next_node = in_node;
     next = next_in;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-      next_node = out_node;
+  	next_node = out_node;
     next = next_out;
   }
 
@@ -228,8 +228,8 @@
 
     if (next == NULL)
     {
-        next_node = pico_tree_firstNode(Transport_proto_tree.root);
-        next = next_node->keyValue;
+    	next_node = pico_tree_firstNode(Transport_proto_tree.root);
+    	next = next_node->keyValue;
     }
     if (next == start)
       break;
@@ -237,12 +237,12 @@
 
   if (direction == PICO_LOOP_DIR_IN)
   {
-      in_node = next_node;
+  	in_node = next_node;
     next_in = next;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-      out_node = next_node;
+  	out_node = next_node;
     next_out = next;
   }
 
@@ -259,25 +259,25 @@
   static struct pico_tree_node * next_node, * in_node, * out_node;
 
   if (next_in == NULL) {
-      in_node = pico_tree_firstNode(Socket_proto_tree.root);
+  	in_node = pico_tree_firstNode(Socket_proto_tree.root);
     if(in_node)
-        next_in = in_node->keyValue;
+  	  next_in = in_node->keyValue;
   }
   if (next_out == NULL) {
-      out_node = pico_tree_firstNode(Socket_proto_tree.root);
+  	out_node = pico_tree_firstNode(Socket_proto_tree.root);
     if(out_node)
       next_out = out_node->keyValue;
   }
   
   if (direction == PICO_LOOP_DIR_IN)
   {
-      next_node = in_node;
+  	next_node = in_node;
     next = next_in;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-         next_node = out_node;
-      next = next_out;
+	 	next_node = out_node;
+  	next = next_out;
   }
 
   /* init start node */
@@ -293,7 +293,7 @@
     if (next == NULL)
     {
       next_node = pico_tree_firstNode(next_node);
-        next = next_node->keyValue;
+    	next = next_node->keyValue;
     }
     if (next == start)
       break;
@@ -301,12 +301,12 @@
 
   if (direction == PICO_LOOP_DIR_IN)
   {
-      in_node = next_node;
+  	in_node = next_node;
     next_in = next;
   }
   else if (direction == PICO_LOOP_DIR_OUT)
   {
-      out_node = next_node;
+  	out_node = next_node;
     next_out = next;
   }
 
--- a/stack/pico_socket.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/stack/pico_socket.c	Mon Sep 02 08:02:21 2013 +0000
@@ -461,7 +461,7 @@
 
   /* IPv4 */
 #ifdef PICO_SUPPORT_NAT
-  if (pico_ipv4_nat_find(port,NULL, 0,proto) == 0) {
+  if (pico_ipv4_nat_find(port, NULL, 0, proto)) {
     dbg("In use by nat....\n");
     return 0;
   }
@@ -518,24 +518,24 @@
 
 struct pico_socket* pico_sockets_find(uint16_t local,uint16_t remote)
 {
-    struct pico_socket * sock = NULL;
-    struct pico_tree_node *index = NULL;
-    struct pico_sockport *sp = NULL;
+	struct pico_socket * sock = NULL;
+	struct pico_tree_node *index = NULL;
+	struct pico_sockport *sp = NULL;
 
-    sp = pico_get_sockport(PICO_PROTO_TCP,local);
-    if(sp)
-    {
-        pico_tree_foreach(index,&sp->socks)
-        {
-            if( ((struct pico_socket *)index->keyValue)->remote_port == remote)
-            {
-                sock = (struct pico_socket *)index->keyValue;
-                break;
-            }
-        }
-    }
+	sp = pico_get_sockport(PICO_PROTO_TCP,local);
+	if(sp)
+	{
+		pico_tree_foreach(index,&sp->socks)
+		{
+			if( ((struct pico_socket *)index->keyValue)->remote_port == remote)
+			{
+				sock = (struct pico_socket *)index->keyValue;
+				break;
+			}
+		}
+	}
 
-    return sock;
+	return sock;
 }
 
 
@@ -569,7 +569,7 @@
 
   pico_tree_insert(&sp->socks,s);
   s->state |= PICO_SOCKET_STATE_BOUND;
-    UNLOCK(Mutex);
+	UNLOCK(Mutex);
 #if DEBUG_SOCKET_TREE
   {
     struct pico_tree_node * index;
@@ -587,6 +587,7 @@
 static void socket_garbage_collect(unsigned long now, void *arg)
 {
   struct pico_socket *s = (struct pico_socket *) arg;
+  IGNORE_PARAMETER(now);
   pico_free(s);
 }
 
@@ -650,7 +651,7 @@
 
   s->state = PICO_SOCKET_STATE_CLOSED;
   pico_timer_add(3000, socket_garbage_collect, s);
-    UNLOCK(Mutex);
+	UNLOCK(Mutex);
   return 0;
 }
 
@@ -2016,14 +2017,14 @@
     if (mode & PICO_SHUT_RDWR)
       pico_socket_alter_state(s, PICO_SOCKET_STATE_CLOSED, PICO_SOCKET_STATE_CLOSING |PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED, 0);
     else if (mode & PICO_SHUT_RD)
-      pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
+      pico_socket_alter_state(s, 0, PICO_SOCKET_STATE_BOUND, 0);
   }
 #endif
 #ifdef PICO_SUPPORT_TCP
   if (PROTO(s) == PICO_PROTO_TCP) {
-    if(mode & PICO_SHUT_RDWR)
-        pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
-    else if (mode & PICO_SHUT_WR)
+  	if(mode & PICO_SHUT_RDWR)
+  		pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
+  	else if (mode & PICO_SHUT_WR)
       pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL, 0, 0);
     else if (mode & PICO_SHUT_RD)
       pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
@@ -2079,7 +2080,8 @@
 #else
 static inline int pico_transport_crc_check(struct pico_frame *f)
 {
-  return 1;
+	IGNORE_PARAMETER(f);
+	return 1;
 }
 #endif /* PICO_SUPPORT_CRC */
 
--- a/stack/pico_stack.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/stack/pico_stack.c	Mon Sep 02 08:02:21 2013 +0000
@@ -376,7 +376,7 @@
       }
 
       if(!ret) pico_frame_discard(f);
-        return ret;
+      	return ret;
     } else {
       return -1;
     }
--- a/stack/pico_tree.c	Tue Aug 06 08:04:03 2013 +0000
+++ b/stack/pico_tree.c	Mon Sep 02 08:02:21 2013 +0000
@@ -7,8 +7,9 @@
 
 #include "pico_tree.h"
 #include "pico_config.h"
+#include "pico_protocol.h"
 
-#define RED     0
+#define RED 	0
 #define BLACK 1
 
 // By default the null leafs are black
@@ -44,81 +45,89 @@
 
 struct pico_tree_node *pico_tree_firstNode(struct pico_tree_node * node)
 {
-    while(IS_NOT_LEAF(node->leftChild))
-        node = node->leftChild;
-    return node;
+	while(IS_NOT_LEAF(node->leftChild))
+		node = node->leftChild;
+	return node;
 }
 
 struct pico_tree_node * pico_tree_lastNode(struct pico_tree_node * node)
 {
-    while(IS_NOT_LEAF(node->rightChild))
-        node = node->rightChild;
-    return node;
+	while(IS_NOT_LEAF(node->rightChild))
+		node = node->rightChild;
+	return node;
 }
 
 struct pico_tree_node * pico_tree_next(struct pico_tree_node * node)
 {
-    if(IS_NOT_LEAF(node->rightChild))
-    {
-        node = node->rightChild;
-        while(IS_NOT_LEAF(node->leftChild))
-            node = node->leftChild;
-    }
-    else
-    {
-        if (IS_NOT_LEAF(node->parent) &&  AM_I_LEFT_CHILD(node))
-                node = node->parent;
-        else {
-            while (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node))
-                node = node->parent;
+	if(IS_NOT_LEAF(node->rightChild))
+	{
+		node = node->rightChild;
+		while(IS_NOT_LEAF(node->leftChild))
+			node = node->leftChild;
+	}
+	else
+	{
+		if (IS_NOT_LEAF(node->parent) &&  AM_I_LEFT_CHILD(node))
+		  		node = node->parent;
+		else {
+			while (IS_NOT_LEAF(node->parent) &&	AM_I_RIGHT_CHILD(node))
+				node = node->parent;
 
-            node = node->parent;
-        }
-    }
-    return node;
+			node = node->parent;
+		}
+	}
+	return node;
 }
 
 struct pico_tree_node * pico_tree_prev(struct pico_tree_node * node)
 {
-    if (IS_NOT_LEAF(node->leftChild)) {
-    node = node->leftChild;
-    while (IS_NOT_LEAF(node->rightChild))
-        node = node->rightChild;
+	if (IS_NOT_LEAF(node->leftChild)) {
+  	node = node->leftChild;
+  	while (IS_NOT_LEAF(node->rightChild))
+  		node = node->rightChild;
   } else {
-    if (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node))
-        node = node->parent;
-    else {
-        while (IS_NOT_LEAF(node) && AM_I_LEFT_CHILD(node))
-            node = node->parent;
+  	if (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node))
+  		node = node->parent;
+  	else {
+  		while (IS_NOT_LEAF(node) &&	AM_I_LEFT_CHILD(node))
+  			node = node->parent;
 
-        node = node->parent;
-    }
+  		node = node->parent;
+  	}
   }
-    return node;
+	return node;
 }
 
 void * pico_tree_insert(struct pico_tree* tree, void * key){
 
-    struct pico_tree_node * last_node = INIT_LEAF;
+	struct pico_tree_node * last_node = INIT_LEAF;
   struct pico_tree_node * temp = tree->root;
   struct pico_tree_node * insert;
   void * LocalKey;
   int result = 0;
 
-    LocalKey = (IS_NOT_LEAF(tree->root) ? pico_tree_findKey(tree,key) : NULL);
-    // if node already in, bail out
+	LocalKey = (IS_NOT_LEAF(tree->root) ? pico_tree_findKey(tree,key) : NULL);
+	// if node already in, bail out
   if(LocalKey)
-    return LocalKey;
+  	return LocalKey;
   else
-    insert = create_node(tree,key);
+  {
+  	insert = create_node(tree,key);
+  	if(!insert)
+  	{
+  		pico_err = PICO_ERR_ENOMEM;
+  		// to let the user know that it couldn't insert
+  		return (void *)&LEAF;
+  	}
+  }
 
   // search for the place to insert the new node
   while(IS_NOT_LEAF(temp))
   {
-        last_node = temp;
-        result = tree->compare(insert->keyValue,temp->keyValue);
+		last_node = temp;
+		result = tree->compare(insert->keyValue,temp->keyValue);
 
-        temp = (result < 0 ? temp->leftChild : temp->rightChild);
+		temp = (result < 0 ? temp->leftChild : temp->rightChild);
   }
 
   // make the needed connections
@@ -127,7 +136,7 @@
   if(IS_LEAF(last_node))
     tree->root = insert;
   else{
-    result = tree->compare(insert->keyValue,last_node->keyValue);
+  	result = tree->compare(insert->keyValue,last_node->keyValue);
     if(result < 0)
       last_node->leftChild = insert;
     else
@@ -137,32 +146,32 @@
   // fix colour issues
   fix_insert_collisions(tree, insert);
 
-    return NULL;
+	return NULL;
 }
 
 struct pico_tree_node * pico_tree_findNode(struct pico_tree * tree, void * key)
 {
-        struct pico_tree_node *found;
+		struct pico_tree_node *found;
 
-        found = tree->root;
+		found = tree->root;
 
-      while(IS_NOT_LEAF(found))
-      {
-        int result;
-        result = tree->compare(found->keyValue, key);
-        if(result == 0)
-        {
-           return found;
-        }
-        else if(result < 0)
-           found = found->rightChild;
-         else
-           found = found->leftChild;
-       }
+	  while(IS_NOT_LEAF(found))
+	  {
+	  	int result;
+	  	result = tree->compare(found->keyValue, key);
+	  	if(result == 0)
+	  	{
+	  	   return found;
+	  	}
+	  	else if(result < 0)
+	       found = found->rightChild;
+	     else
+	       found = found->leftChild;
+	   }
 
 
 
-      return NULL;
+	  return NULL;
 }
 
 void * pico_tree_findKey(struct pico_tree * tree, void * key)
@@ -174,12 +183,12 @@
 
   while(IS_NOT_LEAF(found))
   {
-    int result;
+  	int result;
 
-    result = tree->compare(found->keyValue, key);
-    if(result == 0)
-       return found->keyValue;
-    else if(result < 0)
+  	result = tree->compare(found->keyValue, key);
+  	if(result == 0)
+  	   return found->keyValue;
+  	else if(result < 0)
        found = found->rightChild;
      else
        found = found->leftChild;
@@ -191,24 +200,24 @@
 
 void * pico_tree_first(struct pico_tree * tree)
 {
-    return pico_tree_firstNode(tree->root)->keyValue;
+	return pico_tree_firstNode(tree->root)->keyValue;
 }
 
 void * pico_tree_last(struct pico_tree * tree)
 {
-    return pico_tree_lastNode(tree->root)->keyValue;
+	return pico_tree_lastNode(tree->root)->keyValue;
 }
 
 void * pico_tree_delete(struct pico_tree * tree, void * key){
 
-    uint8_t nodeColor; // keeps the color of the node to be deleted
+	uint8_t nodeColor; // keeps the color of the node to be deleted
   void * lkey; // keeps a copy of the key which will be removed
-    struct pico_tree_node * delete; // keeps a copy of the node to be extracted
-    struct pico_tree_node * temp; // temporary
-    struct pico_tree_node * ltemp; // used for switching nodes, as a copy
+	struct pico_tree_node * delete; // keeps a copy of the node to be extracted
+	struct pico_tree_node * temp; // temporary
+	struct pico_tree_node * ltemp; // used for switching nodes, as a copy
 
-    delete = pico_tree_findNode(tree, key);
-    ltemp = delete;
+	delete = pico_tree_findNode(tree, key);
+	ltemp = delete;
 
   // this key isn't in the tree, bail out
   if(!delete)
@@ -225,22 +234,22 @@
   else
     if(IS_LEAF(delete->rightChild))
     {
-        struct pico_tree_node * ltemp = delete;
-      temp = ltemp->leftChild;
-      switchNodes(tree, ltemp, ltemp->leftChild);
+    	struct pico_tree_node * _ltemp = delete;
+      temp = _ltemp->leftChild;
+      switchNodes(tree, _ltemp, _ltemp->leftChild);
     }
     else{
-        struct pico_tree_node * min;
-        min = pico_tree_firstNode(delete->rightChild);
+    	struct pico_tree_node * min;
+    	min = pico_tree_firstNode(delete->rightChild);
       nodeColor = min->color;
 
        temp = min->rightChild;
        if(min->parent == ltemp && IS_NOT_LEAF(temp))
-     temp->parent = min;
+ 	 temp->parent = min;
        else{
-         switchNodes(tree, min, min->rightChild);
-         min->rightChild = ltemp->rightChild;
-         if(IS_NOT_LEAF(min->rightChild)) min->rightChild->parent = min;
+      	 switchNodes(tree, min, min->rightChild);
+      	 min->rightChild = ltemp->rightChild;
+      	 if(IS_NOT_LEAF(min->rightChild)) min->rightChild->parent = min;
        }
        switchNodes(tree, ltemp, min);
        min->leftChild = ltemp->leftChild;
@@ -259,7 +268,7 @@
 
 int pico_tree_empty(struct pico_tree * tree)
 {
-    return (!tree->root || IS_LEAF(tree->root));
+	return (!tree->root || IS_LEAF(tree->root));
 }
 
 /*
@@ -284,9 +293,9 @@
     tree->root = temp;
   else
     if(node == node->parent->leftChild)
-        node->parent->leftChild = temp;
+    	node->parent->leftChild = temp;
     else
-        node->parent->rightChild = temp;
+    	node->parent->rightChild = temp;
 
   temp->leftChild = node;
   node->parent = temp;
@@ -323,10 +332,11 @@
 static struct pico_tree_node * create_node(struct pico_tree * tree, void* key)
 {
   struct pico_tree_node *temp;
+  IGNORE_PARAMETER(tree);
   temp = (struct pico_tree_node *)pico_zalloc(sizeof(struct pico_tree_node));
 
   if(!temp)
-    return NULL;
+  	return NULL;
 
   temp->keyValue = key;
   temp->parent = &LEAF;
@@ -347,43 +357,43 @@
 
   while(node->parent->color == RED && IS_NOT_LEAF(GRANPA(node)) )
   {
-    if(AM_I_RIGHT_CHILD(node->parent))
-     {
-            temp = GRANPA(node)->leftChild;
-            if(temp->color == RED){
-                node->parent->color = BLACK;
-                temp->color = BLACK;
-                GRANPA(node)->color = RED;
-                node = GRANPA(node);
-            }
-            else if(temp->color == BLACK){
-                if(node == node->parent->leftChild){
-                node = node->parent;
-                rotateToRight(tree, node);
-            }
-            node->parent->color = BLACK;
-            GRANPA(node)->color = RED;
-            rotateToLeft(tree, GRANPA(node));
-            }
-        }
-    else if(AM_I_LEFT_CHILD(node->parent))
+  	if(AM_I_RIGHT_CHILD(node->parent))
+	 {
+			temp = GRANPA(node)->leftChild;
+			if(temp->color == RED){
+				node->parent->color = BLACK;
+				temp->color = BLACK;
+				GRANPA(node)->color = RED;
+				node = GRANPA(node);
+			}
+			else if(temp->color == BLACK){
+				if(node == node->parent->leftChild){
+				node = node->parent;
+				rotateToRight(tree, node);
+			}
+			node->parent->color = BLACK;
+			GRANPA(node)->color = RED;
+			rotateToLeft(tree, GRANPA(node));
+			}
+		}
+  	else if(AM_I_LEFT_CHILD(node->parent))
     {
       temp = GRANPA(node)->rightChild;
       if(temp->color == RED){
-                node->parent->color = BLACK;
-                temp->color = BLACK;
-                GRANPA(node)->color = RED;
-                node = GRANPA(node);
+				node->parent->color = BLACK;
+				temp->color = BLACK;
+				GRANPA(node)->color = RED;
+				node = GRANPA(node);
       }
       else if(temp->color == BLACK){
-                if(AM_I_RIGHT_CHILD(node)){
-                    node = node->parent;
-                    rotateToLeft(tree, node);
-                }
-                node->parent->color = BLACK;
-                GRANPA(node)->color = RED;
-                rotateToRight(tree, GRANPA(node));
-        }
+				if(AM_I_RIGHT_CHILD(node)){
+					node = node->parent;
+					rotateToLeft(tree, node);
+				}
+				node->parent->color = BLACK;
+				GRANPA(node)->color = RED;
+				rotateToRight(tree, GRANPA(node));
+  		}
     }
   }
 
@@ -394,11 +404,11 @@
 static void switchNodes(struct pico_tree* tree, struct pico_tree_node* nodeA, struct pico_tree_node* nodeB)
 {
 
-    if(IS_LEAF(nodeA->parent))
+	if(IS_LEAF(nodeA->parent))
     tree->root = nodeB;
   else
   if(IS_NOT_LEAF(nodeA))
-  { 
+  {	
     if(AM_I_LEFT_CHILD(nodeA))
       nodeA->parent->leftChild = nodeB;
     else
@@ -420,64 +430,64 @@
 
   while( node != tree->root && node->color == BLACK && IS_NOT_LEAF(node))
   {
-    if(AM_I_LEFT_CHILD(node)){
+  	if(AM_I_LEFT_CHILD(node)){
 
       temp = node->parent->rightChild;
       if(temp->color == RED)
       {
-                temp->color = BLACK;
-                node->parent->color = RED;
-                rotateToLeft(tree, node->parent);
-                temp = node->parent->rightChild;
+				temp->color = BLACK;
+				node->parent->color = RED;
+				rotateToLeft(tree, node->parent);
+				temp = node->parent->rightChild;
       }
       if(temp->leftChild->color == BLACK && temp->rightChild->color == BLACK)
       {
-                temp->color = RED;
-                node = node->parent;
+				temp->color = RED;
+				node = node->parent;
       }
       else
       {
-                if(temp->rightChild->color == BLACK)
-                {
-                    temp->leftChild->color = BLACK;
-                    temp->color = RED;
-                    rotateToRight(tree, temp);
-                    temp = temp->parent->rightChild;
-                }
-                temp->color = node->parent->color;
-                node->parent->color = BLACK;
-                temp->rightChild->color = BLACK;
-                rotateToLeft(tree, node->parent);
-                node = tree->root;
+				if(temp->rightChild->color == BLACK)
+				{
+					temp->leftChild->color = BLACK;
+					temp->color = RED;
+					rotateToRight(tree, temp);
+					temp = temp->parent->rightChild;
+				}
+				temp->color = node->parent->color;
+				node->parent->color = BLACK;
+				temp->rightChild->color = BLACK;
+				rotateToLeft(tree, node->parent);
+				node = tree->root;
       }
     }
     else{
       temp = node->parent->leftChild;
       if(temp->color == RED)
       {
-                temp->color = BLACK;
-                node->parent->color = RED;
-                rotateToRight(tree, node->parent);
-                temp = node->parent->leftChild;
+				temp->color = BLACK;
+				node->parent->color = RED;
+				rotateToRight(tree, node->parent);
+				temp = node->parent->leftChild;
       }
       if(temp->rightChild->color == BLACK && temp->leftChild->color == BLACK)
       {
-                temp->color = RED;
-                node = node->parent;
+				temp->color = RED;
+				node = node->parent;
       }
       else{
-                if(temp->leftChild->color == BLACK)
-                {
-                    temp->rightChild->color = BLACK;
-                    temp->color = RED;
-                    rotateToLeft(tree, temp);
-                    temp = temp->parent->leftChild;
-                }
-            temp->color = node->parent->color;
-            node->parent->color = BLACK;
-            temp->leftChild->color = BLACK;
-            rotateToRight(tree, node->parent);
-            node = tree->root;
+				if(temp->leftChild->color == BLACK)
+				{
+					temp->rightChild->color = BLACK;
+					temp->color = RED;
+					rotateToLeft(tree, temp);
+					temp = temp->parent->leftChild;
+				}
+			temp->color = node->parent->color;
+			node->parent->color = BLACK;
+			temp->leftChild->color = BLACK;
+			rotateToRight(tree, node->parent);
+			node = tree->root;
       }
     }
   }