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 picotcp@tass.be
Date:
Wed Apr 09 14:31:41 2014 +0200
Parent:
148:969fdb223792
Child:
150:551effcf6a39
Commit message:
Update from git masterbranch

Changed in this revision

Socket/bsd/stack_endpoint.cpp 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_addressing.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_device.h Show annotated file Show diff for this revision Revisions of this file
include/pico_eth.h Show annotated file Show diff for this revision Revisions of this file
include/pico_frame.h Show annotated file Show diff for this revision Revisions of this file
include/pico_module_eth.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_queue.h Show annotated file Show diff for this revision Revisions of this file
include/pico_socket.h Show annotated file Show diff for this revision Revisions of this file
include/pico_socket_multicast.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_arp.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_arp.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_dev_loop.h 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_dns_client.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_http_client.c Show diff for this revision Revisions of this file
modules/pico_http_client.h Show diff for this revision Revisions of this file
modules/pico_http_server.c Show diff for this revision Revisions of this file
modules/pico_http_server.h Show diff for this revision Revisions of this file
modules/pico_http_util.c Show diff for this revision Revisions of this file
modules/pico_http_util.h 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_icmp4.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_icmp6.h 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_igmp.h 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_ipfilter.h 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_ipv4.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_ipv6.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_ipv6_nd.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_mm.h 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_olsr.c Show diff for this revision Revisions of this file
modules/pico_olsr.h Show diff for this revision Revisions of this file
modules/pico_posix.c Show diff for this revision Revisions of this file
modules/pico_simple_http.c Show diff for this revision Revisions of this file
modules/pico_simple_http.h Show diff for this revision Revisions of this file
modules/pico_slaacv4.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_slaacv4.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_socket_tcp.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_socket_tcp.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_socket_udp.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_socket_udp.h 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_tcp.h 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_udp.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_zmq.c Show diff for this revision Revisions of this file
modules/pico_zmq.h Show diff for this revision Revisions of this file
stack/pico_arp.c 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_socket.c Show annotated file Show diff for this revision Revisions of this file
stack/pico_socket_multicast.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/Socket/bsd/stack_endpoint.cpp	Tue Mar 11 15:34:51 2014 +0100
+++ b/Socket/bsd/stack_endpoint.cpp	Wed Apr 09 14:31:41 2014 +0200
@@ -11,7 +11,6 @@
 #include "mbed.h"
 #include "Socket.h"
 #include "Mutex.h"
-#include "PicoTerm.h"
 
 extern "C"
 {
--- a/include/heap.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/heap.h	Wed Apr 09 14:31:41 2014 +0200
@@ -16,12 +16,12 @@
         uint32_t i; \
         type *newTop; \
         if (++heap->n >= heap->size) {                                                \
-            newTop = pico_zalloc((heap->n + 1) * sizeof(type)); \
+            newTop = PICO_ZALLOC((heap->n + 1) * sizeof(type)); \
             if(!newTop) \
                 return -1; \
             if (heap->top)  { \
                 memcpy(newTop, heap->top, heap->n * sizeof(type)); \
-                pico_free(heap->top); \
+                PICO_FREE(heap->top); \
             } \
             heap->top = newTop;             \
             heap->size++;                                                               \
@@ -45,8 +45,8 @@
         }                     \
         memcpy(first, &heap->top[1], sizeof(type));   \
         last = &heap->top[heap->n--];                 \
-        for(i = 1; (i * 2) <= heap->n; i = child) {   \
-            child = 2 * i;                              \
+        for(i = 1; (i * 2u) <= heap->n; i = child) {   \
+            child = 2u * i;                              \
             if ((child != heap->n) &&                   \
                 (heap->top[child + 1]).orderby          \
                 < (heap->top[child]).orderby)           \
@@ -69,13 +69,13 @@
     } \
     static inline heap_ ## type *heap_init(void) \
     { \
-        heap_ ## type * p = (heap_ ## type *)pico_zalloc(sizeof(heap_ ## type));  \
+        heap_ ## type * p = (heap_ ## type *)PICO_ZALLOC(sizeof(heap_ ## type));  \
         return p;     \
     } \
     /*static inline void heap_destroy(heap_ ## type * h) \
        { \
-        pico_free(h->top); \
-        pico_free(h); \
+        PICO_FREE(h->top); \
+        PICO_FREE(h); \
        } \*/
 
 
--- a/include/pico_addressing.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_addressing.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,30 +3,33 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_ADDRESSING
-#define _INCLUDE_PICO_ADDRESSING
+#ifndef INCLUDE_PICO_ADDRESSING
+#define INCLUDE_PICO_ADDRESSING
+
 #include <stdint.h>
-
+#include "pico_config.h"
 
-struct pico_ip4
+PACKED_STRUCT_DEF pico_ip4
 {
     uint32_t addr;
 };
-#define PICO_SIZE_IP4 4
 
-
-struct pico_ip6
+PACKED_STRUCT_DEF pico_ip6
 {
     uint8_t addr[16];
 };
-#define PICO_SIZE_IP6 16
+
+union pico_address
+{
+    struct pico_ip4 ip4;
+    struct pico_ip6 ip6;
+};
 
 struct pico_eth
 {
     uint8_t addr[6];
     uint8_t padding[2];
 };
-#define PICO_SIZE_ETH 6
 
 extern const uint8_t PICO_ETHADDR_ALL[];
 
@@ -37,8 +40,6 @@
     uint16_t dport;
 
 };
-#define PICO_SIZE_TRANS 8
-
 
 /* Here are some protocols. */
 #define PICO_PROTO_IPV4   0
--- a/include/pico_config.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_config.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,28 +3,34 @@
 See LICENSE and COPYING for usage.
 
 *********************************************************************/
-#ifndef _INCLUDE_PICO_CONFIG
-#define _INCLUDE_PICO_CONFIG
+#ifndef INCLUDE_PICO_CONFIG
+#define INCLUDE_PICO_CONFIG
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
+
+#ifdef __IAR_SYSTEMS_ICC__
+#   define PACKED_STRUCT_DEF __packed struct
+#else
+#   define PACKED_STRUCT_DEF struct __attribute__((packed))
+#endif
+
 #include "pico_constants.h"
 
 #define IGNORE_PARAMETER(x) (void)x
 #define MBED
-//#define PICO_SUPPORT_CRC
+
+#define PICO_SUPPORT_ETH
+#define PICO_SUPPORT_CRC
 #define PICO_SUPPORT_DEVLOOP
 #define PICO_SUPPORT_DHCPC
 #define PICO_SUPPORT_DHCPD
 #define PICO_SUPPORT_DNS_CLIENT
-#define PICO_SUPPORT_HTTP_CLIENT
-#define PICO_SUPPORT_HTTP
-#define PICO_SUPPORT_HTTP_SERVER
 #define PICO_SUPPORT_ICMP4
 #define PICO_SUPPORT_PING
-#define PICO_SUPPORT_IGMP2
+#define PICO_SUPPORT_IGMP
 #define PICO_SUPPORT_IPFILTER
-//#define PICO_SUPPORT_IPFRAG
+#define PICO_SUPPORT_IPFRAG
 #define PICO_SUPPORT_IPV4
 #define PICO_SUPPORT_MCAST
 #define PICO_SUPPORT_NAT
@@ -33,4 +39,13 @@
 #define PICO_SUPPORT_SLAACV4
 
 # include "arch/pico_mbed.h"
-#endif
+
+#ifdef PICO_SUPPORT_MM
+#define PICO_ZALLOC(x) pico_mem_zalloc(x)
+#define PICO_FREE(x) pico_mem_free(x)
+#else
+#define PICO_ZALLOC(x) pico_zalloc(x)
+#define PICO_FREE(x) pico_free(x)
+#endif  /* PICO_SUPPORT_MM */
+
+#endif  /* INCLUDE_PICO_CONFIG */
--- a/include/pico_constants.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_constants.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,9 +3,16 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_CONST
-#define _INCLUDE_PICO_CONST
+#ifndef INCLUDE_PICO_CONST
+#define INCLUDE_PICO_CONST
 /* Included from pico_config.h */
+
+/** Non-endian dependant constants */
+#define PICO_SIZE_IP4    4
+#define PICO_SIZE_IP6   16
+#define PICO_SIZE_ETH    6
+#define PICO_SIZE_TRANS  8
+
 /** Endian-dependant constants **/
 typedef uint64_t pico_time;
 extern volatile uint64_t pico_tick;
@@ -115,6 +122,9 @@
 /*** *** *** *** *** *** ***
  ***     ARP CONFIG      ***
  *** *** *** *** *** *** ***/
+
+#include "pico_addressing.h"
+
 /* Maximum amount of accepted ARP requests per burst interval */
 #define PICO_ARP_MAX_RATE 1
 /* Duration of the burst interval in milliseconds */
--- a/include/pico_device.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_device.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,12 +3,13 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_DEVICE
-#define _INCLUDE_PICO_DEVICE
+#ifndef INCLUDE_PICO_DEVICE
+#define INCLUDE_PICO_DEVICE
 #include "pico_queue.h"
 #include "pico_frame.h"
 #include "pico_addressing.h"
 #include "pico_tree.h"
+#include "pico_ipv6_nd.h"
 #define MAX_DEVICE_NAME 16
 
 
@@ -30,6 +31,9 @@
     int __serving_interrupt;
     /* used to signal the upper layer the number of events arrived since the last processing */
     volatile int eventCnt;
+  #ifdef PICO_SUPPORT_IPV6
+    struct pico_nd_hostvars hostvars;
+  #endif
 };
 
 int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac);
--- a/include/pico_eth.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_eth.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,14 +3,14 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_ETH
-#define _INCLUDE_PICO_ETH
+#ifndef INCLUDE_PICO_ETH
+#define INCLUDE_PICO_ETH
 #include "pico_addressing.h"
 #include "pico_ipv4.h"
 #include "pico_ipv6.h"
 
 
-struct __attribute__((packed)) pico_eth_hdr {
+PACKED_STRUCT_DEF pico_eth_hdr {
     uint8_t daddr[6];
     uint8_t saddr[6];
     uint16_t proto;
--- a/include/pico_frame.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_frame.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,8 +3,8 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_FRAME
-#define _INCLUDE_PICO_FRAME
+#ifndef INCLUDE_PICO_FRAME
+#define INCLUDE_PICO_FRAME
 #include "pico_config.h"
 
 
@@ -70,7 +70,7 @@
     /* Pointer to socket */
     struct pico_socket *sock;
 
-    /* Pointer to transport info, used to store remote UDP duple (IP + port) */
+    /* Pointer to transport info, used to store remote UDP endpoint (IP + port) */
     void *info;
 
     /*Priority. "best-effort" priority, the default value is 0. Priority can be in between -10 and +10*/
@@ -83,6 +83,8 @@
 struct pico_frame *pico_frame_copy(struct pico_frame *f);
 struct pico_frame *pico_frame_deepcopy(struct pico_frame *f);
 struct pico_frame *pico_frame_alloc(uint32_t size);
+struct pico_frame *pico_frame_alloc_skeleton(uint32_t size);
+int pico_frame_skeleton_set_buffer(struct pico_frame *f, void *buf);
 uint16_t pico_checksum(void *inbuf, uint32_t len);
 uint16_t pico_dualbuffer_checksum(void *b1, uint32_t len1, void *b2, uint32_t len2);
 
@@ -94,4 +96,18 @@
     return 1;
 }
 
+static inline int pico_is_hex(char c)
+{
+    if (c >= '0' && c <= '9')
+        return 1;
+
+    if (c >= 'a' && c <= 'f')
+        return 1;
+
+    if (c >= 'A' && c <= 'F')
+        return 1;
+
+    return 0;
+}
+
 #endif
--- a/include/pico_module_eth.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_module_eth.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,8 +3,8 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _PICO_MODULE_IPV4_H
-#define _PICO_MODULE_IPV4_H
+#ifndef PICO_MODULE_IPV4_H
+#define PICO_MODULE_IPV4_H
 
 struct pico_arp_entry {
     struct eth dest;
--- a/include/pico_protocol.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_protocol.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,8 +3,8 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_PROTOCOL
-#define _INCLUDE_PICO_PROTOCOL
+#ifndef INCLUDE_PICO_PROTOCOL
+#define INCLUDE_PICO_PROTOCOL
 #include <stdint.h>
 #include "pico_queue.h"
 
@@ -20,46 +20,46 @@
 
 enum pico_err_e {
     PICO_ERR_NOERR = 0,
-    PICO_ERR_EPERM,
-    PICO_ERR_ENOENT,
+    PICO_ERR_EPERM = 1,
+    PICO_ERR_ENOENT = 2,
     /* ... */
     PICO_ERR_EINTR = 4,
-    PICO_ERR_EIO,
-    PICO_ERR_ENXIO,
+    PICO_ERR_EIO = 5,
+    PICO_ERR_ENXIO = 6,
     /* ... */
     PICO_ERR_EAGAIN = 11,
-    PICO_ERR_ENOMEM,
-    PICO_ERR_EACCESS,
-    PICO_ERR_EFAULT,
+    PICO_ERR_ENOMEM = 12,
+    PICO_ERR_EACCESS = 13,
+    PICO_ERR_EFAULT = 14,
     /* ... */
     PICO_ERR_EBUSY = 16,
     PICO_ERR_EEXIST = 17,
     /* ... */
     PICO_ERR_EINVAL = 22,
     /* ... */
+    PICO_ERR_ENONET = 64,
+    /* ... */
     PICO_ERR_EPROTO = 71,
+    /* ... */
     PICO_ERR_ENOPROTOOPT = 92,
     PICO_ERR_EPROTONOSUPPORT = 93,
-
     /* ... */
     PICO_ERR_EOPNOTSUPP = 95,
     PICO_ERR_EADDRINUSE = 98,
-    PICO_ERR_EADDRNOTAVAIL,
-    PICO_ERR_ENETDOWN,
-    PICO_ERR_ENETUNREACH,
-
+    PICO_ERR_EADDRNOTAVAIL = 99,
+    PICO_ERR_ENETDOWN = 100,
+    PICO_ERR_ENETUNREACH = 101,
     /* ... */
     PICO_ERR_ECONNRESET = 104,
-
     /* ... */
     PICO_ERR_EISCONN = 106,
-    PICO_ERR_ENOTCONN,
-    PICO_ERR_ESHUTDOWN,
+    PICO_ERR_ENOTCONN = 107,
+    PICO_ERR_ESHUTDOWN = 108,
     /* ... */
     PICO_ERR_ETIMEDOUT = 110,
     PICO_ERR_ECONNREFUSED = 111,
-    PICO_ERR_EHOSTDOWN,
-    PICO_ERR_EHOSTUNREACH,
+    PICO_ERR_EHOSTDOWN = 112,
+    PICO_ERR_EHOSTUNREACH = 113,
 };
 
 typedef enum pico_err_e pico_err_t;
@@ -81,6 +81,7 @@
     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. */
+    uint16_t (*get_mtu)(struct pico_protocol *self);
 };
 
 int pico_protocols_loop(int loop_score);
--- a/include/pico_queue.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_queue.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,8 +3,8 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_QUEUE
-#define _INCLUDE_PICO_QUEUE
+#ifndef INCLUDE_PICO_QUEUE
+#define INCLUDE_PICO_QUEUE
 #include <stdint.h>
 #include "pico_config.h"
 #include "pico_frame.h"
@@ -30,16 +30,16 @@
 };
 
 #ifdef PICO_SUPPORT_MUTEX
-#define LOCK(x) { \
+#define PICOTCP_MUTEX_LOCK(x) { \
         if (x == NULL) \
             x = pico_mutex_init(); \
         pico_mutex_lock(x); \
 }
-#define UNLOCK(x) pico_mutex_unlock(x)
+#define PICOTCP_MUTEX_UNLOCK(x) pico_mutex_unlock(x)
 
 #else
-#define LOCK(x) do {} while(0)
-#define UNLOCK(x) do {} while(0)
+#define PICOTCP_MUTEX_LOCK(x) do {} while(0)
+#define PICOTCP_MUTEX_UNLOCK(x) do {} while(0)
 #endif
 
 #ifdef PICO_SUPPORT_DEBUG_TOOLS
@@ -71,7 +71,7 @@
         return -1;
 
     if (q->shared)
-        LOCK(q->mutex);
+        PICOTCP_MUTEX_LOCK(q->mutex);
 
     p->next = NULL;
     if (!q->head) {
@@ -89,7 +89,7 @@
     debug_q(q);
 
     if (q->shared)
-        UNLOCK(q->mutex);
+        PICOTCP_MUTEX_UNLOCK(q->mutex);
 
     return (int32_t)q->size;
 }
@@ -97,11 +97,14 @@
 static inline struct pico_frame *pico_dequeue(struct pico_queue *q)
 {
     struct pico_frame *p = q->head;
+    if (!p)
+        return NULL;
+
     if (q->frames < 1)
         return NULL;
 
     if (q->shared)
-        LOCK(q->mutex);
+        PICOTCP_MUTEX_LOCK(q->mutex);
 
     q->head = p->next;
     q->frames--;
@@ -110,9 +113,10 @@
         q->tail = NULL;
 
     debug_q(q);
+
     p->next = NULL;
     if (q->shared)
-        UNLOCK(q->mutex);
+        PICOTCP_MUTEX_UNLOCK(q->mutex);
 
     return p;
 }
@@ -131,7 +135,7 @@
 {
     struct pico_frame *p = pico_dequeue(q);
     while(p) {
-        pico_free(p);
+        PICO_FREE(p);
         p = pico_dequeue(q);
     }
 }
--- a/include/pico_socket.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_socket.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,12 +3,13 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_SOCKET
-#define _INCLUDE_PICO_SOCKET
+#ifndef INCLUDE_PICO_SOCKET
+#define INCLUDE_PICO_SOCKET
 #include "pico_queue.h"
 #include "pico_addressing.h"
 #include "pico_config.h"
 #include "pico_protocol.h"
+#include "pico_tree.h"
 
 #ifdef __linux__
     #define PICO_DEFAULT_SOCKETQ (16 * 1024) /* Linux host, so we want full throttle */
@@ -20,20 +21,20 @@
 #define PICO_SHUT_WR   2
 #define PICO_SHUT_RDWR 3
 
+struct pico_sockport
+{
+    struct pico_tree socks; /* how you make the connection ? */
+    uint16_t number;
+    uint16_t proto;
+};
+
 
 struct pico_socket {
     struct pico_protocol *proto;
     struct pico_protocol *net;
 
-    union {
-        struct pico_ip4 ip4;
-        struct pico_ip6 ip6;
-    } local_addr;
-
-    union {
-        struct pico_ip4 ip4;
-        struct pico_ip6 ip6;
-    } remote_addr;
+    union pico_address local_addr;
+    union pico_address remote_addr;
 
     uint16_t local_port;
     uint16_t remote_port;
@@ -49,8 +50,8 @@
     struct pico_socket *backlog;
     struct pico_socket *next;
     struct pico_socket *parent;
-    int max_backlog;
-    uint8_t number_of_pending_conn;
+    uint16_t max_backlog;
+    uint16_t number_of_pending_conn;
 #endif
 #ifdef PICO_SUPPORT_MCAST
     struct pico_tree *MCASTListen;
@@ -67,12 +68,8 @@
     void *priv;
 };
 
-struct pico_remote_duple {
-    union {
-        struct pico_ip4 ip4;
-        struct pico_ip6 ip6;
-    } remote_addr;
-
+struct pico_remote_endpoint {
+    union pico_address remote_addr;
     uint16_t remote_port;
 };
 
@@ -89,32 +86,33 @@
     struct pico_ip4 mcast_link_addr;
 };
 
-#define PICO_SOCKET_STATE_UNDEFINED       0x0000
-#define PICO_SOCKET_STATE_SHUT_LOCAL      0x0001
-#define PICO_SOCKET_STATE_SHUT_REMOTE     0x0002
-#define PICO_SOCKET_STATE_BOUND           0x0004
-#define PICO_SOCKET_STATE_CONNECTED       0x0008
-#define PICO_SOCKET_STATE_CLOSING         0x0010
-#define PICO_SOCKET_STATE_CLOSED          0x0020
+#define PICO_SOCKET_STATE_UNDEFINED       0x0000u
+#define PICO_SOCKET_STATE_SHUT_LOCAL      0x0001u
+#define PICO_SOCKET_STATE_SHUT_REMOTE     0x0002u
+#define PICO_SOCKET_STATE_BOUND           0x0004u
+#define PICO_SOCKET_STATE_CONNECTED       0x0008u
+#define PICO_SOCKET_STATE_CLOSING         0x0010u
+#define PICO_SOCKET_STATE_CLOSED          0x0020u
 
-# define PICO_SOCKET_STATE_TCP                0xFF00
-# define PICO_SOCKET_STATE_TCP_UNDEF          0x00FF
-# define PICO_SOCKET_STATE_TCP_CLOSED         0x0100
-# define PICO_SOCKET_STATE_TCP_LISTEN         0x0200
-# define PICO_SOCKET_STATE_TCP_SYN_SENT       0x0300
-# define PICO_SOCKET_STATE_TCP_SYN_RECV       0x0400
-# define PICO_SOCKET_STATE_TCP_ESTABLISHED    0x0500
-# define PICO_SOCKET_STATE_TCP_CLOSE_WAIT     0x0600
-# define PICO_SOCKET_STATE_TCP_LAST_ACK       0x0700
-# define PICO_SOCKET_STATE_TCP_FIN_WAIT1      0x0800
-# define PICO_SOCKET_STATE_TCP_FIN_WAIT2      0x0900
-# define PICO_SOCKET_STATE_TCP_CLOSING        0x0a00
-# define PICO_SOCKET_STATE_TCP_TIME_WAIT      0x0b00
-# define PICO_SOCKET_STATE_TCP_ARRAYSIZ       0x0c
+# define PICO_SOCKET_STATE_TCP                0xFF00u
+# define PICO_SOCKET_STATE_TCP_UNDEF          0x00FFu
+# define PICO_SOCKET_STATE_TCP_CLOSED         0x0100u
+# define PICO_SOCKET_STATE_TCP_LISTEN         0x0200u
+# define PICO_SOCKET_STATE_TCP_SYN_SENT       0x0300u
+# define PICO_SOCKET_STATE_TCP_SYN_RECV       0x0400u
+# define PICO_SOCKET_STATE_TCP_ESTABLISHED    0x0500u
+# define PICO_SOCKET_STATE_TCP_CLOSE_WAIT     0x0600u
+# define PICO_SOCKET_STATE_TCP_LAST_ACK       0x0700u
+# define PICO_SOCKET_STATE_TCP_FIN_WAIT1      0x0800u
+# define PICO_SOCKET_STATE_TCP_FIN_WAIT2      0x0900u
+# define PICO_SOCKET_STATE_TCP_CLOSING        0x0a00u
+# define PICO_SOCKET_STATE_TCP_TIME_WAIT      0x0b00u
+# define PICO_SOCKET_STATE_TCP_ARRAYSIZ       0x0cu
 
+
+/* Socket options */
 # define PICO_TCP_NODELAY                     1
-
-# define PICO_SOCKET_OPT_TCPNODELAY           0x0000
+# define PICO_SOCKET_OPT_TCPNODELAY           0x0000u
 
 # define PICO_IP_MULTICAST_EXCLUDE            0
 # define PICO_IP_MULTICAST_INCLUDE            1
@@ -130,22 +128,26 @@
 
 # define PICO_SOCKET_OPT_MULTICAST_LOOP       1
 
+# define PICO_SOCKET_OPT_RCVBUF               52
+# define PICO_SOCKET_OPT_SNDBUF               53
+
+/* Constants */
 # define PICO_IP_DEFAULT_MULTICAST_TTL        1
 # define PICO_IP_DEFAULT_MULTICAST_LOOP       1
 
 #define PICO_SOCKET_TIMEOUT                   90000u /* 90 seconds */
 #define PICO_SOCKET_BOUND_TIMEOUT             30000u /* 30 seconds */
 
-#define PICO_SOCKET_SHUTDOWN_WRITE 0x01
-#define PICO_SOCKET_SHUTDOWN_READ  0x02
+#define PICO_SOCKET_SHUTDOWN_WRITE 0x01u
+#define PICO_SOCKET_SHUTDOWN_READ  0x02u
 #define TCPSTATE(s) ((s)->state & PICO_SOCKET_STATE_TCP)
 
-#define PICO_SOCK_EV_RD 1
-#define PICO_SOCK_EV_WR 2
-#define PICO_SOCK_EV_CONN 4
-#define PICO_SOCK_EV_CLOSE 8
-#define PICO_SOCK_EV_FIN 0x10
-#define PICO_SOCK_EV_ERR 0x80
+#define PICO_SOCK_EV_RD 1u
+#define PICO_SOCK_EV_WR 2u
+#define PICO_SOCK_EV_CONN 4u
+#define PICO_SOCK_EV_CLOSE 8u
+#define PICO_SOCK_EV_FIN 0x10u
+#define PICO_SOCK_EV_ERR 0x80u
 
 
 struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s));
@@ -160,6 +162,8 @@
 int pico_socket_recv(struct pico_socket *s, void *buf, int len);
 
 int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port);
+int pico_socket_getname(struct pico_socket *s, void *local_addr, uint16_t *port, uint16_t *proto);
+
 int pico_socket_connect(struct pico_socket *s, const void *srv_addr, uint16_t remote_port);
 int pico_socket_listen(struct pico_socket *s, const int backlog);
 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port);
@@ -209,5 +213,14 @@
 /* Port check */
 int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net);
 
+struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port);
+
+uint16_t pico_socket_get_mtu(struct pico_socket *s);
+int pico_socket_set_family(struct pico_socket *s, uint16_t family);
+
+#define PICO_SOCKET_SETOPT_EN(socket, index)  (socket->opt_flags |=  (1 << index))
+#define PICO_SOCKET_SETOPT_DIS(socket, index) (socket->opt_flags &= (uint16_t) ~(1 << index))
+#define PICO_SOCKET_GETOPT(socket, index) ((socket->opt_flags & (1u << index)) != 0)
+
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/pico_socket_multicast.h	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,10 @@
+#ifndef PICO_SOCKET_MULTICAST_H
+#define PICO_SOCKET_MULTICAST_H
+int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src);
+void pico_multicast_delete(struct pico_socket *s);
+int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value);
+int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value);
+int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl);
+int pico_udp_set_mc_ttl(struct pico_socket *s, void *_ttl);
+
+#endif
--- a/include/pico_stack.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_stack.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,12 +3,12 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_STACK
-#define _INCLUDE_PICO_STACK
+#ifndef INCLUDE_PICO_STACK
+#define INCLUDE_PICO_STACK
 #include "pico_config.h"
 #include "pico_frame.h"
 
-#define PICO_MAX_TIMERS 10
+#define PICO_MAX_TIMERS 20
 
 #define PICO_ETH_MTU 1514
 #define PICO_IP_MTU 1500u
@@ -33,19 +33,21 @@
 /* LOWEST LEVEL: interface towards devices. */
 /* Device driver will call this function which returns immediately.
  * Incoming packet will be processed later on in the dev loop.
+ * The zerocopy version will associate the current buffer to the newly created frame.
+ * Warning: the buffer used in the zerocopy version MUST have been allocated using PICO_ZALLOC()
  */
 int32_t pico_stack_recv(struct pico_device *dev, uint8_t *buffer, uint32_t len);
+int32_t pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len);
 
 
 /* ===== SENDIING FUNCTIONS (from socket down to dev) ===== */
 
-int32_t pico_transport_send(struct pico_frame *f);
 int32_t pico_network_send(struct pico_frame *f);
 int32_t pico_ethernet_send(struct pico_frame *f);
 int32_t pico_sendto_dev(struct pico_frame *f);
 
 /* ----- Initialization ----- */
-void pico_stack_init(void);
+int pico_stack_init(void);
 
 /* ----- Loop Function. ----- */
 void pico_stack_tick(void);
@@ -60,7 +62,6 @@
 /* Various. */
 struct pico_timer;
 int pico_source_is_local(struct pico_frame *f);
-int pico_destination_is_local(struct pico_frame *f);
 void pico_store_network_origin(void *src, struct pico_frame *f);
 struct pico_timer *pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg);
 void pico_timer_cancel(struct pico_timer *t);
--- a/include/pico_tree.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/include/pico_tree.h	Wed Apr 09 14:31:41 2014 +0200
@@ -5,8 +5,8 @@
    Author: Andrei Carp <andrei.carp@tass.be>
  *********************************************************************/
 
-#ifndef __PICO_RBTREE_H__
-#define __PICO_RBTREE_H__
+#ifndef PICO_RBTREE_H
+#define PICO_RBTREE_H
 
 #include <stdint.h>
 #include "pico_config.h"
@@ -19,6 +19,9 @@
         compareFunction \
     }
 
+#define USE_PICO_PAGE0_ZALLOC (1)
+#define USE_PICO_ZALLOC (2)
+
 struct pico_tree_node
 {
     void*keyValue; /* generic key */
@@ -37,6 +40,13 @@
 };
 
 extern struct pico_tree_node LEAF; /* generic leaf node */
+
+#ifdef PICO_SUPPORT_MM
+void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
+void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
+#endif
+
+
 /*
  * Manipulation functions
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_arp.c	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,502 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_config.h"
+#include "pico_arp.h"
+#include "pico_tree.h"
+#include "pico_ipv4.h"
+#include "pico_device.h"
+#include "pico_stack.h"
+
+extern const uint8_t PICO_ETHADDR_ALL[6];
+#define PICO_ARP_TIMEOUT 600000llu
+#define PICO_ARP_RETRY 300lu
+
+#ifdef DEBUG_ARP
+    #define arp_dbg dbg
+#else
+    #define arp_dbg(...) do {} while(0)
+#endif
+
+static struct pico_queue pending;
+static int pending_timer_on = 0;
+static int max_arp_reqs = PICO_ARP_MAX_RATE;
+
+
+static void check_pending(pico_time now, void *_unused)
+{
+    struct pico_frame *f = pico_dequeue(&pending);
+    IGNORE_PARAMETER(now);
+    IGNORE_PARAMETER(_unused);
+    if (!f) {
+        pending_timer_on = 0;
+        return;
+    }
+
+    pico_ethernet_send(f);
+
+    pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL);
+}
+
+static void update_max_arp_reqs(pico_time now, void *unused)
+{
+    IGNORE_PARAMETER(now);
+    IGNORE_PARAMETER(unused);
+    if (max_arp_reqs < PICO_ARP_MAX_RATE)
+        max_arp_reqs++;
+
+    pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL);
+}
+
+void pico_arp_init(void)
+{
+    pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL);
+}
+
+PACKED_STRUCT_DEF pico_arp_hdr
+{
+    uint16_t htype;
+    uint16_t ptype;
+    uint8_t hsize;
+    uint8_t psize;
+    uint16_t opcode;
+    uint8_t s_mac[PICO_SIZE_ETH];
+    struct pico_ip4 src;
+    uint8_t d_mac[PICO_SIZE_ETH];
+    struct pico_ip4 dst;
+};
+
+
+
+/* Callback handler for ip conflict service (e.g. IPv4 SLAAC)
+ *  Whenever the IP address registered here is seen in the network,
+ *  the callback is awaken to take countermeasures against IP collisions.
+ *
+ */
+
+struct arp_service_ipconflict {
+    struct pico_eth mac;
+    struct pico_ip4 ip;
+    void (*conflict)(void);
+};
+
+static struct arp_service_ipconflict conflict_ipv4;
+
+
+
+#define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr)))
+
+/* Arp Entries for the tables. */
+struct pico_arp {
+/* CAREFUL MAN! ARP entry MUST begin with a pico_eth structure,
+ * due to in-place casting!!! */
+    struct pico_eth eth;
+    struct pico_ip4 ipv4;
+    int arp_status;
+    pico_time timestamp;
+    struct pico_device *dev;
+    struct pico_timer *timer;
+};
+
+
+
+/*****************/
+/**  ARP TREE **/
+/*****************/
+
+/* Routing destination */
+
+static int arp_compare(void *ka, void *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)
+        return 1;
+
+    return 0;
+}
+
+PICO_TREE_DECLARE(arp_tree, arp_compare);
+
+/*********************/
+/**  END ARP TREE **/
+/*********************/
+
+struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst)
+{
+    struct pico_arp search, *found;
+    search.ipv4.addr = dst->addr;
+    found = pico_tree_findKey(&arp_tree, &search);
+    if (found && (found->arp_status != PICO_ARP_STATUS_STALE))
+        return &found->eth;
+
+    return NULL;
+}
+
+struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst)
+{
+    struct pico_arp*search;
+    struct pico_tree_node *index;
+    pico_tree_foreach(index, &arp_tree){
+        search = index->keyValue;
+        if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0)
+            return &search->ipv4;
+    }
+    return NULL;
+}
+
+void pico_arp_retry(struct pico_frame *f, struct pico_ip4 *where)
+{
+    if (++f->failure_count < 4) {
+        arp_dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count);
+        /* check if dst is local (gateway = 0), or if to use gateway */
+        pico_arp_request(f->dev, where, PICO_ARP_QUERY);
+        pico_enqueue(&pending, f);
+        if (!pending_timer_on) {
+            pending_timer_on++;
+            pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL);
+        }
+    } else {
+        dbg("ARP: Destination Unreachable\n");
+        pico_notify_dest_unreachable(f);
+        pico_frame_discard(f);
+    }
+}
+
+struct pico_eth *pico_arp_get(struct pico_frame *f)
+{
+    struct pico_eth *a4;
+    struct pico_ip4 gateway;
+    struct pico_ip4 *where;
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    struct pico_ipv4_link *l;
+    if (!hdr)
+        return NULL;
+
+    l = pico_ipv4_link_get(&hdr->dst);
+    if(l) {
+        /* address belongs to ourself */
+        return &l->dev->eth->mac;
+    }
+
+    gateway = pico_ipv4_route_get_gateway(&hdr->dst);
+    /* check if dst is local (gateway = 0), or if to use gateway */
+    if (gateway.addr != 0)
+        where = &gateway;
+    else
+        where = &hdr->dst;
+
+    a4 = pico_arp_lookup(where);      /* check if dst ip mac in cache */
+
+    if (!a4)
+        pico_arp_retry(f, where);
+
+    return a4;
+}
+
+#ifdef DEBUG_ARP
+void dbg_arp(void)
+{
+    struct pico_arp *a;
+    struct pico_tree_node *index;
+
+    pico_tree_foreach(index, &arp_tree) {
+        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] );
+    }
+}
+#endif
+
+static void arp_expire(pico_time now, void *_stale)
+{
+    struct pico_arp *stale = (struct pico_arp *) _stale;
+    if (now >= (stale->timestamp + PICO_ARP_TIMEOUT)) {
+        stale->arp_status = PICO_ARP_STATUS_STALE;
+        arp_dbg("ARP: Setting arp_status to STALE\n");
+        pico_arp_request(stale->dev, &stale->ipv4, PICO_ARP_QUERY);
+    } else {
+        /* Timer must be rescheduled, ARP entry has been renewed lately.
+         * No action required to refresh the entry, will check on the next timeout */
+        pico_timer_add(PICO_ARP_TIMEOUT + stale->timestamp - now, arp_expire, stale);
+    }
+}
+
+static void pico_arp_add_entry(struct pico_arp *entry)
+{
+    entry->arp_status = PICO_ARP_STATUS_REACHABLE;
+    entry->timestamp  = PICO_TIME();
+
+    pico_tree_insert(&arp_tree, entry);
+    arp_dbg("ARP ## reachable.\n");
+    pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry);
+}
+
+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;
+
+    pico_arp_add_entry(arp);
+
+    return 0;
+}
+
+static void pico_arp_check_conflict(struct pico_arp_hdr *hdr)
+{
+
+    if ((conflict_ipv4.conflict) &&
+        ((conflict_ipv4.ip.addr == hdr->src.addr) &&
+         (memcmp(hdr->s_mac, conflict_ipv4.mac.addr, PICO_SIZE_ETH) != 0)))
+        conflict_ipv4.conflict();
+}
+
+static struct pico_arp *pico_arp_lookup_entry(struct pico_frame *f)
+{
+    struct pico_arp search;
+    struct pico_arp *found = NULL;
+    struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr;
+    /* Populate a new arp entry */
+    search.ipv4.addr = hdr->src.addr;
+
+    /* Search for already existing entry */
+    found = pico_tree_findKey(&arp_tree, &search);
+    if (found) {
+        if (found->arp_status == PICO_ARP_STATUS_STALE) {
+            /* Replace if stale */
+            pico_tree_delete(&arp_tree, found);
+            pico_arp_add_entry(found);
+        } else {
+            /* Update mac address */
+            memcpy(found->eth.addr, hdr->s_mac, PICO_SIZE_ETH);
+            arp_dbg("ARP entry updated!\n");
+
+            /* Refresh timestamp, this will force a reschedule on the next timeout*/
+            found->timestamp = PICO_TIME();
+        }
+    }
+
+    return found;
+}
+
+
+static int pico_arp_check_incoming_hdr_type(struct pico_arp_hdr *h)
+{
+    /* Check the hardware type and protocol */
+    if ((h->htype != PICO_ARP_HTYPE_ETH) || (h->ptype != PICO_IDETH_IPV4))
+        return -1;
+
+    return 0;
+}
+
+static int pico_arp_check_incoming_hdr(struct pico_frame *f, struct pico_ip4 *dst_addr)
+{
+    struct pico_arp_hdr *hdr = (struct pico_arp_hdr *) f->net_hdr;
+    if (!hdr)
+        return -1;
+
+    dst_addr->addr = hdr->dst.addr;
+    if (pico_arp_check_incoming_hdr_type(hdr) < 0)
+        return -1;
+
+    /* The source mac address must not be a multicast or broadcast address */
+    if (hdr->s_mac[0] & 0x01)
+        return -1;
+
+    return 0;
+}
+
+static void pico_arp_reply_on_request(struct pico_frame *f, struct pico_ip4 me)
+{
+    struct pico_arp_hdr *hdr;
+    struct pico_eth_hdr *eh;
+
+    hdr = (struct pico_arp_hdr *) f->net_hdr;
+    eh = (struct pico_eth_hdr *)f->datalink_hdr;
+    if (hdr->opcode != PICO_ARP_REQUEST)
+        return;
+
+    hdr->opcode = PICO_ARP_REPLY;
+    memcpy(hdr->d_mac, hdr->s_mac, PICO_SIZE_ETH);
+    memcpy(hdr->s_mac, f->dev->eth->mac.addr, PICO_SIZE_ETH);
+    hdr->dst.addr = hdr->src.addr;
+    hdr->src.addr = me.addr;
+
+    /* Prepare eth header for arp reply */
+    memcpy(eh->daddr, eh->saddr, PICO_SIZE_ETH);
+    memcpy(eh->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH);
+    f->start = f->datalink_hdr;
+    f->len = PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR;
+    f->dev->send(f->dev, f->start, (int)f->len);
+}
+
+static int pico_arp_check_flooding(struct pico_frame *f, struct pico_ip4 me)
+{
+    struct pico_device *link_dev;
+    struct pico_arp_hdr *hdr;
+    hdr = (struct pico_arp_hdr *) f->net_hdr;
+
+    /* Prevent ARP flooding */
+    link_dev = pico_ipv4_link_find(&me);
+    if ((link_dev == f->dev) && (hdr->opcode == PICO_ARP_REQUEST)) {
+        if (max_arp_reqs == 0)
+            return -1;
+        else
+            max_arp_reqs--;
+    }
+
+    /* Check if we are the target IP address */
+    if (link_dev != f->dev)
+        return -1;
+
+    return 0;
+}
+
+static int pico_arp_process_in(struct pico_frame *f, struct pico_arp_hdr *hdr, struct pico_arp *found)
+{
+    struct pico_ip4 me;
+    if (pico_arp_check_incoming_hdr(f, &me) < 0) {
+        pico_frame_discard(f);
+        return -1;
+    }
+
+    if (pico_arp_check_flooding(f, me) < 0) {
+        pico_frame_discard(f);
+        return -1;
+    }
+
+    /* If no existing entry was found, create a new entry, or fail trying. */
+    if ((!found) && (pico_arp_create_entry(hdr->s_mac, hdr->src, f->dev) < 0)) {
+        pico_frame_discard(f);
+        return -1;
+    }
+
+    /* If the packet is a request, send a reply */
+    pico_arp_reply_on_request(f, me);
+
+#ifdef DEBUG_ARP
+    dbg_arp();
+#endif
+    pico_frame_discard(f);
+    return 0;
+}
+
+int pico_arp_receive(struct pico_frame *f)
+{
+    struct pico_arp_hdr *hdr;
+    struct pico_arp *found = NULL;
+
+    hdr = (struct pico_arp_hdr *) f->net_hdr;
+    if (!hdr)
+        return -1;
+
+    pico_arp_check_conflict(hdr);
+    found = pico_arp_lookup_entry(f);
+    return pico_arp_process_in(f, hdr, found);
+
+}
+
+int32_t pico_arp_request_xmit(struct pico_device *dev, struct pico_frame *f, struct pico_ip4 *src, struct pico_ip4 *dst, uint8_t type)
+{
+    struct pico_arp_hdr *ah = (struct pico_arp_hdr *) (f->start + PICO_SIZE_ETHHDR);
+    int ret;
+
+    /* Fill arp header */
+    ah->htype  = PICO_ARP_HTYPE_ETH;
+    ah->ptype  = PICO_IDETH_IPV4;
+    ah->hsize  = PICO_SIZE_ETH;
+    ah->psize  = PICO_SIZE_IP4;
+    ah->opcode = PICO_ARP_REQUEST;
+    memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH);
+
+    switch (type) {
+    case PICO_ARP_ANNOUNCE:
+        ah->src.addr = dst->addr;
+        ah->dst.addr = dst->addr;
+        break;
+    case PICO_ARP_PROBE:
+        ah->src.addr = 0;
+        ah->dst.addr = dst->addr;
+        break;
+    case PICO_ARP_QUERY:
+        ah->src.addr = src->addr;
+        ah->dst.addr = dst->addr;
+        break;
+    default:
+        pico_frame_discard(f);
+        return -1;
+    }
+    arp_dbg("Sending arp request.\n");
+    ret = dev->send(dev, f->start, (int) f->len);
+    pico_frame_discard(f);
+    return ret;
+}
+
+int32_t pico_arp_request(struct pico_device *dev, struct pico_ip4 *dst, uint8_t type)
+{
+    struct pico_frame *q = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR);
+    struct pico_eth_hdr *eh;
+    struct pico_ip4 *src = NULL;
+
+    if (!q)
+        return -1;
+
+    if (type == PICO_ARP_QUERY)
+    {
+        src = pico_ipv4_source_find(dst);
+        if (!src) {
+            pico_frame_discard(q);
+            return -1;
+        }
+    }
+
+    arp_dbg("QUERY: %08x\n", dst->addr);
+
+    eh = (struct pico_eth_hdr *)q->start;
+
+    /* Fill eth header */
+    memcpy(eh->saddr, dev->eth->mac.addr, PICO_SIZE_ETH);
+    memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH);
+    eh->proto = PICO_IDETH_ARP;
+
+    return pico_arp_request_xmit(dev, q, src, dst, type);
+}
+
+int pico_arp_get_neighbors(struct pico_device *dev, struct pico_ip4 *neighbors, int maxlen)
+{
+    struct pico_arp*search;
+    struct pico_tree_node *index;
+    int i = 0;
+    pico_tree_foreach(index, &arp_tree){
+        search = index->keyValue;
+        if (search->dev == dev) {
+            neighbors[i++].addr = search->ipv4.addr;
+            if (i >= maxlen)
+                return i;
+        }
+    }
+    return i;
+}
+
+void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void (*cb)(void))
+{
+    conflict_ipv4.conflict = cb;
+    conflict_ipv4.ip.addr = ip->addr;
+    if (mac != NULL)
+        memcpy(conflict_ipv4.mac.addr, mac, 6);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_arp.h	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,31 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_ARP
+#define INCLUDE_PICO_ARP
+#include "pico_eth.h"
+#include "pico_device.h"
+
+int pico_arp_receive(struct pico_frame *);
+
+
+struct pico_eth *pico_arp_get(struct pico_frame *f);
+int32_t pico_arp_request(struct pico_device *dev, struct pico_ip4 *dst, uint8_t type);
+
+#define PICO_ARP_STATUS_REACHABLE 0x00
+#define PICO_ARP_STATUS_PERMANENT 0x01
+#define PICO_ARP_STATUS_STALE     0x02
+
+#define PICO_ARP_QUERY    0x00
+#define PICO_ARP_PROBE    0x01
+#define PICO_ARP_ANNOUNCE 0x02
+
+struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst);
+struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst);
+int pico_arp_create_entry(uint8_t*hwaddr, struct pico_ip4 ipv4, struct pico_device*dev);
+int pico_arp_get_neighbors(struct pico_device *dev, struct pico_ip4 *neighbors, int maxlen);
+void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void (*cb)(void));
+void pico_arp_init(void);
+#endif
--- a/modules/pico_dev_loop.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dev_loop.c	Wed Apr 09 14:31:41 2014 +0200
@@ -45,29 +45,22 @@
     return loop_score;
 }
 
-/* Public interface: create/destroy. */
-
-void pico_loop_destroy(struct pico_device *dev)
-{
-    IGNORE_PARAMETER(dev);
-}
 
 struct pico_device *pico_loop_create(void)
 {
-    struct pico_device *loop = pico_zalloc(sizeof(struct pico_device));
+    struct pico_device *loop = PICO_ZALLOC(sizeof(struct pico_device));
     if (!loop)
         return NULL;
 
-    if( 0 != pico_device_init((struct pico_device *)loop, "loop", NULL)) {
+    if( 0 != pico_device_init(loop, "loop", NULL)) {
         dbg ("Loop init failed.\n");
-        pico_loop_destroy((struct pico_device *)loop);
+        pico_device_destroy(loop);
         return NULL;
     }
 
     loop->send = pico_loop_send;
     loop->poll = pico_loop_poll;
-    loop->destroy = pico_loop_destroy;
     dbg("Device %s created.\n", loop->name);
-    return (struct pico_device *)loop;
+    return loop;
 }
 
--- a/modules/pico_dev_loop.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dev_loop.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,8 +3,8 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_LOOP
-#define _INCLUDE_PICO_LOOP
+#ifndef INCLUDE_PICO_LOOP
+#define INCLUDE_PICO_LOOP
 #include "pico_config.h"
 #include "pico_device.h"
 
--- a/modules/pico_dhcp_client.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dhcp_client.c	Wed Apr 09 14:31:41 2014 +0200
@@ -96,7 +96,7 @@
     if (a->xid == b->xid)
         return 0;
 
-    return (a->xid < b->xid) ? -1 : 1;
+    return (a->xid < b->xid) ? (-1) : (1);
 }
 PICO_TREE_DECLARE(DHCPCookies, dhcp_cookies_cmp);
 
@@ -113,7 +113,7 @@
         return NULL;
     }
 
-    dhcpc = pico_zalloc(sizeof(struct pico_dhcp_client_cookie));
+    dhcpc = PICO_ZALLOC(sizeof(struct pico_dhcp_client_cookie));
     if (!dhcpc) {
         pico_err = PICO_ERR_ENOMEM;
         return NULL;
@@ -145,7 +145,7 @@
     pico_socket_close(found->s);
     pico_ipv4_link_del(found->dev, found->address);
     pico_tree_delete(&DHCPCookies, found);
-    pico_free(found);
+    PICO_FREE(found);
     return 0;
 }
 
@@ -865,7 +865,12 @@
     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((size_t)(sizeof(struct pico_dhcp_hdr) + optlen));
+        hdr = PICO_ZALLOC((size_t)(sizeof(struct pico_dhcp_hdr) + optlen));
+        if (!hdr) {
+            pico_err = PICO_ERR_ENOMEM;
+            return -1;
+        }
+
         /* specific options */
         offset = (uint16_t)(offset + pico_dhcp_opt_maxmsgsize(&hdr->options[offset], DHCP_CLIENT_MAXMSGZISE));
         break;
@@ -874,7 +879,12 @@
         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);
+        hdr = PICO_ZALLOC(sizeof(struct pico_dhcp_hdr) + optlen);
+        if (!hdr) {
+            pico_err = PICO_ERR_ENOMEM;
+            return -1;
+        }
+
         /* specific options */
         offset = (uint16_t)(offset + pico_dhcp_opt_maxmsgsize(&hdr->options[offset], DHCP_CLIENT_MAXMSGZISE));
         if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING) {
@@ -919,13 +929,13 @@
     hdr->htype = PICO_DHCP_HTYPE_ETH;
     hdr->hlen = PICO_SIZE_ETH;
     hdr->xid = dhcpc->xid;
-    //hdr->flags = short_be(PICO_DHCP_FLAG_BROADCAST); /* Nope: see bug #96! */
+    /* hdr->flags = short_be(PICO_DHCP_FLAG_BROADCAST); / * Nope: see bug #96! * / */
     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, (int)(sizeof(struct pico_dhcp_hdr) + optlen), &destination, PICO_DHCPD_PORT);
-    pico_free(hdr);
+    PICO_FREE(hdr);
     if (r < 0)
         return -1;
 
--- a/modules/pico_dhcp_client.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dhcp_client.h	Wed Apr 09 14:31:41 2014 +0200
@@ -5,8 +5,8 @@
    .
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_DHCP_CLIENT
-#define _INCLUDE_PICO_DHCP_CLIENT
+#ifndef INCLUDE_PICO_DHCP_CLIENT
+#define INCLUDE_PICO_DHCP_CLIENT
 #include "pico_dhcp_common.h"
 #include "pico_addressing.h"
 #include "pico_protocol.h"
--- a/modules/pico_dhcp_common.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dhcp_common.c	Wed Apr 09 14:31:41 2014 +0200
@@ -48,7 +48,8 @@
 
         default:
             p++; /* move pointer from code octet to len octet */
-            if ((--len <= 0) || (len - (*p + 1) < 0)) /* (*p + 1) to account for len octet */
+            len--;
+            if ((len <= 0) || (len - (*p + 1) < 0)) /* (*p + 1) to account for len octet */
                 return 0;
 
             optlen = *p;
--- a/modules/pico_dhcp_common.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dhcp_common.h	Wed Apr 09 14:31:41 2014 +0200
@@ -5,8 +5,9 @@
    .
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_DHCP_COMMON
-#define _INCLUDE_PICO_DHCP_COMMON
+#ifndef INCLUDE_PICO_DHCP_COMMON
+#define INCLUDE_PICO_DHCP_COMMON
+#include "pico_config.h"
 #include "pico_addressing.h"
 
 #define PICO_DHCPD_PORT (short_be(67))
@@ -82,7 +83,7 @@
 #define PICO_DHCP_EVENT_LEASE           11
 #define PICO_DHCP_EVENT_RETRANSMIT      12
 
-struct __attribute__((packed)) pico_dhcp_hdr
+PACKED_STRUCT_DEF pico_dhcp_hdr
 {
     uint8_t op;
     uint8_t htype;
@@ -100,14 +101,14 @@
     char hostname[64];
     char bootp_filename[128];
     uint32_t dhcp_magic;
-    uint8_t options[];
+    uint8_t options[0];
 };
 
-struct __attribute__((packed)) pico_dhcp_opt
+PACKED_STRUCT_DEF pico_dhcp_opt
 {
     uint8_t code;
     uint8_t len;
-    union {
+    union dhcp_opt_ext_u {
         struct {
             struct pico_ip4 ip;
         } netmask;
--- a/modules/pico_dhcp_server.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dhcp_server.c	Wed Apr 09 14:31:41 2014 +0200
@@ -28,8 +28,6 @@
 /* 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)))
-
 enum dhcp_server_state {
     PICO_DHCP_STATE_DISCOVER = 0,
     PICO_DHCP_STATE_OFFER,
@@ -44,8 +42,22 @@
     struct pico_dhcp_server_setting *dhcps;
     struct pico_ip4 ciaddr;
     struct pico_eth hwaddr;
+    uint8_t bcast;
 };
 
+static inline int ip_address_is_in_dhcp_range(struct pico_dhcp_server_negotiation *n, uint32_t x)
+{
+    uint32_t ip_hostendian = long_be(x);
+    if (ip_hostendian < long_be(n->dhcps->pool_start))
+        return 0;
+
+    if (ip_hostendian > long_be(n->dhcps->pool_end))
+        return 0;
+
+    return 1;
+}
+
+
 static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s);
 
 static int dhcp_settings_cmp(void *ka, void *kb)
@@ -54,7 +66,7 @@
     if (a->dev == b->dev)
         return 0;
 
-    return (a->dev < b->dev) ? -1 : 1;
+    return (a->dev < b->dev) ? (-1) : (1);
 }
 PICO_TREE_DECLARE(DHCPSettings, dhcp_settings_cmp);
 
@@ -64,7 +76,7 @@
     if (a->xid == b->xid)
         return 0;
 
-    return (a->xid < b->xid) ? -1 : 1;
+    return (a->xid < b->xid) ? (-1) : (1);
 }
 PICO_TREE_DECLARE(DHCPNegotiations, dhcp_negotiations_cmp);
 
@@ -89,7 +101,7 @@
         return NULL;
     }
 
-    dhcps = pico_zalloc(sizeof(struct pico_dhcp_server_setting));
+    dhcps = PICO_ZALLOC(sizeof(struct pico_dhcp_server_setting));
     if (!dhcps) {
         pico_err = PICO_ERR_ENOMEM;
         return NULL;
@@ -118,13 +130,13 @@
     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);
+        PICO_FREE(dhcps);
         return NULL;
     }
 
     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);
+        PICO_FREE(dhcps);
         return NULL;
     }
 
@@ -157,7 +169,7 @@
     if (pico_dhcp_server_find_negotiation(hdr->xid))
         return NULL;
 
-    dhcpn = pico_zalloc(sizeof(struct pico_dhcp_server_negotiation));
+    dhcpn = PICO_ZALLOC(sizeof(struct pico_dhcp_server_negotiation));
     if (!dhcpn) {
         pico_err = PICO_ERR_ENOMEM;
         return NULL;
@@ -165,13 +177,14 @@
 
     dhcpn->xid = hdr->xid;
     dhcpn->state = PICO_DHCP_STATE_DISCOVER;
+    dhcpn->bcast = ((short_be(hdr->flags) & PICO_DHCP_FLAG_BROADCAST) != 0) ? (1) : (0);
     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);
+        PICO_FREE(dhcpn);
         return NULL;
     }
 
@@ -205,7 +218,10 @@
 
     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) + (uint32_t)optlen);
+    hdr = PICO_ZALLOC(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen);
+    if (!hdr) {
+        return;
+    }
 
     hdr->op = PICO_DHCP_OP_REPLY;
     hdr->htype = PICO_DHCP_HTYPE_ETH;
@@ -226,7 +242,13 @@
     offset += pico_dhcp_opt_dns(&hdr->options[offset], &dns);
     offset += pico_dhcp_opt_end(&hdr->options[offset]);
 
-    destination.addr = hdr->yiaddr;
+    if (dhcpn->bcast == 0)
+        destination.addr = hdr->yiaddr;
+    else {
+        hdr->flags |= short_be(PICO_DHCP_FLAG_BROADCAST);
+        destination.addr = broadcast.addr;
+    }
+
     r = pico_socket_sendto(dhcpn->dhcps->s, hdr, (int)(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen), &destination, PICO_DHCP_CLIENT_PORT);
     if (r < 0)
         dhcps_dbg("DHCP server WARNING: failure sending: %s!\n", strerror(pico_err));
@@ -256,7 +278,7 @@
     if (!dhcpn)
         dhcpn = pico_dhcp_server_add_negotiation(dev, hdr);
 
-    if (!ip_inrange(dhcpn->ciaddr.addr))
+    if (!ip_address_is_in_dhcp_range(dhcpn, dhcpn->ciaddr.addr))
         return;
 
     do {
@@ -344,4 +366,21 @@
 
     return 0;
 }
+
+int pico_dhcp_server_destroy(struct pico_device *dev)
+{
+    struct pico_dhcp_server_setting *found, test = {
+        .dev = dev,
+    };
+    found = pico_tree_findKey(&DHCPSettings, &test);
+    if (!found) {
+        pico_err = PICO_ERR_ENOENT;
+        return -1;
+    }
+
+    pico_tree_delete(&DHCPSettings, found);
+    PICO_FREE(found);
+    return 0;
+}
+
 #endif /* PICO_SUPPORT_DHCP */
--- a/modules/pico_dhcp_server.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dhcp_server.h	Wed Apr 09 14:31:41 2014 +0200
@@ -3,8 +3,8 @@
    See LICENSE and COPYING for usage.
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_DHCP_SERVER
-#define _INCLUDE_PICO_DHCP_SERVER
+#ifndef INCLUDE_PICO_DHCP_SERVER
+#define INCLUDE_PICO_DHCP_SERVER
 
 #include "pico_dhcp_common.h"
 #include "pico_addressing.h"
@@ -25,4 +25,7 @@
 /* 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);
 
+/* To destroy an existing DHCP server configuration, running on a given interface */
+int pico_dhcp_server_destroy(struct pico_device *dev);
+
 #endif /* _INCLUDE_PICO_DHCP_SERVER */
--- a/modules/pico_dns_client.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dns_client.c	Wed Apr 09 14:31:41 2014 +0200
@@ -11,6 +11,7 @@
 #include "pico_addressing.h"
 #include "pico_socket.h"
 #include "pico_ipv4.h"
+#include "pico_ipv6.h"
 #include "pico_dns_client.h"
 #include "pico_tree.h"
 
@@ -27,7 +28,7 @@
 #define PICO_DNS_CLIENT_MAX_RETRANS 3
 
 /* Default nameservers + port */
-#define PICO_DNS_NS_GOOGLE "8.8.8.8"
+#define PICO_DNS_NS_DEFAULT "208.67.222.222"
 #define PICO_DNS_NS_PORT 53
 
 /* FLAG values */
@@ -53,6 +54,7 @@
 
 /* QTYPE values */
 #define PICO_DNS_TYPE_A 1
+#define PICO_DNS_TYPE_AAAA 28
 #define PICO_DNS_TYPE_PTR 12
 
 /* QCLASS values */
@@ -71,19 +73,20 @@
 
 /* Len of an IPv4 address string */
 #define PICO_DNS_IPV4_ADDR_LEN 16
+#define PICO_DNS_IPV6_ADDR_LEN 54
 
 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
 static void pico_dns_client_retransmission(pico_time now, void *arg);
 
 /* RFC 1035 section 4. MESSAGES */
-struct __attribute__((packed)) pico_dns_name
+PACKED_STRUCT_DEF pico_dns_name
 {
-    char name[0];
+    char name[1];
 };
 
 /* prefix = header + name pointer
  * flags splitted in 2x uint8 due to endianness */
-struct __attribute__((packed)) pico_dns_prefix
+PACKED_STRUCT_DEF pico_dns_prefix
 {
     uint16_t id;
     uint8_t rd : 1; /* recursion desired  */
@@ -101,13 +104,13 @@
     struct pico_dns_name domain;
 };
 
-struct __attribute__((packed)) pico_dns_query_suffix
+PACKED_STRUCT_DEF pico_dns_query_suffix
 {
     uint16_t qtype;
     uint16_t qclass;
 };
 
-struct __attribute__((packed)) pico_dns_answer_suffix
+PACKED_STRUCT_DEF pico_dns_answer_suffix
 {
     uint16_t qtype;
     uint16_t qclass;
@@ -127,7 +130,7 @@
     if (a->ns.addr == b->ns.addr)
         return 0;
 
-    return (a->ns.addr < b->ns.addr) ? -1 : 1;
+    return (a->ns.addr < b->ns.addr) ? (-1) : (1);
 }
 PICO_TREE_DECLARE(NSTable, dns_ns_cmp);
 
@@ -151,7 +154,7 @@
     if (a->id == b->id)
         return 0;
 
-    return (a->id < b->id) ? -1 : 1;
+    return (a->id < b->id) ? (-1) : (1);
 }
 PICO_TREE_DECLARE(DNSTable, dns_query_cmp);
 
@@ -165,7 +168,7 @@
         return -1;
 
     pico_tree_delete(&NSTable, found);
-    pico_free(found);
+    PICO_FREE(found);
 
     /* no NS left, add default NS */
     if (pico_tree_empty(&NSTable))
@@ -178,7 +181,7 @@
 {
     struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}};
 
-    dns = pico_zalloc(sizeof(struct pico_dns_ns));
+    dns = PICO_ZALLOC(sizeof(struct pico_dns_ns));
     if (!dns) {
         pico_err = PICO_ERR_ENOMEM;
         return NULL;
@@ -188,12 +191,12 @@
 
     found = pico_tree_insert(&NSTable, dns);
     if (found) { /* nameserver already present */
-        pico_free(dns);
+        PICO_FREE(dns);
         return found;
     }
 
     /* default NS found, remove it */
-    pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
+    pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&test.ns.addr);
     found = pico_tree_findKey(&NSTable, &test);
     if (found && (found->ns.addr != ns_addr->addr))
         pico_dns_client_del_ns(&found->ns);
@@ -224,7 +227,7 @@
 {
     struct pico_dns_query *q = NULL, *found = NULL;
 
-    q = pico_zalloc(sizeof(struct pico_dns_query));
+    q = PICO_ZALLOC(sizeof(struct pico_dns_query));
     if (!q)
         return NULL;
 
@@ -239,7 +242,7 @@
     q->arg = arg;
     q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
     if (!q->s) {
-        pico_free(q);
+        PICO_FREE(q);
         return NULL;
     }
 
@@ -247,7 +250,7 @@
     if (found) {
         pico_err = PICO_ERR_EAGAIN;
         pico_socket_close(q->s);
-        pico_free(q);
+        PICO_FREE(q);
         return NULL;
     }
 
@@ -265,10 +268,10 @@
     if (!found)
         return -1;
 
-    pico_free(found->query);
+    PICO_FREE(found->query);
     pico_socket_close(found->s);
     pico_tree_delete(&DNSTable, found);
-    pico_free(found);
+    PICO_FREE(found);
     return 0;
 }
 
@@ -312,6 +315,8 @@
     return ptr + 1;
 }
 
+/* mirror ip6 */
+
 /* mirror ip address numbers
  * f.e. 192.168.0.1 => 1.0.168.192 */
 static int8_t pico_dns_client_mirror(char *ptr)
@@ -461,6 +466,11 @@
 
 static int pico_dns_client_check_asuffix(struct pico_dns_answer_suffix *suf, struct pico_dns_query *q)
 {
+    if (!suf) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
     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;
@@ -480,6 +490,8 @@
     uint16_t comp = 0, compression = 0;
     uint16_t i = 0;
     char *psuffix = suf;
+    if (!suf)
+        return NULL;
 
     while (i++ < short_be(pre->ancount)) {
         comp = short_from(psuffix);
@@ -506,6 +518,9 @@
         }
 
         asuffix = (struct pico_dns_answer_suffix *)psuffix;
+        if (!asuffix)
+            break;
+
         if (pico_dns_client_check_asuffix(asuffix, q) < 0) {
             psuffix += (sizeof(struct pico_dns_answer_suffix) + short_be(asuffix->rdlength));
             continue;
@@ -518,7 +533,12 @@
 
 static int pico_dns_client_send(struct pico_dns_query *q)
 {
-    uint16_t *paramID = pico_zalloc(sizeof(uint16_t));
+    uint16_t *paramID = PICO_ZALLOC(sizeof(uint16_t));
+    if (!paramID) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
     dns_dbg("DNS: sending query to %08X\n", q->q_ns.ns.addr);
     if (!q->s)
         goto failure;
@@ -533,7 +553,7 @@
     return 0;
 
 failure:
-    pico_free(paramID);
+    PICO_FREE(paramID);
     return -1;
 }
 
@@ -549,7 +569,7 @@
     /* search for the dns query and free used space */
     dummy.id = *(uint16_t *)arg;
     q = (struct pico_dns_query *)pico_tree_findKey(&DNSTable, &dummy);
-    pico_free(arg);
+    PICO_FREE(arg);
 
     /* dns query successful? */
     if (!q) {
@@ -575,13 +595,27 @@
     {
     case PICO_DNS_TYPE_A:
         ip = long_from(asuffix->rdata);
-        str = pico_zalloc(PICO_DNS_IPV4_ADDR_LEN);
+        str = PICO_ZALLOC(PICO_DNS_IPV4_ADDR_LEN);
         pico_ipv4_to_string(str, ip);
         break;
-
+#ifdef PICO_SUPPORT_IPV6
+    case PICO_DNS_TYPE_AAAA:
+    {
+        struct pico_ip6 ip6;
+        memcpy(&ip6.addr, asuffix->rdata, sizeof(struct pico_ip6));
+        str = PICO_ZALLOC(PICO_DNS_IPV6_ADDR_LEN);
+        pico_ipv6_to_string(str, ip6.addr);
+        break;
+    }
+#endif
     case PICO_DNS_TYPE_PTR:
         pico_dns_client_answer_domain((char *)asuffix->rdata);
-        str = pico_zalloc((size_t)(asuffix->rdlength - PICO_DNS_LABEL_INITIAL));
+        str = PICO_ZALLOC((size_t)(asuffix->rdlength - PICO_DNS_LABEL_INITIAL));
+        if (!str) {
+            pico_err = PICO_ERR_ENOMEM;
+            return -1;
+        }
+
         memcpy(str, asuffix->rdata + PICO_DNS_LABEL_INITIAL, short_be(asuffix->rdlength) - PICO_DNS_LABEL_INITIAL);
         break;
 
@@ -593,6 +627,7 @@
     if (q->retrans) {
         q->callback(str, q->arg);
         q->retrans = 0;
+        PICO_FREE(str);
         pico_dns_client_del_query(q->id);
     }
 
@@ -647,7 +682,7 @@
     return;
 }
 
-int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
+static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg)
 {
     char *msg = NULL;
     struct pico_dns_prefix *prefix = NULL;
@@ -655,6 +690,7 @@
     struct pico_dns_query_suffix *qsuffix = NULL;
     struct pico_dns_query *q = NULL;
     uint16_t len = 0, lblen = 0, strlen = 0;
+    (void)proto;
 
     if (!url || !callback) {
         pico_err = PICO_ERR_EINVAL;
@@ -664,7 +700,7 @@
     strlen = pico_dns_client_strlen(url);
     lblen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + PICO_DNS_LABEL_ROOT);
     len = (uint16_t)(sizeof(struct pico_dns_prefix) + lblen + sizeof(struct pico_dns_query_suffix));
-    msg = pico_zalloc(len);
+    msg = PICO_ZALLOC(len);
     if (!msg) {
         pico_err = PICO_ERR_ENOMEM;
         return -1;
@@ -678,11 +714,17 @@
     /* assemble dns message */
     pico_dns_client_query_prefix(prefix);
     pico_dns_client_query_domain(domain->name);
+
+#ifdef PICO_SUPPORT_IPV6
+    if (proto == PICO_PROTO_IPV6) {
+        pico_dns_client_query_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN);
+    } else
+#endif
     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);
+        PICO_FREE(msg);
         return -1;
     }
 
@@ -694,6 +736,16 @@
     return 0;
 }
 
+int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
+{
+    return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV4, callback, arg);
+}
+
+int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg)
+{
+    return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV6, callback, arg);
+}
+
 int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
 {
     const char *inaddr_arpa = ".in-addr.arpa";
@@ -713,7 +765,7 @@
     arpalen = pico_dns_client_strlen(inaddr_arpa);
     lblen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT);
     len = (uint16_t)(sizeof(struct pico_dns_prefix) + lblen + sizeof(struct pico_dns_query_suffix));
-    msg = pico_zalloc(len);
+    msg = PICO_ZALLOC(len);
     if (!msg) {
         pico_err = PICO_ERR_ENOMEM;
         return -1;
@@ -725,15 +777,13 @@
     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);
+        PICO_FREE(msg);
         return -1;
     }
 
@@ -745,6 +795,89 @@
     return 0;
 }
 
+
+#ifdef PICO_SUPPORT_IPV6
+#define STRLEN_PTR_IP6 63
+
+static inline char dns_ptr_ip6_nibble_lo(uint8_t byte)
+{
+    uint8_t nibble = byte & 0x0f;
+    if (nibble < 10)
+        return (char)(nibble + '0');
+    else
+        return (char)(nibble - 0xa + 'a');
+}
+
+static inline char dns_ptr_ip6_nibble_hi(uint8_t byte)
+{
+    uint8_t nibble = (byte & 0xf0u) >> 4u;
+    if (nibble < 10u)
+        return (char)(nibble + '0');
+    else
+        return (char)(nibble - 0xa + 'a');
+}
+
+static void pico_dns_ipv6_set_ptr(const char *ip, char *dst)
+{
+    struct pico_ip6 ip6;
+    int i, j = 0;
+    pico_string_to_ipv6(ip, ip6.addr);
+    for (i = 15; i >= 0; i--) {
+        dst[j++] = dns_ptr_ip6_nibble_lo(ip6.addr[i]);
+        dst[j++] = '.';
+        dst[j++] = dns_ptr_ip6_nibble_hi(ip6.addr[i]);
+        dst[j++] = '.';
+    }
+}
+
+int pico_dns_client_getname6(const char *ip, void (*callback)(char *, void *), void *arg)
+{
+    const char *inaddr6_arpa = ".IP6.ARPA";
+    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, arpalen = 0;
+
+    if (!ip || !callback) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    arpalen = pico_dns_client_strlen(inaddr6_arpa);
+    lblen = (uint16_t)(PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6 + arpalen + PICO_DNS_LABEL_ROOT);
+    len = (uint16_t)(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);
+    pico_dns_ipv6_set_ptr(ip, domain->name + PICO_DNS_LABEL_INITIAL);
+    memcpy(domain->name + PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6, inaddr6_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;
+}
+#endif
+
 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
 {
     if (!ns) {
@@ -781,7 +914,7 @@
         0
     };
 
-    if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) < 0)
+    if (pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&default_ns.addr) < 0)
         return -1;
 
     return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD);
--- a/modules/pico_dns_client.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_dns_client.h	Wed Apr 09 14:31:41 2014 +0200
@@ -7,8 +7,8 @@
    Authors: Kristof Roelants
  *********************************************************************/
 
-#ifndef _INCLUDE_PICO_DNS_CLIENT
-#define _INCLUDE_PICO_DNS_CLIENT
+#ifndef INCLUDE_PICO_DNS_CLIENT
+#define INCLUDE_PICO_DNS_CLIENT
 
 #define PICO_DNS_NS_DEL 0
 #define PICO_DNS_NS_ADD 1
@@ -19,5 +19,9 @@
 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag);
 int pico_dns_client_getaddr(const char *url, void (*callback)(char *ip, void *arg), void *arg);
 int pico_dns_client_getname(const char *ip, void (*callback)(char *url, void *arg), void *arg);
+#ifdef PICO_SUPPORT_IPV6
+int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg);
+int pico_dns_client_getname6(const char *url, void (*callback)(char *, void *), void *arg);
+#endif
 
 #endif /* _INCLUDE_PICO_DNS_CLIENT */
--- a/modules/pico_http_client.c	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,817 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Author: Andrei Carp <andrei.carp@tass.be>
- *********************************************************************/
-#include <string.h>
-#include <stdint.h>
-#include "pico_tree.h"
-#include "pico_config.h"
-#include "pico_socket.h"
-#include "pico_tcp.h"
-#include "pico_dns_client.h"
-#include "pico_http_client.h"
-#include "pico_ipv4.h"
-#include "pico_stack.h"
-
-/*
- * This is the size of the following header
- *
- * GET <resource> HTTP/1.1<CRLF>
- * Host: <host>:<port><CRLF>
- * User-Agent: picoTCP<CRLF>
- * Connection: close<CRLF>
- * <CRLF>
- *
- * where <resource>,<host> and <port> will be added later.
- */
-
-#ifdef PICO_SUPPORT_HTTP_CLIENT
-
-#define HTTP_GET_BASIC_SIZE   63u
-#define HTTP_HEADER_LINE_SIZE 50u
-#define RESPONSE_INDEX              9u
-
-#define HTTP_CHUNK_ERROR    0xFFFFFFFFu
-
-#ifdef dbg
-    #undef dbg
-#endif
-
-#define dbg(...) do {} while(0)
-#define nop() do {} while(0)
-
-#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;
-};
-
-/* HTTP Client internal states */
-#define HTTP_READING_HEADER      0
-#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;
-}
-
-PICO_TREE_DECLARE(pico_client_list, compareClients);
-
-/* Local functions */
-int parseHeaderFromServer(struct pico_http_client *client, struct pico_http_header *header);
-int readChunkLine(struct pico_http_client *client);
-/*  */
-static inline void processConnErrClose(uint16_t ev, struct pico_http_client *client)
-{
-    if(ev & PICO_SOCK_EV_CONN)
-        client->wakeup(EV_HTTP_CON, 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);
-    }
-}
-
-static inline void waitForHeader(struct pico_http_client *client)
-{
-    /* 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);
-        }
-    }
-}
-
-static inline void treatReadEvent(struct pico_http_client *client)
-{
-    /* 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;
-        }
-
-        waitForHeader(client);
-    }
-    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);
-    }
-}
-void tcpCallback(uint16_t ev, struct pico_socket *s)
-{
-
-    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;
-        }
-    }
-
-    if(!client)
-    {
-        dbg("Client not found...Something went wrong !\n");
-        return;
-    }
-
-    processConnErrClose(ev, client);
-
-    if(ev & PICO_SOCK_EV_RD)
-    {
-        treatReadEvent(client);
-
-    }
-}
-
-/* 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;
-
-    if(!client)
-    {
-        dbg("Who made the request ?!\n");
-        return;
-    }
-
-    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;
-        }
-
-        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);
-
-        /* close the client (free used heap) */
-        pico_http_client_close(client->connectionID);
-    }
-}
-
-/*
- * API used for opening a new HTTP Client.
- *
- * The accepted uri's are [http:]hostname[:port]/resource
- * no relative uri's are accepted.
- *
- * The function returns a connection ID >= 0 if successful
- * -1 if an error occured.
- */
-int pico_http_client_open(char *uri, void (*wakeup)(uint16_t ev, uint16_t conn))
-{
-    struct pico_http_client *client;
-
-    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->uriKey = pico_zalloc(sizeof(struct pico_http_uri));
-
-    if(!client->uriKey)
-    {
-        pico_err = PICO_ERR_ENOMEM;
-        pico_free(client);
-        return HTTP_RETURN_ERROR;
-    }
-
-    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;
-    }
-
-    /* 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;
-}
-
-/*
- * API for sending a header to the client.
- *
- * if hdr == HTTP_HEADER_RAW , then the parameter header
- * is sent as it is to client.
- *
- * if hdr == HTTP_HEADER_DEFAULT, then the parameter header
- * is ignored and the library will build the response header
- * based on the uri passed when opening the client.
- *
- */
-int32_t pico_http_client_sendHeader(uint16_t conn, char *header, uint8_t hdr)
-{
-    struct pico_http_client search = {
-        .connectionID = conn
-    };
-    struct pico_http_client *http = pico_tree_findKey(&pico_client_list, &search);
-    int32_t 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);
-
-        if(!header)
-        {
-            pico_err = PICO_ERR_ENOMEM;
-            return HTTP_RETURN_ERROR;
-        }
-    }
-
-    length = pico_socket_write(http->sck, (void *)header, (int)strlen(header) + 1);
-
-    if(hdr == HTTP_HEADER_DEFAULT)
-        pico_free(header);
-
-    return length;
-}
-
-
-/* / */
-
-static inline int checkChunkLine(struct pico_http_client *client, int 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)
-        return 0; /* force out */
-
-    return 1;
-}
-
-static inline void updateContentLength(struct pico_http_client *client, int tmpLenRead )
-{
-    if(tmpLenRead > 0)
-    {
-        client->header->contentLengthOrChunk = client->header->contentLengthOrChunk - (uint32_t)tmpLenRead;
-    }
-}
-
-static inline int readBody(struct pico_http_client *client, char *data, uint16_t size, int *lenRead, int *tmpLenRead)
-{
-    *tmpLenRead = 0;
-
-    if(client->state == HTTP_READING_BODY)
-    {
-
-        /* if needed truncate the data */
-        *tmpLenRead = pico_socket_read(client->sck, data + (*lenRead),
-                                       (client->header->contentLengthOrChunk < ((uint32_t)(size - (*lenRead)))) ? ((int)client->header->contentLengthOrChunk) : (size - (*lenRead)));
-
-        updateContentLength(client, *tmpLenRead);
-        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;
-    return 0;
-}
-
-static inline int readBigChunk(struct pico_http_client *client, char *data, uint16_t size, int *lenRead)
-{
-    int value;
-    /* 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((uint16_t)(*lenRead) <= size)
-        {
-            int tmpLenRead = 0;
-            if(readBody(client, data, size, lenRead, &tmpLenRead))
-                return (*lenRead);
-
-            if((value = checkChunkLine(client, tmpLenRead)) <= 0)
-                return value;
-        }
-    }
-
-    return 0;
-}
-
-static inline void readSmallChunk(struct pico_http_client *client, char *data, uint16_t size, int *lenRead)
-{
-    if(size < client->header->contentLengthOrChunk)
-    {
-        /* read the data from the chunk */
-        *lenRead = pico_socket_read(client->sck, (void *)data, size);
-
-        if(*lenRead)
-            client->header->contentLengthOrChunk = client->header->contentLengthOrChunk - (uint32_t)(*lenRead);
-    }
-}
-static inline int readChunkedData(struct pico_http_client *client, char *data, uint16_t size)
-{
-    int lenRead = 0;
-    int value;
-    /* 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;
-    }
-
-
-    readSmallChunk(client, data, size, &lenRead);
-    value = readBigChunk(client, data, size, &lenRead);
-    if(value)
-        return value;
-
-    return lenRead;
-}
-
-/*
- * API for reading received data.
- *
- * This api hides from the user if the transfer-encoding
- * was chunked or a full length was provided, in case of
- * a chunked transfer encoding will "de-chunk" the data
- * and pass it to the user.
- */
-int32_t 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);
-
-    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
-        return readChunkedData(client, data, size);
-}
-
-/*
- * API for reading received data.
- *
- * Reads out the header struct received from server.
- */
-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);
-
-    if(client)
-    {
-        return client->header;
-    }
-    else
-    {
-        /* not found */
-        dbg("Wrong connection id !\n");
-        pico_err = PICO_ERR_EINVAL;
-        return NULL;
-    }
-}
-
-/*
- * API for reading received data.
- *
- * Reads out the uri struct after was processed.
- */
-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;
-    }
-}
-
-/*
- * API for reading received data.
- *
- * Close the client.
- */
-static inline void freeHeader(struct pico_http_client *toBeRemoved)
-{
-    if(toBeRemoved->header)
-    {
-        /* free space used */
-        if(toBeRemoved->header->location)
-            pico_free(toBeRemoved->header->location);
-
-        pico_free(toBeRemoved->header);
-    }
-}
-
-static inline void freeUri(struct pico_http_client *toBeRemoved)
-{
-    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);
-    }
-}
-int pico_http_client_close(uint16_t 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;
-    }
-
-    /* close socket */
-    if(toBeRemoved->sck)
-        pico_socket_close(toBeRemoved->sck);
-
-    freeHeader(toBeRemoved);
-    freeUri(toBeRemoved);
-
-    pico_free(toBeRemoved);
-
-    return 0;
-}
-
-/*
- * API for reading received data.
- *
- * Builds a GET header based on the fields on the uri.
- */
-char *pico_http_client_buildHeader(const struct pico_http_uri *uriData)
-{
-    char *header;
-    char port[6u]; /* 6 = max length of a uint16 + \0 */
-
-    unsigned long headerSize = HTTP_GET_BASIC_SIZE;
-
-    if(!uriData->host || !uriData->resource || !uriData->port)
-    {
-        pico_err = PICO_ERR_EINVAL;
-        return NULL;
-    }
-
-    /*  */
-    headerSize = (headerSize + strlen(uriData->host));
-    headerSize = (headerSize + strlen(uriData->resource));
-    headerSize = (headerSize + 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;
-    }
-
-    /* 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;
-}
-
-
-/*  */
-static inline void readFirstLine(struct pico_http_client *client, char *line, uint32_t *index)
-{
-    char 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 */
-}
-
-static inline void startReadingBody(struct pico_http_client *client, struct pico_http_header *header)
-{
-
-    if(header->transferCoding == HTTP_TRANSFER_CHUNKED)
-    {
-        /* read the first chunk */
-        header->contentLengthOrChunk = 0;
-
-        client->state = HTTP_READING_CHUNK_VALUE;
-        readChunkLine(client);
-
-    }
-    else
-        client->state = HTTP_READING_BODY;
-}
-
-static inline int parseLocAndCont(struct pico_http_client *client, struct pico_http_header *header, char *line, uint32_t *index)
-{
-    char 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);
-
-        memcpy(header->location, line, (*index));
-        return 1;
-    }    /* 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 + (uint32_t)(c - '0');
-        }
-        return 1;
-    }    /* Transfer-Encoding: chunked */
-
-    return 0;
-}
-
-static inline int parseTransferEncoding(struct pico_http_client *client, struct pico_http_header *header, char *line, uint32_t *index)
-{
-    char c;
-
-    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;
-        }
-
-        return 1;
-    } /* just ignore the line */
-
-    return 0;
-}
-
-
-static inline void parseFields(struct pico_http_client *client, struct pico_http_header *header, char *line, uint32_t *index)
-{
-    char c;
-
-    if(!parseLocAndCont(client, header, line, index))
-    {
-        if(!parseTransferEncoding(client, header, line, index))
-        {
-            while(consumeChar(c) > 0 && c != '\r') nop();
-        }
-    }
-
-    /* consume the next one */
-    consumeChar(c);
-    /* reset the index */
-    (*index) = 0u;
-}
-
-static inline void parseRestOfHeader(struct pico_http_client *client, struct pico_http_header *header, char *line, uint32_t *index)
-{
-    char c;
-
-    /* parse the rest of the header */
-    while(consumeChar(c) > 0)
-    {
-        if(c == ':')
-        {
-            parseFields(client, header, line, index);
-        }
-        else if(c == '\r' && !(*index))
-        {
-            /* consume the \n */
-            consumeChar(c);
-            break;
-        }
-        else
-        {
-            line[(*index)++] = c;
-        }
-    }
-}
-
-int parseHeaderFromServer(struct pico_http_client *client, struct pico_http_header *header)
-{
-    char line[HTTP_HEADER_LINE_SIZE];
-    uint32_t index = 0;
-
-    readFirstLine(client, line, &index);
-    /* 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 + 2u) || isNotHTTPv1(line))
-    {
-        /* wrong format of the the response */
-        pico_err = PICO_ERR_EINVAL;
-        return HTTP_RETURN_ERROR;
-    }
-
-    /* extract response code */
-    header->responseCode = (uint16_t)((line[RESPONSE_INDEX] - '0') * 100 +
-                                      (line[RESPONSE_INDEX + 1] - '0') * 10 +
-                                      (line[RESPONSE_INDEX + 2] - '0'));
-
-    if(header->responseCode / 100u > 5u)
-    {
-        /* invalid response type */
-        header->responseCode = 0;
-        return HTTP_RETURN_ERROR;
-    }
-
-    dbg("Server response : %d \n", header->responseCode);
-
-    parseRestOfHeader(client, header, line, &index);
-
-    startReadingBody(client, header);
-    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 */
-static inline void setClientChunkState(struct pico_http_client *client)
-{
-
-    if(client->header->contentLengthOrChunk == 0 && client->state == HTTP_READING_BODY)
-    {
-        client->state = HTTP_READING_CHUNK_VALUE;
-    }
-}
-static inline void readChunkTrail(struct pico_http_client *client)
-{
-    char c;
-
-    if(client->state == HTTP_READING_CHUNK_TRAIL)
-    {
-
-        while(consumeChar(c) > 0 && c != '\n') nop();
-        if(c == '\n') client->state = HTTP_READING_BODY;
-    }
-}
-static inline void readChunkValue(struct pico_http_client *client)
-{
-    char c;
-
-    while(consumeChar(c) > 0 && c != '\r' && c != ';')
-    {
-        if(is_hex_digit(c))
-            client->header->contentLengthOrChunk = (client->header->contentLengthOrChunk << 4u) + (uint32_t)hex_digit_to_dec(c);
-    }
-    if(c == '\r' || c == ';') client->state = HTTP_READING_CHUNK_TRAIL;
-}
-int readChunkLine(struct pico_http_client *client)
-{
-    setClientChunkState(client);
-
-    if(client->state == HTTP_READING_CHUNK_VALUE)
-    {
-        readChunkValue(client);
-    }
-
-    readChunkTrail(client);
-
-    return HTTP_RETURN_OK;
-}
-#endif
--- a/modules/pico_http_client.h	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Author: Andrei Carp <andrei.carp@tass.be>
- *********************************************************************/
-
-
-#ifndef PICO_HTTP_CLIENT_H_
-#define PICO_HTTP_CLIENT_H_
-
-#include "pico_http_util.h"
-
-/*
- * Transfer encodings
- */
-#define HTTP_TRANSFER_CHUNKED  1u
-#define HTTP_TRANSFER_FULL       0u
-
-/*
- * Parameters for the send header function
- */
-#define HTTP_HEADER_RAW                 0u
-#define HTTP_HEADER_DEFAULT         1u
-
-/*
- * Data types
- */
-
-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 */
-
-};
-
-int pico_http_client_open(char *uri, void (*wakeup)(uint16_t ev, uint16_t conn));
-int32_t pico_http_client_sendHeader(uint16_t conn, char *header, uint8_t hdr);
-
-struct pico_http_header *pico_http_client_readHeader(uint16_t conn);
-struct pico_http_uri *pico_http_client_readUriData(uint16_t conn);
-char *pico_http_client_buildHeader(const struct pico_http_uri *uriData);
-
-int32_t pico_http_client_readData(uint16_t conn, char *data, uint16_t size);
-int pico_http_client_close(uint16_t conn);
-
-#endif /* PICO_HTTP_CLIENT_H_ */
--- a/modules/pico_http_server.c	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,643 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Author: Andrei Carp <andrei.carp@tass.be>
- *********************************************************************/
-
-#include "pico_stack.h"
-#include "pico_http_server.h"
-#include "pico_tcp.h"
-#include "pico_tree.h"
-#include "pico_socket.h"
-
-#ifdef PICO_SUPPORT_HTTP_SERVER
-
-#define BACKLOG                             10
-
-#define HTTP_SERVER_CLOSED      0
-#define HTTP_SERVER_LISTEN      1
-
-#define HTTP_HEADER_MAX_LINE    256u
-
-#define consumeChar(c) (pico_socket_read(client->sck, &c, 1u))
-
-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 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 const char errorHeader[] =
-    "HTTP/1.1 400 Bad Request\r\n\
-Host: localhost\r\n\
-Connection: close\r\n\
-\r\n\
-<html><body>There was a problem with your request !</body></html>";
-
-struct httpServer
-{
-    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;
-};
-
-/* Local states for clients */
-#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
-
-static struct httpServer server = {
-    0
-};
-
-/*
- * Private functions
- */
-static int parseRequest(struct httpClient *client);
-static int readRemainingHeader(struct httpClient *client);
-static void sendData(struct httpClient *client);
-static inline int readData(struct httpClient *client);  /* used only in a place */
-static inline struct httpClient *findClient(uint16_t conn);
-
-static int compareClients(void *ka, void *kb)
-{
-    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;
-    uint8_t serverEvent = FALSE;
-
-    /* determine the client for the socket */
-    if( s == server.sck)
-    {
-        serverEvent = TRUE;
-    }
-    else
-    {
-        pico_tree_foreach(index, &pico_http_clients)
-        {
-            client = index->keyValue;
-            if(client->sck == s) break;
-
-            client = NULL;
-        }
-    }
-
-    if(!client && !serverEvent)
-    {
-        return;
-    }
-
-    if (ev & PICO_SOCK_EV_RD)
-    {
-
-        if(readData(client) == HTTP_RETURN_ERROR)
-        {
-            /* send out error */
-            client->state = HTTP_ERROR;
-            pico_socket_write(client->sck, (const 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_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, (uint16_t)(serverEvent ? HTTP_SERVER_ID : client->connectionID));
-    }
-
-    if(ev & PICO_SOCK_EV_ERR)
-    {
-        server.wakeup(EV_HTTP_ERROR, (uint16_t)(serverEvent ? HTTP_SERVER_ID : client->connectionID));
-    }
-}
-
-/*
- * API for starting the server. If 0 is passed as a port, the port 80
- * will be used.
- */
-int8_t pico_http_server_start(uint16_t port, void (*wakeup)(uint16_t ev, uint16_t conn))
-{
-    struct pico_ip4 anything = {
-        0
-    };
-
-    server.port = (uint16_t)(port ? short_be(port) : short_be(80u));
-
-    if(!wakeup)
-    {
-        pico_err = PICO_ERR_EINVAL;
-        return HTTP_RETURN_ERROR;
-    }
-
-    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(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;
-}
-
-/*
- * API for accepting new connections. This function should be
- * called when the event EV_HTTP_CON is triggered, if not called
- * when noticed the connection will be considered rejected and the
- * socket will be dropped.
- *
- * Returns the ID of the new connection or a negative value if error.
- */
-int pico_http_server_accept(void)
-{
-    struct pico_ip4 orig;
-    struct httpClient *client;
-    uint16_t port;
-
-    client = pico_zalloc(sizeof(struct httpClient));
-    if(!client)
-    {
-        pico_err = PICO_ERR_ENOMEM;
-        return HTTP_RETURN_ERROR;
-    }
-
-    client->sck = pico_socket_accept(server.sck, &orig, &port);
-
-    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;
-
-    /* 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;
-}
-
-/*
- * Function used for getting the resource asked by the
- * client. It is useful after the request header (EV_HTTP_REQ)
- * from client was received, otherwise NULL is returned.
- */
-char *pico_http_getResource(uint16_t conn)
-{
-    struct httpClient *client = findClient(conn);
-
-    if(!client)
-        return NULL;
-    else
-        return client->resource;
-}
-
-/*
- * After the resource was asked by the client (EV_HTTP_REQ)
- * before doing anything else, the server has to let know
- * the client if the resource can be provided or not.
- *
- * This is controlled via the code parameter which can
- * have two values :
- *
- * HTTP_RESOURCE_FOUND or HTTP_RESOURCE_NOT_FOUND
- *
- * If a resource is reported not found the 404 header will be sent and the connection
- * will be closed , otherwise the 200 header is sent and the user should
- * immediately submit data.
- *
- */
-int pico_http_respond(uint16_t conn, uint16_t code)
-{
-    struct httpClient *client = findClient(conn);
-
-    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, (const char *)returnOkHeader, sizeof(returnOkHeader) - 1); /* remove \0 */
-        }
-        else
-        {
-            int length;
-
-            length = pico_socket_write(client->sck, (const 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;
-    }
-
-}
-
-/*
- * API used to submit data to the client.
- * Server sends data only using Transfer-Encoding: chunked.
- *
- * With this function the user will submit a data chunk to
- * be sent.
- * The function will send the chunk size in hex and the rest will
- * be sent using WR event from sockets.
- * After each transmision EV_HTTP_PROGRESS is called and at the
- * end of the chunk EV_HTTP_SENT is called.
- *
- * To let the client know this is the last chunk, the user
- * should pass a NULL buffer.
- */
-int8_t pico_http_submitData(uint16_t conn, void *buffer, uint16_t len)
-{
-
-    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->buffer)
-    {
-        dbg("Already a buffer submited\n");
-        return HTTP_RETURN_ERROR;
-    }
-
-    if(!client)
-    {
-        dbg("Wrong connection ID\n");
-        return HTTP_RETURN_ERROR;
-    }
-
-    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;
-
-
-    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;
-    }
-
-    return HTTP_RETURN_OK;
-}
-
-/*
- * When EV_HTTP_PROGRESS is triggered you can use this
- * function to check the state of the chunk.
- */
-
-int pico_http_getProgress(uint16_t conn, uint16_t *sent, uint16_t *total)
-{
-    struct httpClient *client = findClient(conn);
-
-    if(!client)
-    {
-        dbg("Wrong connection id !\n");
-        return HTTP_RETURN_ERROR;
-    }
-
-    *sent = client->bufferSent;
-    *total = client->bufferSize;
-
-    return HTTP_RETURN_OK;
-}
-
-/*
- * This API can be used to close either a client
- * or the server ( if you pass HTTP_SERVER_ID as a connection ID).
- */
-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;
-
-            /* destroy the tree */
-            pico_tree_foreach_safe(index, &pico_http_clients, tmp)
-            {
-                struct httpClient *client = index->keyValue;
-
-                if(client->resource)
-                    pico_free(client->resource);
-
-                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
-    {
-
-        struct httpClient *client = findClient(conn);
-
-        if(!client)
-        {
-            dbg("Client not found..\n");
-            return HTTP_RETURN_ERROR;
-        }
-
-        pico_tree_delete(&pico_http_clients, client);
-
-        if(client->resource)
-            pico_free(client->resource);
-
-        if(client->buffer)
-            pico_free(client->buffer);
-
-        if(client->state != HTTP_CLOSED || !client->sck)
-            pico_socket_close(client->sck);
-
-        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 line[HTTP_HEADER_MAX_LINE];
-        uint32_t index = 0;
-
-        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;
-
-            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;
-        }
-
-        /* 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++;
-        }
-        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;
-        }
-
-        /* 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;
-
-    }
-
-    return HTTP_RETURN_ERROR;
-}
-
-
-
-int readRemainingHeader(struct httpClient *client)
-{
-    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;
-
-            }
-        }
-    }
-    return HTTP_RETURN_OK;
-}
-
-void sendData(struct httpClient *client)
-{
-    uint16_t length;
-    while( client->bufferSent < client->bufferSize &&
-           (length = (uint16_t)pico_socket_write(client->sck, (uint8_t *)client->buffer + client->bufferSent, \
-                                                 client->bufferSize - client->bufferSent)) > 0 )
-    {
-        client->bufferSent = (uint16_t)(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);
-        }
-    }
-
-}
-
-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_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;
-}
-
-struct httpClient *findClient(uint16_t conn)
-{
-    struct httpClient dummy = {
-        .connectionID = conn
-    };
-
-    return pico_tree_findKey(&pico_http_clients, &dummy);
-}
-#endif
--- a/modules/pico_http_server.h	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Author: Andrei Carp <andrei.carp@tass.be>
- *********************************************************************/
-
-#ifndef PICO_HTTP_SERVER_H_
-#define PICO_HTTP_SERVER_H_
-
-#include <stdint.h>
-#include "pico_http_util.h"
-
-/* Response codes */
-#define HTTP_RESOURCE_FOUND             0
-#define HTTP_RESOURCE_NOT_FOUND     1
-
-/* Generic id for the server */
-#define HTTP_SERVER_ID                  0u
-
-/*
- * Server functions
- */
-int8_t pico_http_server_start(uint16_t port, void (*wakeup)(uint16_t ev, uint16_t conn));
-int pico_http_server_accept(void);
-
-/*
- * Client functions
- */
-char *pico_http_getResource(uint16_t conn);
-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);
-int8_t   pico_http_submitData(uint16_t conn, void *buffer, uint16_t len);
-int      pico_http_close(uint16_t conn);
-
-#endif /* PICO_HTTP_SERVER_H_ */
--- a/modules/pico_http_util.c	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,186 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Author: Andrei Carp <andrei.carp@tass.be>
- *********************************************************************/
-
-#include <stdint.h>
-#include "pico_config.h"
-#include "pico_stack.h"
-#include "pico_protocol.h"
-#include "pico_http_util.h"
-
-#define TRUE    1
-#define FALSE 0
-
-#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;
-
-    /* transform to from number to string [ in backwards ] */
-    while(port)
-    {
-        ptr[size] = (char)(((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;
-}
-
-uint16_t pico_itoa(uint16_t port, char *ptr)
-{
-    uint16_t size = 0;
-    uint16_t index;
-
-    /* transform to from number to string [ in backwards ] */
-    while(port)
-    {
-        ptr[size] = (char)(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;
-}
-
-
-int8_t pico_processURI(const char *uri, struct pico_http_uri *urikey)
-{
-
-    uint16_t lastIndex = 0, index;
-
-    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 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;
-
-        goto error;
-    }
-    else
-    {
-        /* extract host */
-        urikey->host = (char *)pico_zalloc((uint32_t)(index - lastIndex + 1));
-
-        if(!urikey->host)
-        {
-            /* no memory */
-            goto error;
-        }
-
-        memcpy(urikey->host, uri + lastIndex, (size_t)(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 = (uint16_t)(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((size_t)(index - lastIndex + 1));
-
-        if(!urikey->resource)
-        {
-            /* no memory */
-            pico_err = PICO_ERR_ENOMEM;
-            goto error;
-        }
-
-        memcpy(urikey->resource, uri + lastIndex, (size_t)(index - lastIndex));
-    }
-
-    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;
-    }
-
-    return HTTP_RETURN_ERROR;
-}
-#endif
--- a/modules/pico_http_util.h	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Author: Andrei Carp <andrei.carp@tass.be>
- *********************************************************************/
-
-#ifndef PICO_HTTP_UTIL_H_
-#define PICO_HTTP_UTIL_H_
-
-/* Informational reponses */
-#define HTTP_CONTINUE                       100u
-#define HTTP_SWITCHING_PROTOCOLS  101u
-#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
-
-/* 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
-
-/* 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
-
-/* 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
-
-/* Returns used  */
-#define HTTP_RETURN_ERROR    -1
-#define HTTP_RETURN_OK              0
-
-/* List of events - shared between client and server */
-#define EV_HTTP_CON         1u
-#define EV_HTTP_REQ       2u
-#define EV_HTTP_PROGRESS  4u
-#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
-
-#ifndef TRUE
-    #define TRUE    1
-#endif
-
-#ifndef FALSE
-    #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 */
-};
-
-/* used for chunks */
-int pico_itoaHex(uint16_t port, char *ptr);
-uint16_t pico_itoa(uint16_t port, char *ptr);
-int8_t pico_processURI(const char *uri, struct pico_http_uri *urikey);
-
-#endif /* PICO_HTTP_UTIL_H_ */
--- a/modules/pico_icmp4.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_icmp4.c	Wed Apr 09 14:31:41 2014 +0200
@@ -52,7 +52,7 @@
     if (hdr->type == PICO_ICMP_ECHO) {
         hdr->type = PICO_ICMP_ECHOREPLY;
         /* outgoing frames require a f->len without the ethernet header len */
-        if (f->dev->eth)
+        if (f->dev && f->dev->eth)
             f->len -= PICO_SIZE_ETHHDR;
 
         pico_icmp4_checksum(f);
@@ -140,6 +140,12 @@
     return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_INTRANS);
 }
 
+int pico_icmp4_mtu_exceeded(struct pico_frame *f)
+{
+    /*Parameter check executed in pico_icmp4_notify*/
+    return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_NEEDFRAG);
+}
+
 int pico_icmp4_packet_filtered(struct pico_frame *f)
 {
     /*Parameter check executed in pico_icmp4_notify*/
@@ -187,10 +193,13 @@
 
 PICO_TREE_DECLARE(Pings, cookie_compare);
 
-static uint8_t pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie)
+static int8_t pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie)
 {
     struct pico_frame *echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size));
     struct pico_icmp4_hdr *hdr;
+    if (!echo) {
+        return -1;
+    }
 
     hdr = (struct pico_icmp4_hdr *) echo->transport_hdr;
 
@@ -226,7 +235,7 @@
         }
 
         pico_tree_delete(&Pings, cookie);
-        pico_free(cookie);
+        PICO_FREE(cookie);
     }
 }
 
@@ -236,7 +245,7 @@
     pico_icmp4_send_echo(cookie);
     cookie->timestamp = pico_tick;
     pico_timer_add((uint32_t)cookie->timeout, ping_timeout, cookie);
-    if (cookie->seq < cookie->count)
+    if (cookie->seq < (uint16_t)cookie->count)
         pico_timer_add((uint32_t)cookie->interval, next_ping, cookie);
 }
 
@@ -246,8 +255,8 @@
     IGNORE_PARAMETER(now);
 
     if(pico_tree_findKey(&Pings, cookie)) {
-        if (cookie->seq < cookie->count) {
-            newcookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie));
+        if (cookie->seq < (uint16_t)cookie->count) {
+            newcookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie));
             if (!newcookie)
                 return;
 
@@ -272,7 +281,7 @@
     if (cookie) {
         struct pico_icmp4_stats stats;
         cookie->err = PICO_PING_ERR_REPLIED;
-        stats.dst = cookie->dst;
+        stats.dst = ((struct pico_ipv4_hdr *)f->net_hdr)->src;
         stats.seq = cookie->seq;
         stats.size = cookie->size;
         stats.time = pico_tick - cookie->timestamp;
@@ -295,15 +304,15 @@
         return -1;
     }
 
-    cookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie));
+    cookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie));
     if (!cookie) {
         pico_err = PICO_ERR_ENOMEM;
         return -1;
     }
 
-    if (pico_string_to_ipv4(dst, &cookie->dst.addr) < 0) {
+    if (pico_string_to_ipv4(dst, (uint32_t *)&cookie->dst.addr) < 0) {
         pico_err = PICO_ERR_EINVAL;
-        pico_free(cookie);
+        PICO_FREE(cookie);
         return -1;
     }
 
--- a/modules/pico_icmp4.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_icmp4.h	Wed Apr 09 14:31:41 2014 +0200
@@ -5,20 +5,20 @@
    .
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_ICMP4
-#define _INCLUDE_PICO_ICMP4
+#ifndef INCLUDE_PICO_ICMP4
+#define INCLUDE_PICO_ICMP4
 #include "pico_addressing.h"
 #include "pico_protocol.h"
 
 extern struct pico_protocol pico_proto_icmp4;
 
-struct __attribute__((packed)) pico_icmp4_hdr {
+PACKED_STRUCT_DEF pico_icmp4_hdr {
     uint8_t type;
     uint8_t code;
     uint16_t crc;
 
     /* hun */
-    union {
+    union hun_u {
         uint8_t ih_pptr;
         struct pico_ip4 ih_gwaddr;
         struct {
@@ -38,7 +38,7 @@
     } hun;
 
     /* dun */
-    union {
+    union dun_u {
         struct {
             uint32_t ts_otime;
             uint32_t ts_rtime;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_icmp6.h	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,214 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+ *********************************************************************/
+#ifndef _INCLUDE_PICO_ICMP6
+#define _INCLUDE_PICO_ICMP6
+#include "pico_addressing.h"
+#include "pico_protocol.h"
+
+/* ICMP header sizes */
+#define PICO_ICMP6HDR_DRY_SIZE          4
+#define PICO_ICMP6HDR_ECHO_REQUEST_SIZE 8
+#define PICO_ICMP6HDR_DEST_UNREACH_SIZE 8
+#define PICO_ICMP6HDR_TIME_XCEEDED_SIZE 8
+#define PICO_ICMP6HDR_NEIGH_SOL_SIZE    24
+#define PICO_ICMP6HDR_NEIGH_ADV_SIZE    24
+#define PICO_ICMP6HDR_ROUTER_SOL_SIZE   8
+#define PICO_ICMP6HDR_ROUTER_ADV_SIZE   16
+#define PICO_ICMP6HDR_REDIRECT_SIZE     40
+
+/* ICMP types */
+#define PICO_ICMP6_DEST_UNREACH        1
+#define PICO_ICMP6_PKT_TOO_BIG         2
+#define PICO_ICMP6_TIME_EXCEEDED       3
+#define PICO_ICMP6_PARAM_PROBLEM       4
+#define PICO_ICMP6_ECHO_REQUEST        128
+#define PICO_ICMP6_ECHO_REPLY          129
+#define PICO_ICMP6_ROUTER_SOL          133
+#define PICO_ICMP6_ROUTER_ADV          134
+#define PICO_ICMP6_NEIGH_SOL           135
+#define PICO_ICMP6_NEIGH_ADV           136
+#define PICO_ICMP6_REDIRECT            137
+
+/* destination unreachable codes */
+#define PICO_ICMP6_UNREACH_NOROUTE     0
+#define PICO_ICMP6_UNREACH_ADMIN       1
+#define PICO_ICMP6_UNREACH_SRCSCOPE    2
+#define PICO_ICMP6_UNREACH_ADDR        3
+#define PICO_ICMP6_UNREACH_PORT        4
+#define PICO_ICMP6_UNREACH_SRCFILTER   5
+#define PICO_ICMP6_UNREACH_REJROUTE    6
+
+/* time exceeded codes */
+#define PICO_ICMP6_TIMXCEED_INTRANS    0
+#define PICO_ICMP6_TIMXCEED_REASS      1
+
+/* parameter problem codes */
+#define PICO_ICMP6_PARAMPROB_HDRFIELD  0
+#define PICO_ICMP6_PARAMPROB_NXTHDR    1
+#define PICO_ICMP6_PARAMPROB_IPV6OPT   2
+
+/* ping error codes */
+#define PICO_PING6_ERR_REPLIED         0
+#define PICO_PING6_ERR_TIMEOUT         1
+#define PICO_PING6_ERR_UNREACH         2
+#define PICO_PING6_ERR_PENDING         0xFFFF
+
+/* custom defines */
+#define PICO_ICMP6_ND_UNICAST          0
+#define PICO_ICMP6_ND_ANYCAST          1
+#define PICO_ICMP6_ND_SOLICITED        2
+#define PICO_ICMP6_ND_DAD              3
+
+#define PICO_ICMP6_MAX_RTR_SOL_DELAY   1000
+
+#define PICO_SIZE_ICMP6HDR ((sizeof(struct pico_icmp6_hdr)))
+
+extern struct pico_protocol pico_proto_icmp6;
+
+PACKED_STRUCT_DEF pico_icmp6_hdr {
+    uint8_t type;
+    uint8_t code;
+    uint16_t crc;
+
+    union icmp6_msg_u {
+        /* error messages */
+        union icmp6_err_u {
+            struct {
+                uint32_t unused;
+                uint8_t data[0];
+            } dest_unreach;
+            struct {
+                uint32_t mtu;
+                uint8_t data[0];
+            } pkt_too_big;
+            struct {
+                uint32_t unused;
+                uint8_t data[0];
+            } time_exceeded;
+            struct {
+                uint32_t ptr;
+                uint8_t data[0];
+            } param_problem;
+        } err;
+
+        /* informational messages */
+        union icmp6_info_u {
+            struct {
+                uint16_t id;
+                uint16_t seq;
+                uint8_t data[0];
+            } echo_request;
+            struct {
+                uint16_t id;
+                uint16_t seq;
+                uint8_t data[0];
+            } echo_reply;
+            struct {
+                uint32_t unused;
+                uint8_t options[0];
+            } router_sol;
+            struct {
+                uint8_t hop;
+                uint8_t mor;
+                uint16_t life_time;
+                uint32_t reachable_time;
+                uint32_t retrans_time;
+                uint8_t options[0];
+            } router_adv;
+            struct {
+                uint32_t unused;
+                struct pico_ip6 target;
+                uint8_t options[0];
+            } neigh_sol;
+            struct {
+                uint32_t rsor;
+                struct pico_ip6 target;
+                uint8_t options[0];
+            } neigh_adv;
+            struct {
+                uint32_t reserved;
+                struct pico_ip6 target;
+                struct pico_ip6 dest;
+                uint8_t options[0];
+            } redirect;
+        } info;
+    } msg;
+};
+
+PACKED_STRUCT_DEF pico_icmp6_opt_lladdr
+{
+    uint8_t type;
+    uint8_t len;
+    union icmp6_opt_hw_addr_u {
+        struct pico_eth mac;
+    } addr;
+};
+
+PACKED_STRUCT_DEF pico_icmp6_opt_prefix
+{
+    uint8_t type;
+    uint8_t len;
+    uint8_t prefix_len;
+    uint8_t res : 6;
+    uint8_t aac : 1;
+    uint8_t onlink : 1;
+    uint32_t val_lifetime;
+    uint32_t pref_lifetime;
+    uint32_t reserved;
+    struct pico_ip6 prefix;
+};
+
+PACKED_STRUCT_DEF pico_icmp6_opt_mtu
+{
+    uint8_t type;
+    uint8_t len;
+    uint16_t res;
+    uint32_t mtu;
+};
+
+PACKED_STRUCT_DEF pico_icmp6_opt_redirect
+{
+    uint8_t type;
+    uint8_t len;
+    uint16_t res0;
+    uint32_t res1;
+    uint8_t data[0];
+};
+
+PACKED_STRUCT_DEF pico_icmp6_opt_na
+{
+    uint8_t type;
+    uint8_t len;
+    uint8_t options[0];
+};
+
+struct pico_icmp6_stats
+{
+    unsigned long size;
+    unsigned long seq;
+    pico_time time;
+    unsigned long ttl;
+    int err;
+    struct pico_ip6 dst;
+};
+
+int pico_icmp6_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp6_stats *));
+
+int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *dst, uint8_t type);
+int pico_icmp6_neighbor_advertisement(struct pico_frame *f, struct pico_ip6 *target);
+int pico_icmp6_router_solicitation(struct pico_device *dev, struct pico_ip6 *src);
+
+int pico_icmp6_port_unreachable(struct pico_frame *f);
+int pico_icmp6_proto_unreachable(struct pico_frame *f);
+int pico_icmp6_dest_unreachable(struct pico_frame *f);
+int pico_icmp6_ttl_expired(struct pico_frame *f);
+int pico_icmp6_packet_filtered(struct pico_frame *f);
+
+uint16_t pico_icmp6_checksum(struct pico_frame *f);
+
+#endif
--- a/modules/pico_igmp.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_igmp.c	Wed Apr 09 14:31:41 2014 +0200
@@ -79,14 +79,14 @@
 #define IP_OPTION_ROUTER_ALERT_LEN        (4u)
 #define IGMP_MAX_GROUPS                   (32) /* max 255 */
 
-struct __attribute__((packed)) igmp_message {
+PACKED_STRUCT_DEF igmp_message {
     uint8_t type;
     uint8_t max_resp_time;
     uint16_t crc;
     uint32_t mcast_group;
 };
 
-struct __attribute__((packed)) igmpv3_query {
+PACKED_STRUCT_DEF igmpv3_query {
     uint8_t type;
     uint8_t max_resp_time;
     uint16_t crc;
@@ -97,7 +97,7 @@
     uint32_t source_addr[];
 };
 
-struct __attribute__((packed)) igmpv3_group_record {
+PACKED_STRUCT_DEF igmpv3_group_record {
     uint8_t type;
     uint8_t aux;
     uint16_t sources;
@@ -105,7 +105,7 @@
     uint32_t source_addr[];
 };
 
-struct __attribute__((packed)) igmpv3_report {
+PACKED_STRUCT_DEF igmpv3_report {
     uint8_t type;
     uint8_t res0;
     uint16_t crc;
@@ -215,6 +215,9 @@
     struct igmp_parameters test = {
         0
     };
+    if (!mcast_link || !mcast_group)
+        return NULL;
+
     test.mcast_link.addr = mcast_link->addr;
     test.mcast_group.addr = mcast_group->addr;
     return pico_tree_findKey(&IGMPParameters, &test);
@@ -223,7 +226,7 @@
 static int pico_igmp_delete_parameter(struct igmp_parameters *p)
 {
     if (pico_tree_delete(&IGMPParameters, p))
-        pico_free(p);
+        PICO_FREE(p);
     else
         return -1;
 
@@ -248,7 +251,7 @@
     }
 
     if (timer->stopped == IGMP_TIMER_STOPPED) {
-        pico_free(t);
+        PICO_FREE(t);
         return;
     }
 
@@ -257,7 +260,7 @@
         if (timer->callback)
             timer->callback(timer);
 
-        pico_free(timer);
+        PICO_FREE(timer);
     } else {
         igmp_dbg("IGMP: restart timer for %08X, delay %lu, new delay %lu\n", t->mcast_group.addr, t->delay,  (timer->start + timer->delay) - PICO_TIME_MS());
         pico_timer_add((timer->start + timer->delay) - PICO_TIME_MS(), &pico_igmp_timer_expired, timer);
@@ -299,7 +302,7 @@
     if (timer)
         return pico_igmp_timer_reset(t);
 
-    timer = pico_zalloc(sizeof(struct igmp_timer));
+    timer = PICO_ZALLOC(sizeof(struct igmp_timer));
     if (!timer) {
         pico_err = PICO_ERR_ENOMEM;
         return -1;
@@ -488,7 +491,7 @@
     mcast_group.addr = message->mcast_group;
     p = pico_igmp_find_parameter(&link->address, &mcast_group);
     if (!p && mcast_group.addr == 0) { /* general query */
-        p = pico_zalloc(sizeof(struct igmp_parameters));
+        p = PICO_ZALLOC(sizeof(struct igmp_parameters));
         if (!p)
             return NULL;
 
@@ -572,12 +575,17 @@
 
     p = pico_igmp_find_parameter(mcast_link, mcast_group);
     if (!p && state == PICO_IGMP_STATE_CREATE) {
-        p = pico_zalloc(sizeof(struct igmp_parameters));
+        p = PICO_ZALLOC(sizeof(struct igmp_parameters));
         if (!p) {
             pico_err = PICO_ERR_ENOMEM;
             return -1;
         }
 
+        if (!mcast_link || !mcast_group) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+
         p->state = IGMP_STATE_NON_MEMBER;
         p->mcast_link = *mcast_link;
         p->mcast_group = *mcast_group;
@@ -1154,7 +1162,7 @@
         return -1;
 
     time_to_run = (uint32_t)(t->start + t->delay - PICO_TIME_MS());
-    if ((p->max_resp_time * 100) < time_to_run) { /* max_resp_time in units of 1/10 seconds */
+    if ((p->max_resp_time * 100u) < time_to_run) { /* max_resp_time in units of 1/10 seconds */
         t->delay = pico_rand() % (p->max_resp_time * 100u);
         pico_igmp_timer_reset(t);
     }
--- a/modules/pico_igmp.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_igmp.h	Wed Apr 09 14:31:41 2014 +0200
@@ -7,8 +7,8 @@
    Authors: Kristof Roelants, Simon Maes, Brecht Van Cauwenberghe
  *********************************************************************/
 
-#ifndef _INCLUDE_PICO_IGMP
-#define _INCLUDE_PICO_IGMP
+#ifndef INCLUDE_PICO_IGMP
+#define INCLUDE_PICO_IGMP
 
 #define PICO_IGMPV1               1
 #define PICO_IGMPV2               2
--- a/modules/pico_ipfilter.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_ipfilter.c	Wed Apr 09 14:31:41 2014 +0200
@@ -134,15 +134,20 @@
 
     ipf_dbg("ipfilter> adding filter\n");
 
-    new_filter = pico_zalloc(sizeof(struct filter_node));
+    new_filter = PICO_ZALLOC(sizeof(struct filter_node));
+
+    if (!new_filter) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
 
     new_filter->fdev = dev;
     new_filter->proto = proto;
 
-    new_filter->out_addr = (!out_addr) ? 0U : out_addr->addr;
-    new_filter->out_addr_netmask = (!out_addr_netmask) ? 0U : out_addr_netmask->addr;
-    new_filter->in_addr = (!in_addr) ? 0U : in_addr->addr;
-    new_filter->in_addr_netmask = (!in_addr_netmask) ? 0U : in_addr_netmask->addr;
+    new_filter->out_addr = (!out_addr) ? (0U) : (out_addr->addr);
+    new_filter->out_addr_netmask = (!out_addr_netmask) ? (0U) : (out_addr_netmask->addr);
+    new_filter->in_addr = (!in_addr) ? (0U) : (in_addr->addr);
+    new_filter->in_addr_netmask = (!in_addr_netmask) ? (0U) : (in_addr_netmask->addr);
 
     new_filter->out_port = out_port;
     new_filter->in_port = in_port;
@@ -171,7 +176,7 @@
     }
     if(pico_tree_insert(&filter_tree, new_filter))
     {
-        pico_free(new_filter);
+        PICO_FREE(new_filter);
         ipf_dbg("ipfilter> failed adding filter to tree.\n");
         return -1;
     }
@@ -191,7 +196,7 @@
         return -1;
     }
 
-    pico_free(node);
+    PICO_FREE(node);
     return 0;
 }
 
--- a/modules/pico_ipfilter.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_ipfilter.h	Wed Apr 09 14:31:41 2014 +0200
@@ -4,8 +4,8 @@
 
    Authors: Simon Maes
  *********************************************************************/
-#ifndef _INCLUDE_PICO_IPFILTER
-#define _INCLUDE_PICO_IPFILTER
+#ifndef INCLUDE_PICO_IPFILTER
+#define INCLUDE_PICO_IPFILTER
 
 #include "pico_device.h"
 
--- a/modules/pico_ipv4.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_ipv4.c	Wed Apr 09 14:31:41 2014 +0200
@@ -19,16 +19,19 @@
 #include "pico_nat.h"
 #include "pico_igmp.h"
 #include "pico_tree.h"
+#include "pico_socket_multicast.h"
 
 #ifdef PICO_SUPPORT_IPV4
 
 #ifdef PICO_SUPPORT_MCAST
 # define ip_mcast_dbg(...) do {} while(0) /* so_mcast_dbg in pico_socket.c */
+/* #define ip_mcast_dbg dbg */
 # define PICO_MCAST_ALL_HOSTS long_be(0xE0000001) /* 224.0.0.1 */
 /* Default network interface for multicast transmission */
 static struct pico_ipv4_link *mcast_default_link = NULL;
 #endif
 #ifdef PICO_SUPPORT_IPFRAG
+/* # define reassembly_dbg dbg */
 # define reassembly_dbg(...) do {} while(0)
 #endif
 
@@ -42,6 +45,7 @@
 
 /* Functions */
 static int ipv4_route_compare(void *ka, void *kb);
+static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, uint16_t size);
 
 int pico_ipv4_to_string(char *ipbuf, const uint32_t ip)
 {
@@ -74,6 +78,18 @@
     return 0;
 }
 
+static int pico_string_check_null_args(const char *ipstr, uint32_t *ip)
+{
+
+    if(!ipstr || !ip) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    return 0;
+
+}
+
 int pico_string_to_ipv4(const char *ipstr, uint32_t *ip)
 {
     unsigned char buf[4] = {
@@ -82,10 +98,9 @@
     int cnt = 0;
     char p;
 
-    if(!ipstr || !ip) {
-        pico_err = PICO_ERR_EINVAL;
+    if (pico_string_check_null_args(ipstr, ip) < 0)
         return -1;
-    }
+
 
     while((p = *ipstr++) != 0)
     {
@@ -172,7 +187,12 @@
     return 0;
 }
 
-int pico_ipv4_is_valid_src(uint32_t address)
+static int pico_ipv4_is_invalid_loopback(uint32_t address, struct pico_device *dev)
+{
+    return pico_ipv4_is_loopback(address) && ((!dev) || strcmp(dev->name, "loop"));
+}
+
+int pico_ipv4_is_valid_src(uint32_t address, struct pico_device *dev)
 {
     if (pico_ipv4_is_broadcast(address)) {
         dbg("Source is a broadcast address, discard packet\n");
@@ -182,7 +202,7 @@
         dbg("Source is a multicast address, discard packet\n");
         return 0;
     }
-    else if (pico_ipv4_is_loopback(address)) {
+    else if (pico_ipv4_is_invalid_loopback(address, dev)) {
         dbg("Source is a loopback address, discard packet\n");
         return 0;
     }
@@ -246,12 +266,16 @@
 {
     struct pico_frame *frame_a = ka, *frame_b = kb;
     struct pico_ipv4_hdr *a, *b;
+    uint16_t a_frag, b_frag;
     a = (struct pico_ipv4_hdr *) frame_a->net_hdr;
     b = (struct pico_ipv4_hdr *) frame_b->net_hdr;
+    a_frag = short_be(a->frag & PICO_IPV4_FRAG_MASK);
+    b_frag = short_be(b->frag & PICO_IPV4_FRAG_MASK);
 
-    if (short_be((a->frag & PICO_IPV4_FRAG_MASK)) < short_be((b->frag & PICO_IPV4_FRAG_MASK)))
+    if (a_frag < b_frag)
         return -1;
-    else if (short_be((a->frag & PICO_IPV4_FRAG_MASK)) > short_be((b->frag & PICO_IPV4_FRAG_MASK)))
+
+    if (b_frag < a_frag)
         return 1;
     else
         return 0;
@@ -271,8 +295,8 @@
         pico_frame_discard(f_frag);
     }
     pico_tree_delete(&pico_ipv4_fragmented_tree, pfrag);
-    pico_free(pfrag->t);
-    pico_free(pfrag);
+    PICO_FREE(pfrag->t);
+    PICO_FREE(pfrag);
 }
 #endif /* PICO_SUPPORT_IPFRAG */
 
@@ -298,8 +322,6 @@
     uint16_t offset = 0;
     uint16_t data_len = 0;
     struct pico_ipv4_hdr *f_frag_hdr = NULL, *hdr = (struct pico_ipv4_hdr *) (*f)->net_hdr;
-    struct pico_udp_hdr *udp_hdr = NULL;
-    struct pico_tcp_hdr *tcp_hdr = NULL;
     struct pico_ipv4_fragmented_packet *pfrag = NULL;
     struct pico_frame *f_new = NULL, *f_frag = NULL;
     struct pico_tree_node *index, *_tmp;
@@ -317,7 +339,7 @@
             }
 
             /* add entry in tree for this ID and create secondary tree to contain fragmented elements */
-            pfrag = pico_zalloc(sizeof(struct pico_ipv4_fragmented_packet));
+            pfrag = PICO_ZALLOC(sizeof(struct pico_ipv4_fragmented_packet));
             if (!pfrag) {
                 pico_err = PICO_ERR_ENOMEM;
                 return -1;
@@ -328,9 +350,9 @@
             pfrag->src.addr = long_be(hdr->src.addr);
             pfrag->dst.addr = long_be(hdr->dst.addr);
             pfrag->total_len = (uint16_t)(short_be(hdr->len) - (*f)->net_len);
-            pfrag->t = pico_zalloc(sizeof(struct pico_tree));
+            pfrag->t = PICO_ZALLOC(sizeof(struct pico_tree));
             if (!pfrag->t) {
-                pico_free(pfrag);
+                PICO_FREE(pfrag);
                 pico_err = PICO_ERR_ENOMEM;
                 return -1;
             }
@@ -378,6 +400,8 @@
             }
 
             f_new = self->alloc(self, pfrag->total_len);
+            if (!f_new)
+                return -1;
 
             f_frag = pico_tree_first(pfrag->t);
             reassembly_dbg("REASSEMBLY: copy IP header information len = %lu\n", f_frag->net_len);
@@ -385,6 +409,7 @@
             data_len = (uint16_t)(short_be(f_frag_hdr->len) - f_frag->net_len);
             memcpy(f_new->net_hdr, f_frag->net_hdr, f_frag->net_len);
             memcpy(f_new->transport_hdr, f_frag->transport_hdr, data_len);
+            f_new->dev = f_frag->dev;
             running_pointer = f_new->transport_hdr + data_len;
             offset = short_be(f_frag_hdr->frag) & PICO_IPV4_FRAG_MASK;
             running_offset = data_len / 8;
@@ -412,7 +437,7 @@
                 reassembly_dbg("REASSEMBLY: reassembled intermediate packet of %u data bytes, offset = %u next expected offset = %u\n", data_len, offset, running_offset);
             }
             pico_tree_delete(&pico_ipv4_fragmented_tree, pfrag);
-            pico_free(pfrag);
+            PICO_FREE(pfrag);
 
             data_len = (uint16_t)(short_be(hdr->len) - (*f)->net_len);
             memcpy(running_pointer, (*f)->transport_hdr, data_len);
@@ -429,12 +454,14 @@
             if (0) {
   #ifdef PICO_SUPPORT_TCP
             } else if (hdr->proto == PICO_PROTO_TCP) {
+                struct pico_tcp_hdr *tcp_hdr = NULL;
                 tcp_hdr = (struct pico_tcp_hdr *) f_new->transport_hdr;
                 tcp_hdr->crc = 0;
-                tcp_hdr->crc = short_be(pico_tcp_checksum_ipv4(f_new));
+                tcp_hdr->crc = short_be(pico_tcp_checksum(f_new));
   #endif
   #ifdef PICO_SUPPORT_UDP
             } else if (hdr->proto == PICO_PROTO_UDP) {
+                struct pico_udp_hdr *udp_hdr = NULL;
                 udp_hdr = (struct pico_udp_hdr *) f_new->transport_hdr;
                 udp_hdr->crc = 0;
                 udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f_new));
@@ -511,14 +538,98 @@
 
 PICO_TREE_DECLARE(Tree_dev_link, ipv4_link_compare);
 
+static int pico_ipv4_process_bcast_in(struct pico_frame *f)
+{
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+#ifdef PICO_SUPPORT_UDP
+    if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_UDP)) {
+        /* Receiving UDP broadcast datagram */
+        f->flags |= PICO_FRAME_FLAG_BCAST;
+        pico_enqueue(pico_proto_udp.q_in, f);
+        return 1;
+    }
+
+    if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_ICMP4)) {
+        /* Receiving ICMP4 bcast packet */
+        f->flags |= PICO_FRAME_FLAG_BCAST;
+        pico_enqueue(pico_proto_icmp4.q_in, f);
+        return 1;
+    }
+
+#endif
+    return 0;
+}
+
+static int pico_ipv4_process_mcast_in(struct pico_frame *f)
+{
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    if (pico_ipv4_is_multicast(hdr->dst.addr)) {
+#ifdef PICO_SUPPORT_MCAST
+        /* Receiving UDP multicast datagram TODO set f->flags? */
+        if (hdr->proto == PICO_PROTO_IGMP) {
+            ip_mcast_dbg("MCAST: received IGMP message\n");
+            pico_transport_receive(f, PICO_PROTO_IGMP);
+            return 1;
+        } else if ((pico_ipv4_mcast_filter(f) == 0) && (hdr->proto == PICO_PROTO_UDP)) {
+            pico_enqueue(pico_proto_udp.q_in, f);
+            return 1;
+        }
+
+#endif
+        pico_frame_discard(f);
+        return 1;
+    }
+
+    return 0;
+}
+
+static int pico_ipv4_process_local_unicast_in(struct pico_frame *f)
+{
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    struct pico_ipv4_link test = {
+        .address = {.addr = PICO_IP4_ANY}, .dev = NULL
+    };
+    if (pico_ipv4_link_find(&hdr->dst)) {
+        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);
+
+        return 1;
+    } 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);
+        return 1;
+#endif
+    }
+
+    return 0;
+}
+
+static void pico_ipv4_process_finally_try_forward(struct pico_frame *f)
+{
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    if((pico_ipv4_is_broadcast(hdr->dst.addr)))
+    {
+        /* don't forward broadcast frame, discard! */
+        pico_frame_discard(f);
+    } else if (pico_ipv4_forward(f) != 0) {
+        pico_frame_discard(f);
+        /* dbg("Forward failed.\n"); */
+    }
+}
+
+
+
 static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f)
 {
     uint8_t option_len = 0;
     int ret = 0;
     struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
-    struct pico_ipv4_link test = {
-        .address = {.addr = PICO_IP4_ANY}, .dev = NULL
-    };
 
     /* NAT needs transport header information */
     if(((hdr->vhl) & 0x0F) > 5) {
@@ -547,7 +658,7 @@
         return ret;
 
     /* Validate source IP address. Discard quietly if invalid */
-    if (!pico_ipv4_is_valid_src(hdr->src.addr)) {
+    if (!pico_ipv4_is_valid_src(hdr->src.addr, f->dev)) {
         pico_frame_discard(f);
         return 0;
     }
@@ -557,50 +668,16 @@
         return 0;
     }
 
-    if (0) {
-#ifdef PICO_SUPPORT_UDP
-    } else if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_UDP)) {
-        /* Receiving UDP broadcast datagram */
-        f->flags |= PICO_FRAME_FLAG_BCAST;
-        pico_enqueue(pico_proto_udp.q_in, f);
-#endif
-    } else if (pico_ipv4_is_multicast(hdr->dst.addr)) {
-#ifdef PICO_SUPPORT_MCAST
-        /* Receiving UDP multicast datagram TODO set f->flags? */
-        if (hdr->proto == PICO_PROTO_IGMP) {
-            ip_mcast_dbg("MCAST: received IGMP message\n");
-            pico_transport_receive(f, PICO_PROTO_IGMP);
-        } else if ((pico_ipv4_mcast_filter(f) == 0) && (hdr->proto == PICO_PROTO_UDP)) {
-            pico_enqueue(pico_proto_udp.q_in, f);
-        } else {
-            pico_frame_discard(f);
-        }
+    if (pico_ipv4_process_bcast_in(f) > 0)
+        return 0;
 
-#endif
-    } else if (pico_ipv4_link_find(&hdr->dst)) {
-        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 {
+    if (pico_ipv4_process_mcast_in(f) > 0)
+        return 0;
 
-        if((pico_ipv4_is_broadcast(hdr->dst.addr)))
-        {
-            /* don't forward broadcast frame, discard! */
-            pico_frame_discard(f);
-        } else if (pico_ipv4_forward(f) != 0) {
-            pico_frame_discard(f);
-            /* dbg("Forward failed.\n"); */
-        }
-    }
+    if (pico_ipv4_process_local_unicast_in(f) > 0)
+        return 0;
+
+    pico_ipv4_process_finally_try_forward(f);
 
     return 0;
 }
@@ -668,12 +745,16 @@
 static int ipv4_route_compare(void *ka, void *kb)
 {
     struct pico_ipv4_route *a = ka, *b = kb;
+    uint32_t a_nm, b_nm;
+
+    a_nm = long_be(a->netmask.addr);
+    b_nm = long_be(b->netmask.addr);
 
     /* Routes are sorted by (host side) netmask len, then by addr, then by metric. */
-    if (long_be(a->netmask.addr) < long_be(b->netmask.addr))
+    if (a_nm < b_nm)
         return -1;
 
-    if (long_be(a->netmask.addr) > long_be(b->netmask.addr))
+    if (b_nm < a_nm)
         return 1;
 
     if (a->dest.addr < b->dest.addr)
@@ -802,9 +883,10 @@
 static void pico_ipv4_mcast_print_groups(struct pico_ipv4_link *mcast_link)
 {
     uint16_t i = 0;
-    struct pico_mcast_group __attribute__ ((unused)) *g = NULL;
-    struct pico_ip4 __attribute__ ((unused)) *source = NULL;
+    struct pico_mcast_group *g = NULL;
+    struct pico_ip4 *source = NULL;
     struct pico_tree_node *index = NULL, *index2 = NULL;
+    (void) source;
 
     ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
     ip_mcast_dbg("+                           MULTICAST list interface %-16s             +\n", mcast_link->dev->name);
@@ -835,20 +917,22 @@
     {
         source = index->keyValue;
         pico_tree_delete(&g->MCASTSources, source);
-        pico_free(source);
+        PICO_FREE(source);
     }
     /* insert new filter */
     if (MCASTFilter) {
         pico_tree_foreach(index, MCASTFilter)
         {
-            source = pico_zalloc(sizeof(struct pico_ip4));
-            if (!source) {
-                pico_err = PICO_ERR_ENOMEM;
-                return -1;
+            if (index->keyValue) {
+                source = PICO_ZALLOC(sizeof(struct pico_ip4));
+                if (!source) {
+                    pico_err = PICO_ERR_ENOMEM;
+                    return -1;
+                }
+
+                source->addr = ((struct pico_ip4 *)index->keyValue)->addr;
+                pico_tree_insert(&g->MCASTSources, source);
             }
-
-            source->addr = ((struct pico_ip4 *)index->keyValue)->addr;
-            pico_tree_insert(&g->MCASTSources, source);
         }
     }
 
@@ -876,7 +960,7 @@
 
         pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE);
     } else {
-        g = pico_zalloc(sizeof(struct pico_mcast_group));
+        g = PICO_ZALLOC(sizeof(struct pico_mcast_group));
         if (!g) {
             pico_err = PICO_ERR_ENOMEM;
             return -1;
@@ -892,8 +976,10 @@
         pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_CREATE);
     }
 
-    if (mcast_group_update(g, MCASTFilter, filter_mode) < 0)
+    if (mcast_group_update(g, MCASTFilter, filter_mode) < 0) {
+        dbg("Error in mcast_group update\n");
         return -1;
+    }
 
     pico_ipv4_mcast_print_groups(link);
     return 0;
@@ -927,10 +1013,10 @@
             {
                 source = index->keyValue;
                 pico_tree_delete(&g->MCASTSources, source);
-                pico_free(source);
+                PICO_FREE(source);
             }
             pico_tree_delete(link->MCASTGroups, g);
-            pico_free(g);
+            PICO_FREE(g);
         } else {
             pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE);
             if (mcast_group_update(g, MCASTFilter, filter_mode) < 0)
@@ -1111,7 +1197,11 @@
 
     hdr->vhl = vhl;
     hdr->len = short_be((uint16_t)(f->transport_len + f->net_len));
-    if (f->transport_hdr != f->payload)
+    if ((f->transport_hdr != f->payload)  &&
+#ifdef PICO_SUPPORT_IPFRAG
+        (0 == (f->frag & PICO_IPV4_MOREFRAG)) &&
+#endif
+        1 )
         ipv4_progressive_id++;
 
     hdr->id = short_be(ipv4_progressive_id);
@@ -1131,7 +1221,10 @@
         hdr->frag = f->frag;
     }
 
-#  endif /* PICO_SUPPORT_UDP */
+    if (proto == PICO_PROTO_ICMP4)
+        hdr->frag = f->frag;
+
+#   endif
 #endif /* PICO_SUPPORT_IPFRAG */
     pico_ipv4_checksum(f);
 
@@ -1172,7 +1265,7 @@
 static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f)
 {
     struct pico_ip4 *dst;
-    struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info;
+    struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *) f->info;
     IGNORE_PARAMETER(self);
 
     if (!f->sock) {
@@ -1180,8 +1273,8 @@
         return -1;
     }
 
-    if (remote_duple) {
-        dst = &remote_duple->remote_addr.ip4;
+    if (remote_endpoint) {
+        dst = &remote_endpoint->remote_addr.ip4;
     } else {
         dst = &f->sock->remote_addr.ip4;
     }
@@ -1202,7 +1295,7 @@
         return -1;
     }
 
-    new = pico_zalloc(sizeof(struct pico_ipv4_route));
+    new = PICO_ZALLOC(sizeof(struct pico_ipv4_route));
     if (!new) {
         pico_err = PICO_ERR_ENOMEM;
         return -1;
@@ -1219,13 +1312,13 @@
         struct pico_ipv4_route *r = route_find(&gateway);
         if (!r ) { /* Specified Gateway is unreachable */
             pico_err = PICO_ERR_EHOSTUNREACH;
-            pico_free(new);
+            PICO_FREE(new);
             return -1;
         }
 
         if (r->gateway.addr) { /* Specified Gateway is not a neighbor */
             pico_err = PICO_ERR_ENETUNREACH;
-            pico_free(new);
+            PICO_FREE(new);
             return -1;
         }
 
@@ -1234,7 +1327,7 @@
 
     if (!new->link) {
         pico_err = PICO_ERR_EINVAL;
-        pico_free(new);
+        PICO_FREE(new);
         return -1;
     }
 
@@ -1255,7 +1348,7 @@
     if (found) {
 
         pico_tree_delete(&Routes, found);
-        pico_free(found);
+        PICO_FREE(found);
 
         /* dbg_route(); */
         return 0;
@@ -1289,7 +1382,7 @@
     }
 
     /** XXX: Check for network already in use (e.g. trying to assign 10.0.0.1/24 where 10.1.0.1/8 is in use) **/
-    new = pico_zalloc(sizeof(struct pico_ipv4_link));
+    new = PICO_ZALLOC(sizeof(struct pico_ipv4_link));
     if (!new) {
         dbg("IPv4: Out of memory!\n");
         pico_err = PICO_ERR_ENOMEM;
@@ -1300,9 +1393,9 @@
     new->netmask.addr = netmask.addr;
     new->dev = dev;
 #ifdef PICO_SUPPORT_MCAST
-    new->MCASTGroups = pico_zalloc(sizeof(struct pico_tree));
+    new->MCASTGroups = PICO_ZALLOC(sizeof(struct pico_tree));
     if (!new->MCASTGroups) {
-        pico_free(new);
+        PICO_FREE(new);
         dbg("IPv4: Out of memory!\n");
         pico_err = PICO_ERR_ENOMEM;
         return -1;
@@ -1388,14 +1481,14 @@
         {
             g = index->keyValue;
             pico_tree_delete(found->MCASTGroups, g);
-            pico_free(g);
+            PICO_FREE(g);
         }
     } while(0);
 #endif
 
     pico_ipv4_cleanup_routes(found);
     pico_tree_delete(&Tree_dev_link, found);
-    pico_free(found);
+    PICO_FREE(found);
 
     return 0;
 }
@@ -1470,6 +1563,51 @@
     return found->dev;
 }
 
+
+
+static int pico_ipv4_rebound_large(struct pico_frame *f)
+{
+    uint32_t total_payload_written = 0;
+    uint32_t len = f->transport_len;
+    struct pico_frame *fr;
+    struct pico_ip4 dst;
+    struct pico_ipv4_hdr *hdr;
+    hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    dst.addr = hdr->src.addr;
+
+#ifdef PICO_SUPPORT_IPFRAG
+    while(total_payload_written < len) {
+        uint32_t space = (uint32_t)len - total_payload_written;
+        if (space > PICO_IPV4_MAXPAYLOAD)
+            space = PICO_IPV4_MAXPAYLOAD;
+
+        fr = pico_ipv4_alloc(&pico_proto_ipv4, (uint16_t)space);
+        if (!fr) {
+            pico_err = PICO_ERR_ENOMEM;
+            return -1;
+        }
+
+        if (space + total_payload_written < len)
+            fr->frag |= short_be(PICO_IPV4_MOREFRAG);
+        else
+            fr->frag &= short_be(PICO_IPV4_FRAG_MASK);
+
+        fr->frag |= short_be((uint16_t)((total_payload_written) >> 3u));
+
+        memcpy(fr->transport_hdr, f->transport_hdr + total_payload_written, fr->transport_len);
+        if (pico_ipv4_frame_push(fr, &dst, hdr->proto) > 0) {
+            total_payload_written += fr->transport_len;
+        } else {
+            pico_frame_discard(fr);
+            break;
+        }
+    } /* while() */
+    return (int)total_payload_written;
+#else
+    return -1;
+#endif
+}
+
 int pico_ipv4_rebound(struct pico_frame *f)
 {
     struct pico_ip4 dst;
@@ -1486,6 +1624,10 @@
     }
 
     dst.addr = hdr->src.addr;
+    if (f->transport_len > PICO_IPV4_MAXPAYLOAD) {
+        return pico_ipv4_rebound_large(f);
+    }
+
     return pico_ipv4_frame_push(f, &dst, hdr->proto);
 }
 
@@ -1503,9 +1645,6 @@
         return -1;
     }
 
-    if (f->dev == rt->link->dev)
-        return -1;
-
     f->dev = rt->link->dev;
     hdr->ttl = (uint8_t)(hdr->ttl - 1);
     if (hdr->ttl < 1) {
@@ -1551,4 +1690,19 @@
 #endif
 }
 
+int pico_ipv4_cleanup_links(struct pico_device *dev)
+{
+    struct pico_tree_node *index = NULL, *_tmp = NULL;
+    struct pico_ipv4_link *link = NULL;
+
+    pico_tree_foreach_safe(index, &Tree_dev_link, _tmp)
+    {
+        link = index->keyValue;
+        if (dev == link->dev)
+            pico_ipv4_link_del(dev, link->address);
+    }
+    return 0;
+}
+
+
 #endif
--- a/modules/pico_ipv4.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_ipv4.h	Wed Apr 09 14:31:41 2014 +0200
@@ -5,28 +5,31 @@
    .
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_IPV4
-#define _INCLUDE_PICO_IPV4
+#ifndef INCLUDE_PICO_IPV4
+#define INCLUDE_PICO_IPV4
 #include "pico_addressing.h"
 #include "pico_protocol.h"
 #include "pico_tree.h"
+#include "pico_device.h"
 
 #define PICO_IPV4_INADDR_ANY 0x00000000U
 
+#define PICO_IPV4_MTU (1500u)
 #define PICO_SIZE_IP4HDR (uint32_t)((sizeof(struct pico_ipv4_hdr)))
+#define PICO_IPV4_MAXPAYLOAD (PICO_IPV4_MTU - PICO_SIZE_IP4HDR)
 #define PICO_IPV4_DONTFRAG 0x4000
 #define PICO_IPV4_MOREFRAG 0x2000
 #define PICO_IPV4_FRAG_MASK 0x1FFF
 #define PICO_IPV4_DEFAULT_TTL 64
 #ifndef MBED
-    #define PICO_IPV4_FRAG_MAX_SIZE (63 * 1024)
+    #define PICO_IPV4_FRAG_MAX_SIZE (uint32_t)(63 * 1024)
 #else
     #define PICO_IPV4_FRAG_MAX_SIZE PICO_DEFAULT_SOCKETQ
 #endif
 
 extern struct pico_protocol pico_proto_ipv4;
 
-struct __attribute__((packed)) pico_ipv4_hdr {
+PACKED_STRUCT_DEF pico_ipv4_hdr {
     uint8_t vhl;
     uint8_t tos;
     uint16_t len;
@@ -40,7 +43,7 @@
     uint8_t options[];
 };
 
-struct __attribute__((packed)) pico_ipv4_pseudo_hdr
+PACKED_STRUCT_DEF pico_ipv4_pseudo_hdr
 {
     struct pico_ip4 src;
     struct pico_ip4 dst;
@@ -80,7 +83,7 @@
 int pico_ipv4_is_multicast(uint32_t address);
 int pico_ipv4_is_broadcast(uint32_t addr);
 int pico_ipv4_is_loopback(uint32_t addr);
-int pico_ipv4_is_valid_src(uint32_t addr);
+int pico_ipv4_is_valid_src(uint32_t addr, struct pico_device *dev);
 
 int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask);
 int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address);
@@ -100,5 +103,6 @@
 int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter);
 int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter);
 struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void);
+int pico_ipv4_cleanup_links(struct pico_device *dev);
 
 #endif /* _INCLUDE_PICO_IPV4 */
--- a/modules/pico_ipv6.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_ipv6.h	Wed Apr 09 14:31:41 2014 +0200
@@ -10,21 +10,94 @@
 #include "pico_addressing.h"
 #include "pico_protocol.h"
 
+#define PICO_SIZE_IP6HDR ((uint32_t)(sizeof(struct pico_ipv6_hdr)))
+#define PICO_IPV6_DEFAULT_HOP 64
+#define PICO_IPV6_MIN_MTU 1280
+
+extern const uint8_t PICO_IP6_ANY[PICO_SIZE_IP6];
 extern struct pico_protocol pico_proto_ipv6;
-extern const uint8_t PICO_IPV6_ANY[PICO_SIZE_IP6];
 
+PACKED_STRUCT_DEF pico_ipv6_hdr {
+    uint32_t vtf;
+    uint16_t len;
+    uint8_t nxthdr;
+    uint8_t hop;
+    struct pico_ip6 src;
+    struct pico_ip6 dst;
+    uint8_t extensions[0];
+};
 
-/* This module is responsible for routing outgoing packets and
- * delivering incoming packets to other layers
- */
+PACKED_STRUCT_DEF pico_ipv6_pseudo_hdr
+{
+    struct pico_ip6 src;
+    struct pico_ip6 dst;
+    uint32_t len;
+    uint8_t zero[3];
+    uint8_t nxthdr;
+};
+
+struct pico_ipv6_link
+{
+    struct pico_device *dev;
+    struct pico_ip6 address;
+    struct pico_ip6 netmask;
+    uint8_t istentative : 1;
+    uint8_t isduplicate : 1;
+};
+
+PACKED_STRUCT_DEF pico_ipv6_exthdr {
+    uint8_t nxthdr;
+
+    union ipv6_ext_u {
+        struct {
+            uint8_t len;
+            uint8_t options[0];
+        } hopbyhop;
 
-/* Interface for processing incoming ipv6 packets (decap/deliver) */
-int pico_ipv6_process_in(struct pico_frame *f);
+        struct {
+            uint8_t len;
+            uint8_t options[0];
+        } destopt;
+
+        struct {
+            uint8_t len;
+            uint8_t routtype;
+            uint8_t segleft;
+        } routing;
+
+        struct {
+            uint8_t res;
+            uint8_t frm[2];
+            uint8_t id[4];
+        } fragm;
+    } ext;
+};
 
-/* Interface for processing outgoing ipv6 frames (encap/push) */
-int pico_ipv6_process_out(struct pico_frame *f);
+int pico_ipv6_compare(struct pico_ip6 *a, struct pico_ip6 *b);
+int pico_string_to_ipv6(const char *ipstr, uint8_t *ip);
+int pico_ipv6_to_string(char *ipbuf, const uint8_t ip[PICO_SIZE_IP6]);
+int pico_ipv6_is_unicast(struct pico_ip6 *a);
+int pico_ipv6_is_multicast(const uint8_t addr[PICO_SIZE_IP6]);
+int pico_ipv6_is_global(const uint8_t addr[PICO_SIZE_IP6]);
+int pico_ipv6_is_uniquelocal(const uint8_t addr[PICO_SIZE_IP6]);
+int pico_ipv6_is_sitelocal(const uint8_t addr[PICO_SIZE_IP6]);
+int pico_ipv6_is_linklocal(const uint8_t addr[PICO_SIZE_IP6]);
+int pico_ipv6_is_solicited(const uint8_t addr[PICO_SIZE_IP6]);
+int pico_ipv6_is_unspecified(const uint8_t addr[PICO_SIZE_IP6]);
 
-/* Return estimated overhead for ipv6 frames to define allocation */
-int pico_ipv6_overhead(struct pico_frame *f);
+int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *dst, uint8_t proto);
+int pico_ipv6_rebound(struct pico_frame *f);
+int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link);
+void pico_ipv6_unreachable(struct pico_frame *f, uint8_t code);
 
+int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask);
+int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address);
+int pico_ipv6_cleanup_links(struct pico_device *dev);
+struct pico_ipv6_link *pico_ipv6_link_istentative(struct pico_ip6 *address);
+struct pico_ipv6_link *pico_ipv6_link_get(struct pico_ip6 *address);
+struct pico_device *pico_ipv6_link_find(struct pico_ip6 *address);
+struct pico_ip6 pico_ipv6_route_get_gateway(struct pico_ip6 *addr);
+struct pico_ip6 *pico_ipv6_source_find(const struct pico_ip6 *dst);
+struct pico_ipv6_link *pico_ipv6_link_by_dev(struct pico_device *dev);
+struct pico_ipv6_link *pico_ipv6_link_by_dev_next(struct pico_device *dev, struct pico_ipv6_link *last);
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_ipv6_nd.h	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,29 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef _INCLUDE_PICO_ND
+#define _INCLUDE_PICO_ND
+#include "pico_frame.h"
+
+/* RFC constants */
+#define PICO_ND_REACHABLE_TIME         30000 /* msec */
+#define PICO_ND_RETRANS_TIMER          1000 /* msec */
+
+struct pico_nd_hostvars {
+    uint32_t mtu;
+    uint8_t hoplimit;
+    pico_time basetime;
+    pico_time reachabletime;
+    pico_time retranstime;
+};
+
+void pico_ipv6_nd_init(void);
+struct pico_eth *pico_nd_get(struct pico_frame *f);
+int pico_nd_neigh_sol_recv(struct pico_frame *f);
+int pico_nd_neigh_adv_recv(struct pico_frame *f);
+int pico_nd_router_sol_recv(struct pico_frame *f);
+int pico_nd_router_adv_recv(struct pico_frame *f);
+int pico_nd_redirect_recv(struct pico_frame *f);
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_mm.h	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,98 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Authors: Gustav Janssens, Jonas Van Nieuwenberg, Sam Van Den Berge
+ *********************************************************************/
+
+
+#ifndef _INCLUDE_PICO_MM
+#define _INCLUDE_PICO_MM
+
+#include <stdint.h>
+
+/*
+ * Memory init function, this will create a memory manager instance
+ * A memory_manager page will be created, along with one page of memory
+ * Memory can be asked for via the pico_mem_zalloc function
+ * More memory will be allocated to the memory manager according to its needs
+ * A maximum amount of memory of uint32_t memsize can be allocated
+ */
+void pico_mem_init(uint32_t memsize);
+/*
+ * Memory deinit function, this will free all memory occupied by the current
+ * memory manager instance.
+ */
+void pico_mem_deinit();
+/*
+ * Zero-initialized malloc function, will reserve a memory segment of length uint32_t len
+ * This memory will be quickly allocated in a slab of fixed size if possible
+ * or less optimally in the heap for a small variable size
+ * The fixed size of the slabs can be changed dynamically via a statistics engine
+ */
+void*pico_mem_zalloc(size_t len);
+/*
+ * Free function, free a block of memory pointed to by ptr.
+ * Unused memory is only returned to the system's control by pico_mem_cleanup
+ */
+void pico_mem_free(void*ptr);
+/*
+ * This cleanup function will be provided by the memory manager
+ * It can be called during processor downtime
+ * This function will return unused pages to the system's control
+ * Pages are unused if they no longer contain slabs or heap, and they have been idle for a longer time
+ */
+void pico_mem_cleanup(uint32_t timestamp);
+
+
+
+#ifdef PICO_SUPPORT_MM_PROFILING
+/***********************************************************************************************************************
+ ***********************************************************************************************************************
+   MEMORY PROFILING FUNCTIONS
+ ***********************************************************************************************************************
+ ***********************************************************************************************************************/
+/* General info struct */
+struct profiling_data
+{
+    uint32_t free_heap_space;
+    uint32_t free_slab_space;
+    uint32_t used_heap_space;
+    uint32_t used_slab_space;
+};
+
+/*
+ * This function fills up a struct with used and free slab and heap space in the memory manager
+ * The user is responsible for resource managment
+ */
+void pico_mem_profile_collect_data(struct profiling_data*profiling_page_struct);
+
+/*
+ * This function prints the general structure of the memory manager
+ * Printf in this function can be rerouted to send this data over a serial port, or to write it away to memory
+ */
+void pico_mem_profile_scan_data();
+
+/*
+ * This function returns the total size that the manager has received from the system
+ * This can give an indication of the total system resource commitment, but keep in mind that
+ * there can be many free blocks in this "used" size
+ * Together with pico_mem_profile_collect_data, this can give a good estimation of the total
+ * resource commitment
+ */
+uint32_t pico_mem_profile_used_size();
+
+/*
+ * This function returns a pointer to page 0, the main memory manager housekeeping (struct pico_mem_manager).
+ * This can be used to collect data about the memory in user defined functions.
+ * Use with care!
+ */
+void*pico_mem_profile_manager();
+
+/*
+ * paramter manager is a pointer to a struct pico_mem_manager
+ */
+void pico_mem_init_profiling(void*manager, uint32_t memsize);
+#endif /* PICO_SUPPORT_MM_PROFILING */
+
+#endif /* _INCLUDE_PICO_MM */
--- a/modules/pico_nat.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_nat.c	Wed Apr 09 14:31:41 2014 +0200
@@ -93,8 +93,9 @@
 
 void pico_ipv4_nat_print_table(void)
 {
-    struct pico_nat_tuple __attribute__((unused)) *t = NULL;
+    struct pico_nat_tuple *t = NULL;
     struct pico_tree_node *index = NULL;
+    (void)t;
 
     nat_dbg("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
     nat_dbg("+                                                        NAT table                                                       +\n");
@@ -155,7 +156,7 @@
 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)
 {
-    struct pico_nat_tuple *t = pico_zalloc(sizeof(struct pico_nat_tuple));
+    struct pico_nat_tuple *t = PICO_ZALLOC(sizeof(struct pico_nat_tuple));
     if (!t) {
         pico_err = PICO_ERR_ENOMEM;
         return NULL;
@@ -176,13 +177,13 @@
     t->fin_out = 0;
 
     if (pico_tree_insert(&NATOutbound, t)) {
-        pico_free(t);
+        PICO_FREE(t);
         return NULL;
     }
 
     if (pico_tree_insert(&NATInbound, t)) {
         pico_tree_delete(&NATOutbound, t);
-        pico_free(t);
+        PICO_FREE(t);
         return NULL;
     }
 
@@ -196,7 +197,7 @@
     if (t) {
         pico_tree_delete(&NATOutbound, t);
         pico_tree_delete(&NATInbound, t);
-        pico_free(t);
+        PICO_FREE(t);
     }
 
     return 0;
@@ -227,13 +228,13 @@
     case PICO_PROTO_TCP:
     {
         struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
-        trans = &tcp->trans;
+        trans = (struct pico_trans *)&tcp->trans;
         break;
     }
     case PICO_PROTO_UDP:
     {
         struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
-        trans = &udp->trans;
+        trans = (struct pico_trans *)&udp->trans;
         break;
     }
     case PICO_PROTO_ICMP4:
@@ -384,10 +385,11 @@
         return -1;
 
     switch (net->proto) {
+#ifdef PICO_SUPPORT_TCP
     case PICO_PROTO_TCP:
     {
         struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
-        trans = &tcp->trans;
+        trans = (struct pico_trans *)&tcp->trans;
         tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
         if (!tuple)
             return -1;
@@ -400,10 +402,12 @@
         tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
         break;
     }
+#endif
+#ifdef PICO_SUPPORT_UDP
     case PICO_PROTO_UDP:
     {
         struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
-        trans = &udp->trans;
+        trans = (struct pico_trans *)&udp->trans;
         tuple = pico_ipv4_nat_find_tuple(trans->dport, 0, 0, net->proto);
         if (!tuple)
             return -1;
@@ -416,6 +420,7 @@
         udp->crc = short_be(pico_udp_checksum_ipv4(f));
         break;
     }
+#endif
     case PICO_PROTO_ICMP4:
         /* XXX reimplement */
         break;
@@ -445,10 +450,11 @@
         return -1;
 
     switch (net->proto) {
+#ifdef PICO_SUPPORT_TCP
     case PICO_PROTO_TCP:
     {
         struct pico_tcp_hdr *tcp = (struct pico_tcp_hdr *)f->transport_hdr;
-        trans = &tcp->trans;
+        trans = (struct pico_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);
@@ -461,10 +467,12 @@
         tcp->crc = short_be(pico_tcp_checksum_ipv4(f));
         break;
     }
+#endif
+#ifdef PICO_SUPPORT_UDP
     case PICO_PROTO_UDP:
     {
         struct pico_udp_hdr *udp = (struct pico_udp_hdr *)f->transport_hdr;
-        trans = &udp->trans;
+        trans = (struct pico_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);
@@ -477,6 +485,7 @@
         udp->crc = short_be(pico_udp_checksum_ipv4(f));
         break;
     }
+#endif
     case PICO_PROTO_ICMP4:
         /* XXX reimplement */
         break;
--- a/modules/pico_nat.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_nat.h	Wed Apr 09 14:31:41 2014 +0200
@@ -7,8 +7,8 @@
    Authors: Kristof Roelants, Simon Maes, Brecht Van Cauwenberghe
  *********************************************************************/
 
-#ifndef _INCLUDE_PICO_NAT
-#define _INCLUDE_PICO_NAT
+#ifndef INCLUDE_PICO_NAT
+#define INCLUDE_PICO_NAT
 #include "pico_frame.h"
 
 #define PICO_NAT_PORT_FORWARD_DEL 0
--- a/modules/pico_olsr.c	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1064 +0,0 @@
-/*********************************************************************
-   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_device.h"
-#include "pico_ipv4.h"
-#include "pico_arp.h"
-#include "pico_socket.h"
-#ifdef PICO_SUPPORT_OLSR
-#define DGRAM_MAX_SIZE (576)
-#define MAX_OLSR_MEM (4 * DGRAM_MAX_SIZE)
-
-
-#define OLSR_HELLO_INTERVAL   ((uint32_t)2000)
-#define OLSR_TC_INTERVAL      ((uint32_t)5000)
-#define OLSR_MAXJITTER        ((uint32_t)(OLSR_HELLO_INTERVAL >> 2))
-static const struct pico_ip4 HOST_NETMASK = {
-    0xFFFFFFFF
-};
-#ifndef MIN
-# define MIN(a, b) (a < b ? a : b)
-#endif
-
-#define fresher(a, b) ((a > b) || ((b - a) > 32768))
-
-
-/* Objects */
-struct olsr_route_entry
-{
-    struct olsr_route_entry         *next;
-    uint32_t time_left;
-    struct pico_ip4 destination;
-    struct olsr_route_entry         *gateway;
-    struct pico_device              *iface;
-    uint16_t metric;
-    uint8_t link_type;
-    struct olsr_route_entry         *children;
-    uint16_t ansn;
-    uint16_t seq;
-    uint8_t lq, nlq;
-    uint8_t                         *advertised_tc;
-};
-
-struct olsr_dev_entry
-{
-    struct olsr_dev_entry *next;
-    struct pico_device *dev;
-    uint16_t pkt_counter;
-};
-
-
-/* OLSR Protocol */
-#define OLSRMSG_HELLO   0xc9
-#define OLSRMSG_MID    0x03
-#define OLSRMSG_TC    0xca
-
-#define OLSRLINK_SYMMETRIC 0x06
-#define OLSRLINK_UNKNOWN 0x08
-#define OLSRLINK_MPR  0x0a
-
-
-#define OLSR_PORT (short_be((uint16_t)698))
-
-
-/* Headers */
-
-struct __attribute__((packed)) olsr_link
-{
-    uint8_t link_code;
-    uint8_t reserved;
-    uint16_t link_msg_size;
-};
-
-struct __attribute__((packed)) olsr_neighbor
-{
-    uint32_t addr;
-    uint8_t lq;
-    uint8_t nlq;
-    uint16_t reserved;
-};
-
-struct __attribute__((packed)) olsr_hmsg_hello
-{
-    uint16_t reserved;
-    uint8_t htime;
-    uint8_t willingness;
-};
-
-struct __attribute__((packed)) olsr_hmsg_tc
-{
-    uint16_t ansn;
-    uint16_t reserved;
-};
-
-
-struct __attribute__((packed)) olsrmsg
-{
-    uint8_t type;
-    uint8_t vtime;
-    uint16_t size;
-    struct pico_ip4 orig;
-    uint8_t ttl;
-    uint8_t hop;
-    uint16_t seq;
-};
-
-struct __attribute__((packed)) olsrhdr
-{
-    uint16_t len;
-    uint16_t seq;
-};
-
-
-
-/* Globals */
-static struct pico_socket *udpsock = NULL;
-uint16_t my_ansn = 0;
-static struct olsr_route_entry  *Local_interfaces = NULL;
-static struct olsr_dev_entry    *Local_devices    = NULL;
-
-static struct olsr_dev_entry *olsr_get_deventry(struct pico_device *dev)
-{
-    struct olsr_dev_entry *cur = Local_devices;
-    while(cur) {
-        if (cur->dev == dev)
-            return cur;
-
-        cur = cur->next;
-    }
-    return NULL;
-}
-
-static struct olsr_route_entry *olsr_get_ethentry(struct pico_device *vif)
-{
-    struct olsr_route_entry *cur = Local_interfaces;
-    while(cur) {
-        if (cur->iface == vif)
-            return cur;
-
-        cur = cur->next;
-    }
-    return NULL;
-}
-
-static struct olsr_route_entry *get_next_hop(struct olsr_route_entry *dst)
-{
-    struct olsr_route_entry *hop = dst;
-    while(hop) {
-        if(hop->metric <= 1)
-            return hop;
-
-        hop = hop->gateway;
-    }
-    return NULL;
-}
-
-static inline void olsr_route_add(struct olsr_route_entry *el)
-{
-    struct olsr_route_entry *nexthop;
-
-    my_ansn++;
-
-    if (el->gateway) {
-        nexthop = get_next_hop(el);
-        /* 2-hops route or more */
-        el->next = el->gateway->children;
-        el->gateway->children = el;
-        el->link_type = OLSRLINK_MPR;
-        if (nexthop->destination.addr != el->destination.addr) {
-            /* dbg("[OLSR] Adding route to %08x via %08x metric %d..................", el->destination.addr, nexthop->destination.addr, el->metric); */
-            pico_ipv4_route_add(el->destination, HOST_NETMASK, nexthop->destination, el->metric, NULL);
-            /* dbg("route added: %d err: %s\n", ret, strerror(pico_err)); */
-        }
-    } else if (el->iface) {
-        /* neighbor */
-        struct olsr_route_entry *ei = olsr_get_ethentry(el->iface);
-        if (el->link_type == OLSRLINK_UNKNOWN)
-            el->link_type = OLSRLINK_SYMMETRIC;
-
-        if (ei) {
-            el->next = ei->children;
-            ei->children = el;
-        }
-    }
-}
-
-static inline void olsr_route_del(struct olsr_route_entry *r)
-{
-    struct olsr_route_entry *cur, *prev = NULL, *lst;
-    /* dbg("[OLSR] DELETING route..................\n"); */
-    my_ansn++;
-    if (r->gateway) {
-        lst = r->gateway->children;
-    } else if (r->iface) {
-        lst = olsr_get_ethentry(r->iface);
-    } else {
-        lst = Local_interfaces;
-    }
-
-    cur = lst, prev = NULL;
-    while(cur) {
-        if (cur == r) {
-            /* found */
-            if (r->gateway) {
-                pico_ipv4_route_del(r->destination, HOST_NETMASK, r->metric);
-                if (!prev)
-                    r->gateway->children = r->next;
-                else
-                    prev->next = r->next;
-            }
-
-            while (r->children) {
-                olsr_route_del(r->children);
-                /* Orphans must die. */
-                pico_free(r->children);
-            }
-            return;
-        }
-
-        prev = cur;
-        cur = cur->next;
-    }
-}
-
-static struct olsr_route_entry *get_route_by_address(struct olsr_route_entry *lst, uint32_t ip)
-{
-    struct olsr_route_entry *found;
-    if(lst) {
-        if (lst->destination.addr == ip) {
-            return lst;
-        }
-
-        found = get_route_by_address(lst->children, ip);
-        if (found)
-            return found;
-
-        found = get_route_by_address(lst->next, ip);
-        if (found)
-            return found;
-    }
-
-    return NULL;
-}
-
-#define OLSR_C_SHIFT (uint32_t)4 /* 1/16 */
-#define DEFAULT_VTIME 288UL
-
-uint8_t seconds2olsr(uint32_t seconds)
-{
-    uint16_t a, b;
-    /* dbg("seconds=%u\n", (uint16_t)seconds); */
-
-    if (seconds > 32767)
-        seconds = 32767;
-
-    /* find largest b such as seconds/C >= 2^b */
-    for (b = 1; b <= 0x0fu; b++) {
-        if ((uint16_t)(seconds * 16u) < (1u << b)) {
-            b--;
-            break;
-        }
-    }
-    /* dbg("b=%u", b); */
-    /* compute the expression 16*(T/(C*(2^b))-1), which may not be a
-       integer, and round it up.  This results in the value for 'a' */
-    /* a = (T / ( C * (1u << b) ) ) - 1u; */
-    {
-        uint16_t den = ((uint16_t)(1u << b) >> 4u);
-        /* dbg(" den=%u ", den); */
-        if (den == 0)
-        {
-            /* dbg("div by 0!\n"); */
-            den = 1u;
-        }
-
-        a = (uint16_t)(((uint16_t)seconds / den) - (uint16_t)1);
-    }
-    /* a = a & 0x0Fu; */
-
-    /* dbg(" a=%u\n", a); */
-
-    /* if 'a' is equal to 16: increment 'b' by one, and set 'a' to 0 */
-    if (16u == a) {
-        b++;
-        a = 0u;
-    }
-
-    return (uint8_t)((a << 4u) + b);
-}
-
-uint32_t olsr2seconds(uint8_t olsr)
-{
-    uint8_t a, b;
-    uint16_t seconds;
-    /* dbg("olsr format: %u -- ", olsr); */
-    a = (olsr >> 4) & 0xFu;
-    b = olsr & 0x0f;
-    /* dbg("o2s: a=%u, b=%u\n", a,b); */
-    if (b < 4)
-        seconds = (uint16_t)(((1u << b) + (uint16_t)(((uint16_t)(a << b) >> 4u) & 0xFu)) >> OLSR_C_SHIFT);
-    else
-        seconds = (uint16_t)(((1u << b) + (uint16_t)(((uint16_t)(a << (b - 4))) & 0xFu)) >> OLSR_C_SHIFT);
-
-    /* dbg("o2s: seconds: %u\n", seconds); */
-    return seconds;
-}
-
-
-static void refresh_neighbors(struct pico_device *iface)
-{
-    struct pico_ip4 neighbors[256];
-    int i;
-    struct olsr_route_entry *found = NULL, *ancestor = NULL;
-    int n_vec_size;
-
-    n_vec_size = pico_arp_get_neighbors(iface, neighbors, 256);
-
-    ancestor = olsr_get_ethentry(iface);
-    if (!ancestor)
-        return;
-
-    for (i = 0; i < n_vec_size; i++) {
-        found = get_route_by_address(Local_interfaces, neighbors[i].addr);
-        if (found) {
-            if (found->metric > 1) { /* Reposition among neighbors */
-                olsr_route_del(found);
-                found->gateway = olsr_get_ethentry(iface);
-                found->iface = iface;
-                found->metric = 1;
-                found->lq = 0xFF;
-                found->nlq = 0xFF;
-                olsr_route_add(found);
-            }
-
-            if (found->link_type == OLSRLINK_UNKNOWN)
-                found->link_type = OLSRLINK_SYMMETRIC;
-
-            found->time_left = (OLSR_HELLO_INTERVAL << 2);
-        } else {
-            struct olsr_route_entry *e = pico_zalloc(sizeof (struct olsr_route_entry));
-            if (!e) {
-                dbg("olsr: adding local route entry\n");
-                return;
-            }
-
-            e->destination.addr = neighbors[i].addr;
-            e->link_type = OLSRLINK_SYMMETRIC;
-            e->time_left = (OLSR_HELLO_INTERVAL << 2);
-            e->gateway = olsr_get_ethentry(iface);
-            e->iface = iface;
-            e->metric = 1;
-            e->lq = 0xFF;
-            e->nlq = 0xFF;
-            olsr_route_add(e);
-        }
-    }
-}
-
-static void olsr_garbage_collector(struct olsr_route_entry *sublist)
-{
-    if(!sublist)
-        return;
-
-    if (sublist->time_left <= 0) {
-        olsr_route_del(sublist);
-        pico_free(sublist);
-        return;
-    } else {
-        sublist->time_left -= 2u;
-    }
-
-    olsr_garbage_collector(sublist->children);
-    olsr_garbage_collector(sublist->next);
-}
-
-struct olsr_fwd_pkt
-{
-    void *buf;
-    uint16_t len;
-    struct pico_device *pdev;
-};
-
-static uint32_t buffer_mem_used = 0U;
-
-void olsr_process_out(pico_time now, void *arg)
-{
-    struct olsr_fwd_pkt *p = (struct olsr_fwd_pkt *)arg;
-    struct pico_ip4 bcast;
-    struct pico_ipv4_link *addr;
-    struct olsr_dev_entry *pdev = Local_devices;
-    struct olsrhdr *ohdr;
-    (void)now;
-
-    /* Send the thing out */
-    ohdr = (struct olsrhdr *)p->buf;
-    ohdr->len = short_be((uint16_t)p->len);
-
-    if (p->pdev) {
-        struct olsr_dev_entry *odev = olsr_get_deventry(p->pdev);
-        if (!odev) {
-            goto out_free;
-        }
-
-        addr = pico_ipv4_link_by_dev(p->pdev);
-        if (!addr)
-            goto out_free;
-
-        ohdr->seq = short_be((uint16_t)(odev->pkt_counter)++);
-        bcast.addr = (addr->netmask.addr & addr->address.addr) | (~addr->netmask.addr);
-        if ( 0 > pico_socket_sendto(udpsock, p->buf, p->len, &bcast, OLSR_PORT)) {
-            dbg("olsr send\n");
-        }
-    } else {
-        while(pdev) {
-            ohdr->seq = short_be((uint16_t)(pdev->pkt_counter++));
-            addr = pico_ipv4_link_by_dev(pdev->dev);
-            if (!addr)
-                continue;
-
-            bcast.addr = (addr->netmask.addr & addr->address.addr) | (~addr->netmask.addr);
-            if ( 0 > pico_socket_sendto(udpsock, p->buf, p->len, &bcast, OLSR_PORT)) {
-                dbg("olsr send\n");
-            }
-
-            pdev = pdev->next;
-        }
-    }
-
-out_free:
-    pico_free(p->buf);
-    buffer_mem_used -= DGRAM_MAX_SIZE;
-    pico_free(p);
-}
-
-static void olsr_scheduled_output(uint32_t when, void *buffer, uint16_t size, struct pico_device *pdev)
-{
-    struct olsr_fwd_pkt *p;
-    if ((buffer_mem_used + DGRAM_MAX_SIZE) > MAX_OLSR_MEM)
-        return;
-
-    p = pico_zalloc(sizeof(struct olsr_fwd_pkt));
-    if (!p) {
-        pico_free(buffer);
-        return;
-    }
-
-    p->buf = buffer;
-    p->len = size;
-    p->pdev = pdev;
-    buffer_mem_used += DGRAM_MAX_SIZE;
-    pico_timer_add(1 + when - ((pico_rand() % OLSR_MAXJITTER)), &olsr_process_out, p);
-}
-
-
-static void refresh_routes(void)
-{
-    struct olsr_route_entry *local, *neighbor = NULL;
-    struct olsr_dev_entry *icur = Local_devices;
-
-    /* Refresh local entries */
-
-    /* Step 1: set zero expire time for local addresses and neighbors*/
-    local = Local_interfaces;
-    while(local) {
-        local->time_left = 0;
-        neighbor = local->children;
-        while (neighbor && (neighbor->metric < 2)) {
-            /* dbg("Setting to zero. Neigh: %08x metric %d\n", neighbor->destination, neighbor->metric); */
-            neighbor->time_left = 0;
-            neighbor = neighbor->next;
-        }
-        local = local->next;
-    }
-    /* Step 2: refresh timer for entries that are still valid.
-     * Add new entries.
-     */
-    while(icur) {
-        struct pico_ipv4_link *lnk = NULL;
-        do {
-            lnk = pico_ipv4_link_by_dev_next(icur->dev, lnk);
-            if (!lnk) break;
-
-            local = olsr_get_ethentry(icur->dev);
-            if (local) {
-                local->time_left = (OLSR_HELLO_INTERVAL << 2);
-            } else if (lnk) {
-                struct olsr_route_entry *e = pico_zalloc(sizeof (struct olsr_route_entry));
-                if (!e) {
-                    dbg("olsr: adding local route entry\n");
-                    return;
-                }
-
-                e->destination.addr = lnk->address.addr; /* Always pick the first address */
-                e->time_left = (OLSR_HELLO_INTERVAL << 2);
-                e->iface = icur->dev;
-                e->metric = 0;
-                e->lq = 0xFF;
-                e->nlq = 0xFF;
-                e->next = Local_interfaces;
-                Local_interfaces = e;
-            }
-        } while (lnk);
-
-        refresh_neighbors(icur->dev);
-        icur = icur->next;
-    }
-}
-
-static uint32_t olsr_build_hello_neighbors(uint8_t *buf, uint32_t size)
-{
-    uint32_t ret = 0;
-    struct olsr_route_entry *local, *neighbor;
-    struct olsr_neighbor *dst = (struct olsr_neighbor *) buf;
-    local = Local_interfaces;
-    while (local) {
-        neighbor = local->children;
-        while (neighbor) {
-            struct olsr_link *li = (struct olsr_link *) (buf + ret);
-            li->link_code = neighbor->link_type;
-            li->reserved = 0;
-            li->link_msg_size = short_be(sizeof(struct olsr_neighbor) + sizeof(struct olsr_link));
-            ret += (uint32_t)sizeof(struct olsr_link);
-            dst = (struct olsr_neighbor *) (buf + ret);
-            dst->addr = neighbor->destination.addr;
-            dst->nlq = neighbor->nlq;
-            dst->lq = neighbor->lq;
-            dst->reserved = 0;
-            ret += (uint32_t)sizeof(struct olsr_neighbor);
-            if (ret >= size)
-                return (uint32_t)((uint32_t)(ret - sizeof(struct olsr_neighbor)) - sizeof(struct olsr_link));
-
-            neighbor = neighbor->next;
-        }
-        local = local->next;
-    }
-    return ret;
-}
-
-static uint32_t olsr_build_tc_neighbors(uint8_t *buf, uint32_t size)
-{
-    uint32_t ret = 0;
-    struct olsr_route_entry *local, *neighbor;
-    struct olsr_neighbor *dst = (struct olsr_neighbor *) buf;
-    local = Local_interfaces;
-    while (local) {
-        neighbor = local->children;
-        while (neighbor) {
-            dst->addr = neighbor->destination.addr;
-            dst->nlq = neighbor->nlq;
-            dst->lq = neighbor->lq;
-            dst->reserved = 0;
-            ret += (uint32_t)sizeof(struct olsr_neighbor);
-            dst = (struct olsr_neighbor *) (buf + ret);
-            if (ret >= size)
-                return (uint32_t)(ret - sizeof(struct olsr_neighbor));
-
-            neighbor = neighbor->next;
-        }
-        local = local->next;
-    }
-    return ret;
-}
-
-static uint32_t olsr_build_mid(uint8_t *buf, uint32_t size, struct pico_device *excluded)
-{
-    uint32_t ret = 0;
-    struct olsr_route_entry *local;
-    struct pico_ip4 *dst = (struct pico_ip4 *) buf;
-    local = Local_interfaces;
-    while (local) {
-        if (local->iface != excluded) {
-            dst->addr = local->destination.addr;
-            ret += (uint32_t)sizeof(uint32_t);
-            dst = (struct pico_ip4 *) (buf + ret);
-            if (ret >= size)
-                return (uint32_t)(ret - sizeof(uint32_t));
-        }
-
-        local = local->next;
-    }
-    return ret;
-}
-
-static void olsr_make_dgram(struct pico_device *pdev, int full)
-{
-    uint8_t *dgram;
-    uint32_t size = 0, r;
-    struct pico_ipv4_link *ep;
-    struct olsrmsg *msg_hello, *msg_mid, *msg_tc;
-    struct olsr_hmsg_hello *hello;
-    struct olsr_hmsg_tc *tc;
-    static uint16_t msg_counter; /* Global message sequence number */
-    uint32_t interval = OLSR_HELLO_INTERVAL;
-
-    dgram = pico_zalloc(DGRAM_MAX_SIZE);
-    if (!dgram)
-        return;
-
-    size += (uint32_t)sizeof(struct olsrhdr);
-    ep = pico_ipv4_link_by_dev(pdev);
-    if (!ep) {
-        pico_free(dgram);
-        return;
-    }
-
-    if (!full) {
-        /* HELLO Message */
-
-        msg_hello = (struct olsrmsg *) (dgram + size);
-        size += (uint32_t)sizeof(struct olsrmsg);
-        msg_hello->type = OLSRMSG_HELLO;
-        msg_hello->vtime = seconds2olsr(DEFAULT_VTIME);
-        msg_hello->orig.addr = ep->address.addr;
-        msg_hello->ttl = 1;
-        msg_hello->hop = 0;
-        msg_hello->seq = short_be(msg_counter++);
-        hello = (struct olsr_hmsg_hello *)(dgram + size);
-        size += (uint32_t)sizeof(struct olsr_hmsg_hello);
-        hello->reserved = 0;
-        hello->htime = seconds2olsr(OLSR_HELLO_INTERVAL);
-        hello->htime = 0x05; /* Todo: find and define values */
-        hello->willingness = 0x07;
-        r = olsr_build_hello_neighbors(dgram + size, DGRAM_MAX_SIZE - size);
-        if (r == 0) {
-            /* dbg("Building hello message\n"); */
-            pico_free(dgram);
-            return;
-        }
-
-        size += r;
-        msg_hello->size = short_be((uint16_t)(sizeof(struct olsrmsg) + sizeof(struct olsr_hmsg_hello) + r));
-
-    } else {
-        /* MID Message */
-
-        msg_mid = (struct olsrmsg *)(dgram + size);
-        size += (uint32_t)sizeof(struct olsrmsg);
-        msg_mid->type = OLSRMSG_MID;
-        msg_mid->vtime = seconds2olsr(60);
-        msg_mid->orig.addr = ep->address.addr;
-        msg_mid->ttl = 0xFF;
-        msg_mid->hop = 0;
-        msg_mid->seq = short_be(msg_counter++);
-        r = olsr_build_mid(dgram + size, DGRAM_MAX_SIZE - size, pdev);
-        if (r == 0) {
-            size -= (uint32_t)sizeof(struct olsrmsg);
-        } else {
-            size += r;
-            msg_mid->size = short_be((uint16_t)(sizeof(struct olsrmsg) + r));
-        }
-
-        msg_tc = (struct olsrmsg *) (dgram + size);
-        size += (uint32_t)sizeof(struct olsrmsg);
-        msg_tc->type = OLSRMSG_TC;
-        msg_tc->vtime = seconds2olsr(DEFAULT_VTIME);
-        msg_tc->orig.addr = ep->address.addr;
-        msg_tc->ttl = 0xFF;
-        msg_tc->hop = 0;
-        msg_tc->seq = short_be(msg_counter++);
-        tc = (struct olsr_hmsg_tc *)(dgram + size);
-        size += (uint32_t)sizeof(struct olsr_hmsg_tc);
-        tc->ansn = short_be(my_ansn);
-        r = olsr_build_tc_neighbors(dgram + size, DGRAM_MAX_SIZE  - size);
-        size += r;
-        msg_tc->size = short_be((uint16_t)(sizeof(struct olsrmsg) + sizeof(struct olsr_hmsg_tc) + r));
-        interval = OLSR_TC_INTERVAL;
-    } /*if full */
-
-    /* Send the thing out */
-    olsr_scheduled_output(interval, dgram, (uint16_t)size, pdev );
-}
-
-static inline void arp_storm(struct pico_ip4 *addr)
-{
-    struct olsr_dev_entry *icur = Local_devices;
-    while(icur) {
-        pico_arp_request(icur->dev, addr, PICO_ARP_QUERY);
-        icur = icur->next;
-    }
-}
-
-static void recv_mid(uint8_t *buffer, uint32_t len, struct olsr_route_entry *origin)
-{
-    uint32_t parsed = 0;
-    uint32_t *address;
-    struct olsr_route_entry *e;
-
-    if (len % sizeof(uint32_t)) /*drop*/
-        return;
-
-    while (len > parsed) {
-        address = (uint32_t *)(buffer + parsed);
-        e = get_route_by_address(Local_interfaces, *address);
-        if (!e) {
-            e = pico_zalloc(sizeof(struct olsr_route_entry));
-            if (!e) {
-                dbg("olsr allocating route\n");
-                return;
-            }
-
-            e->time_left = (OLSR_HELLO_INTERVAL << 2);
-            e->destination.addr = *address;
-            e->gateway = origin;
-            e->iface = origin->iface;
-            e->metric = (uint16_t)(origin->metric + 1u);
-            e->lq = origin->lq;
-            e->nlq = origin->nlq;
-            olsr_route_add(e);
-            arp_storm(&e->destination);
-        } else if (e->metric > (origin->metric + 1)) {
-            olsr_route_del(e);
-            e->metric = origin->metric;
-            e->gateway = origin;
-            olsr_route_add(e);
-        }
-
-        parsed += (uint32_t)sizeof(uint32_t);
-    }
-}
-
-static void recv_hello(uint8_t *buffer, uint32_t len, struct olsr_route_entry *origin)
-{
-    struct olsr_link *li;
-    struct olsr_route_entry *e;
-    uint32_t parsed = 0;
-    struct olsr_neighbor *neigh;
-
-    if (!origin)
-        return;
-
-    while (len > parsed) {
-        li = (struct olsr_link *) buffer;
-        neigh = (struct olsr_neighbor *)(buffer + parsed + sizeof(struct olsr_link));
-        parsed += short_be(li->link_msg_size);
-        e = get_route_by_address(Local_interfaces, neigh->addr);
-        if (!e) {
-            e = pico_zalloc(sizeof(struct olsr_route_entry));
-            if (!e) {
-                dbg("olsr allocating route\n");
-                return;
-            }
-
-            e->time_left = (OLSR_HELLO_INTERVAL << 2);
-            e->destination.addr = neigh->addr;
-            e->gateway = origin;
-            e->iface = origin->iface;
-            e->metric = (uint16_t)(origin->metric + 1u);
-            e->link_type = OLSRLINK_UNKNOWN;
-            e->lq = MIN(origin->lq, neigh->lq);
-            e->nlq = MIN(origin->nlq, neigh->nlq);
-            olsr_route_add(e);
-            arp_storm(&e->destination);
-        } else if ((e->gateway != origin) && (e->metric > (origin->metric + 1))) {
-            olsr_route_del(e);
-            e->metric = (uint16_t)(origin->metric + 1u);
-            e->gateway = origin;
-            olsr_route_add(e);
-        }
-    }
-}
-
-static uint32_t reconsider_topology(uint8_t *buf, uint32_t size, struct olsr_route_entry *e)
-{
-    struct olsr_hmsg_tc *tc = (struct olsr_hmsg_tc *) buf;
-    uint16_t new_ansn = short_be(tc->ansn);
-    uint32_t parsed = sizeof(struct olsr_hmsg_tc);
-    struct olsr_route_entry *rt;
-    struct olsr_neighbor *n;
-    uint32_t retval = 0;
-
-    if (!e->advertised_tc)
-        retval = 1;
-
-    if (e->advertised_tc && fresher(new_ansn, e->ansn))
-    {
-        pico_free(e->advertised_tc);
-        e->advertised_tc = NULL;
-        retval = 1;
-    }
-
-    if (!e->advertised_tc) {
-        e->advertised_tc = pico_zalloc(size);
-        if (!e->advertised_tc) {
-            dbg("Allocating forward packet\n");
-            return 0;
-        }
-
-        memcpy(e->advertised_tc, buf, size);
-        e->ansn = new_ansn;
-        while (parsed < size) {
-            n = (struct olsr_neighbor *) (buf + parsed);
-            parsed += (uint32_t)sizeof(struct olsr_neighbor);
-            rt = get_route_by_address(Local_interfaces, n->addr);
-            if (rt && (rt->gateway == e)) {
-                /* Refresh existing node */
-                rt->time_left = e->time_left;
-            } else if (!rt || (rt->metric > (e->metric + 1)) || (rt->nlq < n->nlq)) {
-                if (!rt) {
-                    rt = pico_zalloc(sizeof (struct olsr_route_entry));
-                    rt->destination.addr = n->addr;
-                    rt->link_type = OLSRLINK_UNKNOWN;
-                } else {
-                    olsr_route_del(rt);
-                }
-
-                rt->iface = e->iface;
-                rt->gateway = e;
-                rt->metric = (uint16_t)(e->metric + 1);
-                rt->lq = n->lq;
-                rt->nlq = n->nlq;
-                rt->time_left = e->time_left;
-                olsr_route_add(rt);
-            }
-        }
-        /* dbg("Routes changed...\n"); */
-    }
-
-    return retval;
-}
-
-
-static void olsr_recv(uint8_t *buffer, uint32_t len)
-{
-    struct olsrmsg *msg;
-    struct olsrhdr *oh = (struct olsrhdr *) buffer;
-    struct olsr_route_entry *ancestor;
-    uint32_t parsed = 0;
-    uint16_t outsize = 0;
-    uint8_t *datagram;
-
-    if (len != short_be(oh->len)) {
-        return;
-    }
-
-    /* RFC 3626, section 3.4, if a packet is too small, it is silently discarded */
-    if (len < 16) {
-        return;
-    }
-
-    parsed += (uint32_t)sizeof(struct olsrhdr);
-
-    datagram = pico_zalloc(DGRAM_MAX_SIZE);
-    if (!datagram)
-        return;
-
-    outsize = (uint16_t) (outsize + (sizeof(struct olsrhdr)));
-
-    /* Section 1: parsing received messages. */
-
-    while (len > parsed) {
-        struct olsr_route_entry *origin;
-        msg = (struct olsrmsg *) (buffer + parsed);
-        origin = get_route_by_address(Local_interfaces, msg->orig.addr);
-
-        if(pico_ipv4_link_find(&msg->orig) != NULL) {
-            /* dbg("rebound\n"); */
-            parsed += short_be(msg->size);
-            continue;
-        }
-
-        /* OLSR's TTL expired. */
-        if (msg->ttl < 1u) {
-            parsed += short_be(msg->size);
-            continue;
-        }
-
-        if (!origin) {
-            arp_storm(&msg->orig);
-            parsed += short_be(msg->size);
-            continue;
-        }
-
-        /* We know this is a Master host and a neighbor */
-        origin->link_type = OLSRLINK_MPR;
-        origin->time_left = olsr2seconds(msg->vtime);
-        switch(msg->type) {
-        case OLSRMSG_HELLO:
-            ancestor = olsr_get_ethentry(origin->iface);
-            if ((origin->metric > 1) && ancestor) {
-                olsr_route_del(origin);
-                origin->gateway = ancestor;
-                origin->metric = 1;
-                olsr_route_add(origin);
-            }
-
-            recv_hello(buffer + (uint32_t)parsed + (uint32_t)sizeof(struct olsrmsg) + (uint32_t)sizeof(struct olsr_hmsg_hello),
-                       (uint32_t) ((short_be(msg->size) - (sizeof(struct olsrmsg))) - (uint32_t)sizeof(struct olsr_hmsg_hello)),
-                       origin);
-            msg->ttl = 0;
-            break;
-        case OLSRMSG_MID:
-            if ((origin->seq != 0) && (!fresher(short_be(msg->seq), origin->seq))) {
-                msg->ttl = 0;
-            } else {
-                recv_mid(buffer + parsed + sizeof(struct olsrmsg), (uint32_t)(short_be(msg->size) - (sizeof(struct olsrmsg))), origin);
-                /* dbg("MID forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */
-                origin->seq = short_be(msg->seq);
-            }
-
-            break;
-        case OLSRMSG_TC:
-            reconsider_topology(buffer + parsed + sizeof(struct olsrmsg), (uint32_t)(short_be(msg->size) - (sizeof(struct olsrmsg))), origin);
-            if ((origin->seq != 0) && (!fresher(short_be(msg->seq), origin->seq))) {
-                msg->ttl = 0;
-            } else {
-                /* dbg("TC forwarded from origin %08x (seq: %u)\n", long_be(msg->orig.addr), short_be(msg->seq)); */
-                origin->seq = short_be(msg->seq);
-            }
-
-            break;
-        default:
-            pico_free(datagram);
-            return;
-        }
-        if (msg->ttl > 1) {
-            msg->ttl--;
-            msg->hop++;
-            memcpy(datagram + outsize, msg, short_be(msg->size));
-            outsize = (uint16_t)(outsize + short_be(msg->size));
-        }
-
-        parsed += short_be(msg->size);
-    }
-    /* Section 2: forwarding parsed messages that got past the filter. */
-    if ((outsize > sizeof(struct olsrhdr))) {
-        /* Finalize FWD packet */
-        olsr_scheduled_output(OLSR_MAXJITTER, datagram, outsize, NULL);
-    } else {
-        /* Nothing to forward. */
-        pico_free(datagram);
-    }
-}
-
-static void wakeup(uint16_t ev, struct pico_socket *s)
-{
-    unsigned char *recvbuf;
-    int r = 0;
-    struct pico_ip4 ANY = {
-        0
-    };
-    uint16_t port = OLSR_PORT;
-    recvbuf = pico_zalloc(DGRAM_MAX_SIZE);
-    if (!recvbuf)
-        return;
-
-    if (ev & PICO_SOCK_EV_RD) {
-        r = pico_socket_recv(s, recvbuf, DGRAM_MAX_SIZE);
-        if (r > 0)
-            olsr_recv(recvbuf, (uint32_t)r);
-    }
-
-    if (ev == PICO_SOCK_EV_ERR) {
-        pico_socket_close(udpsock);
-        udpsock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &wakeup);
-        if (udpsock)
-            pico_socket_bind(udpsock, &ANY, &port);
-    }
-
-    pico_free(recvbuf);
-}
-
-static void olsr_hello_tick(pico_time when, void *unused)
-{
-    struct olsr_dev_entry *d;
-    (void)when;
-    (void)unused;
-    olsr_garbage_collector(Local_interfaces);
-    refresh_routes();
-    d = Local_devices;
-    while(d) {
-        olsr_make_dgram(d->dev, 0);
-        d = d->next;
-    }
-    pico_timer_add(OLSR_HELLO_INTERVAL, &olsr_hello_tick, NULL);
-}
-
-static void olsr_tc_tick(pico_time when, void *unused)
-{
-    struct olsr_dev_entry *d;
-    (void)when;
-    (void)unused;
-    d = Local_devices;
-    while(d) {
-        olsr_make_dgram(d->dev, 1);
-        d = d->next;
-    }
-    pico_timer_add(OLSR_TC_INTERVAL, &olsr_tc_tick, NULL);
-}
-
-
-/* Public interface */
-
-void pico_olsr_init(void)
-{
-    struct pico_ip4 ANY = {
-        0
-    };
-    uint16_t port = OLSR_PORT;
-    dbg("OLSR initialized.\n");
-    if (!udpsock) {
-        udpsock = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &wakeup);
-        if (udpsock)
-            pico_socket_bind(udpsock, &ANY, &port);
-    }
-
-    pico_timer_add(100, &olsr_hello_tick, NULL);
-    pico_timer_add(1100, &olsr_tc_tick, NULL);
-}
-
-int pico_olsr_add(struct pico_device *dev)
-{
-    struct pico_ipv4_link *lnk = NULL;
-    struct olsr_dev_entry *od;
-    if (!dev) {
-        pico_err = PICO_ERR_EINVAL;
-        return -1;
-    }
-
-    dbg("OLSR: Adding device %s\n", dev->name);
-    od = pico_zalloc(sizeof(struct olsr_dev_entry));
-    if (!od) {
-        pico_err = PICO_ERR_ENOMEM;
-        return -1;
-    }
-
-    od->dev = dev;
-    od->next = Local_devices;
-    Local_devices = od;
-
-    do {
-        char ipaddr[20];
-        lnk = pico_ipv4_link_by_dev_next(dev, lnk);
-        if (lnk) {
-            struct olsr_route_entry *e = pico_zalloc(sizeof(struct olsr_route_entry));
-            /* dbg("OLSR: Found IP address %08x\n", long_be(lnk->address.addr)); */
-            pico_ipv4_to_string(ipaddr, (lnk->address.addr));
-            dbg("OLSR: Found IP address %s\n", ipaddr);
-            if (!e) {
-                pico_err = PICO_ERR_ENOMEM;
-                return -1;
-            }
-
-            e->destination.addr = lnk->address.addr;
-            e->link_type = OLSRLINK_SYMMETRIC;
-            e->time_left = (OLSR_HELLO_INTERVAL << 2);
-            e->gateway = NULL;
-            e->iface = dev;
-            e->metric = 0;
-            e->lq = 0xFF;
-            e->nlq = 0xFF;
-            e->next = Local_interfaces;
-            Local_interfaces = e;
-
-        }
-    } while(lnk);
-    return 0;
-}
-
-#endif
--- a/modules/pico_olsr.h	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Authors: Daniele Lacamera
- *********************************************************************/
-#ifndef __PICO_OLSR_H
-#define __PICO_OLSR_H
-
-
-void pico_olsr_init(void);
-int pico_olsr_add(struct pico_device *dev);
-#endif
--- a/modules/pico_posix.c	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Authors: Andrei Carp, Maarten Vandersteegen
- *********************************************************************/
-
-#ifdef PICO_SUPPORT_THREADING
-
-#include <pthread.h>
-#include <semaphore.h>
-#include "pico_config.h"
-
-/* POSIX mutex implementation */
-void *pico_mutex_init(void)
-{
-    pthread_mutex_t *m;
-    m = (pthread_mutex_t *)pico_zalloc(sizeof(pthread_mutex_t));
-    pthread_mutex_init(m, NULL);
-    return m;
-}
-
-void pico_mutex_destroy(void *mux)
-{
-    pico_free(mux);
-    mux = NULL;
-}
-
-void pico_mutex_lock(void *mux)
-{
-    if (mux == NULL) return;
-
-    pthread_mutex_t *m = (pthread_mutex_t *)mux;
-    pthread_mutex_lock(m);
-}
-
-void pico_mutex_unlock(void *mux)
-{
-    if (mux == NULL) return;
-
-    pthread_mutex_t *m = (pthread_mutex_t *)mux;
-    pthread_mutex_unlock(m);
-}
-
-/* POSIX semaphore implementation */
-void *pico_sem_init(void)
-{
-    sem_t *s;
-    s = (sem_t *)pico_zalloc(sizeof(sem_t));
-    sem_init(s, 0, 0);
-    return s;
-}
-
-void pico_sem_destroy(void *sem)
-{
-    pico_free(sem);
-    sem = NULL;
-}
-
-void pico_sem_post(void *sem)
-{
-    if (sem == NULL) return;
-
-    sem_t *s = (sem_t *)sem;
-    sem_post(s);
-}
-
-int pico_sem_wait(void *sem, int timeout)
-{
-    struct timespec t;
-    if (sem == NULL) return 0;
-
-    sem_t *s = (sem_t *)sem;
-
-    if (timeout < 0) {
-        sem_wait(s);
-    } else {
-        clock_gettime(CLOCK_REALTIME, &t);
-        t.tv_sec += timeout / 1000;
-        t.tv_nsec += (timeout % 1000) * 1000000;
-        if (sem_timedwait(s, &t) == -1)
-            return -1;
-    }
-
-    return 0;
-}
-
-/* POSIX thread implementation */
-void *pico_thread_create(void *(*routine)(void *), void *arg)
-{
-    pthread_t *thread;
-    thread = (pthread_t *)pico_zalloc(sizeof(pthread_t));
-
-    if (pthread_create(thread, NULL, routine, arg) == -1)
-        return NULL;
-
-    return thread;
-}
-#endif  /* PICO_SUPPORT_THREADING */
--- a/modules/pico_simple_http.c	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Author: Andrei Carp <andrei.carp@tass.be>
- *********************************************************************/
-
-#include "pico_config.h"
-#include "pico_socket.h"
-#include "pico_tcp.h"
-#include "pico_ipv4.h"
-#include "pico_simple_http.h"
-
-/* 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_HEADER_SIZE  256u
-
-#define HTTP_SUCCESS            0
-#define HTTP_ERROR              -1
-
-static struct pico_socket *httpServer = NULL;
-static char httpResponse[] =
-    "HTTP/1.0 200 OK\r\n\
-Content-Type: text/html\r\n\
-\r\n\
-<html><head>\r\n\
-<title>picoTCP Simple Http server</title>\r\n\
-</head>\r\n\
-<body>\r\n\
-<h1>Hello world from picoTCP !!</h1>\r\n\
-</body>\r\n";
-
-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];
-
-    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_ERR:
-    case PICO_SOCK_EV_CLOSE:
-        /* free the used socket */
-        client = NULL;
-        break;
-
-    default:
-        break;
-    }
-}
-
-int pico_startHttpServer(struct pico_ip4 *address)
-{
-
-    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;
-    }
-
-    httpServer = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, httpEventCbk);
-
-    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;
-
-    if(pico_socket_listen(httpServer, HTTP_BACKLOG))
-        return HTTP_ERROR;
-
-    return HTTP_SUCCESS;
-}
-
-int pico_stopHttpServer(void)
-{
-    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;
-    }
-
-    httpServer = NULL;
-    return HTTP_SUCCESS;
-}
-
-#endif
-
-
--- a/modules/pico_simple_http.h	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   Author: Andrei Carp <andrei.carp@tass.be>
- *********************************************************************/
-
-#ifndef PICO_SIMPLE_HTTP
-#define PICO_SIMPLE_HTTP
-
-extern int pico_startHttpServer(struct pico_ip4 *address);
-extern int pico_stopHttpServer(void);
-
-#endif
--- a/modules/pico_slaacv4.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_slaacv4.c	Wed Apr 09 14:31:41 2014 +0200
@@ -38,7 +38,7 @@
 };
 
 struct slaacv4_cookie {
-    uint8_t state;
+    enum slaacv4_state state;
     uint8_t probe_try_nb;
     uint8_t conflict_nb;
     uint8_t announce_nb;
@@ -85,12 +85,13 @@
     tmp->timer = NULL;
 }
 
-static void pico_slaacv4_send_announce_timer(pico_time __attribute__((unused)) now, void *arg)
+static void pico_slaacv4_send_announce_timer(pico_time now, void *arg)
 {
     struct slaacv4_cookie *tmp = (struct slaacv4_cookie *)arg;
     struct pico_ip4 netmask = {
-        .addr = 0x0000FFFF
+        .addr = long_be(0xFFFF0000)
     };
+    (void)now;
 
     if (tmp->announce_nb < ANNOUNCE_NB)
     {
@@ -107,10 +108,10 @@
     }
 }
 
-static void pico_slaacv4_send_probe_timer(pico_time __attribute__((unused)) now, void *arg)
+static void pico_slaacv4_send_probe_timer(pico_time now, void *arg)
 {
-
     struct slaacv4_cookie *tmp = (struct slaacv4_cookie *)arg;
+    (void)now;
 
     if (tmp->probe_try_nb < PROBE_NB)
     {
@@ -162,10 +163,15 @@
 
 }
 
-uint8_t pico_slaacv4_claimip(struct pico_device *dev, void (*cb)(struct pico_ip4 *ip,  uint8_t code))
+int pico_slaacv4_claimip(struct pico_device *dev, void (*cb)(struct pico_ip4 *ip,  uint8_t code))
 {
     struct pico_ip4 ip;
 
+    if (!dev->eth) {
+        pico_err = PICO_ERR_EPROTONOSUPPORT;
+        return -1;
+    }
+
     ip.addr = long_be(pico_slaacv4_getip(dev, 0));
 
     pico_slaacv4_init_cookie(&ip, dev, &slaacv4_local, cb);
--- a/modules/pico_slaacv4.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_slaacv4.h	Wed Apr 09 14:31:41 2014 +0200
@@ -4,14 +4,14 @@
 
    Authors: Bogdan Lupu
  *********************************************************************/
-#ifndef _INCLUDE_PICO_SUPPORT_SLAACV4
-#define _INCLUDE_PICO_SUPPORT_SLAACV4
+#ifndef INCLUDE_PICO_SUPPORT_SLAACV4
+#define INCLUDE_PICO_SUPPORT_SLAACV4
 #include "pico_arp.h"
 
 #define PICO_SLAACV4_SUCCESS  0
 #define PICO_SLAACV4_ERROR    1
 
-uint8_t pico_slaacv4_claimip(struct pico_device *dev, void (*cb)(struct pico_ip4 *ip,  uint8_t code));
+int     pico_slaacv4_claimip(struct pico_device *dev, void (*cb)(struct pico_ip4 *ip,  uint8_t code));
 void    pico_slaacv4_unregisterip(void);
 
 #endif /* _INCLUDE_PICO_SUPPORT_SLAACV4 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_socket_tcp.c	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,211 @@
+#include <stdint.h>
+#include "pico_socket.h"
+#include "pico_ipv4.h"
+#include "pico_ipv6.h"
+#include "pico_tcp.h"
+
+int pico_getsockopt_tcp(struct pico_socket *s, int option, void *value)
+{
+    if (!value) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    if (s->proto->proto_number != PICO_PROTO_TCP) {
+        pico_err = PICO_ERR_EPROTONOSUPPORT;
+        return -1;
+    }
+
+#ifdef PICO_SUPPORT_TCP
+    if (option == PICO_TCP_NODELAY) {
+        /* state of the NODELAY option */
+        *(int *)value = PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_TCPNODELAY);
+        return 0;
+    }
+    else if (option == PICO_SOCKET_OPT_RCVBUF) {
+        return pico_tcp_get_bufsize_in(s, (uint32_t *)value);
+    }
+
+    if (option == PICO_SOCKET_OPT_SNDBUF) {
+        return pico_tcp_get_bufsize_out(s, (uint32_t *)value);
+    }
+
+#endif
+    return -1;
+}
+
+int pico_setsockopt_tcp(struct pico_socket *s, int option, void *value)
+{
+    if (!value) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    if (s->proto->proto_number != PICO_PROTO_TCP) {
+        pico_err = PICO_ERR_EPROTONOSUPPORT;
+        return -1;
+    }
+
+#ifdef PICO_SUPPORT_TCP
+    if (option ==  PICO_TCP_NODELAY) {
+        int *val = (int*)value;
+        if (*val > 0) {
+            dbg("setsockopt: Nagle algorithm disabled.\n");
+            PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_TCPNODELAY);
+        } else {
+            dbg("setsockopt: Nagle algorithm enabled.\n");
+            PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_TCPNODELAY);
+        }
+
+        return 0;
+    }
+
+    if (option == PICO_SOCKET_OPT_RCVBUF) {
+        uint32_t *val = (uint32_t*)value;
+        pico_tcp_set_bufsize_in(s, *val);
+        return 0;
+    }
+
+    if (option == PICO_SOCKET_OPT_SNDBUF) {
+        uint32_t *val = (uint32_t*)value;
+        pico_tcp_set_bufsize_out(s, *val);
+        return 0;
+    }
+
+#endif
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+}
+
+void pico_socket_tcp_cleanup(struct pico_socket *sock)
+{
+#ifdef PICO_SUPPORT_TCP
+    /* for tcp sockets go further and clean the sockets inside queue */
+    if(sock->proto == &pico_proto_tcp)
+        pico_tcp_cleanup_queues(sock);
+
+#endif
+}
+
+
+void pico_socket_tcp_delete(struct pico_socket *s)
+{
+#ifdef PICO_SUPPORT_TCP
+    if(s->parent)
+        s->parent->number_of_pending_conn--;
+
+#endif
+}
+
+int pico_socket_tcp_deliver(struct pico_sockport *sp, struct pico_frame *f)
+{
+    struct pico_socket *found = NULL;
+    struct pico_tree_node *index = NULL;
+    struct pico_tree_node *_tmp;
+    struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
+    struct pico_socket *s = NULL;
+
+
+    pico_tree_foreach_safe(index, &sp->socks, _tmp){
+        s = index->keyValue;
+        /* 4-tuple identification of socket (port-IP) */
+        #ifdef PICO_SUPPORT_IPV4
+        if (IS_IPV4(f)) {
+            struct pico_ip4 s_local, s_remote, p_src, p_dst;
+            struct pico_ipv4_hdr *ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
+            s_local.addr = s->local_addr.ip4.addr;
+            s_remote.addr = s->remote_addr.ip4.addr;
+            p_src.addr = ip4hdr->src.addr;
+            p_dst.addr = ip4hdr->dst.addr;
+            if ((s->remote_port == tr->sport) && /* remote port check */
+                (s_remote.addr == p_src.addr) && /* remote addr check */
+                ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
+                found = s;
+                break;
+            } else if ((s->remote_port == 0)  && /* not connected... listening */
+                       ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
+                /* listen socket */
+                found = s;
+            }
+        }
+
+        #endif
+        #ifdef PICO_SUPPORT_IPV6
+        if (IS_IPV6(f)) {
+            struct pico_ip6 s_local = {{0}}, s_remote = {{0}}, p_src = {{0}}, p_dst = {{0}};
+            struct pico_ipv6_hdr *ip6hdr = (struct pico_ipv6_hdr *)(f->net_hdr);
+            s_local = s->local_addr.ip6;
+            s_remote = s->remote_addr.ip6;
+            p_src = ip6hdr->src;
+            p_dst = ip6hdr->dst;
+            if ((s->remote_port == tr->sport) &&
+                (!memcmp(s_remote.addr, p_src.addr, PICO_SIZE_IP6)) &&
+                ((!memcmp(s_local.addr, PICO_IP6_ANY, PICO_SIZE_IP6)) || (!memcmp(s_local.addr, p_dst.addr, PICO_SIZE_IP6)))) {
+                found = s;
+                break;
+            } else if ((s->remote_port == 0)  && /* not connected... listening */
+                       ((!memcmp(s_local.addr, PICO_IP6_ANY, PICO_SIZE_IP6)) || (!memcmp(s_local.addr, p_dst.addr, PICO_SIZE_IP6)))) {
+                /* listen socket */
+                found = s;
+            }
+        }
+
+        #endif
+    } /* FOREACH */
+    if (found != NULL) {
+        pico_tcp_input(found, f);
+        if ((found->ev_pending) && found->wakeup) {
+            found->wakeup(found->ev_pending, found);
+            if(!found->parent)
+                found->ev_pending = 0;
+        }
+
+        return 0;
+    } else {
+        dbg("TCP SOCKET> Not found.\n");
+        return -1;
+    }
+}
+
+struct pico_socket *pico_socket_tcp_open(uint16_t family)
+{
+    struct pico_socket *s = NULL;
+    (void) family;
+#ifdef PICO_SUPPORT_TCP
+    s = pico_tcp_open(family);
+    if (!s) {
+        pico_err = PICO_ERR_ENOMEM;
+        return NULL;
+    }
+
+    s->proto = &pico_proto_tcp;
+    /*check if Nagle enabled */
+    /*
+       if (!IS_NAGLE_ENABLED(s))
+           dbg("ERROR Nagle should be enabled here\n\n");
+     */
+#endif
+    return s;
+}
+
+int pico_socket_tcp_read(struct pico_socket *s, void *buf, uint32_t len)
+{
+#ifdef PICO_SUPPORT_TCP
+    /* check if in shutdown state and if no more data in tcpq_in */
+    if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
+        pico_err = PICO_ERR_ESHUTDOWN;
+        return -1;
+    } else {
+        return (int)(pico_tcp_read(s, buf, (uint32_t)len));
+    }
+
+#endif
+    return 0;
+}
+
+void transport_flags_update(struct pico_frame *f, struct pico_socket *s)
+{
+#ifdef PICO_SUPPORT_TCP
+    pico_tcp_flags_update(f, s);
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_socket_tcp.h	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,33 @@
+#ifndef PICO_SOCKET_TCP_H
+#define PICO_SOCKET_TCP_H
+#include "pico_socket.h"
+
+#ifdef PICO_SUPPORT_TCP
+
+/* Functions/macros: conditional! */
+
+# define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY)))))
+int pico_setsockopt_tcp(struct pico_socket *s, int option, void *value);
+int pico_getsockopt_tcp(struct pico_socket *s, int option, void *value);
+int pico_socket_tcp_deliver(struct pico_sockport *sp, struct pico_frame *f);
+void pico_socket_tcp_delete(struct pico_socket *s);
+void pico_socket_tcp_cleanup(struct pico_socket *sock);
+struct pico_socket *pico_socket_tcp_open(uint16_t family);
+int pico_socket_tcp_read(struct pico_socket *s, void *buf, uint32_t len);
+void transport_flags_update(struct pico_frame *, struct pico_socket *);
+
+#else
+#   define pico_getsockopt_tcp(...) (-1)
+#   define pico_setsockopt_tcp(...) (-1)
+#   define pico_socket_tcp_deliver(...) (-1)
+#   define IS_NAGLE_ENABLED(s) (0)
+#   define pico_socket_tcp_delete(...) do {} while(0)
+#   define pico_socket_tcp_cleanup(...) do {} while(0)
+#   define pico_socket_tcp_open(f) (NULL)
+#   define pico_socket_tcp_read(...) (-1)
+#   define transport_flags_update(...) do {} while(0)
+
+#endif
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_socket_udp.c	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,182 @@
+#include <stdint.h>
+#include "pico_socket.h"
+#include "pico_udp.h"
+#include "pico_socket_multicast.h"
+#include "pico_ipv4.h"
+#include "pico_ipv6.h"
+
+#define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame))
+
+
+struct pico_socket *pico_socket_udp_open(void)
+{
+    struct pico_socket *s = NULL;
+#ifdef PICO_SUPPORT_UDP
+    s = pico_udp_open();
+    if (!s) {
+        pico_err = PICO_ERR_ENOMEM;
+        return NULL;
+    }
+
+    s->proto = &pico_proto_udp;
+    s->q_in.overhead = s->q_out.overhead = UDP_FRAME_OVERHEAD;
+#endif
+    return s;
+}
+
+
+#ifdef PICO_SUPPORT_IPV4
+static int pico_socket_udp_deliver_ipv4(struct pico_socket *s, struct pico_frame *f)
+{
+    struct pico_ip4 s_local, p_dst;
+    struct pico_ipv4_hdr *ip4hdr;
+    struct pico_frame *cpy;
+    ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
+    s_local.addr = s->local_addr.ip4.addr;
+    p_dst.addr = ip4hdr->dst.addr;
+    if ((pico_ipv4_is_broadcast(p_dst.addr)) || pico_ipv4_is_multicast(p_dst.addr)) {
+        struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);
+        if (pico_ipv4_is_multicast(p_dst.addr) && (pico_socket_mcast_filter(s, (union pico_address *)&ip4hdr->dst, (union pico_address *)&ip4hdr->src) < 0))
+            return -1;
+
+        if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */
+            (dev == f->dev)) { /* the source of the bcast packet is a neighbor... */
+            cpy = pico_frame_copy(f);
+            if (!cpy)
+                return -1;
+
+            if (pico_enqueue(&s->q_in, cpy) > 0) {
+                if (s->wakeup)
+                    s->wakeup(PICO_SOCK_EV_RD, s);
+            }
+            else
+                pico_frame_discard(cpy);
+
+        }
+    } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))
+    { /* Either local socket is ANY, or matches dst */
+        cpy = pico_frame_copy(f);
+        if (!cpy)
+            return -1;
+
+        if (pico_enqueue(&s->q_in, cpy) > 0) {
+            if (s->wakeup)
+                s->wakeup(PICO_SOCK_EV_RD, s);
+        } else {
+            pico_frame_discard(cpy);
+        }
+    }
+
+    pico_frame_discard(f);
+    return 0;
+}
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+static int pico_socket_udp_deliver_ipv6(struct pico_socket *s, struct pico_frame *f)
+{
+    struct pico_ip6 s_local, p_dst;
+    struct pico_ipv6_hdr *ip6hdr;
+    struct pico_frame *cpy;
+    ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
+    s_local = s->local_addr.ip6;
+    p_dst = ip6hdr->dst;
+    if ((pico_ipv6_is_multicast(p_dst.addr))) {
+        cpy = pico_frame_copy(f);
+        if (!cpy)
+            return -1;
+
+        if (pico_enqueue(&s->q_in, cpy) > 0) {
+            if (s->wakeup)
+                s->wakeup(PICO_SOCK_EV_RD, s);
+        }
+        else
+            pico_frame_discard(cpy);
+    } else if (pico_ipv6_is_unspecified(s->local_addr.ip6.addr) || (pico_ipv6_compare(&s_local, &p_dst) == 0))
+    { /* Either local socket is ANY, or matches dst */
+        cpy = pico_frame_copy(f);
+        if (!cpy)
+            return -1;
+
+        if (pico_enqueue(&s->q_in, cpy) > 0) {
+            if (s->wakeup)
+                s->wakeup(PICO_SOCK_EV_RD, s);
+        }
+    }
+
+    pico_frame_discard(f);
+    return 0;
+}
+#endif
+
+
+int pico_socket_udp_deliver(struct pico_sockport *sp, struct pico_frame *f)
+{
+    struct pico_tree_node *index = NULL;
+    struct pico_tree_node *_tmp;
+    struct pico_socket *s = NULL;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    #ifdef PICO_SUPPORT_UDP
+    pico_err = PICO_ERR_NOERR;
+    pico_tree_foreach_safe(index, &sp->socks, _tmp){
+        s = index->keyValue;
+        if (IS_IPV4(f)) { /* IPV4 */
+#ifdef PICO_SUPPORT_IPV4
+            return pico_socket_udp_deliver_ipv4(s, f);
+#endif
+        } else {
+#ifdef PICO_SUPPORT_IPV6
+            return pico_socket_udp_deliver_ipv6(s, f);
+#endif
+        }
+    } /* FOREACH */
+    pico_frame_discard(f);
+    if (s)
+        return 0;
+
+    pico_err = PICO_ERR_ENXIO;
+  #endif
+    return -1;
+}
+
+int pico_setsockopt_udp(struct pico_socket *s, int option, void *value)
+{
+    switch(option) {
+    case PICO_SOCKET_OPT_RCVBUF:
+        s->q_in.max_size = (*(uint32_t*)value);
+        return 0;
+    case PICO_SOCKET_OPT_SNDBUF:
+        s->q_out.max_size = (*(uint32_t*)value);
+        return 0;
+    }
+
+    /* switch's default */
+#ifdef PICO_SUPPORT_MCAST
+    return pico_setsockopt_mcast(s, option, value);
+#else
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+#endif
+}
+
+int pico_getsockopt_udp(struct pico_socket *s, int option, void *value)
+{
+    uint32_t *val = (uint32_t *)value;
+    switch(option) {
+    case PICO_SOCKET_OPT_RCVBUF:
+        *val = s->q_in.max_size;
+        return 0;
+    case PICO_SOCKET_OPT_SNDBUF:
+        *val = s->q_out.max_size;
+        return 0;
+    }
+
+    /* switch's default */
+#ifdef PICO_SUPPORT_MCAST
+    return pico_getsockopt_mcast(s, option, value);
+#else
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+#endif
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_socket_udp.h	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,19 @@
+#ifndef PICO_SOCKET_UDP_H
+#define PICO_SOCKET_UDP_H
+
+struct pico_socket *pico_socket_udp_open(void);
+int pico_socket_udp_deliver(struct pico_sockport *sp, struct pico_frame *f);
+
+
+#ifdef PICO_SUPPORT_UDP
+int pico_setsockopt_udp(struct pico_socket *s, int option, void *value);
+int pico_getsockopt_udp(struct pico_socket *s, int option, void *value);
+#   define pico_socket_udp_recv(s, buf, len, addr, port) pico_udp_recv(s, buf, len, addr, port)
+#else
+#   define pico_socket_udp_recv(...) (0)
+#   define pico_getsockopt_udp(...) (-1)
+#   define pico_setsockopt_udp(...) (-1)
+#endif
+
+
+#endif
--- a/modules/pico_tcp.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_tcp.c	Wed Apr 09 14:31:41 2014 +0200
@@ -16,15 +16,15 @@
 #include "pico_queue.h"
 #include "pico_tree.h"
 
-#define TCP_IS_STATE(s, st) (s->state & st)
+#define TCP_IS_STATE(s, st) ((s->state & PICO_SOCKET_STATE_TCP) == st)
 #define TCP_SOCK(s) ((struct pico_socket_tcp *)s)
 #define SEQN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->seq)) : 0)
 #define ACKN(f) ((f) ? (long_be(((struct pico_tcp_hdr *)((f)->transport_hdr))->ack)) : 0)
 
 #define TCP_TIME (PICO_TIME_MS())
 
-#define PICO_TCP_RTO_MIN 50
-#define PICO_TCP_RTO_MAX 120000
+#define PICO_TCP_RTO_MIN (70)
+#define PICO_TCP_RTO_MAX (120000)
 #define PICO_TCP_IW          2
 #define PICO_TCP_SYN_TO  1000u
 #define PICO_TCP_ZOMBIE_TO 30000
@@ -41,7 +41,7 @@
 #define PICO_TCP_WINDOW_FULL    0x06
 
 /* check if the Nagle algorithm is enabled on the socket */
-#define IS_NAGLE_ENABLED(s)     (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY)))))
+#define IS_NAGLE_ENABLED(s)     (!(!(!(s->opt_flags & (1u << PICO_SOCKET_OPT_TCPNODELAY)))))
 /* check if tcp connection is "idle" according to Nagle (RFC 896) */
 #define IS_TCP_IDLE(t)          ((t->in_flight == 0) && (t->tcpq_out.size == 0))
 /* check if the hold queue contains data (again Nagle) */
@@ -61,34 +61,39 @@
 
 #ifdef PICO_SUPPORT_MUTEX
 static void *Mutex = NULL;
-#define LOCK(x) { \
+#define PICOTCP_MUTEX_LOCK(x) { \
         if (x == NULL) \
             x = pico_mutex_init(); \
         pico_mutex_lock(x); \
 }
-#define UNLOCK(x) pico_mutex_unlock(x)
+#define PICOTCP_MUTEX_UNLOCK(x) pico_mutex_unlock(x)
 
 #else
-#define LOCK(x) do {} while(0)
-#define UNLOCK(x) do {} while(0)
+#define PICOTCP_MUTEX_LOCK(x) do {} while(0)
+#define PICOTCP_MUTEX_UNLOCK(x) do {} while(0)
 #endif
 
 
-static inline int seq_compare(uint32_t a, uint32_t b)
+static /* inline*/ int32_t seq_compare(uint32_t a, uint32_t b)
 {
     uint32_t thresh = ((uint32_t)(-1)) >> 1;
-    if (((a > thresh) && (b > thresh)) || ((a <= thresh) && (b <= thresh))) {
-        if (a > b)
-            return 1;
-
-        if (b > a)
-            return -1;
-    } else {
-        if (a > b)
-            return -2;
-
-        if (b > a)
-            return 2;
+
+    if (a > b) /* return positive number, if not wrapped */
+    {
+        if ((a - b) > thresh) /* b wrapped */
+            return -(int32_t)(b - a); /* b = very small,     a = very big      */
+        else
+            return (int32_t)(a - b); /* a = biggest,        b = a bit smaller */
+
+    }
+
+    if (a < b) /* return negative number, if not wrapped */
+    {
+        if ((b - a) > thresh) /* a wrapped */
+            return (int32_t)(a - b); /* a = very small,     b = very big      */
+        else
+            return -(int32_t)(b - a); /* b = biggest,        a = a bit smaller */
+
     }
 
     return 0;
@@ -112,14 +117,14 @@
 
 static struct tcp_input_segment *segment_from_frame(struct pico_frame *f)
 {
-    struct tcp_input_segment *seg = pico_zalloc(sizeof(struct tcp_input_segment));
+    struct tcp_input_segment *seg = PICO_ZALLOC(sizeof(struct tcp_input_segment));
     if(!seg)
         return NULL;
 
-    seg->payload = pico_zalloc(f->payload_len);
+    seg->payload = PICO_ZALLOC(f->payload_len);
     if(!seg->payload)
     {
-        pico_free(seg);
+        PICO_FREE(seg);
         return NULL;
     }
 
@@ -141,7 +146,6 @@
     uint32_t max_size;
     uint32_t size;
     uint32_t frames;
-    uint16_t overhead;
 };
 
 static void tcp_discard_all_segments(struct pico_tcp_queue *tq);
@@ -192,17 +196,22 @@
 static int32_t pico_enqueue_segment(struct pico_tcp_queue *tq, void *f)
 {
     int32_t ret = -1;
-    uint16_t payload_len = (uint16_t)(IS_INPUT_QUEUE(tq) ?
-                                      ((struct tcp_input_segment *)f)->payload_len :
-                                      ((struct pico_frame *)f)->buffer_len);
+    uint16_t payload_len;
+
+    if (!f)
+        return -1;
+
+    payload_len = (uint16_t)((IS_INPUT_QUEUE(tq)) ?
+                             (((struct tcp_input_segment *)f)->payload_len) :
+                             (((struct pico_frame *)f)->buffer_len));
 
     if (payload_len <= 0) {
         tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n");
-        /* abort(); */
-        return -1;
+        ret = -2; /* Fail harder */
+        goto out;
     }
 
-    LOCK(Mutex);
+    PICOTCP_MUTEX_LOCK(Mutex);
     if ((tq->size + payload_len) > tq->max_size)
     {
         ret = 0;
@@ -215,41 +224,41 @@
         goto out;
     }
 
-    tq->size += (uint16_t)(payload_len + tq->overhead);
+    tq->size += (uint16_t)payload_len;
     if (payload_len > 0)
         tq->frames++;
 
     ret = (int32_t)payload_len;
 
 out:
-    UNLOCK(Mutex);
+    PICOTCP_MUTEX_UNLOCK(Mutex);
     return ret;
 }
 
 static void pico_discard_segment(struct pico_tcp_queue *tq, void *f)
 {
     void *f1;
-    uint16_t payload_len = (uint16_t)(IS_INPUT_QUEUE(tq) ?
-                                      ((struct tcp_input_segment *)f)->payload_len :
-                                      ((struct pico_frame *)f)->buffer_len);
-    LOCK(Mutex);
+    uint16_t payload_len = (uint16_t)((IS_INPUT_QUEUE(tq)) ?
+                                      (((struct tcp_input_segment *)f)->payload_len) :
+                                      (((struct pico_frame *)f)->buffer_len));
+    PICOTCP_MUTEX_LOCK(Mutex);
     f1 = pico_tree_delete(&tq->pool, f);
     if (f1) {
-        tq->size -= (uint16_t)(payload_len + tq->overhead);
+        tq->size -= (uint16_t)payload_len;
         if (payload_len > 0)
             tq->frames--;
     }
 
-    if(IS_INPUT_QUEUE(tq))
+    if(f1 && IS_INPUT_QUEUE(tq))
     {
         struct tcp_input_segment *inp = f1;
-        pico_free(inp->payload);
-        pico_free(inp);
+        PICO_FREE(inp->payload);
+        PICO_FREE(inp);
     }
     else
         pico_frame_discard(f);
 
-    UNLOCK(Mutex);
+    PICOTCP_MUTEX_UNLOCK(Mutex);
 }
 
 /* Structure for TCP socket */
@@ -293,6 +302,7 @@
     uint32_t rcv_processed;
     uint16_t wnd;
     uint16_t wnd_scale;
+    uint16_t remote_closed;
 
     /* options */
     uint32_t ts_nxt;
@@ -338,39 +348,50 @@
 {
     void *head = first_segment(q);
     int ret = 0;
-    int seq_result = 0;
-    if(head)
-        seq_result = IS_INPUT_QUEUE(q) ?
-                     seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq) :
-                     seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq);
-
-    while (head && (seq_result <= 0)) {
+    int32_t seq_result = 0;
+
+    if (!head)
+        return ret;
+
+    do {
         void *cur = head;
-        head = next_segment(q, cur);
-        tcp_dbg("Releasing %p\n", q);
-        pico_discard_segment(q, cur);
-        ret++;
-        if(head)
-            seq_result = IS_INPUT_QUEUE(q) ?
-                         seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq) :
-                         seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq);
-    }
+
+        if (IS_INPUT_QUEUE(q))
+            seq_result = seq_compare(((struct tcp_input_segment *)head)->seq + ((struct tcp_input_segment *)head)->payload_len, seq);
+        else
+            seq_result = seq_compare(SEQN((struct pico_frame *)head) + ((struct pico_frame *)head)->payload_len, seq);
+
+        if (seq_result <= 0)
+        {
+            head = next_segment(q, cur);
+            tcp_dbg("Releasing %08x, len: %d\n", SEQN((struct pico_frame *)head), ((struct pico_frame *)head)->payload_len);
+            pico_discard_segment(q, cur);
+            ret++;
+        } else {
+            break;
+        }
+    } while (head);
+
     return ret;
 }
 
 static int release_all_until(struct pico_tcp_queue *q, uint32_t seq, pico_time *timestamp)
 {
-    void *f = NULL, *tmp __attribute__((unused));
+    void *f = NULL;
     struct pico_tree_node *idx, *temp;
     int seq_result;
     int ret = 0;
     *timestamp = 0;
 
-    pico_tree_foreach_safe(idx, &q->pool, temp){
+    pico_tree_foreach_safe(idx, &q->pool, temp)
+    {
         f = idx->keyValue;
-        seq_result = IS_INPUT_QUEUE(q) ?
-                     seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq) :
-                     seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq);
+
+        if (IS_INPUT_QUEUE(q))
+            seq_result = seq_compare(((struct tcp_input_segment *)f)->seq + ((struct tcp_input_segment *)f)->payload_len, seq);
+        else
+            seq_result = seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq);
+
         if (seq_result <= 0) {
             tcp_dbg("Releasing %p\n", f);
             if(seq_result == 0)
@@ -378,12 +399,14 @@
 
             pico_discard_segment(q, f);
             ret++;
-        } else
+        } else {
             return ret;
+        }
     }
     return ret;
 }
 
+
 /* API calls */
 
 uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f)
@@ -412,6 +435,58 @@
     return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len);
 }
 
+#ifdef PICO_SUPPORT_IPV6
+uint16_t pico_tcp_checksum_ipv6(struct pico_frame *f)
+{
+    struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
+    struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *)f->transport_hdr;
+    struct pico_ipv6_pseudo_hdr pseudo;
+    struct pico_socket *s = f->sock;
+
+    /* XXX If the IPv6 packet contains a Routing header, the Destination
+     *     Address used in the pseudo-header is that of the final destination */
+    if (s) {
+        /* Case of outgoing frame */
+        pseudo.src = s->local_addr.ip6;
+        pseudo.dst = s->remote_addr.ip6;
+    } else {
+        /* Case of incomming frame */
+        pseudo.src = ipv6_hdr->src;
+        pseudo.dst = ipv6_hdr->dst;
+    }
+
+    pseudo.zero[0] = 0;
+    pseudo.zero[1] = 0;
+    pseudo.zero[2] = 0;
+    pseudo.len = long_be(f->transport_len);
+    pseudo.nxthdr = PICO_PROTO_TCP;
+
+    return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), tcp_hdr, f->transport_len);
+}
+#endif
+
+uint16_t pico_tcp_checksum(struct pico_frame *f)
+{
+    (void)f;
+    #ifdef PICO_SUPPORT_IPV4
+    if (IS_IPV4(f))
+        return pico_tcp_checksum_ipv4(f);
+
+    if (f->sock && (f->sock->net == &pico_proto_ipv4))
+        return pico_tcp_checksum_ipv4(f);
+
+    #endif
+    #ifdef PICO_SUPPORT_IPV6
+    if (IS_IPV6(f))
+        return pico_tcp_checksum_ipv6(f);
+
+    if (f->sock && (f->sock->net == &pico_proto_ipv6))
+        return pico_tcp_checksum_ipv6(f);
+
+    #endif
+    return 0xffff;
+}
+
 static void tcp_send_fin(struct pico_socket_tcp *t);
 static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f)
 {
@@ -459,7 +534,7 @@
 {
     static uint32_t _paws = 0;
     _paws = pico_rand();
-    return long_be(_paws); /*XXX: implement paws */
+    return long_be(_paws);
 }
 
 static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, uint16_t optsiz)
@@ -507,7 +582,7 @@
                 memcpy(f->start + i, sb, 2 * sizeof(uint32_t));
                 i += (2 * (uint32_t)sizeof(uint32_t));
                 f->start[len_off] = (uint8_t)(f->start[len_off] + (2 * sizeof(uint32_t)));
-                pico_free(sb);
+                PICO_FREE(sb);
             }
         }
     }
@@ -526,7 +601,7 @@
         size = (uint16_t)(size + PICO_TCPOPTLEN_TIMESTAMP);
 
     size = (uint16_t)(size + PICO_TCPOPTLEN_END);
-    size = (uint16_t)(((size + 3) >> 2) << 2);
+    size = (uint16_t)(((uint16_t)(size + 3u) >> 2u) << 2u);
     return size;
 }
 
@@ -564,25 +639,23 @@
 
 static void tcp_set_space(struct pico_socket_tcp *t)
 {
-    uint32_t mtu;
     int32_t space;
     uint32_t shift = 0;
 
-    mtu = t->mss + PICO_SIZE_TCPHDR + PICO_SIZE_TCPOPT_SYN;
     if (t->tcpq_in.max_size == 0) {
         space = 1024 * 1024 * 1024; /* One Gigabyte, for unlimited sockets. */
     } else {
-        space = (int32_t)(((t->tcpq_in.max_size - t->tcpq_in.size) / mtu) * t->mss);
+        space = (int32_t)(t->tcpq_in.max_size - t->tcpq_in.size);
     }
 
     if (space < 0)
         space = 0;
 
     while(space > 0xFFFF) {
-        space >>= 1;
+        space = (int32_t)(((uint32_t)space >> 1u));
         shift++;
     }
-    if ((space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (space >> 2))) {
+    if (((uint32_t)space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (int32_t)((uint32_t)space >> 2u))) {
         t->wnd = (uint16_t)space;
         t->wnd_scale = (uint16_t)shift;
 
@@ -623,7 +696,7 @@
         }
     }
 
-    size = (uint16_t)(((size + 3) >> 2) << 2);
+    size = (uint16_t)(((size + 3u) >> 2u) << 2u);
     return size;
 }
 
@@ -684,7 +757,7 @@
     hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK;
     hdr->ack = long_be(t->rcv_nxt);
     hdr->crc = 0;
-    hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
+    hdr->crc = short_be(pico_tcp_checksum(f));
 }
 
 static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len)
@@ -825,17 +898,22 @@
     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
     hdr->rwnd = short_be(ts->wnd);
     hdr->crc = 0;
-    hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
+    hdr->crc = short_be(pico_tcp_checksum(f));
 
     /* TCP: ENQUEUE to PROTO ( Transmit ) */
     cpy = pico_frame_copy(f);
+    if (!cpy) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
     if ((pico_enqueue(&tcp_out, cpy) > 0)) {
         if (f->payload_len > 0) {
             ts->in_flight++;
             ts->snd_nxt += f->payload_len; /* update next pointer here to prevent sending same segment twice when called twice in same tick */
         }
 
-        tcp_dbg("DBG> [tcp output] state: %02x --> local port:%d remote port: %d seq: %08x ack: %08x flags: %02x = t_len: %d, hdr: %u payload: %d\n",
+        tcp_dbg("DBG> [tcp output] state: %02x --> local port:%u remote port: %u seq: %08x ack: %08x flags: %02x = t_len: %u, hdr: %u payload: %d\n",
                 TCPSTATE(&ts->sock) >> 8, short_be(hdr->trans.sport), short_be(hdr->trans.dport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len );
     } else {
         pico_frame_discard(cpy);
@@ -856,23 +934,21 @@
 }
 #endif
 
-struct pico_socket *pico_tcp_open(void)
+struct pico_socket *pico_tcp_open(uint16_t family)
 {
-    struct pico_socket_tcp *t = pico_zalloc(sizeof(struct pico_socket_tcp));
+    struct pico_socket_tcp *t = PICO_ZALLOC(sizeof(struct pico_socket_tcp));
     if (!t)
         return NULL;
 
     t->sock.timestamp = TCP_TIME;
-    t->mss = PICO_TCP_DEFAULT_MSS;
-
+    pico_socket_set_family(&t->sock, family);
+    t->mss = (uint16_t)(pico_socket_get_mtu(&t->sock) - PICO_SIZE_TCPHDR);
     t->tcpq_in.pool.root = t->tcpq_hold.pool.root = t->tcpq_out.pool.root = &LEAF;
     t->tcpq_hold.pool.compare = t->tcpq_out.pool.compare = segment_compare;
     t->tcpq_in.pool.compare = input_segment_compare;
     t->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
     t->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
-    t->tcpq_hold.max_size = 2 * PICO_TCP_DEFAULT_MSS;
-    t->tcpq_in.overhead = (sizeof(struct tcp_input_segment) + sizeof(struct pico_tree_node));
-    t->tcpq_out.overhead = t->tcpq_hold.overhead = sizeof(struct pico_frame) + sizeof(struct pico_tree_node);
+    t->tcpq_hold.max_size = 2u * t->mss;
     /* disable Nagle by default */
     t->sock.opt_flags |= (1 << PICO_SOCKET_OPT_TCPNODELAY);
     /* Nagle is enabled by default */
@@ -890,7 +966,8 @@
 {
     struct pico_socket_tcp *t = TCP_SOCK(s);
     struct tcp_input_segment *f;
-    uint32_t in_frame_off, in_frame_len;
+    int32_t in_frame_off;
+    uint32_t in_frame_len;
     uint32_t tot_rd_len = 0;
 
     while (tot_rd_len < len) {
@@ -900,27 +977,28 @@
         if (!f)
             goto out;
 
+        in_frame_off = seq_compare(t->rcv_processed, f->seq);
         /* Hole at the beginning of data, awaiting retransmissions. */
-        if (seq_compare(t->rcv_processed, f->seq) < 0) {
+        if (in_frame_off < 0) {
             tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n", t->rcv_processed, f->seq, t->rcv_nxt);
             goto out;
         }
 
-        if(seq_compare(t->rcv_processed, f->seq) > 0) {
-            in_frame_off = t->rcv_processed - f->seq;
-            in_frame_len = f->payload_len - in_frame_off;
+        else if (in_frame_off > 0)
+        {
+            if ((uint32_t)in_frame_off > f->payload_len)
+                dbg("FATAL TCP ERR: in_frame_off > f->payload_len\n");
+
+            in_frame_len = f->payload_len - (uint32_t)in_frame_off;
         } else {
-            in_frame_off = 0;
             in_frame_len = f->payload_len;
         }
 
+
         if ((in_frame_len + tot_rd_len) > (uint32_t)len) {
             in_frame_len = len - tot_rd_len;
         }
 
-        if (in_frame_len > f->payload_len - in_frame_off)
-            in_frame_len = f->payload_len - in_frame_off;
-
         memcpy((uint8_t *)buf + tot_rd_len, f->payload + in_frame_off, in_frame_len);
         tot_rd_len += in_frame_len;
         t->rcv_processed += in_frame_len;
@@ -935,6 +1013,17 @@
         s->ev_pending &= (uint16_t)(~PICO_SOCK_EV_RD);
     }
 
+    if (t->remote_closed) {
+        s->ev_pending |= (uint16_t)(PICO_SOCK_EV_CLOSE);
+        s->state &= 0x00FFU;
+        s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT;
+        /* set SHUT_REMOTE */
+        s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
+        if (s->wakeup) {
+            s->wakeup(PICO_SOCK_EV_CLOSE, s);
+        }
+    }
+
     return tot_rd_len;
 }
 
@@ -967,7 +1056,7 @@
     struct pico_socket_tcp *ts = TCP_SOCK(s);
     struct pico_frame *syn;
     struct pico_tcp_hdr *hdr;
-    uint16_t opt_len = tcp_options_size(ts, PICO_TCP_SYN);
+    uint16_t mtu, opt_len = tcp_options_size(ts, PICO_TCP_SYN);
 
     syn = s->net->alloc(s->net, (uint16_t)(PICO_SIZE_TCPHDR + opt_len));
     if (!syn)
@@ -980,7 +1069,9 @@
 
     ts->snd_last = ts->snd_nxt;
     ts->cwnd = PICO_TCP_IW;
-    ts->ssthresh = 40;
+    mtu = pico_socket_get_mtu(s);
+    ts->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR);
+    ts->ssthresh = (uint16_t)((uint16_t)(PICO_DEFAULT_SOCKETQ / ts->mss) -  (((uint16_t)(PICO_DEFAULT_SOCKETQ / ts->mss)) >> 3u));
     syn->sock = s;
     hdr->seq = long_be(ts->snd_nxt);
     hdr->len = (uint8_t)((PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo);
@@ -992,12 +1083,12 @@
     hdr->trans.dport = ts->sock.remote_port;
 
     hdr->crc = 0;
-    hdr->crc = short_be(pico_tcp_checksum_ipv4(syn));
+    hdr->crc = short_be(pico_tcp_checksum(syn));
 
     /* TCP: ENQUEUE to PROTO ( SYN ) */
     tcp_dbg("Sending SYN... (ports: %d - %d) size: %d\n", short_be(ts->sock.local_port), short_be(ts->sock.remote_port), syn->buffer_len);
     pico_enqueue(&tcp_out, syn);
-    pico_timer_add(PICO_TCP_SYN_TO << ts->backoff, initconn_retry, ts);
+    ts->retrans_tmr = pico_timer_add(PICO_TCP_SYN_TO << ts->backoff, initconn_retry, ts);
     return 0;
 }
 
@@ -1061,7 +1152,7 @@
     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
     hdr->rwnd = short_be(t->wnd);
     hdr->crc = 0;
-    hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
+    hdr->crc = short_be(pico_tcp_checksum(f));
 
     /* TCP: ENQUEUE to PROTO */
     pico_enqueue(&tcp_out, f);
@@ -1069,13 +1160,13 @@
 
 static void tcp_send_ack(struct pico_socket_tcp *t)
 {
-    return tcp_send_empty(t, PICO_TCP_ACK, 0);
+    tcp_send_empty(t, PICO_TCP_ACK, 0);
 }
 
 static void tcp_send_probe(struct pico_socket_tcp *t)
 {
     /* tcp_dbg("Sending probe\n"); */
-    return tcp_send_empty(t, PICO_TCP_PSH, 0);
+    tcp_send_empty(t, PICO_TCP_PSHACK, 1);
 }
 
 static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr)
@@ -1125,7 +1216,7 @@
     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
     hdr->rwnd = short_be(t->wnd);
     hdr->crc = 0;
-    hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
+    hdr->crc = short_be(pico_tcp_checksum(f));
 
     /* TCP: ENQUEUE to PROTO */
     pico_enqueue(&tcp_out, f);
@@ -1154,15 +1245,31 @@
     struct pico_frame *f;
     uint16_t size = PICO_SIZE_TCPHDR;
 
-    tcp_dbg("TCP>>>>>>>>>>>>>>>> sending RST ... <<<<<<<<<<<<<<<<<<\n");
 
     hdr1 = (struct pico_tcp_hdr *) (fr->transport_hdr);
+    if ((hdr1->flags & PICO_TCP_RST) != 0)
+        return -1;
+
+    tcp_dbg("TCP> sending RST ... \n");
+
     f = fr->sock->net->alloc(fr->sock->net, size);
+    if (!f) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
 
     /* fill in IP data from original frame */
-    /* TODO if IPv4 */
-    ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr;
-    ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr;
+    if (IS_IPV4(fr)) {
+        memcpy(f->net_hdr, fr->net_hdr, sizeof(struct pico_ipv4_hdr));
+        ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr;
+        ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr;
+        tcp_dbg("Making IPv4 reset frame...\n");
+
+    } else {
+        memcpy(f->net_hdr, fr->net_hdr, sizeof(struct pico_ipv6_hdr));
+        ((struct pico_ipv6_hdr *)(f->net_hdr))->dst = ((struct pico_ipv6_hdr *)(fr->net_hdr))->src;
+        ((struct pico_ipv6_hdr *)(f->net_hdr))->src = ((struct pico_ipv6_hdr *)(fr->net_hdr))->dst;
+    }
 
     /* fill in TCP data from original frame */
     ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport;
@@ -1184,9 +1291,16 @@
     if(!(hdr1->flags & PICO_TCP_ACK))
         hdr->ack = long_be(long_be(((struct pico_tcp_hdr *)(fr->transport_hdr))->seq) + fr->payload_len);
 
-    hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
-    /* enqueue for transmission */
-    pico_ipv4_frame_push(f, &(((struct pico_ipv4_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP);
+    hdr->crc = short_be(pico_tcp_checksum(f));
+    if (IS_IPV4(f)) {
+        tcp_dbg("Pushing IPv4 reset frame...\n");
+        pico_ipv4_frame_push(f, &(((struct pico_ipv4_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP);
+#ifdef PICO_SUPPORT_IPV6
+    } else {
+        pico_ipv6_frame_push(f, &(((struct pico_ipv6_hdr *)(f->net_hdr))->dst), PICO_PROTO_TCP);
+#endif
+    }
+
 
     return 0;
 }
@@ -1197,10 +1311,13 @@
     struct pico_frame *f;
     struct pico_tcp_hdr *hdr, *hdr_rcv;
     uint16_t opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK);
+    hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr;
 
     tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n", (s->state & PICO_SOCKET_STATE_TCP));
     if (((s->state & PICO_SOCKET_STATE_TCP) ==  PICO_SOCKET_STATE_TCP_LISTEN)) {
-        /* XXX TODO NOTE: to prevent the parent socket from trying to send, because this socket has no knowledge of dst IP !!! */
+        if ((fr->flags & PICO_TCP_RST) != 0)
+            return 0;
+
         return pico_tcp_reply_rst(fr);
     }
 
@@ -1212,7 +1329,6 @@
         return -1;
     }
 
-    hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr;
 
     f->sock = &t->sock;
     hdr = (struct pico_tcp_hdr *) f->transport_hdr;
@@ -1237,7 +1353,7 @@
     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
     hdr->rwnd = short_be(t->wnd);
     hdr->crc = 0;
-    hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
+    hdr->crc = short_be(pico_tcp_checksum(f));
 
     /* TCP: ENQUEUE to PROTO */
     pico_enqueue(&tcp_out, f);
@@ -1275,7 +1391,7 @@
     f->start = f->transport_hdr + PICO_SIZE_TCPHDR;
     hdr->rwnd = short_be(t->wnd);
     hdr->crc = 0;
-    hdr->crc = short_be(pico_tcp_checksum_ipv4(f));
+    hdr->crc = short_be(pico_tcp_checksum(f));
     /* tcp_dbg("SENDING FIN...\n"); */
     /* TCP: ENQUEUE to PROTO ( Pure ACK ) */
     pico_enqueue(&tcp_out, f);
@@ -1295,7 +1411,7 @@
     while(n < 3) {
         if (!pkt) {
             if(left) {
-                sb = pico_zalloc(sizeof(struct tcp_sack_block));
+                sb = PICO_ZALLOC(sizeof(struct tcp_sack_block));
                 if (!sb)
                     break;
 
@@ -1328,7 +1444,7 @@
             pkt = next_segment(&t->tcpq_in, pkt);
             continue;
         } else {
-            sb = pico_zalloc(sizeof(struct tcp_sack_block));
+            sb = PICO_ZALLOC(sizeof(struct tcp_sack_block));
             if (!sb)
                 break;
 
@@ -1348,17 +1464,11 @@
 {
     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
-    uint16_t payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0) >> 2));
-
-    if (payload_len == 0 && (hdr->flags & PICO_TCP_PSH)) {
-        tcp_send_ack(t);
-        return 0;
-    }
-
-
-    if (((hdr->len & 0xf0) >> 2) <= f->transport_len) {
+    uint16_t payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0u) >> 2u));
+    int ret = 0;
+    if (((hdr->len & 0xf0u) >> 2u) <= f->transport_len) {
         tcp_parse_options(f);
-        f->payload = f->transport_hdr + ((hdr->len & 0xf0) >> 2);
+        f->payload = f->transport_hdr + ((hdr->len & 0xf0u) >> 2u);
         f->payload_len = payload_len;
         tcp_dbg("TCP> Received segment. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
 
@@ -1367,21 +1477,27 @@
             if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */
                 /* Create new segment and enqueue it */
                 struct tcp_input_segment *input = segment_from_frame(f);
-                if(input && pico_enqueue_segment(&t->tcpq_in, input) <= 0)
+                if (!input) {
+                    pico_err = PICO_ERR_ENOMEM;
+                    return -1;
+                }
+
+                if(pico_enqueue_segment(&t->tcpq_in, input) <= 0)
                 {
                     /* failed to enqueue, destroy segment */
-                    pico_free(input->payload);
-                    pico_free(input);
+                    PICO_FREE(input->payload);
+                    PICO_FREE(input);
+                    ret = -1;
+                } else {
+                    t->rcv_nxt = SEQN(f) + f->payload_len;
+                    nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
+                    while(nxt) {
+                        tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt);
+                        t->rcv_nxt += nxt->payload_len;
+                        nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
+                    }
+                    t->sock.ev_pending |= PICO_SOCK_EV_RD;
                 }
-
-                t->rcv_nxt = SEQN(f) + f->payload_len;
-                nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
-                while(nxt) {
-                    tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt);
-                    t->rcv_nxt += nxt->payload_len;
-                    nxt = peek_segment(&t->tcpq_in, t->rcv_nxt);
-                }
-                t->sock.ev_pending |= PICO_SOCK_EV_RD;
             } else {
                 tcp_dbg("TCP> lo segment. Uninteresting retransmission. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
             }
@@ -1389,10 +1505,16 @@
             tcp_dbg("TCP> hi segment. Possible packet loss. I'll dupack this. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f));
             if (t->sack_ok) {
                 struct tcp_input_segment *input = segment_from_frame(f);
-                if(input && pico_enqueue_segment(&t->tcpq_in, input) <= 0) {
+                if (!input) {
+                    pico_err = PICO_ERR_ENOMEM;
+                    return -1;
+                }
+
+                if(pico_enqueue_segment(&t->tcpq_in, input) <= 0) {
                     /* failed to enqueue, destroy segment */
-                    pico_free(input->payload);
-                    pico_free(input);
+                    PICO_FREE(input->payload);
+                    PICO_FREE(input);
+                    return -1;
                 }
 
                 tcp_sack_prepare(t);
@@ -1402,12 +1524,13 @@
         /* In either case, ack til recv_nxt. */
         if (((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSE_WAIT) && ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_SENT) && ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_RECV)) {
             /* tcp_dbg("SENDACK CALLED FROM OUTSIDE tcp_synack, state %x\n",t->sock.state); */
+            if (hdr->flags & PICO_TCP_RST)
+                return -1;
+
             tcp_send_ack(t);
-        } else {
-            /* tcp_dbg("SENDACK PREVENTED IN SYNSENT STATE\n"); */
         }
 
-        return 0;
+        return ret;
     } else {
         tcp_dbg("TCP: invalid data in pkt len, exp: %d, got %d\n", (hdr->len & 0xf0) >> 2, f->transport_len);
         return -1;
@@ -1432,6 +1555,17 @@
         return (uint16_t)(b - a);
 }
 
+static inline void rto_set(struct pico_socket_tcp *t, uint32_t rto)
+{
+    if (rto < PICO_TCP_RTO_MIN)
+        rto = PICO_TCP_RTO_MIN;
+
+    if (rto > PICO_TCP_RTO_MAX)
+        rto = PICO_TCP_RTO_MAX;
+
+    t->rto = rto;
+}
+
 static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt)
 {
 
@@ -1447,9 +1581,9 @@
          */
         t->avg_rtt = rtt;
         t->rttvar = rtt >> 1;
-        t->rto = t->avg_rtt + (t->rttvar << 4);
+        rto_set(t, t->avg_rtt + (t->rttvar << 2));
     } else {
-        int32_t var = (int32_t)(t->avg_rtt - rtt);
+        int32_t var = (int32_t)t->avg_rtt - (int32_t)rtt;
         if (var < 0)
             var = 0 - var;
 
@@ -1468,7 +1602,7 @@
         t->avg_rtt >>= 3;
 
         /* Finally, assign a new value for the RTO, as specified in the RFC, with K=4 */
-        t->rto = t->avg_rtt + (t->rttvar << 2);
+        rto_set(t, t->avg_rtt + (t->rttvar << 2));
     }
 
     tcp_dbg(" -----=============== RTT CUR: %u AVG: %u RTTVAR: %u RTO: %u ======================----\n", rtt, t->avg_rtt, t->rttvar, t->rto);
@@ -1479,14 +1613,6 @@
     if (t->x_mode > PICO_TCP_LOOKAHEAD)
         return;
 
-    if (t->cwnd > t->tcpq_out.frames) {
-        tcp_dbg("Limited by app: %d\n", t->cwnd);
-        if (t->sock.wakeup)
-            t->sock.wakeup(PICO_SOCK_EV_WR, &t->sock);
-
-        return;
-    }
-
     tcp_dbg("Doing congestion control\n");
     if (t->cwnd < t->ssthresh) {
         t->cwnd++;
@@ -1518,6 +1644,11 @@
     struct pico_frame *cpy;
     /* TCP: ENQUEUE to PROTO ( retransmit )*/
     cpy = pico_frame_copy(f);
+    if (!cpy) {
+        add_retransmission_timer(t, (t->rto << t->backoff) + TCP_TIME);
+        return -1;
+    }
+
     if (pico_enqueue(&tcp_out, cpy) > 0) {
         t->snd_last_out = SEQN(cpy);
         add_retransmission_timer(t, (t->rto << (++t->backoff)) + TCP_TIME);
@@ -1525,6 +1656,7 @@
         tcp_dbg("Sending RTO!\n");
         return 1;
     } else {
+        tcp_dbg("RTO fail, retry!\n");
         add_retransmission_timer(t, (t->rto << t->backoff) + TCP_TIME);
         pico_frame_discard(cpy);
         return 0;
@@ -1555,25 +1687,25 @@
 
     t->retrans_tmr = NULL;
 
-    if (t->retrans_tmr_due == 0ull)
+    if (t->retrans_tmr_due == 0ull) {
         return;
+    }
 
     if (t->retrans_tmr_due > val) {
         /* Timer was postponed... */
-        add_retransmission_timer(t, (t->rto << (t->backoff)) + TCP_TIME);
+        add_retransmission_timer(t, t->retrans_tmr_due);
         return;
     }
 
     tcp_dbg("TIMEOUT! backoff = %d, rto: %d\n", t->backoff, t->rto);
-    tcp_dbg("TIMEOUT! backoff = %d, rto: %d\n", t->backoff, t->rto);
     t->retrans_tmr_due = 0ull;
 
     if (tcp_is_allowed_to_send(t)) {
         f = first_segment(&t->tcpq_out);
         while (f) {
+            tcp_dbg("Checking frame in queue \n");
             if (t->x_mode == PICO_TCP_WINDOW_FULL) {
                 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);
-                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);
                 tcp_next_zerowindow_probe(t);
                 return;
             }
@@ -1592,12 +1724,14 @@
     }
     else if(t->backoff >= PICO_TCP_MAX_RETRANS && (t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED )
     {
-        dbg("Connection timeout!\n");
+        tcp_dbg("Connection timeout!\n");
         /* the retransmission timer, failed to get an ack for a frame, gives up on the connection */
         tcp_discard_all_segments(&t->tcpq_out);
         if(t->sock.wakeup)
             t->sock.wakeup(PICO_SOCK_EV_FIN, &t->sock);
 
+        /* delete socket */
+        pico_socket_del(&t->sock);
         return;
     } else {
         tcp_dbg("Retransmission not allowed, rescheduling\n");
@@ -1607,8 +1741,10 @@
 static void add_retransmission_timer(struct pico_socket_tcp *t, pico_time next_ts)
 {
     struct pico_tree_node *index;
+    pico_time now = TCP_TIME;
     pico_time val = 0;
 
+
     if (next_ts == 0) {
         struct pico_frame *f;
 
@@ -1623,17 +1759,15 @@
         val = next_ts;
     }
 
-    if (val > 0) {
-        if (val > TCP_TIME) {
-            t->retrans_tmr_due = val;
-        } else {
-            t->retrans_tmr_due = TCP_TIME + 1;
-        }
+    if ((val > 0) || (val > now)) {
+        t->retrans_tmr_due = val;
+    } else {
+        t->retrans_tmr_due = now + 1;
     }
 
     if (!t->retrans_tmr) {
-        t->retrans_tmr = pico_timer_add(t->retrans_tmr_due - TCP_TIME, tcp_retrans_timeout, t);
-    } else {
+        t->retrans_tmr = pico_timer_add(t->retrans_tmr_due - now, tcp_retrans_timeout, t);
+        tcp_dbg("Next timeout in %u msec\n", (uint32_t) (t->retrans_tmr_due - now));
     }
 }
 
@@ -1645,6 +1779,10 @@
         tcp_add_header(t, f);
         /* TCP: ENQUEUE to PROTO ( retransmit )*/
         cpy = pico_frame_copy(f);
+        if (!cpy) {
+            return -1;
+        }
+
         if (pico_enqueue(&tcp_out, cpy) > 0) {
             t->in_flight++;
             t->snd_last_out = SEQN(cpy);
@@ -1789,8 +1927,9 @@
         if (t->x_mode < PICO_TCP_RECOVER) {
             t->x_mode++;
             tcp_dbg("Mode: DUPACK %d, due to PURE ACK %0x, len = %d\n", t->x_mode, SEQN(f), f->payload_len);
-            tcp_dbg("ACK: %x - QUEUE: %x\n", ACKN(f), SEQN(first_segment(&t->tcpq_out)));
+            /* tcp_dbg("ACK: %x - QUEUE: %x\n", ACKN(f), SEQN(first_segment(&t->tcpq_out))); */
             if (t->x_mode == PICO_TCP_RECOVER) {              /* Switching mode */
+                t->cwnd = (uint16_t)t->in_flight;
                 t->snd_retry = SEQN((struct pico_frame *)first_segment(&t->tcpq_out));
                 if (t->ssthresh > t->cwnd)
                     t->ssthresh >>= 2;
@@ -1801,7 +1940,7 @@
                     t->ssthresh = 2;
             }
         } else if (t->x_mode == PICO_TCP_RECOVER) {
-            tcp_dbg("TCP RECOVER> DUPACK! snd_una: %08x, snd_nxt: %08x, acked now: %08x\n", SEQN(first_segment(&t->tcpq_out)), t->snd_nxt, ACKN(f));
+            /* tcp_dbg("TCP RECOVER> DUPACK! snd_una: %08x, snd_nxt: %08x, acked now: %08x\n", SEQN(first_segment(&t->tcpq_out)), t->snd_nxt, ACKN(f)); */
             if (t->in_flight <= t->cwnd) {
                 struct pico_frame *nxt = peek_segment(&t->tcpq_out, t->snd_retry);
                 if (!nxt)
@@ -1814,7 +1953,7 @@
                 if (nxt && (seq_compare(SEQN(nxt), t->snd_nxt)) > 0)
                     nxt = NULL;
 
-                if (nxt && (seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (t->recv_wnd << t->recv_wnd_scale)))
+                if (nxt && (seq_compare(SEQN(nxt), SEQN((struct pico_frame *)first_segment(&t->tcpq_out))) > (int)(t->recv_wnd << t->recv_wnd_scale)))
                     nxt = NULL;
 
                 if(!nxt)
@@ -1839,6 +1978,15 @@
         }
     }              /* End case duplicate ack detection */
 
+    /* Linux very special zero-window probe detection (see bug #107) */
+    if ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && /* This is a pure ack, and... */
+        (ACKN(f) == t->snd_nxt) &&                           /* it's acking our snd_nxt, and... */
+        (seq_compare(SEQN(f), t->rcv_nxt) < 0))             /* Has an old seq number */
+    {
+        tcp_send_ack(t);
+    }
+
+
     /* Do congestion control */
     tcp_congestion_control(t);
     if ((acked > 0) && t->sock.wakeup) {
@@ -1850,7 +1998,7 @@
 
     /* if Nagle enabled, check if no unack'ed data and fill out queue (till window) */
     if (IS_NAGLE_ENABLED((&(t->sock)))) {
-        while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) {
+        while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= t->mss)) {
             tcp_dbg_nagle("TCP_ACK - NAGLE add new segment\n");
             f_new = pico_hold_segment_make(t);
             if (f_new == NULL)
@@ -1972,6 +2120,7 @@
 {
     struct pico_socket_tcp *new = NULL;
     struct pico_tcp_hdr *hdr = NULL;
+    uint16_t mtu;
     if(s->number_of_pending_conn >= s->max_backlog)
         return -1;
 
@@ -2000,21 +2149,19 @@
 
 #endif
 
-    /* Set socket limits */
-    new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
-    new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
-    new->tcpq_hold.max_size = 2 * PICO_TCP_DEFAULT_MSS;
-    new->tcpq_in.overhead = (sizeof(struct tcp_input_segment) + sizeof(struct pico_tree_node));
-    new->tcpq_out.overhead = new->tcpq_hold.overhead = sizeof(struct pico_frame) + sizeof(struct pico_tree_node);
 
     f->sock = &new->sock;
     tcp_parse_options(f);
-    new->mss = PICO_TCP_DEFAULT_MSS;
+    mtu = pico_socket_get_mtu(s);
+    new->mss = (uint16_t)(mtu - PICO_SIZE_TCPHDR);
+    new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ;
+    new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ;
+    new->tcpq_hold.max_size = 2u * mtu;
     new->rcv_nxt = long_be(hdr->seq) + 1;
     new->snd_nxt = long_be(pico_paws());
     new->snd_last = new->snd_nxt;
     new->cwnd = PICO_TCP_IW;
-    new->ssthresh = 40;
+    new->ssthresh = (uint16_t)((uint16_t)(PICO_DEFAULT_SOCKETQ / new->mss) -  (((uint16_t)(PICO_DEFAULT_SOCKETQ / new->mss)) >> 3u));
     new->recv_wnd = short_be(hdr->rwnd);
     new->jumbo = hdr->len & 0x07;
     s->number_of_pending_conn++;
@@ -2028,18 +2175,53 @@
     return 0;
 }
 
+static int tcp_synrecv_syn(struct pico_socket *s, struct pico_frame *f)
+{
+    struct pico_tcp_hdr *hdr = NULL;
+    struct pico_socket_tcp *t = TCP_SOCK(s);
+    hdr = (struct pico_tcp_hdr *)f->transport_hdr;
+    if (t->rcv_nxt == long_be(hdr->seq) + 1) {
+        /* take back our own SEQ number to its original value,
+         * so the synack retransmitted is identical to the original. 
+         */
+        t->snd_nxt--; 
+        tcp_send_synack(s);
+    } else {
+        tcp_send_rst(s, f);
+        return -1;
+    }
+
+    return 0;
+}
+
 static void tcp_set_init_point(struct pico_socket *s)
 {
     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
     t->rcv_processed = t->rcv_nxt;
 }
 
+
+uint16_t pico_tcp_get_socket_mtu(struct pico_socket *s)
+{
+    struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
+    if (t->mss > 0)
+        return (uint16_t)(t->mss + PICO_SIZE_TCPHDR);
+    else
+        return pico_socket_get_mtu(s);
+}
+
 static int tcp_synack(struct pico_socket *s, struct pico_frame *f)
 {
     struct pico_socket_tcp *t = (struct pico_socket_tcp *) s;
     struct pico_tcp_hdr *hdr  = (struct pico_tcp_hdr *)f->transport_hdr;
 
-    if (ACKN(f) ==  (1 + t->snd_nxt)) {
+    if (ACKN(f) ==  (1u + t->snd_nxt)) {
+        /* Get rid of initconn retry */
+        if(t->retrans_tmr) {
+            pico_timer_cancel(t->retrans_tmr);
+            t->retrans_tmr = NULL;
+        }
+
         t->rcv_nxt = long_be(hdr->seq);
         t->rcv_processed = t->rcv_nxt + 1;
         tcp_ack(s, f);
@@ -2059,16 +2241,20 @@
 
         return 0;
 
-    } else {
+    } else if ((hdr->flags & PICO_TCP_RST) == 0) {
         tcp_dbg("TCP> Not established, RST sent.\n");
         tcp_nosync_rst(s, f);
         return 0;
+    } else {
+        /* The segment has the reset flag on: Ignore! */
+        return 0;
     }
 }
 
 static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f)
 {
     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
+    struct pico_tcp_hdr *hdr  = (struct pico_tcp_hdr *)f->transport_hdr;
     tcp_dbg("ACK in SYN_RECV: expecting %08x got %08x\n", t->snd_nxt, ACKN(f));
     if (t->snd_nxt == ACKN(f)) {
         tcp_set_init_point(s);
@@ -2090,8 +2276,11 @@
         s->ev_pending |= PICO_SOCK_EV_WR;
         tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt);
         return 0;
+    } else if ((hdr->flags & PICO_TCP_RST) == 0) {
+        tcp_nosync_rst(s, f);
+        return 0;
     } else {
-        tcp_nosync_rst(s, f);
+        /* The segment has the reset flag on: Ignore! */
         return 0;
     }
 }
@@ -2109,34 +2298,45 @@
     if (f->flags & PICO_TCP_ACK)
         tcp_ack(s, f);
 
+    tcp_dbg("called close_wait, in state %08x\n", s->state);
+
     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 */
-        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;
-            }else
+        if (seq_compare(SEQN(f), t->rcv_processed) == 0) {
+            if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) {
+                tcp_dbg("Changing state to CLOSE_WAIT\n");
+                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) {
                 s->wakeup(PICO_SOCK_EV_CLOSE, s);
+            }
+        } else {
+            t->remote_closed = 1;
         }
-    } else {
-        tcp_send_ack(t);              /* return ACK */
+    }
+
+    /* Ensure that the notification given to the socket
+     * did not put us in LAST_ACK state before sending the ACK: i.e. if
+     * pico_socket_close() has been called in the socket callback, we don't need to send
+     * an ACK here.
+     *
+     */
+    if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) ||
+        ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED))
+    {
+        tcp_dbg("In closewait: Sending ack! (state is %08x)\n", s->state);
+        tcp_send_ack(t);
     }
 
     return 0;
 }
 
-/*static int tcp_fin(struct pico_socket *s, struct pico_frame *f)
-   {
-   return 0;
-   }*/
-
 static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f)
 {
     struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
@@ -2199,7 +2399,7 @@
     tcp_dbg("TCP >>>>>>>>>>>>>> received RST <<<<<<<<<<<<<<<<<<<<\n");
     if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) {
         /* the RST is acceptable if the ACK field acknowledges the SYN */
-        if ((t->snd_nxt + 1) == ACKN(f)) {              /* valid, got to closed state */
+        if ((t->snd_nxt + 1u) == ACKN(f)) {              /* valid, got to closed state */
             tcp_force_closed(s);
             pico_err = PICO_ERR_ECONNRESET;
             tcp_wakeup_pending(s, PICO_SOCK_EV_ERR);
@@ -2211,7 +2411,8 @@
     } else {              /* all other states */
         /* all reset (RST) segments are validated by checking their SEQ-fields,
            a reset is valid if its sequence number is in the window */
-        if ((long_be(hdr->seq) >= t->rcv_ackd) && (long_be(hdr->seq) <= ((uint32_t)(short_be(hdr->rwnd) << (t->wnd_scale)) + t->rcv_ackd))) {
+        uint32_t this_seq = long_be(hdr->seq);
+        if ((this_seq >= t->rcv_ackd) && (this_seq <= ((uint32_t)(short_be(hdr->rwnd) << (t->wnd_scale)) + t->rcv_ackd))) {
             if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_RECV) {
                 tcp_force_closed(s);
                 pico_err = PICO_ERR_ECONNRESET;
@@ -2272,14 +2473,14 @@
     int (*rst)(struct pico_socket *s, struct pico_frame *f);
 };
 
-static struct tcp_action_entry tcp_fsm[] = {
+static const struct tcp_action_entry tcp_fsm[] = {
     /* State                              syn              synack             ack                data             fin              finack           rst*/
     { PICO_SOCKET_STATE_TCP_UNDEF,        NULL,            NULL,              NULL,              NULL,            NULL,            NULL,            NULL     },
     { PICO_SOCKET_STATE_TCP_CLOSED,       NULL,            NULL,              NULL,              NULL,            NULL,            NULL,            NULL     },
     { PICO_SOCKET_STATE_TCP_LISTEN,       &tcp_syn,        NULL,              NULL,              NULL,            NULL,            NULL,            NULL     },
     { PICO_SOCKET_STATE_TCP_SYN_SENT,     NULL,            &tcp_synack,       NULL,              NULL,            NULL,            NULL,            &tcp_rst },
-    { PICO_SOCKET_STATE_TCP_SYN_RECV,     NULL,            NULL,              &tcp_first_ack,    &tcp_data_in,    NULL,            &tcp_closeconn,  &tcp_rst },
-    { PICO_SOCKET_STATE_TCP_ESTABLISHED,  &tcp_halfopencon, &tcp_ack,          &tcp_ack,          &tcp_data_in,    &tcp_closewait,  &tcp_closewait,  &tcp_rst },
+    { PICO_SOCKET_STATE_TCP_SYN_RECV,     &tcp_synrecv_syn, NULL,              &tcp_first_ack,    &tcp_data_in,    NULL,            &tcp_closeconn,  &tcp_rst },
+    { PICO_SOCKET_STATE_TCP_ESTABLISHED,  &tcp_halfopencon, &tcp_ack,         &tcp_ack,          &tcp_data_in,    &tcp_closewait,  &tcp_closewait,  &tcp_rst },
     { PICO_SOCKET_STATE_TCP_CLOSE_WAIT,   NULL,            &tcp_ack,          &tcp_ack,          &tcp_send_rst,   &tcp_closewait,  &tcp_closewait,  &tcp_rst },
     { PICO_SOCKET_STATE_TCP_LAST_ACK,     NULL,            &tcp_ack,          &tcp_lastackwait,  &tcp_send_rst,   &tcp_send_rst,   &tcp_send_rst,   &tcp_rst },
     { PICO_SOCKET_STATE_TCP_FIN_WAIT1,    NULL,            &tcp_ack,          &tcp_finwaitack,   &tcp_data_in,    &tcp_rcvfin,     &tcp_finack,     &tcp_rst },
@@ -2288,19 +2489,16 @@
     { PICO_SOCKET_STATE_TCP_TIME_WAIT,    NULL,            &tcp_ack,          &tcp_send_rst,     &tcp_send_rst,   &tcp_send_rst,   &tcp_send_rst,   &tcp_rst }
 };
 
-/*
-   NOTE: in SYN-RECV receiving syn when cloned by default (see yellow pos-it), should send reset.
- */
 #define MAX_VALID_FLAGS  9  /* Maximum number of valid flag combinations */
 static uint8_t invalid_flags(struct pico_socket *s, uint8_t flags)
 {
     uint8_t i;
-    static uint8_t valid_flags[PICO_SOCKET_STATE_TCP_ARRAYSIZ][MAX_VALID_FLAGS] = {
-        { /* PICO_SOCKET_STATE_TCP_UNDEF      */ },
-        { /* PICO_SOCKET_STATE_TCP_CLOSED     */ },
+    static const uint8_t valid_flags[PICO_SOCKET_STATE_TCP_ARRAYSIZ][MAX_VALID_FLAGS] = {
+        { /* PICO_SOCKET_STATE_TCP_UNDEF      */ 0, },
+        { /* PICO_SOCKET_STATE_TCP_CLOSED     */ 0, },
         { /* PICO_SOCKET_STATE_TCP_LISTEN     */ PICO_TCP_SYN },
         { /* PICO_SOCKET_STATE_TCP_SYN_SENT   */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK},
-        { /* PICO_SOCKET_STATE_TCP_SYN_RECV   */ PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
+        { /* PICO_SOCKET_STATE_TCP_SYN_RECV   */ PICO_TCP_SYN, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
         { /* PICO_SOCKET_STATE_TCP_ESTABLISHED*/ PICO_TCP_SYN, PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
         { /* PICO_SOCKET_STATE_TCP_CLOSE_WAIT */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
         { /* PICO_SOCKET_STATE_TCP_LAST_ACK   */ PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
@@ -2312,10 +2510,10 @@
     if(!flags)
         return 1;
 
-    for(i = 0; i < MAX_VALID_FLAGS; i++)
+    for(i = 0; i < MAX_VALID_FLAGS; i++) {
         if(valid_flags[s->state >> 8u][i] == flags)
             return 0;
-
+    }
     return 1;
 }
 int pico_tcp_input(struct pico_socket *s, struct pico_frame *f)
@@ -2323,21 +2521,24 @@
     struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr);
     int ret = 0;
     uint8_t flags = hdr->flags;
-    struct tcp_action_entry *action = &tcp_fsm[s->state >> 8];
-
-    f->payload = (f->transport_hdr + ((hdr->len & 0xf0) >> 2));
-    f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0) >> 2));
-
-    tcp_dbg("[%lu] TCP> [tcp input] socket: %p state: %d <-- local port:%d remote port: %d seq: %08x ack: %08x flags: %02x = t_len: %d, hdr: %u payload: %d\n", TCP_TIME,
-            s, s->state >> 8, short_be(hdr->trans.dport), short_be(hdr->trans.sport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len );
+    const struct tcp_action_entry *action = &tcp_fsm[s->state >> 8];
+
+    f->payload = (f->transport_hdr + ((hdr->len & 0xf0u) >> 2u));
+    f->payload_len = (uint16_t)(f->transport_len - ((hdr->len & 0xf0u) >> 2u));
+
+    tcp_dbg("[sam] TCP> [tcp input] t_len: %u\n", f->transport_len);
+    tcp_dbg("[sam] TCP> flags = %02x\n", hdr->flags);
+    tcp_dbg("[sam] TCP> s->state >> 8 = %u\n", s->state >> 8);
+    tcp_dbg("[%lu] TCP> [tcp input] socket: %p state: %d <-- local port:%u remote port: %u seq: %08x ack: %08x flags: %02x t_len: %u, hdr: %u payload: %d\n", TCP_TIME, s, s->state >> 8, short_be(hdr->trans.dport), short_be(hdr->trans.sport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len );
 
     /* This copy of the frame has the current socket as owner */
     f->sock = s;
     s->timestamp = TCP_TIME;
     /* Those are not supported at this time. */
     /* flags &= (uint8_t) ~(PICO_TCP_CWR | PICO_TCP_URG | PICO_TCP_ECN); */
-    if(invalid_flags(s, flags))
+    if(invalid_flags(s, flags)) {
         pico_tcp_reply_rst(f);
+    }
     else if (flags == PICO_TCP_SYN) {
         if (action->syn)
             action->syn(s, f);
@@ -2375,6 +2576,9 @@
         }
     }
 
+    if (s->ev_pending)
+        tcp_wakeup_pending(s, s->ev_pending);
+
 /* discard: */
     pico_frame_discard(f);
     return ret;
@@ -2384,6 +2588,66 @@
 inline static int checkLocalClosing(struct pico_socket *s);
 inline static int checkRemoteClosing(struct pico_socket *s);
 
+static struct pico_frame *tcp_split_segment(struct pico_socket_tcp *t, struct pico_frame *f, uint16_t size)
+{
+    struct pico_frame *f1, *f2;
+    uint16_t size1, size2, size_f;
+    uint16_t overhead;
+    struct pico_tcp_hdr *hdr1, *hdr2, *hdr = (struct pico_tcp_hdr *)f->transport_hdr;
+    overhead = pico_tcp_overhead(&t->sock);
+    size_f = f->payload_len;
+
+
+    if (size >= size_f)
+        return f; /* no need to split! */
+
+    size1 = size;
+    size2 = (uint16_t)(size_f - size);
+
+    f1 = pico_socket_frame_alloc(&t->sock, (uint16_t) (size1 + overhead));
+    f2 = pico_socket_frame_alloc(&t->sock, (uint16_t) (size2 + overhead));
+
+    if (!f1 || !f2) {
+        pico_err = PICO_ERR_ENOMEM;
+        return NULL;
+    }
+
+    /* Advance payload pointer to the beginning of segment data */
+    f1->payload += overhead;
+    f1->payload_len = (uint16_t)(f1->payload_len - overhead);
+    f2->payload += overhead;
+    f2->payload_len = (uint16_t)(f2->payload_len - overhead);
+
+    hdr1 = (struct pico_tcp_hdr *)f1->transport_hdr;
+    hdr2 = (struct pico_tcp_hdr *)f2->transport_hdr;
+
+    /* Copy payload */
+    memcpy(f1->payload, f->payload, size1);
+    memcpy(f2->payload, f->payload + size1, size2);
+
+    /* Copy tcp hdr */
+    memcpy(hdr1, hdr, sizeof(struct pico_tcp_hdr));
+    memcpy(hdr2, hdr, sizeof(struct pico_tcp_hdr));
+
+    /* Adjust f2's sequence number */
+    hdr2->seq = long_be(SEQN(f) + size1);
+
+    /* Add TCP options */
+    pico_tcp_flags_update(f1, &t->sock);
+    pico_tcp_flags_update(f2, &t->sock);
+    tcp_add_options_frame(t, f1);
+    tcp_add_options_frame(t, f2);
+
+    /* Get rid of the full frame */
+    pico_discard_segment(&t->tcpq_out, f);
+
+    /* Enqueue f2 for later send... */
+    pico_enqueue_segment(&t->tcpq_out, f2);
+
+    /* Return the partial frame */
+    return f1;
+}
+
 
 int pico_tcp_output(struct pico_socket *s, int loop_score)
 {
@@ -2391,35 +2655,46 @@
     struct pico_frame *f, *una;
     int sent = 0;
     int data_sent = 0;
+    int32_t seq_diff = 0;
 
     una = first_segment(&t->tcpq_out);
     f = peek_segment(&t->tcpq_out, t->snd_nxt);
 
     while((f) && (t->cwnd >= t->in_flight)) {
         f->timestamp = TCP_TIME;
+        add_retransmission_timer(t, t->rto + TCP_TIME);
         tcp_add_options_frame(t, f);
-        if (seq_compare((SEQN(f) + f->payload_len), (SEQN(una) + (uint32_t)(t->recv_wnd << t->recv_wnd_scale))) > 0) {
-            t->cwnd = (uint16_t)t->in_flight;
-            if (t->cwnd < 1)
-                t->cwnd = 1;
-
+        seq_diff = seq_compare(SEQN(f), SEQN(una));
+        if (seq_diff < 0) {
+            dbg(">>> FATAL: seq diff is negative!\n");
+            break;
+        }
+
+        /* Check if advertised window is full */
+        if ((uint32_t)seq_diff >= (uint32_t)(t->recv_wnd << t->recv_wnd_scale)) {
             if (t->x_mode != PICO_TCP_WINDOW_FULL) {
                 tcp_dbg("TCP> RIGHT SIZING (rwnd: %d, frame len: %d\n", t->recv_wnd << t->recv_wnd_scale, f->payload_len);
                 tcp_dbg("In window full...\n");
-                t->snd_nxt = SEQN(una);              /* XXX prevent out-of-order-packets ! */ /*DLA re-enabled.*/
-                t->snd_retry = SEQN(una);              /* XXX replace by retry pointer? */
-
-                /* Alternative to the line above:  (better performance, but seems to lock anyway with larger buffers)
-                   if (seq_compare(t->snd_nxt, SEQN(una)) > 0)
-                   t->snd_nxt -= f->payload_len;
-                 */
-
+                t->snd_nxt = SEQN(una);
+                t->snd_retry = SEQN(una);
                 t->x_mode = PICO_TCP_WINDOW_FULL;
             }
 
             break;
         }
 
+        /* Check if the advertised window is too small to receive the current frame */
+        if ((uint32_t)(seq_diff + f->payload_len) > (uint32_t)(t->recv_wnd << t->recv_wnd_scale)) {
+            f = tcp_split_segment(t, f, (uint16_t)(t->recv_wnd << t->recv_wnd_scale));
+            if (!f)
+                break;
+
+            /* Limit sending window to packets in flight (right sizing) */
+            t->cwnd = (uint16_t)t->in_flight;
+            if (t->cwnd < 1)
+                t->cwnd = 1;
+        }
+
         tcp_dbg("TCP> DEQUEUED (for output) frame %08x, acks %08x len= %d, remaining frames %d\n", SEQN(f), ACKN(f), f->payload_len, t->tcpq_out.frames);
         tcp_send(t, f);
         sent++;
@@ -2436,8 +2711,7 @@
         }
     }
     if ((sent > 0 && data_sent > 0)) {
-        if (t->rto < PICO_TCP_RTO_MIN)
-            t->rto = PICO_TCP_RTO_MIN;
+        rto_set(t, t->rto);
     } else {
         /* Nothing to transmit. */
     }
@@ -2469,7 +2743,7 @@
     f_temp = next_segment(&t->tcpq_hold, f_temp);
 
     /* check till total_len <= MSS */
-    while ((f_temp != NULL) && ((total_len + f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) {
+    while ((f_temp != NULL) && ((total_len + f_temp->payload_len) <= t->mss)) {
         total_len = (uint16_t)(total_len + f_temp->payload_len);
         f_temp = next_segment(&t->tcpq_hold, f_temp);
         if (f_temp == NULL)
@@ -2482,6 +2756,7 @@
         return f_new;
     }
 
+    pico_tcp_flags_update(f_new,&t->sock);
     hdr = (struct pico_tcp_hdr *) f_new->transport_hdr;
     /* init new frame */
     f_new->payload += off;
@@ -2494,7 +2769,7 @@
     hdr->trans.dport = t->sock.remote_port;
 
     /* check till total_payload_len <= MSS */
-    while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) {
+    while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= t->mss)) {
         /* cpy data and discard frame */
         test++;
         memcpy(f_new->payload + total_payload_len, f_temp->payload, f_temp->payload_len);
@@ -2502,9 +2777,10 @@
         pico_discard_segment(&t->tcpq_hold, f_temp);
         f_temp = first_segment(&t->tcpq_hold);
     }
-    hdr->len = (uint8_t)((f_new->payload - f_new->transport_hdr) << 2 | t->jumbo);
+    hdr->len = (uint8_t)((f_new->payload - f_new->transport_hdr) << 2u | (int8_t)t->jumbo);
 
     tcp_dbg_nagle("NAGLE make - joined %d segments, len %d bytes\n", test, total_payload_len);
+    tcp_add_options_frame(t,f_new);
 
     return f_new;
 }
@@ -2522,7 +2798,7 @@
     hdr->trans.sport = t->sock.local_port;
     hdr->trans.dport = t->sock.remote_port;
     hdr->seq = long_be(t->snd_last + 1);
-    hdr->len = (uint8_t)((f->payload - f->transport_hdr) << 2 | t->jumbo);
+    hdr->len = (uint8_t)((f->payload - f->transport_hdr) << 2u | (int8_t)t->jumbo);
 
     if ((uint32_t)f->payload_len > (uint32_t)(t->tcpq_out.max_size - t->tcpq_out.size))
         t->sock.ev_pending &= (uint16_t)(~PICO_SOCK_EV_WR);
@@ -2554,7 +2830,7 @@
             }
         } else {                                    /* opt 2. hold data back */
             total_len = f->payload_len + t->tcpq_hold.size;
-            if ((total_len >= PICO_TCP_DEFAULT_MSS) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) {              /* TODO check mss socket */
+            if ((total_len >= t->mss) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= t->mss)) {              /* TODO check mss socket */
                 /* IF enough data in hold (>mss) AND space in out queue (>mss) */
                 /* add current frame in hold and make new segment */
                 if (pico_enqueue_segment(&t->tcpq_hold, f) > 0 ) {
@@ -2594,7 +2870,7 @@
 inline static void tcp_discard_all_segments(struct pico_tcp_queue *tq)
 {
     struct pico_tree_node *index = NULL, *index_safe = NULL;
-    LOCK(Mutex);
+    PICOTCP_MUTEX_LOCK(Mutex);
     pico_tree_foreach_safe(index, &tq->pool, index_safe)
     {
         void *f = index->keyValue;
@@ -2605,15 +2881,15 @@
         if(IS_INPUT_QUEUE(tq))
         {
             struct tcp_input_segment *inp = (struct tcp_input_segment *)f;
-            pico_free(inp->payload);
-            pico_free(inp);
+            PICO_FREE(inp->payload);
+            PICO_FREE(inp);
         }
         else
             pico_frame_discard(f);
     }
     tq->frames = 0;
     tq->size = 0;
-    UNLOCK(Mutex);
+    PICOTCP_MUTEX_UNLOCK(Mutex);
 }
 
 void pico_tcp_cleanup_queues(struct pico_socket *sck)
@@ -2678,8 +2954,47 @@
     }
 }
 
-void transport_flags_update(struct pico_frame *f, struct pico_socket *s)
+
+int pico_tcp_check_listen_close(struct pico_socket *s)
+{
+    if (TCP_IS_STATE(s, PICO_SOCKET_STATE_TCP_LISTEN)) {
+        pico_socket_del(s);
+        return 0;
+    }
+    return -1;
+}
+
+void pico_tcp_flags_update(struct pico_frame *f, struct pico_socket *s)
 {
     f->transport_flags_saved = ((struct pico_socket_tcp *)s)->ts_ok;
 }
+
+int pico_tcp_set_bufsize_in(struct pico_socket *s, uint32_t value)
+{
+    struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
+    t->tcpq_in.max_size = value;
+    return 0;
+}
+
+int pico_tcp_set_bufsize_out(struct pico_socket *s, uint32_t value)
+{
+    struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
+    t->tcpq_out.max_size = value;
+    return 0;
+}
+
+int pico_tcp_get_bufsize_in(struct pico_socket *s, uint32_t *value)
+{
+    struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
+    *value = t->tcpq_in.max_size;
+    return 0;
+}
+
+int pico_tcp_get_bufsize_out(struct pico_socket *s, uint32_t *value)
+{
+    struct pico_socket_tcp *t = (struct pico_socket_tcp *)s;
+    *value = t->tcpq_out.max_size;
+    return 0;
+}
+
 #endif /* PICO_SUPPORT_TCP */
--- a/modules/pico_tcp.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_tcp.h	Wed Apr 09 14:31:41 2014 +0200
@@ -5,15 +5,15 @@
    .
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_TCP
-#define _INCLUDE_PICO_TCP
+#ifndef INCLUDE_PICO_TCP
+#define INCLUDE_PICO_TCP
 #include "pico_addressing.h"
 #include "pico_protocol.h"
 #include "pico_socket.h"
 
 extern struct pico_protocol pico_proto_tcp;
 
-struct __attribute__((packed)) pico_tcp_hdr {
+PACKED_STRUCT_DEF pico_tcp_hdr {
     struct pico_trans trans;
     uint32_t seq;
     uint32_t ack;
@@ -24,7 +24,7 @@
     uint16_t urgent;
 };
 
-struct __attribute__((packed)) tcp_pseudo_hdr_ipv4
+PACKED_STRUCT_DEF tcp_pseudo_hdr_ipv4
 {
     struct pico_ip4 src;
     struct pico_ip4 dst;
@@ -37,10 +37,6 @@
 #define PICO_SIZE_TCPOPT_SYN 20
 #define PICO_SIZE_TCPHDR (uint32_t)(sizeof(struct pico_tcp_hdr))
 
-#define PICO_TCP_DEFAULT_MSS 1444
-
-
-
 /* TCP options */
 #define PICO_TCP_OPTION_END         0x00
 #define PICO_TCPOPTLEN_END        1u
@@ -58,11 +54,11 @@
 #define PICO_TCPOPTLEN_TIMESTAMP  10u
 
 /* TCP flags */
-#define PICO_TCP_FIN 0x01
-#define PICO_TCP_SYN 0x02
-#define PICO_TCP_RST 0x04
-#define PICO_TCP_PSH 0x08
-#define PICO_TCP_ACK 0x10
+#define PICO_TCP_FIN 0x01u
+#define PICO_TCP_SYN 0x02u
+#define PICO_TCP_RST 0x04u
+#define PICO_TCP_PSH 0x08u
+#define PICO_TCP_ACK 0x10u
 #define PICO_TCP_URG 0x20u
 #define PICO_TCP_ECN 0x40u
 #define PICO_TCP_CWR 0x80u
@@ -74,33 +70,33 @@
 #define PICO_TCP_RSTACK    (PICO_TCP_RST | PICO_TCP_ACK)
 
 
-struct __attribute__((packed)) pico_tcp_option
+PACKED_STRUCT_DEF pico_tcp_option
 {
     uint8_t kind;
     uint8_t len;
-#if 0
-    union {
-        uint16_t mss;
-        uint8_t wshift;
-        struct {
-            uint32_t tsval;
-            uint32_t tsecr;
-        } timestamp;
-    } data;
-#endif
 };
 
-struct pico_socket *pico_tcp_open(void);
+struct pico_socket *pico_tcp_open(uint16_t family);
 uint32_t pico_tcp_read(struct pico_socket *s, void *buf, uint32_t len);
 int pico_tcp_initconn(struct pico_socket *s);
 int pico_tcp_input(struct pico_socket *s, struct pico_frame *f);
+uint16_t pico_tcp_checksum(struct pico_frame *f);
 uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f);
+#ifdef PICO_SUPPORT_IPV6
+uint16_t pico_tcp_checksum_ipv6(struct pico_frame *f);
+#endif
 uint16_t pico_tcp_overhead(struct pico_socket *s);
 int pico_tcp_output(struct pico_socket *s, int loop_score);
 int pico_tcp_queue_in_is_empty(struct pico_socket *s);
 int pico_tcp_reply_rst(struct pico_frame *f);
 void pico_tcp_cleanup_queues(struct pico_socket *sck);
 void pico_tcp_notify_closing(struct pico_socket *sck);
-void transport_flags_update(struct pico_frame *, struct pico_socket *);
+void pico_tcp_flags_update(struct pico_frame *f, struct pico_socket *s);
+int pico_tcp_set_bufsize_in(struct pico_socket *s, uint32_t value);
+int pico_tcp_set_bufsize_out(struct pico_socket *s, uint32_t value);
+int pico_tcp_get_bufsize_in(struct pico_socket *s, uint32_t *value);
+int pico_tcp_get_bufsize_out(struct pico_socket *s, uint32_t *value);
+uint16_t pico_tcp_get_socket_mtu(struct pico_socket *s);
+int pico_tcp_check_listen_close(struct pico_socket *s);
 
 #endif
--- a/modules/pico_udp.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_udp.c	Wed Apr 09 14:31:41 2014 +0200
@@ -14,6 +14,8 @@
 #include "pico_socket.h"
 #include "pico_stack.h"
 
+#define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame))
+
 
 /* Queues */
 static struct pico_queue udp_in = {
@@ -52,31 +54,65 @@
     return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), udp_hdr, f->transport_len);
 }
 
+#ifdef PICO_SUPPORT_IPV6
+uint16_t pico_udp_checksum_ipv6(struct pico_frame *f)
+{
+    struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
+    struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *)f->transport_hdr;
+    struct pico_ipv6_pseudo_hdr pseudo;
+    struct pico_socket *s = f->sock;
+    struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *)f->info;
+
+    /* XXX If the IPv6 packet contains a Routing header, the Destination
+     *     Address used in the pseudo-header is that of the final destination */
+    if (s) {
+        /* Case of outgoing frame */
+        pseudo.src = s->local_addr.ip6;
+        if (remote_endpoint)
+            pseudo.dst = remote_endpoint->remote_addr.ip6;
+        else
+            pseudo.dst = s->remote_addr.ip6;
+    } else {
+        /* Case of incomming frame */
+        pseudo.src = ipv6_hdr->src;
+        pseudo.dst = ipv6_hdr->dst;
+    }
+
+    pseudo.len = long_be(f->transport_len);
+    pseudo.nxthdr = PICO_PROTO_UDP;
+
+    return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv6_pseudo_hdr), udp_hdr, f->transport_len);
+}
+#endif
+
+
 
 static int pico_udp_process_out(struct pico_protocol *self, struct pico_frame *f)
 {
     IGNORE_PARAMETER(self);
-    return pico_network_send(f);
+    return (int)pico_network_send(f);
 }
 
 static int pico_udp_push(struct pico_protocol *self, struct pico_frame *f)
 {
     struct pico_udp_hdr *hdr = (struct pico_udp_hdr *) f->transport_hdr;
-    struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info;
+    struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *) f->info;
 
     /* this (fragmented) frame should contain a transport header */
     if (f->transport_hdr != f->payload) {
         hdr->trans.sport = f->sock->local_port;
-        if (remote_duple) {
-            hdr->trans.dport = remote_duple->remote_port;
+        if (remote_endpoint) {
+            hdr->trans.dport = remote_endpoint->remote_port;
         } else {
             hdr->trans.dport = f->sock->remote_port;
         }
 
         hdr->len = short_be(f->transport_len);
+
         /* do not perform CRC validation. If you want to, a system needs to be
            implemented to calculate the CRC over the total payload of a
-           fragmented payload */
+           fragmented payload
+         */
         hdr->crc = 0;
     }
 
@@ -100,48 +136,10 @@
 };
 
 
-#define PICO_UDP_MODE_UNICAST 0x01
-#define PICO_UDP_MODE_MULTICAST 0x02
-#define PICO_UDP_MODE_BROADCAST 0xFF
-
-struct pico_socket_udp
-{
-    struct pico_socket sock;
-    int mode;
-#ifdef PICO_SUPPORT_MCAST
-    uint8_t mc_ttl; /* Multicasting TTL */
-#endif
-};
-
-#ifdef PICO_SUPPORT_MCAST
-int pico_udp_set_mc_ttl(struct pico_socket *s, uint8_t ttl)
-{
-    struct pico_socket_udp *u;
-    if(!s) {
-        pico_err = PICO_ERR_EINVAL;
-        return -1;
-    }
-
-    u = (struct pico_socket_udp *) s;
-    u->mc_ttl = ttl;
-    return 0;
-}
-
-int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl)
-{
-    struct pico_socket_udp *u;
-    if(!s)
-        return -1;
-
-    u = (struct pico_socket_udp *) s;
-    *ttl = u->mc_ttl;
-    return 0;
-}
-#endif /* PICO_SUPPORT_MCAST */
 
 struct pico_socket *pico_udp_open(void)
 {
-    struct pico_socket_udp *u = pico_zalloc(sizeof(struct pico_socket_udp));
+    struct pico_socket_udp *u = PICO_ZALLOC(sizeof(struct pico_socket_udp));
     if (!u)
         return NULL;
 
@@ -165,7 +163,7 @@
             f->payload_len = (uint16_t)(f->transport_len - sizeof(struct pico_udp_hdr));
         }
 
-/*    dbg("expected: %d, got: %d\n", len, f->payload_len); */
+        /*    dbg("expected: %d, got: %d\n", len, f->payload_len); */
         if (src)
             pico_store_network_origin(src, f);
 
--- a/modules/pico_udp.h	Tue Mar 11 15:34:51 2014 +0100
+++ b/modules/pico_udp.h	Wed Apr 09 14:31:41 2014 +0200
@@ -5,14 +5,26 @@
    .
 
  *********************************************************************/
-#ifndef _INCLUDE_PICO_UDP
-#define _INCLUDE_PICO_UDP
+#ifndef INCLUDE_PICO_UDP
+#define INCLUDE_PICO_UDP
 #include "pico_addressing.h"
 #include "pico_protocol.h"
+#include "pico_socket.h"
+#define PICO_UDP_MODE_UNICAST 0x01
+#define PICO_UDP_MODE_MULTICAST 0x02
+#define PICO_UDP_MODE_BROADCAST 0xFF
+
+struct pico_socket_udp
+{
+    struct pico_socket sock;
+    int mode;
+    uint8_t mc_ttl; /* Multicasting TTL */
+};
+
 
 extern struct pico_protocol pico_proto_udp;
 
-struct __attribute__((packed)) pico_udp_hdr {
+PACKED_STRUCT_DEF pico_udp_hdr {
     struct pico_trans trans;
     uint16_t len;
     uint16_t crc;
@@ -23,20 +35,11 @@
 uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port);
 uint16_t pico_udp_checksum_ipv4(struct pico_frame *f);
 
-#ifdef PICO_SUPPORT_MCAST
-int pico_udp_set_mc_ttl(struct pico_socket *s, uint8_t ttl);
-int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl);
-#else
-static inline int pico_udp_set_mc_ttl(struct pico_socket *s, uint8_t ttl)
-{
-    pico_err = PICO_ERR_EPROTONOSUPPORT;
-    return -1;
-}
-static inline int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl)
-{
-    pico_err = PICO_ERR_EPROTONOSUPPORT;
-    return -1;
-}
-#endif /* PICO_SUPPORT_MCAST */
+#ifdef PICO_SUPPORT_IPV6
+uint16_t pico_udp_checksum_ipv6(struct pico_frame *f);
+#endif
+
+
+int pico_udp_setsockopt(struct pico_socket *s, int option, void *value);
 
 #endif
--- a/modules/pico_zmq.c	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,515 +0,0 @@
-/*********************************************************************
-   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[];
-};
-
-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 = (uint8_t)(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)
-{
-    uint8_t incoming[258];
-    int ret;
-    (void)ret;
-
-    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 = {
-        0
-    };
-    struct zmq_connector *z_c;
-    uint8_t sockopts = 1;
-    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;
-    }
-
-    pico_socket_setoption(z_c->sock, PICO_TCP_NODELAY, &sockopts);
-    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
-    };
-    uint8_t sockopts = 1;
-    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;
-
-    pico_socket_setoption(s, PICO_TCP_NODELAY, &sockopts);
-
-    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((size_t)(len + 2));
-    msg->flags = 4;
-    msg->len = (uint8_t) len;
-    memcpy(msg->txt, txt, (size_t) 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);
-}
--- a/modules/pico_zmq.h	Tue Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-#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 Mar 11 15:34:51 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,447 +0,0 @@
-/*********************************************************************
-   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
-   See LICENSE and COPYING for usage.
-
-   .
-
-   Authors: Daniele Lacamera
- *********************************************************************/
-
-
-#include "pico_config.h"
-#include "pico_arp.h"
-#include "pico_tree.h"
-#include "pico_ipv4.h"
-#include "pico_device.h"
-#include "pico_stack.h"
-
-const uint8_t PICO_ETHADDR_ALL[6] = {
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-};
-#define PICO_ARP_TIMEOUT 600000
-#define PICO_ARP_RETRY 300
-
-#ifdef DEBUG_ARP
-    #define arp_dbg dbg
-#else
-    #define arp_dbg(...) do {} while(0)
-#endif
-
-static struct pico_queue pending;
-static int pending_timer_on = 0;
-static int max_arp_reqs = PICO_ARP_MAX_RATE;
-
-static void check_pending(pico_time now, void *_unused)
-{
-    struct pico_frame *f = pico_dequeue(&pending);
-    IGNORE_PARAMETER(now);
-    IGNORE_PARAMETER(_unused);
-    if (!f) {
-        pending_timer_on = 0;
-        return;
-    }
-
-    pico_ethernet_send(f);
-
-    pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL);
-}
-
-static void update_max_arp_reqs(pico_time now, void *unused)
-{
-    IGNORE_PARAMETER(now);
-    IGNORE_PARAMETER(unused);
-    if (max_arp_reqs < PICO_ARP_MAX_RATE)
-        max_arp_reqs++;
-
-    pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL);
-}
-
-void pico_arp_init()
-{
-    pico_timer_add(PICO_ARP_INTERVAL / PICO_ARP_MAX_RATE, &update_max_arp_reqs, NULL);
-}
-
-struct
-__attribute__ ((__packed__))
-pico_arp_hdr
-{
-    uint16_t htype;
-    uint16_t ptype;
-    uint8_t hsize;
-    uint8_t psize;
-    uint16_t opcode;
-    uint8_t s_mac[PICO_SIZE_ETH];
-    struct pico_ip4 src;
-    uint8_t d_mac[PICO_SIZE_ETH];
-    struct pico_ip4 dst;
-};
-
-struct arp_service_ipconflict {
-    struct pico_eth mac;
-    struct pico_ip4 ip;
-    void (*conflict)(void);
-};
-
-static struct arp_service_ipconflict conflict_ipv4;
-
-#define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr)))
-
-/* Arp Entries for the tables. */
-struct pico_arp {
-/* CAREFUL MAN! ARP entry MUST begin with a pico_eth structure,
- * due to in-place casting!!! */
-    struct pico_eth eth;
-    struct pico_ip4 ipv4;
-    int arp_status;
-    pico_time timestamp;
-    struct pico_device *dev;
-    struct pico_timer *timer;
-};
-
-
-
-/*****************/
-/**  ARP TREE **/
-/*****************/
-
-/* Routing destination */
-
-static int arp_compare(void *ka, void *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)
-        return 1;
-
-    return 0;
-}
-
-PICO_TREE_DECLARE(arp_tree, arp_compare);
-
-/*********************/
-/**  END ARP TREE **/
-/*********************/
-
-struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst)
-{
-    struct pico_arp search, *found;
-    search.ipv4.addr = dst->addr;
-    found = pico_tree_findKey(&arp_tree, &search);
-    if (found && (found->arp_status != PICO_ARP_STATUS_STALE))
-        return &found->eth;
-
-    return NULL;
-}
-
-struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst)
-{
-    struct pico_arp*search;
-    struct pico_tree_node *index;
-    pico_tree_foreach(index, &arp_tree){
-        search = index->keyValue;
-        if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0)
-            return &search->ipv4;
-    }
-    return NULL;
-}
-
-struct pico_eth *pico_arp_get(struct pico_frame *f)
-{
-    struct pico_eth *a4;
-    struct pico_ip4 gateway;
-    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
-    struct pico_ipv4_link *l;
-
-#ifndef PICO_SUPPORT_IPV4
-    return NULL;
-#endif
-
-    l = pico_ipv4_link_get(&hdr->dst);
-    if(l) {
-        /* address belongs to ourself */
-        return &l->dev->eth->mac;
-    }
-
-    gateway = pico_ipv4_route_get_gateway(&hdr->dst);
-    /* check if dst is local (gateway = 0), or if to use gateway */
-    if (gateway.addr != 0)
-        a4 = pico_arp_lookup(&gateway);      /* check if gateway ip mac in cache */
-    else
-        a4 = pico_arp_lookup(&hdr->dst);     /* check if local ip mac in cache */
-
-    if (!a4) {
-        if (++f->failure_count < 4) {
-            arp_dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count);
-            /* check if dst is local (gateway = 0), or if to use gateway */
-            if (gateway.addr != 0)
-                pico_arp_request(f->dev, &gateway, PICO_ARP_QUERY); /* arp to gateway */
-            else
-                pico_arp_request(f->dev, &hdr->dst, PICO_ARP_QUERY); /* arp to dst */
-
-            pico_enqueue(&pending, f);
-            if (!pending_timer_on) {
-                pending_timer_on++;
-                pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL);
-            }
-        } else {
-            dbg("ARP: Destination Unreachable\n");
-            pico_notify_dest_unreachable(f);
-            pico_frame_discard(f);
-        }
-    }
-
-    return a4;
-}
-
-#ifdef DEBUG_ARP
-void dbg_arp(void)
-{
-    struct pico_arp *a;
-    struct pico_tree_node *index;
-
-    pico_tree_foreach(index, &arp_tree) {
-        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] );
-    }
-}
-#endif
-
-static void arp_expire(pico_time now, void *_stale)
-{
-    struct pico_arp *stale = (struct pico_arp *) _stale;
-    if (now >= (stale->timestamp + PICO_ARP_TIMEOUT)) {
-        stale->arp_status = PICO_ARP_STATUS_STALE;
-        arp_dbg("ARP: Setting arp_status to STALE\n");
-        pico_arp_request(stale->dev, &stale->ipv4, PICO_ARP_QUERY);
-    } else {
-        /* Timer must be rescheduled, ARP entry has been renewed lately.
-         * No action required to refresh the entry, will check on the next timeout */
-        pico_timer_add(PICO_ARP_TIMEOUT + stale->timestamp - now, arp_expire, stale);
-    }
-}
-
-static void pico_arp_add_entry(struct pico_arp *entry)
-{
-    entry->arp_status = PICO_ARP_STATUS_REACHABLE;
-    entry->timestamp  = PICO_TIME();
-
-    pico_tree_insert(&arp_tree, entry);
-    arp_dbg("ARP ## reachable.\n");
-    pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry);
-}
-
-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;
-
-    pico_arp_add_entry(arp);
-
-    return 0;
-}
-
-int pico_arp_receive(struct pico_frame *f)
-{
-    struct pico_arp_hdr *hdr;
-    struct pico_arp search, *found, *new = NULL;
-    struct pico_ip4 me;
-    struct pico_device *link_dev;
-    struct pico_eth_hdr *eh;
-    int ret = -1;
-    hdr = (struct pico_arp_hdr *) f->net_hdr;
-    eh = (struct pico_eth_hdr *)f->datalink_hdr;
-
-    if (!hdr)
-        goto end;
-
-#ifndef PICO_SUPPORT_IPV4
-    goto end;
-#endif
-
-    me.addr = hdr->dst.addr;
-
-    /* Validate the incoming arp packet */
-
-    /* Check the hardware type and protocol */
-    if ((hdr->htype != PICO_ARP_HTYPE_ETH) || (hdr->ptype != PICO_IDETH_IPV4))
-        goto end;
-
-    /* The source mac address must not be a multicast or broadcast address */
-    if (hdr->s_mac[0] & 0x01)
-        goto end;
-
-    /* Prevent ARP flooding */
-    link_dev = pico_ipv4_link_find(&me);
-    if ((link_dev == f->dev) && (hdr->opcode == PICO_ARP_REQUEST)) {
-        if (max_arp_reqs == 0)
-            goto end;
-        else
-            max_arp_reqs--;
-    }
-
-    if (conflict_ipv4.conflict != NULL)
-    {
-        if ((conflict_ipv4.ip.addr == hdr->src.addr) && (memcmp(hdr->s_mac, conflict_ipv4.mac.addr, 6) != 0))
-            conflict_ipv4.conflict();
-    }
-
-    /* Populate a new arp entry */
-    search.ipv4.addr = hdr->src.addr;
-    memcpy(search.eth.addr, hdr->s_mac, PICO_SIZE_ETH);
-
-    /* Search for already existing entry */
-    found = pico_tree_findKey(&arp_tree, &search);
-    if (found) {
-        if (found->arp_status == PICO_ARP_STATUS_STALE) {
-            /* Replace if stale */
-            new = found;
-
-            pico_tree_delete(&arp_tree, new);
-        } else {
-            /* Update mac address */
-            memcpy(found->eth.addr, hdr->s_mac, PICO_SIZE_ETH);
-
-            /* Refresh timestamp, this will force a reschedule on the next timeout*/ 
-            found->timestamp = PICO_TIME();
-            new = NULL; /* Avoid re-inserting the entry in the table */
-        }
-    }
-
-    /* Check if we are the target IP address */
-    if (link_dev != f->dev)
-        goto end;
-
-    /* If no existing entry was found, create a new entry */
-    if (!found) {
-        new = pico_zalloc(sizeof(struct pico_arp));
-        if (!new)
-            goto end;
-
-        new->ipv4.addr = hdr->src.addr;
-        memcpy(new->eth.addr, hdr->s_mac, PICO_SIZE_ETH);
-        new->dev = f->dev;
-    }
-
-    if (new)
-        pico_arp_add_entry(new);
-
-    ret = 0;
-
-    /* If the packet is a request, send a reply */
-    if (hdr->opcode == PICO_ARP_REQUEST) {
-        hdr->opcode = PICO_ARP_REPLY;
-        memcpy(hdr->d_mac, hdr->s_mac, PICO_SIZE_ETH);
-        memcpy(hdr->s_mac, f->dev->eth->mac.addr, PICO_SIZE_ETH);
-        hdr->dst.addr = hdr->src.addr;
-        hdr->src.addr = me.addr;
-
-        /* Prepare eth header for arp reply */
-        memcpy(eh->daddr, eh->saddr, PICO_SIZE_ETH);
-        memcpy(eh->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH);
-        f->start = f->datalink_hdr;
-        f->len = PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR;
-        f->dev->send(f->dev, f->start, (int)f->len);
-    }
-
-#ifdef DEBUG_ARG
-    dbg_arp();
-#endif
-
-end:
-    pico_frame_discard(f);
-    return ret;
-}
-
-int32_t pico_arp_request(struct pico_device *dev, struct pico_ip4 *dst, uint8_t type)
-{
-    struct pico_frame *q = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR);
-    struct pico_eth_hdr *eh;
-    struct pico_arp_hdr *ah;
-    struct pico_ip4 *src = NULL;
-    int ret;
-
-    if (!q)
-        return -1;
-
-#ifndef PICO_SUPPORT_IPV4
-    return -1;
-#endif
-
-    if (type == PICO_ARP_QUERY)
-    {
-        src = pico_ipv4_source_find(dst);
-        if (!src) {
-            pico_frame_discard(q);
-            return -1;
-        }
-    }
-
-    arp_dbg("QUERY: %08x\n", dst->addr);
-
-    eh = (struct pico_eth_hdr *)q->start;
-    ah = (struct pico_arp_hdr *) (q->start + PICO_SIZE_ETHHDR);
-
-    /* Fill eth header */
-    memcpy(eh->saddr, dev->eth->mac.addr, PICO_SIZE_ETH);
-    memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH);
-    eh->proto = PICO_IDETH_ARP;
-
-    /* Fill arp header */
-    ah->htype  = PICO_ARP_HTYPE_ETH;
-    ah->ptype  = PICO_IDETH_IPV4;
-    ah->hsize  = PICO_SIZE_ETH;
-    ah->psize  = PICO_SIZE_IP4;
-    ah->opcode = PICO_ARP_REQUEST;
-    memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH);
-
-    switch (type) {
-    case PICO_ARP_ANNOUNCE:
-        ah->src.addr = dst->addr;
-        ah->dst.addr = dst->addr;
-        break;
-    case PICO_ARP_PROBE:
-        ah->src.addr = 0;
-        ah->dst.addr = dst->addr;
-        break;
-    case PICO_ARP_QUERY:
-        ah->src.addr = src->addr;
-        ah->dst.addr = dst->addr;
-    }
-
-    arp_dbg("Sending arp request.\n");
-    ret = dev->send(dev, q->start, (int) q->len);
-    pico_frame_discard(q);
-    return ret;
-}
-
-int pico_arp_get_neighbors(struct pico_device *dev, struct pico_ip4 *neighbors, int maxlen)
-{
-    struct pico_arp*search;
-    struct pico_tree_node *index;
-    int i = 0;
-    pico_tree_foreach(index, &arp_tree){
-        search = index->keyValue;
-        if (search->dev == dev) {
-            neighbors[i++].addr = search->ipv4.addr;
-            if (i >= maxlen)
-                return i;
-        }
-    }
-    return i;
-}
-
-void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void (*cb)(void))
-{
-    conflict_ipv4.conflict = cb;
-    conflict_ipv4.ip.addr = ip->addr;
-    if (mac != NULL)
-        memcpy(conflict_ipv4.mac.addr, mac, 6);
-}
--- a/stack/pico_device.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/stack/pico_device.c	Wed Apr 09 14:31:41 2014 +0200
@@ -13,6 +13,9 @@
 #include "pico_stack.h"
 #include "pico_protocol.h"
 #include "pico_tree.h"
+#include "pico_ipv6.h"
+#include "pico_ipv4.h"
+#include "pico_icmp6.h"
 
 struct pico_devices_rr_info {
     struct pico_tree_node *node_in, *node_out;
@@ -38,6 +41,11 @@
 
 int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac)
 {
+    #ifdef PICO_SUPPORT_IPV6
+    struct pico_ip6 linklocal = {{0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xff, 0xfe, 0xaa, 0xaa, 0xaa}};
+    struct pico_ip6 netmask6 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+    #endif
+
     uint32_t len = (uint32_t)strlen(name);
     if(len > MAX_DEVICE_NAME)
         len = MAX_DEVICE_NAME;
@@ -45,21 +53,81 @@
     memcpy(dev->name, name, len);
     dev->hash = pico_hash(dev->name, len);
 
-    pico_tree_insert(&Device_tree, dev);
     Devices_rr_info.node_in  = NULL;
     Devices_rr_info.node_out = NULL;
-    dev->q_in = pico_zalloc(sizeof(struct pico_queue));
-    dev->q_out = pico_zalloc(sizeof(struct pico_queue));
+    dev->q_in = PICO_ZALLOC(sizeof(struct pico_queue));
+    dev->q_out = PICO_ZALLOC(sizeof(struct pico_queue));
+    if (!dev->q_in || !dev->q_out)
+        return -1;
+
+    pico_tree_insert(&Device_tree, dev);
 
     if (mac) {
-        dev->eth = pico_zalloc(sizeof(struct pico_ethdev));
-        memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH);
+        dev->eth = PICO_ZALLOC(sizeof(struct pico_ethdev));
+        if (dev->eth) {
+            memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH);
+            #ifdef PICO_SUPPORT_IPV6
+            /* modified EUI-64 + invert universal/local bit */
+            linklocal.addr[8] = (mac[0] ^ 0x02);
+            linklocal.addr[9] = mac[1];
+            linklocal.addr[10] = mac[2];
+            linklocal.addr[13] = mac[3];
+            linklocal.addr[14] = mac[4];
+            linklocal.addr[15] = mac[5];
+            if (pico_ipv6_link_add(dev, linklocal, netmask6)) {
+                PICO_FREE(dev->q_in);
+                PICO_FREE(dev->q_out);
+                PICO_FREE(dev->eth);
+                return -1;
+            }
+
+            #endif
+        }
+
+
     } else {
         dev->eth = NULL;
+        #ifdef PICO_SUPPORT_IPV6
+        if (strcmp(dev->name, "loop")) {
+            do {
+                /* privacy extension + unset universal/local and individual/group bit */
+                len = pico_rand();
+                linklocal.addr[8]  = (uint8_t)((len & 0xffu) & (uint8_t)(~0x03));
+                linklocal.addr[9]  = (uint8_t)(len >> 8);
+                linklocal.addr[10] = (uint8_t)(len >> 16);
+                linklocal.addr[11] = (uint8_t)(len >> 24);
+                len = pico_rand();
+                linklocal.addr[12] = (uint8_t)len;
+                linklocal.addr[13] = (uint8_t)(len >> 8);
+                linklocal.addr[14] = (uint8_t)(len >> 16);
+                linklocal.addr[15] = (uint8_t)(len >> 24);
+                pico_rand_feed(dev->hash);
+            } while (pico_ipv6_link_get(&linklocal));
+
+            if (pico_ipv6_link_add(dev, linklocal, netmask6)) {
+                PICO_FREE(dev->q_in);
+                PICO_FREE(dev->q_out);
+                return -1;
+            }
+        }
+
+        #endif
     }
 
-    if (!dev->q_in || !dev->q_out || (mac && !dev->eth))
-        return -1;
+    #ifdef PICO_SUPPORT_IPV6
+    if (dev->eth)
+    {
+        dev->hostvars.mtu = PICO_ETH_MTU;
+        dev->hostvars.basetime = PICO_ND_REACHABLE_TIME;
+        /* RFC 4861 $6.3.2 value between 0.5 and 1.5 times basetime */
+        dev->hostvars.reachabletime = ((5 + (pico_rand() % 10)) * PICO_ND_REACHABLE_TIME) / 10;
+        dev->hostvars.retranstime = PICO_ND_RETRANS_TIMER;
+        pico_icmp6_router_solicitation(dev, &linklocal);
+    }
+
+    dev->hostvars.hoplimit = PICO_IPV6_DEFAULT_HOP;
+    #endif
+
 
     return 0;
 }
@@ -68,7 +136,7 @@
 {
     if (q) {
         pico_queue_empty(q);
-        pico_free(q);
+        PICO_FREE(q);
     }
 }
 
@@ -81,12 +149,21 @@
     pico_queue_destroy(dev->q_out);
 
     if (dev->eth)
-        pico_free(dev->eth);
+        PICO_FREE(dev->eth);
+
+#ifdef PICO_SUPPORT_IPV4
+    pico_ipv4_cleanup_links(dev);
+#endif
+#ifdef PICO_SUPPORT_IPV6
+    pico_ipv6_cleanup_links(dev);
+#endif
+    pico_tree_delete(&Device_tree, dev);
+
 
     pico_tree_delete(&Device_tree, dev);
     Devices_rr_info.node_in  = NULL;
     Devices_rr_info.node_out = NULL;
-    pico_free(dev);
+    PICO_FREE(dev);
 }
 
 static int check_dev_serve_interrupt(struct pico_device *dev, int loop_score)
--- a/stack/pico_frame.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/stack/pico_frame.c	Wed Apr 09 14:31:41 2014 +0200
@@ -18,16 +18,19 @@
 /** frame alloc/dealloc/copy **/
 void pico_frame_discard(struct pico_frame *f)
 {
+    if (!f)
+        return;
+
     (*f->usage_count)--;
     if (*f->usage_count <= 0) {
-        pico_free(f->usage_count);
+        PICO_FREE(f->usage_count);
 #ifdef PICO_SUPPORT_DEBUG_MEMORY
         dbg("Discarded buffer @%p, caller: %p\n", f->buffer, __builtin_return_address(3));
         dbg("DEBUG MEMORY: %d frames in use.\n", --n_frames_allocated);
 #endif
-        pico_free(f->buffer);
+        PICO_FREE(f->buffer);
         if (f->info)
-            pico_free(f->info);
+            PICO_FREE(f->info);
     }
 
 #ifdef PICO_SUPPORT_DEBUG_MEMORY
@@ -35,12 +38,12 @@
         dbg("Removed frame @%p(copy), usage count now: %d\n", f, *f->usage_count);
     }
 #endif
-    pico_free(f);
+    PICO_FREE(f);
 }
 
 struct pico_frame *pico_frame_copy(struct pico_frame *f)
 {
-    struct pico_frame *new = pico_zalloc(sizeof(struct pico_frame));
+    struct pico_frame *new = PICO_ZALLOC(sizeof(struct pico_frame));
     if (!new)
         return NULL;
 
@@ -54,22 +57,28 @@
 }
 
 
-struct pico_frame *pico_frame_alloc(uint32_t size)
+static struct pico_frame *pico_frame_do_alloc(uint32_t size, int zerocopy)
 {
-    struct pico_frame *p = pico_zalloc(sizeof(struct pico_frame));
+    struct pico_frame *p = PICO_ZALLOC(sizeof(struct pico_frame));
     if (!p)
         return NULL;
 
-    p->buffer = pico_zalloc(size);
-    if (!p->buffer) {
-        pico_free(p);
-        return NULL;
+    if (!zerocopy) {
+        p->buffer = PICO_ZALLOC(size);
+        if (!p->buffer) {
+            PICO_FREE(p);
+            return NULL;
+        }
+    } else {
+        p->buffer = NULL;
     }
 
-    p->usage_count = pico_zalloc(sizeof(uint32_t));
+    p->usage_count = PICO_ZALLOC(sizeof(uint32_t));
     if (!p->usage_count) {
-        pico_free(p->buffer);
-        pico_free(p);
+        if (p->buffer)
+            PICO_FREE(p->buffer);
+
+        PICO_FREE(p);
         return NULL;
     }
 
@@ -87,6 +96,26 @@
     return p;
 }
 
+struct pico_frame *pico_frame_alloc(uint32_t size)
+{
+    return pico_frame_do_alloc(size, 0);
+}
+
+struct pico_frame *pico_frame_alloc_skeleton(uint32_t size)
+{
+    return pico_frame_do_alloc(size, 1);
+}
+
+int pico_frame_skeleton_set_buffer(struct pico_frame *f, void *buf)
+{
+    if (!buf)
+        return -1;
+
+    f->buffer = (uint8_t *) buf;
+    f->start = f->buffer;
+    return 0;
+}
+
 struct pico_frame *pico_frame_deepcopy(struct pico_frame *f)
 {
     struct pico_frame *new = pico_frame_alloc(f->buffer_len);
@@ -132,13 +161,11 @@
     uint32_t sum = 0;
     uint32_t i = 0;
 
-    for(i = 0; i < len; i++) {
-        if (i % 2) {
-            sum += buf[i];
-        } else {
-            tmp = buf[i];
-            sum += (tmp << 8);
-        }
+    for(i = 0; i < len; i += 2u) {
+        tmp = buf[i];
+        sum += (tmp << 8lu);
+        if (len > (i + 1))
+            sum += buf[i + 1];
     }
     while (sum >> 16) { /* a second carry is possible! */
         sum = (sum & 0x0000FFFF) + (sum >> 16);
@@ -150,30 +177,21 @@
 {
     uint8_t *b1 = (uint8_t *) inbuf1;
     uint8_t *b2 = (uint8_t *) inbuf2;
-    uint16_t tmp = 0;
+    uint32_t tmp = 0;
     uint32_t sum = 0;
-    uint32_t i = 0, j = 0;
-
-    for(i = 0; i < len1; i++) {
-        if (j % 2) {
-            sum += b1[i];
-        } else {
-            tmp = b1[i];
-            sum = sum + (uint32_t)(tmp << 8);
-        }
+    uint32_t i = 0;
 
-        j++;
+    for(i = 0; i < len1; i += 2u) {
+        tmp = b1[i];
+        sum += (tmp << 8lu);
+        if (len1 > (i + 1))
+            sum += b1[i + 1];
     }
-    j = 0; /* j has to be reset if len1 is odd */
-    for(i = 0; i < len2; i++) {
-        if (j % 2) {
-            sum += b2[i];
-        } else {
-            tmp = b2[i];
-            sum = sum + (uint32_t)(tmp << 8);
-        }
-
-        j++;
+    for(i = 0; i < len2; i += 2u) {
+        tmp = b2[i];
+        sum += (tmp << 8lu);
+        if (len2 > (i + 1))
+            sum += b2[i + 1];
     }
     while (sum >> 16) { /* a second carry is possible! */
         sum = (sum & 0x0000FFFF) + (sum >> 16);
--- a/stack/pico_socket.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/stack/pico_socket.c	Wed Apr 09 14:31:41 2014 +0200
@@ -19,11 +19,13 @@
 #include "pico_nat.h"
 #include "pico_tree.h"
 #include "pico_device.h"
+#include "pico_socket_multicast.h"
+#include "pico_socket_tcp.h"
+#include "pico_socket_udp.h"
 
 #if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6)
 #if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP)
 
-#define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame))
 
 #define PROTO(s) ((s)->proto->proto_number)
 #define PICO_SOCKET4_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
@@ -32,25 +34,21 @@
 
 #ifdef PICO_SUPPORT_MUTEX
 static void *Mutex = NULL;
-#define LOCK(x) { \
+#define PICOTCP_MUTEX_LOCK(x) { \
         if (x == NULL) \
             x = pico_mutex_init(); \
         pico_mutex_lock(x); \
 }
-#define UNLOCK(x) pico_mutex_unlock(x)
+#define PICOTCP_MUTEX_UNLOCK(x) pico_mutex_unlock(x)
 
 #else
-#define LOCK(x) do {} while(0)
-#define UNLOCK(x) do {} while(0)
+#define PICOTCP_MUTEX_LOCK(x) do {} while(0)
+#define PICOTCP_MUTEX_UNLOCK(x) do {} while(0)
 #endif
 
 
 #define PROTO(s) ((s)->proto->proto_number)
 
-#ifdef PICO_SUPPORT_TCP
-# define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY)))))
-#endif
-
 #define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
 
 #ifdef PICO_SUPPORT_IPV4
@@ -65,76 +63,111 @@
 # define IS_SOCK_IPV6(s) (0)
 #endif
 
-#ifdef PICO_SUPPORT_IPFRAG
 # define frag_dbg(...) do {} while(0)
-#endif
 
-#ifdef PICO_SUPPORT_MCAST
-# define so_mcast_dbg(...) do {} while(0) /* ip_mcast_dbg in pico_ipv4.c */
-#endif
 
 static struct pico_sockport *sp_udp = NULL, *sp_tcp = NULL;
 
 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len);
 
-static int32_t socket_cmp(void *ka, void *kb)
+static int socket_cmp_family(struct pico_socket *a, struct pico_socket *b)
 {
-    struct pico_socket *a = ka, *b = kb;
     uint32_t a_is_ip6 = is_sock_ipv6(a);
     uint32_t b_is_ip6 = is_sock_ipv6(b);
-
-    int32_t diff;
-
-    /* First, order by network ver */
+    (void)a;
+    (void)b;
     if (a_is_ip6 < b_is_ip6)
         return -1;
 
     if (a_is_ip6 > b_is_ip6)
         return 1;
 
-    /* If either socket is PICO_IPV4_INADDR_ANY mode, skip local address comparison */
+    return 0;
+}
+
 
-    /* At this point, sort by local host */
+static int socket_cmp_ipv6(struct pico_socket *a, struct pico_socket *b)
+{
+    int ret = 0;
+    (void)a;
+    (void)b;
+    if (!is_sock_ipv6(a) || !is_sock_ipv6(b))
+        return 0;
 
-    if (0) {
 #ifdef PICO_SUPPORT_IPV6
-    } else if (a_is_ip6) {
-        if ((memcmp(a->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0) || memcmp((b->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0))
-            diff = 0;
-        else
-            diff = memcmp(a->local_addr.ip6.addr, b->local_addr.ip6.addr, PICO_SIZE_IP6);
+    if ((memcmp(a->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0) || (memcmp(b->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0))
+        ret = 0;
+    else
+        ret = memcmp(a->local_addr.ip6.addr, b->local_addr.ip6.addr, PICO_SIZE_IP6);
+
+#endif
+    return ret;
+}
+
+static int socket_cmp_ipv4(struct pico_socket *a, struct pico_socket *b)
+{
+    int ret = 0;
+    (void)a;
+    (void)b;
+    if (!is_sock_ipv4(a) || !is_sock_ipv4(b))
+        return 0;
+
+#ifdef PICO_SUPPORT_IPV4
+    if ((a->local_addr.ip4.addr == PICO_IP4_ANY) || (b->local_addr.ip4.addr == PICO_IP4_ANY))
+        ret = 0;
+    else
+        ret = (int)(a->local_addr.ip4.addr - b->local_addr.ip4.addr);
 
 #endif
-    } else {
-        if ((a->local_addr.ip4.addr == PICO_IP4_ANY) || (b->local_addr.ip4.addr == PICO_IP4_ANY))
-            diff = 0;
-        else
-            diff = (int32_t)(a->local_addr.ip4.addr - b->local_addr.ip4.addr);
-    }
+    return ret;
+}
+
+static int socket_cmp_remotehost(struct pico_socket *a, struct pico_socket *b)
+{
+    int ret = 0;
+    if (is_sock_ipv6(a))
+        ret = memcmp(a->remote_addr.ip6.addr, b->remote_addr.ip6.addr, PICO_SIZE_IP6);
+    else
+        ret = (int)(a->remote_addr.ip4.addr - b->remote_addr.ip4.addr);
 
-    if (diff)
-        return diff;
+    return ret;
+}
 
+static int socket_cmp_addresses(struct pico_socket *a, struct pico_socket *b)
+{
+    int ret = 0;
+    /* At this point, sort by local host */
+    ret = socket_cmp_ipv6(a, b);
+
+    if (ret == 0)
+        ret = socket_cmp_ipv4(a, b);
 
     /* Sort by remote host */
-    if (a_is_ip6)
-        diff = memcmp(a->remote_addr.ip6.addr, b->remote_addr.ip6.addr, PICO_SIZE_IP6);
-    else
-        diff = (int32_t)(a->remote_addr.ip4.addr - b->remote_addr.ip4.addr);
+    if (ret == 0)
+        ret = socket_cmp_remotehost(a, b);
+
+    return 0;
+}
 
-    if (diff)
-        return diff;
+static int socket_cmp(void *ka, void *kb)
+{
+    struct pico_socket *a = ka, *b = kb;
+    int ret = 0;
+
+    /* First, order by network family */
+    ret = socket_cmp_family(a, b);
+
+    /* Then, compare by source/destination addresses */
+    if (ret == 0)
+        ret = socket_cmp_addresses(a, b);
 
     /* And finally by remote port. The two sockets are coincident if the quad is the same. */
-    return b->remote_port - a->remote_port;
+    if (ret == 0)
+        ret = b->remote_port - a->remote_port;
+
+    return ret;
 }
 
-struct pico_sockport
-{
-    struct pico_tree socks; /* how you make the connection ? */
-    uint16_t number;
-    uint16_t proto;
-};
 
 #define INIT_SOCKPORT { {&LEAF, socket_cmp}, 0, 0 }
 
@@ -153,304 +186,7 @@
 PICO_TREE_DECLARE(UDPTable, sockport_cmp);
 PICO_TREE_DECLARE(TCPTable, sockport_cmp);
 
-#ifdef PICO_SUPPORT_MCAST
-/*                       socket
- *                         |
- *                    MCASTListen
- *                    |    |     |
- *         ------------    |     ------------
- *         |               |                |
- *   MCASTSources    MCASTSources     MCASTSources
- *   |  |  |  |      |  |  |  |       |  |  |  |
- *   S  S  S  S      S  S  S  S       S  S  S  S
- *
- *   MCASTListen: RBTree(mcast_link, mcast_group)
- *   MCASTSources: RBTree(source)
- */
-struct pico_mcast_listen
-{
-    uint8_t filter_mode;
-    struct pico_ip4 mcast_link;
-    struct pico_ip4 mcast_group;
-    struct pico_tree MCASTSources;
-};
-
-static int mcast_listen_cmp(void *ka, void *kb)
-{
-    struct pico_mcast_listen *a = ka, *b = kb;
-    if (a->mcast_group.addr < b->mcast_group.addr)
-        return -1;
-
-    if (a->mcast_group.addr > b->mcast_group.addr)
-        return 1;
-
-    if (a->mcast_link.addr < b->mcast_link.addr)
-        return -1;
-
-    if (a->mcast_link.addr > b->mcast_link.addr)
-        return 1;
-
-    return 0;
-}
-
-static int mcast_sources_cmp(void *ka, void *kb)
-{
-    struct pico_ip4 *a = ka, *b = kb;
-    if (a->addr < b->addr)
-        return -1;
-
-    if (a->addr > b->addr)
-        return 1;
-
-    return 0;
-}
-
-static int mcast_socket_cmp(void *ka, void *kb)
-{
-    struct pico_socket *a = ka, *b = kb;
-    if (a < b)
-        return -1;
-
-    if (a > b)
-        return 1;
-
-    return 0;
-}
-/* gather all multicast sockets to hasten filter aggregation */
-PICO_TREE_DECLARE(MCASTSockets, mcast_socket_cmp);
-
-static int mcast_filter_cmp(void *ka, void *kb)
-{
-    struct pico_ip4 *a = ka, *b = kb;
-    if (a->addr < b->addr)
-        return -1;
-
-    if (a->addr > b->addr)
-        return 1;
-
-    return 0;
-}
-/* gather sources to be filtered */
-PICO_TREE_DECLARE(MCASTFilter, mcast_filter_cmp);
-
-static struct pico_mcast_listen *listen_find(struct pico_socket *s, struct pico_ip4 *lnk, struct pico_ip4 *grp)
-{
-    struct pico_mcast_listen ltest = {
-        0
-    };
-    ltest.mcast_link.addr = lnk->addr;
-    ltest.mcast_group.addr = grp->addr;
-    return pico_tree_findKey(s->MCASTListen, &ltest);
-}
-
-/* MCASTFilter will be empty if no socket is listening on mcast_group on mcast_link anymore */
-static int pico_socket_aggregate_mcastfilters(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group)
-{
-    uint8_t filter_mode = PICO_IP_MULTICAST_INCLUDE;
-    struct pico_mcast_listen *listen = NULL;
-    struct pico_ip4 *source = NULL;
-    struct pico_socket *mcast_sock = NULL;
-    struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
-
-
-    /* cleanup old filter */
-    pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
-    {
-        pico_tree_delete(&MCASTFilter, index->keyValue);
-    }
-
-    /* construct new filter */
-    pico_tree_foreach(index, &MCASTSockets)
-    {
-        mcast_sock = index->keyValue;
-        listen = listen_find(mcast_sock, mcast_link, mcast_group);
-        if (listen) {
-            /* aggregate filter */
-            switch(filter_mode)
-            {
-            case PICO_IP_MULTICAST_INCLUDE:
-                switch (listen->filter_mode)
-                {
-                case PICO_IP_MULTICAST_INCLUDE:
-                    /* filter = summation of INCLUDEs */
-                    /* mode stays INCLUDE, add all sources to filter */
-                    pico_tree_foreach(index2, &listen->MCASTSources)
-                    {
-                        source = index2->keyValue;
-                        pico_tree_insert(&MCASTFilter, source);
-                    }
-                    break;
-
-                case PICO_IP_MULTICAST_EXCLUDE:
-                    /* filter = EXCLUDE - INCLUDE */
-                    /* delete from the interface INCLUDE filter any source NOT in the socket EXCLUDE filter */
-                    pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
-                    {
-                        source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
-                        if (!source)
-                            pico_tree_delete(&MCASTFilter, index2->keyValue);
-                    }
-                    /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
-                    filter_mode = PICO_IP_MULTICAST_EXCLUDE;
-                    /* add to the interface EXCLUDE filter any socket source NOT in the former interface INCLUDE filter */
-                    pico_tree_foreach(index2, &listen->MCASTSources)
-                    {
-                        source = pico_tree_insert(&MCASTFilter, index2->keyValue);
-                        if (source)
-                            pico_tree_delete(&MCASTFilter, source);
-                    }
-                    break;
-
-                default:
-                    return -1;
-                }
-                break;
-
-            case PICO_IP_MULTICAST_EXCLUDE:
-                switch (listen->filter_mode)
-                {
-                case PICO_IP_MULTICAST_INCLUDE:
-                    /* filter = EXCLUDE - INCLUDE */
-                    /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
-                    /* remove from the interface EXCLUDE filter any source in the socket INCLUDE filter */
-                    pico_tree_foreach(index2, &listen->MCASTSources)
-                    {
-                        source = pico_tree_findKey(&MCASTFilter, index2->keyValue);
-                        if (source)
-                            pico_tree_delete(&MCASTFilter, source);
-                    }
-                    break;
-
-                case PICO_IP_MULTICAST_EXCLUDE:
-                    /* filter = intersection of EXCLUDEs */
-                    /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
-                    /* remove from the interface EXCLUDE filter any source not in the socket EXCLUDE filter */
-                    pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
-                    {
-                        source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
-                        if (!source)
-                            pico_tree_delete(&MCASTFilter, index2->keyValue);
-                    }
-                    break;
-
-                default:
-                    return -1;
-                }
-                break;
-
-            default:
-                return -1;
-            }
-        }
-    }
-    return filter_mode;
-}
-
-static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src)
-{
-    struct pico_ipv4_link *mcast_link = NULL;
-    struct pico_mcast_listen *listen = NULL;
-    struct pico_tree_node *index = NULL;
-
-    /* no multicast enabled on socket */
-    if (!s->MCASTListen)
-        return 0;
-
-    mcast_link = pico_ipv4_link_get(&s->local_addr.ip4);
-    if (!mcast_link)
-        return -1;
-
-    listen = listen_find(s, &mcast_link->address, mcast_group);
-    if (!listen)
-        return -1;
-
-    /* perform source filtering */
-    switch (listen->filter_mode)
-    {
-    case PICO_IP_MULTICAST_INCLUDE:
-        pico_tree_foreach(index, &listen->MCASTSources)
-        {
-            if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) {
-                so_mcast_dbg("MCAST: IP %08X in included socket source list\n", src->addr);
-                return 0;
-            }
-        }
-        so_mcast_dbg("MCAST: IP %08X NOT in included socket source list\n", src->addr);
-        return -1;
-
-    case PICO_IP_MULTICAST_EXCLUDE:
-        pico_tree_foreach(index, &listen->MCASTSources)
-        {
-            if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) {
-                so_mcast_dbg("MCAST: IP %08X in excluded socket source list\n", src->addr);
-                return -1;
-            }
-        }
-        so_mcast_dbg("MCAST: IP %08X NOT in excluded socket source list\n", src->addr);
-        return 0;
-    }
-    return -1;
-}
-
-static inline struct pico_ipv4_link *pico_socket_setoption_mcastargs_validation(struct pico_ip_mreq *mreq, struct pico_ip_mreq_source *mreq_source)
-{
-    struct pico_ipv4_link *mcast_link = NULL;
-
-    if (!mreq && !mreq_source)
-        return NULL;
-
-    if (mreq) {
-        if (!mreq->mcast_group_addr.addr)
-            return NULL;
-
-        if (pico_ipv4_is_unicast(mreq->mcast_group_addr.addr))
-            return NULL;
-
-        if (!mreq->mcast_link_addr.addr) {
-            mcast_link = pico_ipv4_get_default_mcastlink();
-            if (!mcast_link)
-                return NULL;
-        } else {
-            mcast_link = pico_ipv4_link_get(&mreq->mcast_link_addr);
-            if (!mcast_link)
-                return NULL;
-        }
-    }
-
-    if (mreq_source) {
-        if (!mreq_source->mcast_group_addr.addr)
-            return NULL;
-
-        if (pico_ipv4_is_unicast(mreq_source->mcast_group_addr.addr))
-            return NULL;
-
-        if (!mreq_source->mcast_source_addr.addr)
-            return NULL;
-
-        if (!pico_ipv4_is_unicast(mreq_source->mcast_source_addr.addr))
-            return NULL;
-
-        if (!mreq_source->mcast_link_addr.addr) {
-            mcast_link = pico_ipv4_get_default_mcastlink();
-            if (!mcast_link)
-                return NULL;
-        } else {
-            mcast_link = pico_ipv4_link_get(&mreq_source->mcast_link_addr);
-            if (!mcast_link)
-                return NULL;
-        }
-    }
-
-    return mcast_link;
-}
-#else
-static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src)
-{
-    return 0;
-}
-#endif /* PICO_SUPPORT_MCAST */
-
-static struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port)
+struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port)
 {
     struct pico_sockport test = INIT_SOCKPORT;
     test.number = port;
@@ -464,42 +200,25 @@
     else return NULL;
 }
 
-int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net)
-{
-    struct pico_sockport *sp;
-    struct pico_ip4 ip;
-    sp = pico_get_sockport(proto, port);
+#ifdef PICO_SUPPORT_IPV4
 
-    if (!net)
-        net = &pico_proto_ipv4;
-
-    /** IPv6 (wip) ***/
-    if (net != &pico_proto_ipv4) {
-        dbg("IPV6!!!!!\n");
-        return (!sp);
-    }
-
-    /* IPv4 */
+static int pico_port_in_use_by_nat(uint16_t proto, uint16_t port)
+{
+    int ret = 0;
+    (void) proto;
+    (void) port;
 #ifdef PICO_SUPPORT_NAT
     if (pico_ipv4_nat_find(port, NULL, 0, (uint8_t)proto)) {
         dbg("In use by nat....\n");
-        return 0;
+        ret = 1;
     }
 
 #endif
-    if (addr)
-        ip.addr = ((struct pico_ip4 *)addr)->addr;
-    else
-        ip.addr = PICO_IPV4_INADDR_ANY;
+    return ret;
+}
 
-    if (ip.addr == PICO_IPV4_INADDR_ANY) {
-        if (!sp) return 1;
-        else {
-            dbg("In use, and asked for ANY\n");
-            return 0;
-        }
-    }
-
+static int pico_port_in_use_with_this_ipv4_address(struct pico_sockport *sp, struct pico_ip4 ip)
+{
     if (sp) {
         struct pico_ip4 *s_local;
         struct pico_tree_node *idx;
@@ -508,12 +227,116 @@
             s = idx->keyValue;
             if (s->net == &pico_proto_ipv4) {
                 s_local = (struct pico_ip4*) &s->local_addr;
-                if ((s_local->addr == PICO_IPV4_INADDR_ANY) || (s_local->addr == ip.addr))
-                    return 0;
+                if ((s_local->addr == PICO_IPV4_INADDR_ANY) || (s_local->addr == ip.addr)) {
+                    return 1;
+                }
+            }
+        }
+    }
+
+    return 0;
+}
+
+
+static int pico_port_in_use_ipv4(struct pico_sockport *sp, void *addr)
+{
+    struct pico_ip4 ip;
+    /* IPv4 */
+    if (addr)
+        ip.addr = ((struct pico_ip4 *)addr)->addr;
+    else
+        ip.addr = PICO_IPV4_INADDR_ANY;
+
+    if (ip.addr == PICO_IPV4_INADDR_ANY) {
+        if (!sp)
+            return 0;
+        else {
+            dbg("In use, and asked for ANY\n");
+            return 1;
+        }
+    }
+
+    return pico_port_in_use_with_this_ipv4_address(sp, ip);
+}
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+static int pico_port_in_use_with_this_ipv6_address(struct pico_sockport *sp, struct pico_ip6 ip)
+{
+    if (sp) {
+        struct pico_ip6 *s_local;
+        struct pico_tree_node *idx;
+        struct pico_socket *s;
+        pico_tree_foreach(idx, &sp->socks) {
+            s = idx->keyValue;
+            if (s->net == &pico_proto_ipv6) {
+                s_local = (struct pico_ip6*) &s->local_addr;
+                if ((pico_ipv6_is_unspecified(s_local->addr)) || (!memcmp(s_local->addr, ip.addr, PICO_SIZE_IP6))) {
+                    return 1;
+                }
             }
         }
     }
 
+    return 0;
+}
+
+static int pico_port_in_use_ipv6(struct pico_sockport *sp, void *addr)
+{
+    struct pico_ip6 ip;
+    /* IPv6 */
+    if (addr)
+        memcpy(&ip.addr, ((struct pico_ip6 *)addr)->addr, sizeof(struct pico_ip6));
+    else
+        memcpy(&ip.addr, PICO_IP6_ANY, sizeof(struct pico_ip6));
+
+    if (memcmp(ip.addr, PICO_IP6_ANY, sizeof(struct pico_ip6)) ==  0) {
+        if (!sp)
+            return 0;
+        else {
+            dbg("In use, and asked for ANY\n");
+            return 1;
+        }
+    }
+
+    return pico_port_in_use_with_this_ipv6_address(sp, ip);
+}
+#endif
+
+
+
+static int pico_generic_port_in_use(uint16_t proto, uint16_t port, struct pico_sockport *sp, void *addr)
+{
+#ifdef PICO_SUPPORT_IPV4
+    if (pico_port_in_use_by_nat(proto, port)) {
+        return 1;
+    }
+
+    if (pico_port_in_use_ipv4(sp, addr)) {
+        return 1;
+    }
+
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+    if (pico_port_in_use_ipv6(sp, addr)) {
+        return 1;
+    }
+
+#endif
+
+    return 0;
+}
+
+int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net)
+{
+    struct pico_sockport *sp;
+    (void) net;
+    sp = pico_get_sockport(proto, port);
+
+    if (pico_generic_port_in_use(proto, port, sp, addr))
+        return 0;
+
     return 1;
 }
 
@@ -539,7 +362,7 @@
     return -1;
 }
 
-struct pico_socket*pico_sockets_find(uint16_t local, uint16_t remote)
+struct pico_socket *pico_sockets_find(uint16_t local, uint16_t remote)
 {
     struct pico_socket *sock = NULL;
     struct pico_tree_node *index = NULL;
@@ -565,14 +388,14 @@
 int8_t pico_socket_add(struct pico_socket *s)
 {
     struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
-    LOCK(Mutex);
+    PICOTCP_MUTEX_LOCK(Mutex);
     if (!sp) {
         /* dbg("Creating sockport..%04x\n", s->local_port); / * In comment due to spam during test * / */
-        sp = pico_zalloc(sizeof(struct pico_sockport));
+        sp = PICO_ZALLOC(sizeof(struct pico_sockport));
 
         if (!sp) {
             pico_err = PICO_ERR_ENOMEM;
-            UNLOCK(Mutex);
+            PICOTCP_MUTEX_UNLOCK(Mutex);
             return -1;
         }
 
@@ -593,7 +416,7 @@
 
     pico_tree_insert(&sp->socks, s);
     s->state |= PICO_SOCKET_STATE_BOUND;
-    UNLOCK(Mutex);
+    PICOTCP_MUTEX_UNLOCK(Mutex);
 #if DEBUG_SOCKET_TREE
     {
         struct pico_tree_node *index;
@@ -608,6 +431,7 @@
     return 0;
 }
 
+
 static void socket_clean_queues(struct pico_socket *sock)
 {
     struct pico_frame *f_in = pico_dequeue(&sock->q_in);
@@ -626,9 +450,7 @@
             f_out = pico_dequeue(&sock->q_out);
         }
     }
-    /* for tcp sockets go further and clean the sockets inside queue */
-    if(sock->proto == &pico_proto_tcp)
-        pico_tcp_cleanup_queues(sock);
+    pico_socket_tcp_cleanup(sock);
 }
 
 static void socket_garbage_collect(pico_time now, void *arg)
@@ -637,21 +459,12 @@
     IGNORE_PARAMETER(now);
 
     socket_clean_queues(s);
-    pico_free(s);
+    PICO_FREE(s);
 }
 
-int8_t pico_socket_del(struct pico_socket *s)
+
+static void pico_socket_check_empty_sockport(struct pico_socket *s, struct pico_sockport *sp)
 {
-    struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
-
-    if (!sp) {
-        pico_err = PICO_ERR_ENXIO;
-        return -1;
-    }
-
-    LOCK(Mutex);
-    pico_tree_delete(&sp->socks, s);
-    s->net = NULL;
     if(pico_tree_empty(&sp->socks)) {
         if (PROTO(s) == PICO_PROTO_UDP)
         {
@@ -662,55 +475,43 @@
             pico_tree_delete(&TCPTable, sp);
         }
 
-        if(sp_tcp == sp) sp_tcp = NULL;
+        if(sp_tcp == sp)
+            sp_tcp = NULL;
+
+        if(sp_udp == sp)
+            sp_udp = NULL;
 
-        if(sp_udp == sp) sp_udp = NULL;
+        PICO_FREE(sp);
+    }
+}
 
-        pico_free(sp);
-
+int8_t pico_socket_del(struct pico_socket *s)
+{
+    struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
+    if (!sp) {
+        pico_err = PICO_ERR_ENXIO;
+        return -1;
     }
 
-#ifdef PICO_SUPPORT_MCAST
-    do {
-        int filter_mode;
-        struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
-        struct pico_mcast_listen *listen = NULL;
-        struct pico_ip4 *source = NULL;
-        if (s->MCASTListen) {
-            pico_tree_delete(&MCASTSockets, s);
-            pico_tree_foreach_safe(index, s->MCASTListen, _tmp)
-            {
-                listen = index->keyValue;
-                pico_tree_foreach_safe(index2, &listen->MCASTSources, _tmp2)
-                {
-                    source = index->keyValue;
-                    pico_tree_delete(&listen->MCASTSources, source);
-                    pico_free(source);
-                }
-                filter_mode = pico_socket_aggregate_mcastfilters(&listen->mcast_link, &listen->mcast_group);
-                if (filter_mode >= 0)
-                    pico_ipv4_mcast_leave(&listen->mcast_link, &listen->mcast_group, 1, (uint8_t)filter_mode, &MCASTFilter);
-
-                pico_tree_delete(s->MCASTListen, listen);
-                pico_free(listen);
-            }
-            pico_free(s->MCASTListen);
-        }
-    } while (0);
-#endif
-
-#ifdef PICO_SUPPORT_TCP
-    if(s->parent)
-        s->parent->number_of_pending_conn--;
-
-#endif
-
+    PICOTCP_MUTEX_LOCK(Mutex);
+    pico_tree_delete(&sp->socks, s);
+    pico_socket_check_empty_sockport(s, sp);
+    pico_multicast_delete(s);
+    pico_socket_tcp_delete(s);
     s->state = PICO_SOCKET_STATE_CLOSED;
     pico_timer_add(3000, socket_garbage_collect, s);
-    UNLOCK(Mutex);
+    PICOTCP_MUTEX_UNLOCK(Mutex);
     return 0;
 }
 
+static void pico_socket_update_tcp_state(struct pico_socket *s, uint16_t tcp_state)
+{
+    if (tcp_state) {
+        s->state &= 0x00FF;
+        s->state |= tcp_state;
+    }
+}
+
 static int8_t pico_socket_alter_state(struct pico_socket *s, uint16_t more_states, uint16_t less_states, uint16_t tcp_state)
 {
     struct pico_sockport *sp;
@@ -728,154 +529,73 @@
 
     s->state |= more_states;
     s->state = (uint16_t)(s->state & (~less_states));
-    if (tcp_state) {
-        s->state &= 0x00FF;
-        s->state |= tcp_state;
-    }
-
+    pico_socket_update_tcp_state(s, tcp_state);
     return 0;
 }
 
+
+static int pico_socket_transport_deliver(struct pico_protocol *p, struct pico_sockport *sp, struct pico_frame *f)
+{
+    if (p->proto_number == PICO_PROTO_TCP)
+        return pico_socket_tcp_deliver(sp, f);
+
+    if (p->proto_number == PICO_PROTO_UDP)
+        return pico_socket_udp_deliver(sp, f);
+
+    return -1;
+}
+
+
 static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, uint16_t localport)
 {
-    struct pico_frame *cpy = NULL;
     struct pico_sockport *sp = NULL;
-    struct pico_socket *s = NULL;
-    struct pico_tree_node *index = NULL;
-    struct pico_tree_node *_tmp;
     struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
-  #ifdef PICO_SUPPORT_IPV4
-    struct pico_ipv4_hdr *ip4hdr;
-  #endif
-  #ifdef PICO_SUPPORT_IPV6
-    struct pico_ipv6_hdr *ip6hdr;
-  #endif
-
-#ifdef PICO_SUPPORT_TCP
-    struct pico_socket *found = NULL;
-#endif
 
     if (!tr)
         return -1;
 
     sp = pico_get_sockport(p->proto_number, localport);
-
     if (!sp) {
         dbg("No such port %d\n", short_be(localport));
         return -1;
     }
 
-  #ifdef PICO_SUPPORT_TCP
-    if (p->proto_number == PICO_PROTO_TCP) {
-        pico_tree_foreach_safe(index, &sp->socks, _tmp){
-            s = index->keyValue;
-            /* 4-tuple identification of socket (port-IP) */
-      #ifdef PICO_SUPPORT_IPV4
-            if (IS_IPV4(f)) {
-                struct pico_ip4 s_local, s_remote, p_src, p_dst;
-                ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
-                s_local.addr = s->local_addr.ip4.addr;
-                s_remote.addr = s->remote_addr.ip4.addr;
-                p_src.addr = ip4hdr->src.addr;
-                p_dst.addr = ip4hdr->dst.addr;
-                if ((s->remote_port == tr->sport) && /* remote port check */
-                    (s_remote.addr == p_src.addr) && /* remote addr check */
-                    ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
-                    found = s;
-                    break;
-                } else if ((s->remote_port == 0)  && /* not connected... listening */
-                           ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
-                    /* listen socket */
-                    found = s;
-                }
-            }
+    return pico_socket_transport_deliver(p, sp, f);
+}
+
+int pico_socket_set_family(struct pico_socket *s, uint16_t family)
+{
+    (void) family;
 
-      #endif
-      #ifdef PICO_SUPPORT_IPV6    /* XXX TODO make compare for ipv6 addresses */
-            if (IS_IPV6(f)) {
-                ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
-                if ((s->remote_port == localport)) { /* && (((struct pico_ip6) s->remote_addr.ip6).addr == ((struct pico_ip6)(ip6hdr->src)).addr) ) { */
-                    found = s;
-                    break;
-                } else if (s->remote_port == 0) {
-                    /* listen socket */
-                    found = s;
-                }
-            }
+  #ifdef PICO_SUPPORT_IPV4
+    if (family == PICO_PROTO_IPV4)
+        s->net = &pico_proto_ipv4;
 
-      #endif
-        } /* FOREACH */
-        if (found != NULL) {
-            pico_tcp_input(found, f);
-            if ((found->ev_pending) && found->wakeup) {
-                found->wakeup(found->ev_pending, found);
-                if(!found->parent)
-                    found->ev_pending = 0;
-            }
+  #endif
 
-            return 0;
-        } else {
-            dbg("SOCKET> mmm something wrong (prob sockport)\n");
-            return -1;
-        }
-    } /* TCP CASE */
+  #ifdef PICO_SUPPORT_IPV6
+    if (family == PICO_PROTO_IPV6)
+        s->net = &pico_proto_ipv6;
 
-#endif
+  #endif
 
-#ifdef PICO_SUPPORT_UDP
-    if (p->proto_number == PICO_PROTO_UDP) {
-        pico_tree_foreach_safe(index, &sp->socks, _tmp){
-            s = index->keyValue;
-            if (IS_IPV4(f)) { /* IPV4 */
-                struct pico_ip4 s_local, p_dst;
-                ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
-                s_local.addr = s->local_addr.ip4.addr;
-                p_dst.addr = ip4hdr->dst.addr;
-                if ((pico_ipv4_is_broadcast(p_dst.addr)) || pico_ipv4_is_multicast(p_dst.addr)) {
-                    struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);
-                    if (pico_ipv4_is_multicast(p_dst.addr) && (pico_socket_mcast_filter(s, &ip4hdr->dst, &ip4hdr->src) < 0))
-                        return -1;
+    if (s->net == NULL)
+        return -1;
 
-                    if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */
-                        (dev == f->dev)) { /* the source of the bcast packet is a neighbor... */
-                        cpy = pico_frame_copy(f);
-                        if (!cpy)
-                            return -1;
+    return 0;
+}
 
-                        if (pico_enqueue(&s->q_in, cpy) > 0) {
-                            if (s->wakeup)
-                                s->wakeup(PICO_SOCK_EV_RD, s);
-                        }
-                        else
-                            pico_frame_discard(cpy);
-
-                    }
-                } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))
-                { /* Either local socket is ANY, or matches dst */
-                    cpy = pico_frame_copy(f);
-                    if (!cpy)
-                        return -1;
+static struct pico_socket *pico_socket_transport_open(uint16_t proto, uint16_t family)
+{
+    struct pico_socket *s = NULL;
+    if (proto == PICO_PROTO_UDP)
+        s = pico_socket_udp_open();
 
-                    if (pico_enqueue(&s->q_in, cpy) > 0) {
-                        if (s->wakeup)
-                            s->wakeup(PICO_SOCK_EV_RD, s);
-                    }
-                    else
-                        pico_frame_discard(cpy);
-                }
-            } else {
-                /*... IPv6 */
-            }
-        } /* FOREACH */
-        pico_frame_discard(f);
-        if (s)
-            return 0;
-        else
-            return -1;
-    }
+    if (proto == PICO_PROTO_TCP)
+        s = pico_socket_tcp_open(family);
 
-#endif
-    return -1;
+    return s;
+
 }
 
 struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *))
@@ -883,89 +603,29 @@
 
     struct pico_socket *s = NULL;
 
-#ifdef PICO_SUPPORT_UDP
-    if (proto == PICO_PROTO_UDP) {
-        s = pico_udp_open();
-        s->proto = &pico_proto_udp;
-        s->q_in.overhead = s->q_out.overhead = UDP_FRAME_OVERHEAD;
-    }
-
-#endif
-
-#ifdef PICO_SUPPORT_TCP
-    if (proto == PICO_PROTO_TCP) {
-        s = pico_tcp_open();
-        s->proto = &pico_proto_tcp;
-        /*check if Nagle enabled */
-        /* 
-        if (!IS_NAGLE_ENABLED(s))
-            dbg("ERROR Nagle should be enabled here\n\n");
-        */
-    }
-
-#endif
+    s = pico_socket_transport_open(proto, net);
 
     if (!s) {
         pico_err = PICO_ERR_EPROTONOSUPPORT;
         return NULL;
     }
 
-#ifdef PICO_SUPPORT_IPV4
-    if (net == PICO_PROTO_IPV4)
-        s->net = &pico_proto_ipv4;
-
-#endif
-
-#ifdef PICO_SUPPORT_IPV6
-    if (net == PICO_PROTO_IPV6)
-        s->net = &pico_proto_ipv6;
-
-#endif
+    if (pico_socket_set_family(s, net) != 0) {
+        PICO_FREE(s);
+        pico_err = PICO_ERR_ENETUNREACH;
+        return NULL;
+    }
 
     s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
     s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
 
     s->wakeup = wakeup;
-
-    if (!s->net) {
-        pico_free(s);
-        pico_err = PICO_ERR_ENETUNREACH;
-        return NULL;
-    }
-
     return s;
 }
 
 
-struct pico_socket *pico_socket_clone(struct pico_socket *facsimile)
+static void pico_socket_clone_assign_address(struct pico_socket *s, struct pico_socket *facsimile)
 {
-    struct pico_socket *s = NULL;
-
-#ifdef PICO_SUPPORT_UDP
-    if (facsimile->proto->proto_number == PICO_PROTO_UDP) {
-        s = pico_udp_open();
-        s->proto = &pico_proto_udp;
-        s->q_in.overhead = s->q_out.overhead = UDP_FRAME_OVERHEAD;
-    }
-
-#endif
-
-#ifdef PICO_SUPPORT_TCP
-    if (facsimile->proto->proto_number == PICO_PROTO_TCP) {
-        s = pico_tcp_open();
-        s->proto = &pico_proto_tcp;
-    }
-
-#endif
-
-    if (!s) {
-        pico_err = PICO_ERR_EPROTONOSUPPORT;
-        return NULL;
-    }
-
-    s->local_port = facsimile->local_port;
-    s->remote_port = facsimile->remote_port;
-    s->state = facsimile->state;
 
 #ifdef PICO_SUPPORT_IPV4
     if (facsimile->net == &pico_proto_ipv4) {
@@ -977,25 +637,51 @@
 #endif
 
 #ifdef PICO_SUPPORT_IPV6
-    if (net == &pico_proto_ipv6) {
+    if (facsimile->net == &pico_proto_ipv6) {
         s->net = &pico_proto_ipv6;
         memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip6));
         memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip6));
     }
 
 #endif
-    s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
-    s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
-    s->wakeup = NULL;
+
+}
+
+struct pico_socket *pico_socket_clone(struct pico_socket *facsimile)
+{
+    struct pico_socket *s = NULL;
+
+    s = pico_socket_transport_open(facsimile->proto->proto_number, facsimile->net->proto_number);
+    if (!s) {
+        pico_err = PICO_ERR_EPROTONOSUPPORT;
+        return NULL;
+    }
+
+    s->local_port = facsimile->local_port;
+    s->remote_port = facsimile->remote_port;
+    s->state = facsimile->state;
+    pico_socket_clone_assign_address(s, facsimile);
     if (!s->net) {
-        pico_free(s);
+        PICO_FREE(s);
         pico_err = PICO_ERR_ENETUNREACH;
         return NULL;
     }
 
+    s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
+    s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
+    s->wakeup = NULL;
     return s;
 }
 
+static int pico_socket_transport_read(struct pico_socket *s, void *buf, int len)
+{
+    if (PROTO(s) == PICO_PROTO_UDP)
+        return pico_socket_udp_recv(s, buf, (uint16_t)len, NULL, NULL);
+    else if (PROTO(s) == PICO_PROTO_TCP)
+        return pico_socket_tcp_read(s, buf, (uint32_t)len);
+    else return 0;
+}
+
 int pico_socket_read(struct pico_socket *s, void *buf, int len)
 {
     if (!s || buf == NULL) {
@@ -1015,27 +701,38 @@
         return -1;
     }
 
-#ifdef PICO_SUPPORT_UDP
-    if (PROTO(s) == PICO_PROTO_UDP)
-        return pico_udp_recv(s, buf, (uint16_t)len, NULL, NULL);
-
-#endif
+    return pico_socket_transport_read(s, buf, len);
+}
 
-#ifdef PICO_SUPPORT_TCP
-    if (PROTO(s) == PICO_PROTO_TCP) {
-        /* check if in shutdown state and if no more data in tcpq_in */
-        if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
-            pico_err = PICO_ERR_ESHUTDOWN;
-            return -1;
-        } else {
-            return (int)pico_tcp_read(s, buf, (uint32_t)len);
-        }
+static int pico_socket_write_check_state(struct pico_socket *s)
+{
+    if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
+        pico_err = PICO_ERR_EIO;
+        return -1;
+    }
+
+    if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
+        pico_err = PICO_ERR_ENOTCONN;
+        return -1;
     }
 
-#endif
+    if (s->state & PICO_SOCKET_STATE_SHUT_LOCAL) { /* check if in shutdown state */
+        pico_err = PICO_ERR_ESHUTDOWN;
+        return -1;
+    }
+
     return 0;
 }
 
+static int pico_socket_write_attempt(struct pico_socket *s, const void *buf, int len)
+{
+    if (pico_socket_write_check_state(s) < 0) {
+        return -1;
+    } else {
+        return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
+    }
+}
+
 int pico_socket_write(struct pico_socket *s, const void *buf, int len)
 {
     if (!s || buf == NULL) {
@@ -1050,20 +747,7 @@
         }
     }
 
-    if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
-        pico_err = PICO_ERR_EIO;
-        return -1;
-    }
-
-    if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
-        pico_err = PICO_ERR_ENOTCONN;
-        return -1;
-    } else if (s->state & PICO_SOCKET_STATE_SHUT_LOCAL) { /* check if in shutdown state */
-        pico_err = PICO_ERR_ESHUTDOWN;
-        return -1;
-    } else {
-        return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
-    }
+    return pico_socket_write_attempt(s, buf, len);
 }
 
 uint16_t pico_socket_high_port(uint16_t proto)
@@ -1089,22 +773,102 @@
     else return 0U;
 }
 
-
-int pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port)
+static void *pico_socket_sendto_get_ip4_src(struct pico_socket *s, struct pico_ip4 *dst)
 {
-    struct pico_frame *f;
-    struct pico_remote_duple *remote_duple = NULL;
-    int socket_mtu = PICO_SOCKET4_MTU;
-    int header_offset = 0;
-    int total_payload_written = 0;
+    struct pico_ip4 *src4 = NULL;
 
 #ifdef PICO_SUPPORT_IPV4
-    struct pico_ip4 *src4;
+    /* Check if socket is connected: destination address MUST match the
+     * current connected endpoint
+     */
+    if ((s->state & PICO_SOCKET_STATE_CONNECTED)) {
+        src4 = &s->local_addr.ip4;
+        if  (s->remote_addr.ip4.addr != ((struct pico_ip4 *)dst)->addr ) {
+            pico_err = PICO_ERR_EADDRNOTAVAIL;
+            return NULL;
+        }
+    } else {
+
+        src4 = pico_ipv4_source_find(dst);
+        if (!src4) {
+            pico_err = PICO_ERR_EHOSTUNREACH;
+            return NULL;
+        }
+
+    }
+
+    if (src4->addr != PICO_IPV4_INADDR_ANY)
+        s->local_addr.ip4.addr = src4->addr;
+
+#else
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
 #endif
+    return src4;
+}
+
+static void *pico_socket_sendto_get_ip6_src(struct pico_socket *s, struct pico_ip6 *dst)
+{
+    struct pico_ip6 *src6 = NULL;
+    (void)s;
+    (void)dst;
 
 #ifdef PICO_SUPPORT_IPV6
-    struct pico_ip6 *src6;
+
+    /* Check if socket is connected: destination address MUST match the
+     * current connected endpoint
+     */
+    if ((s->state & PICO_SOCKET_STATE_CONNECTED)) {
+        src6 = &s->local_addr.ip6;
+        if (memcmp(&s->remote_addr, dst, PICO_SIZE_IP6)) {
+            pico_err = PICO_ERR_EADDRNOTAVAIL;
+            return NULL;
+        }
+    } else {
+        src6 = pico_ipv6_source_find(dst);
+        if (!src6) {
+            pico_err = PICO_ERR_EHOSTUNREACH;
+            return NULL;
+        }
+
+        if (!pico_ipv6_is_unspecified(src6->addr))
+            s->local_addr.ip6 = *src6;
+    }
+
+#else
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
 #endif
+    return src6;
+}
+
+
+static int pico_socket_sendto_dest_check(struct pico_socket *s, void *dst, uint16_t port)
+{
+
+    /* For the sendto call to be valid,
+     * dst and remote_port should be always populated.
+     */
+    if (!dst || !port) {
+        pico_err = PICO_ERR_EADDRNOTAVAIL;
+        return -1;
+    }
+
+    /* When coming from pico_socket_send (or _write),
+     * the destination is automatically assigned to the currently connected endpoint.
+     * This check will ensure that there is no mismatch when sendto() is called directly
+     * on a connected socket
+     */
+    if ((s->state & PICO_SOCKET_STATE_CONNECTED) != 0) {
+        if (port != s->remote_port) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int pico_socket_sendto_initial_checks(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port)
+{
     if (len == 0) {
         return 0;
     } else if (len < 0) {
@@ -1117,182 +881,380 @@
         return -1;
     }
 
-    if (!dst || !remote_port) {
-        pico_err = PICO_ERR_EADDRNOTAVAIL;
-        return -1;
+    return pico_socket_sendto_dest_check(s, dst, remote_port);
+}
+
+static void *pico_socket_sendto_get_src(struct pico_socket *s, void *dst)
+{
+    void *src = NULL;
+    if (is_sock_ipv4(s))
+        src = pico_socket_sendto_get_ip4_src(s, (struct pico_ip4 *)dst);
+
+    if (is_sock_ipv6(s))
+        src = pico_socket_sendto_get_ip6_src(s, (struct pico_ip6 *)dst);
+
+    return src;
+}
+
+static struct pico_remote_endpoint *pico_socket_sendto_destination_ipv4(struct pico_socket *s, struct pico_ip4 *dst, uint16_t port)
+{
+    struct pico_remote_endpoint *ep = NULL;
+    (void)s;
+    ep = PICO_ZALLOC(sizeof(struct pico_remote_endpoint));
+    if (!ep) {
+        pico_err = PICO_ERR_ENOMEM;
+        return NULL;
     }
 
-    if ((s->state & PICO_SOCKET_STATE_CONNECTED) != 0) {
-        if (remote_port != s->remote_port) {
+    ep->remote_addr.ip4.addr = ((struct pico_ip4 *)dst)->addr;
+    ep->remote_port = port;
+    return ep;
+}
+
+static void pico_endpoint_free(struct pico_remote_endpoint *ep)
+{
+    if (ep)
+        PICO_FREE(ep);
+}
+
+static struct pico_remote_endpoint *pico_socket_sendto_destination_ipv6(struct pico_socket *s, struct pico_ip6 *dst, uint16_t port)
+{
+    struct pico_remote_endpoint *ep = NULL;
+    (void)s;
+    (void)dst;
+    (void)port;
+#ifdef PICO_SUPPORT_IPV6
+    ep = PICO_ZALLOC(sizeof(struct pico_remote_endpoint));
+    if (!ep) {
+        pico_err = PICO_ERR_ENOMEM;
+        return NULL;
+    }
+
+    memcpy(&ep->remote_addr.ip6, dst, sizeof(struct pico_ip6));
+    ep->remote_port = port;
+#endif
+    return ep;
+}
+
+
+static struct pico_remote_endpoint *pico_socket_sendto_destination(struct pico_socket *s, void *dst, uint16_t port)
+{
+    struct pico_remote_endpoint *ep = NULL;
+    (void)pico_socket_sendto_destination_ipv6;
+    /* socket remote info could change in a consecutive call, make persistent */
+#   ifdef PICO_SUPPORT_UDP
+    if (PROTO(s) == PICO_PROTO_UDP) {
+#       ifdef PICO_SUPPORT_IPV6
+        if (is_sock_ipv6(s))
+            ep = pico_socket_sendto_destination_ipv6(s, (struct pico_ip6 *)dst, port);
+
+#       endif
+#       ifdef PICO_SUPPORT_IPV4
+        if (is_sock_ipv4(s))
+            ep = pico_socket_sendto_destination_ipv4(s, (struct pico_ip4 *)dst, port);
+
+#       endif
+    }
+
+#  endif
+    return ep;
+}
+
+static int32_t pico_socket_sendto_set_localport(struct pico_socket *s)
+{
+
+    if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
+        s->local_port = pico_socket_high_port(s->proto->proto_number);
+        if (s->local_port == 0) {
             pico_err = PICO_ERR_EINVAL;
             return -1;
         }
     }
 
-#ifdef PICO_SUPPORT_IPV4
-    if (IS_SOCK_IPV4(s)) {
-        socket_mtu = PICO_SOCKET4_MTU;
-        if ((s->state & PICO_SOCKET_STATE_CONNECTED)) {
-            if  (s->remote_addr.ip4.addr != ((struct pico_ip4 *)dst)->addr ) {
-                pico_err = PICO_ERR_EADDRNOTAVAIL;
-                return -1;
-            }
-        } else {
-            src4 = pico_ipv4_source_find(dst);
-            if (!src4) {
-                pico_err = PICO_ERR_EHOSTUNREACH;
-                return -1;
-            }
+    return s->local_port;
+}
 
-            if (src4->addr != PICO_IPV4_INADDR_ANY)
-                s->local_addr.ip4.addr = src4->addr;
+static int pico_socket_sendto_transport_offset(struct pico_socket *s)
+{
+    int header_offset = -1;
+    #ifdef PICO_SUPPORT_TCP
+    if (PROTO(s) == PICO_PROTO_TCP)
+        header_offset = pico_tcp_overhead(s);
 
-#     ifdef PICO_SUPPORT_UDP
-            /* socket remote info could change in a consecutive call, make persistent */
-            if (PROTO(s) == PICO_PROTO_UDP) {
-                remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
-                remote_duple->remote_addr.ip4.addr = ((struct pico_ip4 *)dst)->addr;
-                remote_duple->remote_port = remote_port;
-            }
+    #endif
 
-#     endif
-        }
+    #ifdef PICO_SUPPORT_UDP
+    if (PROTO(s) == PICO_PROTO_UDP)
+        header_offset = sizeof(struct pico_udp_hdr);
 
     #endif
+    return header_offset;
 }
-else if (IS_SOCK_IPV6(s)) {
-    socket_mtu = PICO_SOCKET6_MTU;
-    #ifdef PICO_SUPPORT_IPV6
-    if (s->state & PICO_SOCKET_STATE_CONNECTED) {
-        if (memcmp(&s->remote_addr, dst, PICO_SIZE_IP6))
-            return -1;
-    } else {
-        src6 = pico_ipv6_source_find(dst);
-        if (!src6) {
-            pico_err = PICO_ERR_EHOSTUNREACH;
-            return -1;
-        }
+
 
-        memcpy(&s->local_addr, src6, PICO_SIZE_IP6);
-        memcpy(&s->remote_addr, dst, PICO_SIZE_IP6);
-#     ifdef PICO_SUPPORT_UDP
-        if (PROTO(s) == PICO_PROTO_UDP) {
-            remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
-            remote_duple->remote_addr.ip6.addr = ((struct pico_ip6 *)dst)->addr;
-            remote_duple->remote_port = remote_port;
-        }
-
-#     endif
+static struct pico_remote_endpoint *pico_socket_set_info(struct pico_remote_endpoint *ep)
+{
+    struct pico_remote_endpoint *info;
+    info = PICO_ZALLOC(sizeof(struct pico_remote_endpoint));
+    if (!info) {
+        pico_err = PICO_ERR_ENOMEM;
+        return NULL;
     }
 
+    memcpy(info, ep, sizeof(struct pico_remote_endpoint));
+    return info;
+}
+
+static void pico_xmit_frame_set_nofrag(struct pico_frame *f)
+{
+#ifdef PICO_SUPPORT_IPFRAG
+    f->frag = short_be(PICO_IPV4_DONTFRAG);
 #endif
 }
 
-if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
-    s->local_port = pico_socket_high_port(s->proto->proto_number);
-    if (s->local_port == 0) {
-        pico_err = PICO_ERR_EINVAL;
-        return -1;
+static int pico_socket_final_xmit(struct pico_socket *s, struct pico_frame *f)
+{
+    if (s->proto->push(s->proto, f) > 0) {
+        return f->payload_len;
+    } else {
+        pico_frame_discard(f);
+        return 0;
     }
 }
 
-if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
-    s->remote_port = remote_port;
-}
-
-#ifdef PICO_SUPPORT_TCP
-if (PROTO(s) == PICO_PROTO_TCP)
-    header_offset = pico_tcp_overhead(s);
-
-#endif
-
-#ifdef PICO_SUPPORT_UDP
-if (PROTO(s) == PICO_PROTO_UDP)
-    header_offset = sizeof(struct pico_udp_hdr);
+static int pico_socket_xmit_one(struct pico_socket *s, const void *buf, const int len, void *src, struct pico_remote_endpoint *ep)
+{
+    struct pico_frame *f;
+    uint16_t hdr_offset = (uint16_t)pico_socket_sendto_transport_offset(s);
+    int ret = 0;
+    (void)src;
 
-#endif
-
-while (total_payload_written < len) {
-    int transport_len = (len - total_payload_written) + header_offset;
-    if (transport_len > socket_mtu)
-        transport_len = socket_mtu;
-
-    #ifdef PICO_SUPPORT_IPFRAG
-    else {
-        if (total_payload_written)
-            transport_len -= header_offset; /* last fragment, do not allocate memory for transport header */
-
-    }
-#endif /* PICO_SUPPORT_IPFRAG */
-
-    f = pico_socket_frame_alloc(s, (uint16_t)transport_len);
+    f = pico_socket_frame_alloc(s, (uint16_t)(len + hdr_offset));
     if (!f) {
         pico_err = PICO_ERR_ENOMEM;
         return -1;
     }
 
-    f->payload += header_offset;
-    f->payload_len = (uint16_t)(f->payload_len - header_offset);
+    f->payload += hdr_offset;
+    f->payload_len = (uint16_t)(len);
     f->sock = s;
     transport_flags_update(f, s);
-    if (remote_duple) {
-        f->info = pico_zalloc(sizeof(struct pico_remote_duple));
-        memcpy(f->info, remote_duple, sizeof(struct pico_remote_duple));
+    pico_xmit_frame_set_nofrag(f);
+    if (ep) {
+        f->info = pico_socket_set_info(ep);
+        if (!f->info) {
+            pico_frame_discard(f);
+            return -1;
+        }
+    }
+
+    memcpy(f->payload, (const uint8_t *)buf, f->payload_len);
+    /* dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len); */
+    ret = pico_socket_final_xmit(s, f);
+    return ret;
+}
+
+static int pico_socket_xmit_avail_space(struct pico_socket *s);
+
+static void pico_socket_xmit_first_fragment_setup(struct pico_frame *f, int space, int hdr_offset)
+{
+    frag_dbg("FRAG: first fragmented frame %p | len = %u offset = 0\n", f, f->payload_len);
+    /* transport header length field contains total length + header length */
+    f->transport_len = (uint16_t)(space);
+#ifdef PICO_SUPPORT_IPFRAG
+    f->frag = short_be(PICO_IPV4_MOREFRAG);
+#endif
+    f->payload += hdr_offset;
+    f->payload_len = (uint16_t) space;
+}
+
+static void pico_socket_xmit_next_fragment_setup(struct pico_frame *f, int hdr_offset, int total_payload_written, int len)
+{
+    /* no transport header in fragmented IP */
+    f->payload = f->transport_hdr;
+    f->payload_len = (uint16_t)(f->payload_len + hdr_offset);
+    /* set offset in octets */
+#ifdef PICO_SUPPORT_IPFRAG
+    f->frag = short_be((uint16_t)((uint16_t)(total_payload_written + (uint16_t)hdr_offset) >> 3u));
+#endif
+    if (total_payload_written + f->payload_len < len) {
+        frag_dbg("FRAG: intermediate fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
+#ifdef PICO_SUPPORT_IPFRAG
+        f->frag |= short_be(PICO_IPV4_MOREFRAG);
+#endif
+    } else {
+        frag_dbg("FRAG: last fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
+#ifdef PICO_SUPPORT_IPFRAG
+        f->frag &= short_be(PICO_IPV4_FRAG_MASK);
+#endif
+    }
+}
+
+static int pico_socket_xmit_fragments(struct pico_socket *s, const void *buf, const int len, void *src, struct pico_remote_endpoint *ep)
+{
+    int space = pico_socket_xmit_avail_space(s);
+    int hdr_offset = pico_socket_sendto_transport_offset(s);
+    int total_payload_written = 0;
+    struct pico_frame *f = NULL;
+
+    if (space > len) {
+        return pico_socket_xmit_one(s, buf, len, src, ep);
     }
 
-    #ifdef PICO_SUPPORT_IPFRAG
-    #ifdef PICO_SUPPORT_UDP
-    if (PROTO(s) == PICO_PROTO_UDP && ((len + header_offset) > socket_mtu)) {
-        /* hacking way to identify fragmentation frames: payload != transport_hdr -> first frame */
-        if (!total_payload_written) {
-            frag_dbg("FRAG: first fragmented frame %p | len = %u offset = 0\n", f, f->payload_len);
-            /* transport header length field contains total length + header length */
-            f->transport_len = (uint16_t)(len + header_offset);
-            f->frag = short_be(PICO_IPV4_MOREFRAG);
-        } else {
-            /* no transport header in fragmented IP */
-            f->payload = f->transport_hdr;
-            f->payload_len = (uint16_t)(f->payload_len + header_offset);
-            /* set offset in octets */
-            f->frag = short_be((uint16_t)((total_payload_written + header_offset) / 8));
-            if (total_payload_written + f->payload_len < len) {
-                frag_dbg("FRAG: intermediate fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
-                f->frag |= short_be(PICO_IPV4_MOREFRAG);
-            } else {
-                frag_dbg("FRAG: last fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
-                f->frag &= short_be(PICO_IPV4_FRAG_MASK);
+#ifdef PICO_SUPPORT_IPFRAG
+    while(total_payload_written < len) {
+        /* Always allocate the max space available: space + offset */
+        if (len < space)
+            space = len;
+
+        f = pico_socket_frame_alloc(s, (uint16_t)(space + hdr_offset));
+        if (!f) {
+            pico_err = PICO_ERR_ENOMEM;
+            pico_endpoint_free(ep);
+            return -1;
+        }
+
+        f->sock = s;
+        if (ep) {
+            f->info = pico_socket_set_info(ep);
+            if (!f->info) {
+                pico_frame_discard(f);
+                pico_endpoint_free(ep);
+                return -1;
             }
         }
-    } else {
-        f->frag = short_be(PICO_IPV4_DONTFRAG);
+
+        if (!total_payload_written == 0) {
+            /* First fragment: no payload written yet! */
+            pico_socket_xmit_first_fragment_setup(f, space, hdr_offset);
+        } else {
+            /* Next fragment */
+            pico_socket_xmit_next_fragment_setup(f, hdr_offset, total_payload_written, len);
+        }
+
+        memcpy(f->payload, (const uint8_t *)buf + total_payload_written, f->payload_len);
+        transport_flags_update(f, s);
+        if (s->proto->push(s->proto, f) > 0) {
+            total_payload_written += f->payload_len;
+        } else {
+            pico_frame_discard(f);
+            break;
+        }
+    } /* while() */
+    pico_endpoint_free(ep);
+    return total_payload_written;
+
+#else
+    /* Careful with that axe, Eugene!
+     *
+     * cropping down datagrams to the MTU value.
+     */
+    (void) f;
+    (void) hdr_offset;
+    (void) total_payload_written;
+    return pico_socket_xmit_one(s, buf, space, src, ep);
+
+#endif
+}
+
+uint16_t pico_socket_get_mtu(struct pico_socket *s)
+{
+    (void)s;
+#ifdef PICO_SUPPORT_IPV6
+    if (is_sock_ipv6(s))
+        return PICO_SOCKET6_MTU;
+
+#endif
+    return PICO_SOCKET4_MTU;
+}
+
+
+static int pico_socket_xmit_avail_space(struct pico_socket *s)
+{
+    int transport_len;
+    int header_offset;
+
+#ifdef PICO_SUPPORT_TCP
+    if (PROTO(s) == PICO_PROTO_TCP) {
+        transport_len = pico_tcp_get_socket_mtu(s);
+    } else
+#endif
+    transport_len = pico_socket_get_mtu(s);
+    header_offset = pico_socket_sendto_transport_offset(s);
+    if (header_offset < 0) {
+        pico_err = PICO_ERR_EPROTONOSUPPORT;
+        return -1;
     }
 
-#  endif /* PICO_SUPPORT_UDP */
-#endif /* PICO_SUPPORT_IPFRAG */
+    transport_len -= pico_socket_sendto_transport_offset(s);
+    return transport_len;
+}
+
 
-    if (f->payload_len <= 0) {
-        pico_frame_discard(f);
-        if (remote_duple)
-            pico_free(remote_duple);
+static int pico_socket_xmit(struct pico_socket *s, const void *buf, const int len, void *src, struct pico_remote_endpoint *ep)
+{
+    int space = pico_socket_xmit_avail_space(s);
+    int total_payload_written = 0;
 
-        return total_payload_written;
+    if (space < 0) {
+        pico_err = PICO_ERR_EPROTONOSUPPORT;
+        return -1;
+    }
+
+    if ((PROTO(s) == PICO_PROTO_UDP) && (len > space)) {
+        return pico_socket_xmit_fragments(s, buf, len, src, ep);
     }
 
-    memcpy(f->payload, (const uint8_t *)buf + total_payload_written, f->payload_len);
-    /* dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len); */
+    while (total_payload_written < len) {
+        int w, chunk_len = len - total_payload_written;
+        if (chunk_len > space)
+            chunk_len = space;
+
+        w = pico_socket_xmit_one(s, (const void *)((const uint8_t *)buf + total_payload_written), chunk_len, src, ep);
+        if (w <= 0) {
+            break;
+        }
 
-    if (s->proto->push(s->proto, f) > 0) {
-        total_payload_written += (int)f->payload_len;
-    } else {
-        pico_frame_discard(f);
-        pico_err = PICO_ERR_EAGAIN;
-        break;
+        total_payload_written += w;
+        if (PROTO(s) == PICO_PROTO_UDP) {
+            /* Break after the first datagram sent with at most MTU bytes. */
+            break;
+        }
+    }
+    pico_endpoint_free(ep);
+    return total_payload_written;
+}
+
+static void pico_socket_sendto_set_dport(struct pico_socket *s, uint16_t port)
+{
+    if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
+        s->remote_port = port;
     }
 }
-if (remote_duple)
-    pico_free(remote_duple);
+
+
+int pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port)
+{
+    struct pico_remote_endpoint *remote_endpoint = NULL;
+    void *src = NULL;
+
+
+    if (pico_socket_sendto_initial_checks(s, buf, len, dst, remote_port) < 0)
+        return -1;
+
 
-return total_payload_written;
+    src = pico_socket_sendto_get_src(s, dst);
+    if (!src) {
+        return -1;
+    }
+
+    remote_endpoint = pico_socket_sendto_destination(s, dst, remote_port);
+    if (pico_socket_sendto_set_localport(s) < 0)
+        return -1;
+
+    pico_socket_sendto_set_dport(s, remote_port);
+
+    return pico_socket_xmit(s, buf, len, src, remote_endpoint);
 }
 
 int pico_socket_send(struct pico_socket *s, const void *buf, int len)
@@ -1365,6 +1327,34 @@
 }
 
 
+int pico_socket_getname(struct pico_socket *s, void *local_addr, uint16_t *port, uint16_t *proto)
+{
+
+    if (!s || !local_addr || !port || !proto) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    if (is_sock_ipv4(s)) {
+    #ifdef PICO_SUPPORT_IPV4
+        struct pico_ip4 *ip = (struct pico_ip4 *)local_addr;
+        ip->addr = s->local_addr.ip4.addr;
+        *proto = PICO_PROTO_IPV4;
+    #endif
+    } else if (is_sock_ipv6(s)) {
+    #ifdef PICO_SUPPORT_IPV6
+        struct pico_ip6 *ip = (struct pico_ip6 *)local_addr;
+        memcpy(ip->addr, s->local_addr.ip6.addr, PICO_SIZE_IP6);
+        *proto = PICO_PROTO_IPV6;
+    #endif
+    } else {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+    *port = s->local_port;
+    return 0;
+}
+
 int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port)
 {
     if (!s || !local_addr || !port) {
@@ -1372,7 +1362,8 @@
         return -1;
     }
 
-    if (!is_sock_ipv6(s)) {
+    if (is_sock_ipv4(s)) {
+    #ifdef PICO_SUPPORT_IPV4
         struct pico_ip4 *ip = (struct pico_ip4 *)local_addr;
         if (ip->addr != PICO_IPV4_INADDR_ANY) {
             if (!pico_ipv4_link_find(local_addr)) {
@@ -1380,8 +1371,22 @@
                 return -1;
             }
         }
+
+    #endif
+    } else if (is_sock_ipv6(s)) {
+    #ifdef PICO_SUPPORT_IPV6
+        struct pico_ip6 *ip = (struct pico_ip6 *)local_addr;
+        if (!pico_ipv6_is_unspecified(ip->addr)) {
+            if (!pico_ipv6_link_find(local_addr)) {
+                pico_err = PICO_ERR_EINVAL;
+                return -1;
+            }
+        }
+
+    #endif
     } else {
-        /*... IPv6 */
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
     }
 
 
@@ -1401,23 +1406,25 @@
 
     s->local_port = *port;
 
-    if (is_sock_ipv6(s)) {
-        struct pico_ip6 *ip = (struct pico_ip6 *) local_addr;
-        memcpy(s->local_addr.ip6.addr, ip, PICO_SIZE_IP6);
-        /* XXX: port ipv4 functionality to ipv6 */
-        /* Check for port already in use */
-        if (pico_is_port_free(PROTO(s), *port, &local_addr, s->net)) {
-            pico_err = PICO_ERR_EADDRINUSE;
-            return -1;
-        }
-    } else if (is_sock_ipv4(s)) {
-        struct pico_ip4 *ip = (struct pico_ip4 *) local_addr;
-        s->local_addr.ip4.addr = ip->addr;
+    if (is_sock_ipv4(s)) {
+    #ifdef PICO_SUPPORT_IPV4
+        struct pico_ip4 *ip = (struct pico_ip4 *)local_addr;
+        s->local_addr.ip4 = *ip;
+    #endif
+    } else if (is_sock_ipv6(s)) {
+    #ifdef PICO_SUPPORT_IPV6
+        struct pico_ip6 *ip = (struct pico_ip6 *)local_addr;
+        s->local_addr.ip6 = *ip;
+    #endif
+    } else {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
     }
 
     return pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
 }
 
+
 int pico_socket_connect(struct pico_socket *s, const void *remote_addr, uint16_t remote_port)
 {
     int ret = -1;
@@ -1437,19 +1444,37 @@
         }
     }
 
-    if (is_sock_ipv6(s)) {
-        const struct pico_ip6 *ip = (const struct pico_ip6 *) remote_addr;
-        memcpy(s->remote_addr.ip6.addr, ip, PICO_SIZE_IP6);
-    } else if (is_sock_ipv4(s)) {
-        const struct pico_ip4 *local, *ip = (const struct pico_ip4 *) remote_addr;
-        s->remote_addr.ip4.addr = ip->addr;
+    if (is_sock_ipv4(s)) {
+    #ifdef PICO_SUPPORT_IPV4
+        struct pico_ip4 *local = NULL;
+        const struct pico_ip4 *ip = (const struct pico_ip4 *)remote_addr;
+        s->remote_addr.ip4 = *ip;
         local = pico_ipv4_source_find(ip);
         if (local) {
-            s->local_addr.ip4.addr = local->addr;
+            s->local_addr.ip4 = *local;
         } else {
             pico_err = PICO_ERR_EHOSTUNREACH;
             return -1;
         }
+
+    #endif
+    } else if (is_sock_ipv6(s)) {
+    #ifdef PICO_SUPPORT_IPV6
+        struct pico_ip6 *local = NULL;
+        const struct pico_ip6 *ip = (const struct pico_ip6 *)remote_addr;
+        s->remote_addr.ip6 = *ip;
+        local = pico_ipv6_source_find(ip);
+        if (local) {
+            s->local_addr.ip6 = *local;
+        } else {
+            pico_err = PICO_ERR_EHOSTUNREACH;
+            return -1;
+        }
+
+    #endif
+    } else {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
     }
 
     pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
@@ -1479,6 +1504,7 @@
     return ret;
 }
 
+
 #ifdef PICO_SUPPORT_TCP
 
 int pico_socket_listen(struct pico_socket *s, int backlog)
@@ -1505,15 +1531,10 @@
         return -1;
     }
 
-    if (backlog < 1) {
-        pico_err = PICO_ERR_EINVAL;
-        return -1;
-    }
-
     if (PROTO(s) == PICO_PROTO_TCP)
         pico_socket_alter_state(s, PICO_SOCKET_STATE_TCP_SYN_SENT, 0, PICO_SOCKET_STATE_TCP_LISTEN);
 
-    s->max_backlog = backlog;
+    s->max_backlog = (uint16_t)backlog;
 
     return 0;
 }
@@ -1538,6 +1559,7 @@
     if (TCPSTATE(s) == PICO_SOCKET_STATE_TCP_LISTEN) {
         struct pico_sockport *sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port);
         struct pico_socket *found;
+        uint32_t socklen = sizeof(struct pico_ip4);
         /* If at this point no incoming connection socket is found,
          * the accept call is valid, but no connection is established yet.
          */
@@ -1550,7 +1572,12 @@
                 if ((s == found->parent) && ((found->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) {
                     found->parent = NULL;
                     pico_err = PICO_ERR_NOERR;
-                    memcpy(orig, &found->remote_addr, sizeof(struct pico_ip4));
+                    #ifdef PICO_SUPPORT_IPV6
+                    if (is_sock_ipv6(s))
+                        socklen = sizeof(struct pico_ip6);
+
+                    #endif
+                    memcpy(orig, &found->remote_addr, socklen);
                     *port = found->remote_port;
                     s->number_of_pending_conn--;
                     return found;
@@ -1583,506 +1610,43 @@
 
 #endif
 
-#define PICO_SOCKET_SETOPT_EN(socket, index)  (socket->opt_flags |=  (1 << index))
-#define PICO_SOCKET_SETOPT_DIS(socket, index) (socket->opt_flags &= (uint16_t) ~(1 << index))
 
-#ifdef PICO_SUPPORT_MCAST
-static struct pico_ipv4_link *setopt_multicast_check(struct pico_socket *s, void *value, int alloc, int bysource)
+int pico_socket_setoption(struct pico_socket *s, int option, void *value)
 {
-    struct pico_ip_mreq *mreq = NULL;
-    struct pico_ipv4_link *mcast_link = NULL;
-    struct pico_ip_mreq_source *mreq_src = NULL;
 
-    if (!value) {
+    if (s == NULL) {
         pico_err = PICO_ERR_EINVAL;
-        return NULL;
+        return -1;
     }
 
-    if (!bysource) {
-        mreq = (struct pico_ip_mreq *) value;
-        mcast_link = pico_socket_setoption_mcastargs_validation(mreq, NULL);
-        if (!mreq->mcast_link_addr.addr)
-            mreq->mcast_link_addr.addr = mcast_link->address.addr;
-    } else {
-        mreq_src = (struct pico_ip_mreq_source *) value;
-        mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq_src);
-        if (!mreq_src->mcast_link_addr.addr)
-            mreq_src->mcast_link_addr.addr = mcast_link->address.addr;
-    }
 
-    if (!mcast_link) {
-        pico_err = PICO_ERR_EINVAL;
-        return NULL;
-    }
+    if (PROTO(s) == PICO_PROTO_TCP)
+        return pico_setsockopt_tcp(s, option, value);
+
+    if (PROTO(s) == PICO_PROTO_UDP)
+        return pico_setsockopt_udp(s, option, value);
 
-    if (!s->MCASTListen) { /* No RBTree allocated yet */
-        if (alloc) {
-            s->MCASTListen = pico_zalloc(sizeof(struct pico_tree));
-            if (!s->MCASTListen) {
-                pico_err = PICO_ERR_ENOMEM;
-                return NULL;
-            }
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
 
-            s->MCASTListen->root = &LEAF;
-            s->MCASTListen->compare = mcast_listen_cmp;
-        } else return NULL;
-    }
 
-    return mcast_link;
-}
-#endif
-
-int pico_socket_setoption(struct pico_socket *s, int option, void *value) /* XXX no check against proto (vs setsockopt) or implicit by socket? */
+int pico_socket_getoption(struct pico_socket *s, int option, void *value)
 {
     if (s == NULL) {
         pico_err = PICO_ERR_EINVAL;
         return -1;
     }
 
-    pico_err = PICO_ERR_NOERR;
 
-    switch (option)
-    {
-#ifdef PICO_SUPPORT_TCP
-    case PICO_TCP_NODELAY:
-        if (!value) {
-            pico_err = PICO_ERR_EINVAL;
-            return -1;
-        }
-
-        if (s->proto->proto_number == PICO_PROTO_TCP) {
-            int *val = (int*)value;
-            if (*val > 0) {
-                dbg("setsockopt: Nagle algorithm disabled.\n");
-                PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_TCPNODELAY);
-            } else {
-                dbg("setsockopt: Nagle algorithm enabled.\n");
-                PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_TCPNODELAY);
-            }
-        } else {
-            pico_err = PICO_ERR_EINVAL;
-        }
-
-        break;
-#endif
-
-
-#ifdef PICO_SUPPORT_MCAST
-    case PICO_IP_MULTICAST_IF:
-        pico_err = PICO_ERR_EOPNOTSUPP;
-        return -1;
-
-    case PICO_IP_MULTICAST_TTL:
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            return pico_udp_set_mc_ttl(s, *((uint8_t *) value));
-        }
-
-        break;
-
-    case PICO_IP_MULTICAST_LOOP:
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            switch (*(uint8_t *) value)
-            {
-            case 0:
-                /* do not loop back multicast datagram */
-                PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
-                break;
-
-            case 1:
-                /* do loop back multicast datagram */
-                PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
-                break;
-
-            default:
-                pico_err = PICO_ERR_EINVAL;
-                return -1;
-            }
-        }
-
-        break;
-
-    case PICO_IP_ADD_MEMBERSHIP:
-        /* EXCLUDE mode */
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            int filter_mode;
-            struct pico_mcast_listen *listen;
-            struct pico_ip_mreq *mreq = (struct pico_ip_mreq *)value;
-            struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 1, 0);
-            if (!mcast_link)
-                return -1;
-
-            listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
-            if (listen) {
-                if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
-                    so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
-                    pico_err = PICO_ERR_EINVAL;
-                    return -1;
-                } else {
-                    so_mcast_dbg("pico_socket_setoption: ERROR duplicate PICO_IP_ADD_MEMBERSHIP\n");
-                    pico_err = PICO_ERR_EINVAL;
-                    return -1;
-                }
-            } else {
-                listen = pico_zalloc(sizeof(struct pico_mcast_listen));
-                if (!listen) {
-                    pico_err = PICO_ERR_ENOMEM;
-                    return -1;
-                }
-
-                listen->filter_mode = PICO_IP_MULTICAST_EXCLUDE;
-                listen->mcast_link = mreq->mcast_link_addr;
-                listen->mcast_group = mreq->mcast_group_addr;
-                listen->MCASTSources.root = &LEAF;
-                listen->MCASTSources.compare = mcast_sources_cmp;
-                pico_tree_insert(s->MCASTListen, listen);
-            }
-
-            pico_tree_insert(&MCASTSockets, s);
-            filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
-            if (filter_mode < 0)
-                return -1;
-
-            return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
-        }
-
-        break;
-
-    case PICO_IP_DROP_MEMBERSHIP:
-        /* EXCLUDE mode */
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            int filter_mode = 0;
-            struct pico_mcast_listen *listen;
-            struct pico_ip_mreq *mreq = (struct pico_ip_mreq *)value;
-            struct pico_ip4 *source = NULL;
-            struct pico_tree_node *index, *_tmp;
-            struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 0);
-            if (!mcast_link)
-                return -1;
-
-            listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
-            if (!listen) {
-                so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n");
-                pico_err = PICO_ERR_EADDRNOTAVAIL;
-                return -1;
-            } else {
-                pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
-                {
-                    source = index->keyValue;
-                    pico_tree_delete(&listen->MCASTSources, source);
-                    pico_free(source);
-                }
-                pico_tree_delete(s->MCASTListen, listen);
-                pico_free(listen);
-                if (pico_tree_empty(s->MCASTListen)) {
-                    pico_free(s->MCASTListen);
-                    s->MCASTListen = NULL;
-                    pico_tree_delete(&MCASTSockets, s);
-                }
-            }
-
-            filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
-            if (filter_mode < 0)
-                return -1;
-
-            return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
-        }
-
-        break;
-
-    case PICO_IP_UNBLOCK_SOURCE:
-        /* EXCLUDE mode */
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            int filter_mode = 0;
-            struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
-            struct pico_mcast_listen *listen = NULL;
-            struct pico_ip4 *source = NULL, stest = {
-                0
-            };
-            struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
-            if (!mcast_link)
-                return -1;
-
-            listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
-            if (!listen) {
-                so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
-                pico_err = PICO_ERR_EINVAL;
-                return -1;
-            } else {
-                if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
-                    so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
-                    pico_err = PICO_ERR_EINVAL;
-                    return -1;
-                }
-
-                stest.addr = mreq->mcast_source_addr.addr;
-                source = pico_tree_findKey(&listen->MCASTSources, &stest);
-                if (!source) {
-                    so_mcast_dbg("pico_socket_setoption: ERROR address to unblock not in source list\n");
-                    pico_err = PICO_ERR_EADDRNOTAVAIL;
-                    return -1;
-                } else {
-                    pico_tree_delete(&listen->MCASTSources, source);
-                    pico_free(source);
-                }
-            }
-
-            filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
-            if (filter_mode < 0)
-                return -1;
-
-            return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
-        }
-
-        break;
-
-    case PICO_IP_BLOCK_SOURCE:
-        /* EXCLUDE mode */
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            int filter_mode = 0;
-            struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
-            struct pico_mcast_listen *listen = NULL;
-            struct pico_ip4 *source = NULL, stest = {
-                0
-            };
-            struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
-            if (!mcast_link)
-                return -1;
-
-            listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
-            if (!listen) {
-                dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
-                pico_err = PICO_ERR_EINVAL;
-                return -1;
-            } else {
-                if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
-                    so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
-                    pico_err = PICO_ERR_EINVAL;
-                    return -1;
-                }
+    if (PROTO(s) == PICO_PROTO_TCP)
+        return pico_getsockopt_tcp(s, option, value);
 
-                stest.addr = mreq->mcast_source_addr.addr;
-                source = pico_tree_findKey(&listen->MCASTSources, &stest);
-                if (source) {
-                    so_mcast_dbg("pico_socket_setoption: ERROR address to block already in source list\n");
-                    pico_err = PICO_ERR_EADDRNOTAVAIL;
-                    return -1;
-                } else {
-                    source = pico_zalloc(sizeof(struct pico_ip4));
-                    if (!source) {
-                        pico_err = PICO_ERR_ENOMEM;
-                        return -1;
-                    }
-
-                    source->addr = mreq->mcast_source_addr.addr;
-                    pico_tree_insert(&listen->MCASTSources, source);
-                }
-            }
-
-            filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
-            if (filter_mode < 0)
-                return -1;
-
-            return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
-        }
-
-        break;
-
-    case PICO_IP_ADD_SOURCE_MEMBERSHIP:
-        /* INCLUDE mode */
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            int filter_mode = 0, reference_count = 0;
-            struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
-            struct pico_mcast_listen *listen = NULL;
-            struct pico_ip4 *source = NULL, stest = {
-                0
-            };
-            struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 1, 1);
-            if (!mcast_link)
-                return -1;
-
-            listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
-            if (listen) {
-                if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
-                    so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
-                    pico_err = PICO_ERR_EINVAL;
-                    return -1;
-                }
-
-                stest.addr = mreq->mcast_source_addr.addr;
-                source = pico_tree_findKey(&listen->MCASTSources, &stest);
-                if (source) {
-                    so_mcast_dbg("pico_socket_setoption: ERROR source address to allow already in source list\n");
-                    pico_err = PICO_ERR_EADDRNOTAVAIL;
-                    return -1;
-                } else {
-                    source = pico_zalloc(sizeof(struct pico_ip4));
-                    if (!source) {
-                        pico_err = PICO_ERR_ENOMEM;
-                        return -1;
-                    }
-
-                    source->addr = mreq->mcast_source_addr.addr;
-                    pico_tree_insert(&listen->MCASTSources, source);
-                }
-            } else {
-                listen = pico_zalloc(sizeof(struct pico_mcast_listen));
-                if (!listen) {
-                    pico_err = PICO_ERR_ENOMEM;
-                    return -1;
-                }
-
-                listen->filter_mode = PICO_IP_MULTICAST_INCLUDE;
-                listen->mcast_link = mreq->mcast_link_addr;
-                listen->mcast_group = mreq->mcast_group_addr;
-                listen->MCASTSources.root = &LEAF;
-                listen->MCASTSources.compare = mcast_sources_cmp;
-                source = pico_zalloc(sizeof(struct pico_ip4));
-                if (!source) {
-                    pico_free(listen);
-                    pico_err = PICO_ERR_ENOMEM;
-                    return -1;
-                }
-
-                source->addr = mreq->mcast_source_addr.addr;
-                pico_tree_insert(&listen->MCASTSources, source);
-                pico_tree_insert(s->MCASTListen, listen);
-                reference_count = 1;
-            }
-
-            pico_tree_insert(&MCASTSockets, s);
-            filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
-            if (filter_mode < 0)
-                return -1;
-
-            return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
-        }
-
-        break;
-
-    case PICO_IP_DROP_SOURCE_MEMBERSHIP:
-        /* INCLUDE mode */
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            int filter_mode = 0, reference_count = 0;
-            struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
-            struct pico_mcast_listen *listen = NULL;
-            struct pico_ip4 *source = NULL, stest = {
-                0
-            };
-            struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
-            if (!mcast_link)
-                return -1;
+    if (PROTO(s) == PICO_PROTO_UDP)
+        return pico_getsockopt_udp(s, option, value);
 
-            listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
-            if (!listen) {
-                so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before PICO_IP_ADD_SOURCE_MEMBERSHIP\n");
-                pico_err = PICO_ERR_EADDRNOTAVAIL;
-                return -1;
-            } else {
-                if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
-                    so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
-                    pico_err = PICO_ERR_EINVAL;
-                    return -1;
-                }
-
-                stest.addr = mreq->mcast_source_addr.addr;
-                source = pico_tree_findKey(&listen->MCASTSources, &stest);
-                if (!source) {
-                    so_mcast_dbg("pico_socket_setoption: ERROR address to drop not in source list\n");
-                    pico_err = PICO_ERR_EADDRNOTAVAIL;
-                    return -1;
-                } else {
-                    pico_tree_delete(&listen->MCASTSources, source);
-                    pico_free(source);
-                    if (pico_tree_empty(&listen->MCASTSources)) { /* 1 if empty, 0 otherwise */
-                        reference_count = 1;
-                        pico_tree_delete(s->MCASTListen, listen);
-                        pico_free(listen);
-                        if (pico_tree_empty(s->MCASTListen)) {
-                            pico_free(s->MCASTListen);
-                            s->MCASTListen = NULL;
-                            pico_tree_delete(&MCASTSockets, s);
-                        }
-                    }
-                }
-            }
-
-            filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
-            if (filter_mode < 0)
-                return -1;
-
-            return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
-        }
-
-        break;
-#endif /* PICO_SUPPORT_MCAST */
-
-    default:
-        pico_err = PICO_ERR_EINVAL;
-        return -1;
-    }
-
-    if (pico_err != PICO_ERR_NOERR)
-        return -1;
-    else
-        return 0;
-}
-
-#define PICO_SOCKET_GETOPT(socket, index) ((socket->opt_flags & (1 << index)) != 0)
-
-int pico_socket_getoption(struct pico_socket *s, int option, void *value)
-{
-    if (!s || !value) {
-        pico_err = PICO_ERR_EINVAL;
-        return -1;
-    }
-
-    switch (option)
-    {
-#ifdef PICO_SUPPORT_TCP
-    case PICO_TCP_NODELAY:
-        if (s->proto->proto_number == PICO_PROTO_TCP)
-            /* state of the NODELAY option */
-            *(int *)value = PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_TCPNODELAY);
-        else
-            *(int *)value = 0;
-
-        break;
-#endif
-
-#ifdef PICO_SUPPORT_MCAST
-    case PICO_IP_MULTICAST_IF:
-        pico_err = PICO_ERR_EOPNOTSUPP;
-        return -1;
-
-    case PICO_IP_MULTICAST_TTL:
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            pico_udp_get_mc_ttl(s, (uint8_t *) value);
-        } else {
-            *(uint8_t *)value = 0;
-            pico_err = PICO_ERR_EINVAL;
-            return -1;
-        }
-
-        break;
-
-    case PICO_IP_MULTICAST_LOOP:
-        if (s->proto->proto_number == PICO_PROTO_UDP) {
-            *(uint8_t *)value = PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
-        } else {
-            *(uint8_t *)value = 0;
-            pico_err = PICO_ERR_EINVAL;
-            return -1;
-        }
-
-        break;
-#endif /* PICO_SUPPORT_MCAST */
-
-    default:
-        pico_err = PICO_ERR_EINVAL;
-        return -1;
-    }
-
-    return 0;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
 }
 
 
@@ -2091,13 +1655,12 @@
     if (!s) {
         pico_err = PICO_ERR_EINVAL;
         return -1;
-    } else {
-        /* check if exists in tree */
-        /* See task #178 */
-        if (pico_check_socket(s) != 0) {
-            pico_free(s); /* close socket after bind or connect failed */
-            return 0;
-        }
+    }
+
+    /* Check if the socket has already been closed */
+    if (s->state & PICO_SOCKET_STATE_CLOSED) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
     }
 
 #ifdef PICO_SUPPORT_UDP
@@ -2129,6 +1692,14 @@
 
 int pico_socket_close(struct pico_socket *s)
 {
+    if (!s)
+        return -1;
+#ifdef PICO_SUPPORT_TCP
+    if (PROTO(s) == PICO_PROTO_TCP) {
+        if (pico_tcp_check_listen_close(s) == 0)
+            return 0;
+    }
+#endif
     return pico_socket_shutdown(s, PICO_SHUT_RDWR);
 }
 
@@ -2142,10 +1713,10 @@
     switch (net_hdr->proto)
     {
     case PICO_PROTO_TCP:
-        checksum_invalid = short_be(pico_tcp_checksum_ipv4(f));
+        checksum_invalid = short_be(pico_tcp_checksum(f));
         /* dbg("TCP CRC validation == %u\n", checksum_invalid); */
         if (checksum_invalid) {
-            /* dbg("TCP CRC: validation failed!\n"); */
+            dbg("TCP CRC: validation failed!\n");
             pico_frame_discard(f);
             return 0;
         }
@@ -2155,7 +1726,16 @@
     case PICO_PROTO_UDP:
         udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
         if (short_be(udp_hdr->crc)) {
-            checksum_invalid = short_be(pico_udp_checksum_ipv4(f));
+#ifdef PICO_SUPPORT_IPV4
+            if (IS_IPV4(f))
+                checksum_invalid = short_be(pico_udp_checksum_ipv4(f));
+
+#endif
+#ifdef PICO_SUPPORT_IPV6
+            if (IS_IPV6(f))
+                checksum_invalid = short_be(pico_udp_checksum_ipv6(f));
+
+#endif
             /* dbg("UDP CRC validation == %u\n", checksum_invalid); */
             if (checksum_invalid) {
                 /* dbg("UDP CRC: validation failed!\n"); */
@@ -2202,11 +1782,6 @@
     if (!IS_BCAST(f)) {
         dbg("Socket not found... \n");
         pico_notify_socket_unreachable(f);
-#ifdef PICO_SUPPORT_TCP
-        /* if tcp protocol send RST segment */
-        /* if (self->proto_number == PICO_PROTO_TCP) */
-        /*  pico_tcp_reply_rst(f); */
-#endif
         ret = -1;
         pico_err = PICO_ERR_ENOENT;
     }
@@ -2221,48 +1796,30 @@
 static int checkSocketSanity(struct pico_socket *s)
 {
 
-/* checking for pending connections */
+    /* checking for pending connections */
     if(TCP_STATE(s) == PICO_SOCKET_STATE_TCP_SYN_RECV) {
-        if((pico_time)(PICO_TIME_MS() - s->timestamp) >= PICO_SOCKET_BOUND_TIMEOUT)
+        if((PICO_TIME_MS() - s->timestamp) >= PICO_SOCKET_BOUND_TIMEOUT)
             return -1;
     }
 
-    if((pico_time)(PICO_TIME_MS() - s->timestamp) >= PICO_SOCKET_TIMEOUT) {
+    if((PICO_TIME_MS() - s->timestamp) >= PICO_SOCKET_TIMEOUT) {
         /* checking for hanging sockets */
         if((TCP_STATE(s) != PICO_SOCKET_STATE_TCP_LISTEN) && (TCP_STATE(s) != PICO_SOCKET_STATE_TCP_ESTABLISHED))
             return -1;
-
-        /* if no activity, force the socket into closing state */
-        /* DLA: Why? This seems off-specs. */
-#ifdef TCP_OFF_SPECS
-        if( TCP_STATE(s) == PICO_SOCKET_STATE_TCP_ESTABLISHED )
-        {
-            s->wakeup(PICO_SOCK_EV_CLOSE, s);
-            pico_socket_close(s);
-            s->timestamp = PICO_TIME_MS();
-        }
-
-#endif
     }
 
     return 0;
 }
 #endif
 
-int pico_sockets_loop(int loop_score)
+
+static int pico_sockets_loop_udp(int loop_score)
 {
+
 #ifdef PICO_SUPPORT_UDP
     static struct pico_tree_node *index_udp;
-#endif
-
-#ifdef PICO_SUPPORT_TCP
-    static struct pico_tree_node*index_tcp;
-#endif
-
     struct pico_sockport *start;
     struct pico_socket *s;
-
-#ifdef PICO_SUPPORT_UDP
     struct pico_frame *f;
 
     if (sp_udp == NULL)
@@ -2301,8 +1858,15 @@
             break;
     }
 #endif
+    return loop_score;
+}
 
+static int pico_sockets_loop_tcp(int loop_score)
+{
 #ifdef PICO_SUPPORT_TCP
+    struct pico_sockport *start;
+    struct pico_socket *s;
+    static struct pico_tree_node *index_tcp;
     if (sp_tcp == NULL)
     {
         index_tcp = pico_tree_firstNode(TCPTable.root);
@@ -2354,7 +1918,15 @@
             break;
     }
 #endif
+    return loop_score;
 
+
+}
+
+int pico_sockets_loop(int loop_score)
+{
+    loop_score = pico_sockets_loop_udp(loop_score);
+    loop_score = pico_sockets_loop_tcp(loop_score);
     return loop_score;
 }
 
@@ -2364,14 +1936,14 @@
     struct pico_frame *f = NULL;
 
 #ifdef PICO_SUPPORT_IPV6
-    if (IS_SOCK_IPV6(s))
+    if (is_sock_ipv6(s))
         f = pico_proto_ipv6.alloc(&pico_proto_ipv6, len);
 
 #endif
 
 #ifdef PICO_SUPPORT_IPV4
-    if (IS_SOCK_IPV4(s))
-        f = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t)len);
+    if (is_sock_ipv4(s))
+        f = pico_proto_ipv4.alloc(&pico_proto_ipv4, len);
 
 #endif
     if (!f) {
@@ -2385,6 +1957,48 @@
     return f;
 }
 
+static void pico_transport_error_set_picoerr(int code)
+{
+    /* dbg("SOCKET ERROR FROM ICMP NOTIFICATION. (icmp code= %d)\n\n", code); */
+    switch(code) {
+    case PICO_ICMP_UNREACH_NET:
+        pico_err = PICO_ERR_ENETUNREACH;
+        break;
+
+    case PICO_ICMP_UNREACH_HOST:
+        pico_err = PICO_ERR_EHOSTUNREACH;
+        break;
+
+    case PICO_ICMP_UNREACH_PROTOCOL:
+        pico_err = PICO_ERR_ENOPROTOOPT;
+        break;
+
+    case PICO_ICMP_UNREACH_PORT:
+        pico_err = PICO_ERR_ECONNREFUSED;
+        break;
+
+    case PICO_ICMP_UNREACH_NET_UNKNOWN:
+        pico_err = PICO_ERR_ENETUNREACH;
+        break;
+
+    case PICO_ICMP_UNREACH_HOST_UNKNOWN:
+        pico_err = PICO_ERR_EHOSTDOWN;
+        break;
+
+    case PICO_ICMP_UNREACH_ISOLATED:
+        pico_err = PICO_ERR_ENONET;
+        break;
+
+    case PICO_ICMP_UNREACH_NET_PROHIB:
+    case PICO_ICMP_UNREACH_HOST_PROHIB:
+        pico_err = PICO_ERR_EHOSTUNREACH;
+        break;
+
+    default:
+        pico_err = PICO_ERR_EOPNOTSUPP;
+    }
+}
+
 int pico_transport_error(struct pico_frame *f, uint8_t proto, int code)
 {
     int ret = -1;
@@ -2418,35 +2032,9 @@
             s = index->keyValue;
             if (trans->dport == s->remote_port) {
                 if (s->wakeup) {
-                    /* dbg("SOCKET ERROR FROM ICMP NOTIFICATION. (icmp code= %d)\n\n", code); */
-                    switch(code) {
-                    case PICO_ICMP_UNREACH_NET:
-                        pico_err = PICO_ERR_ENETUNREACH;
-                        break;
-
-                    case PICO_ICMP_UNREACH_HOST:
-                        pico_err = PICO_ERR_EHOSTUNREACH;
-                        break;
-
-                    case PICO_ICMP_UNREACH_PROTOCOL:
-                        pico_err = PICO_ERR_ENOPROTOOPT;
-                        break;
-
-                    case PICO_ICMP_UNREACH_PORT:
-                        pico_err = PICO_ERR_ECONNREFUSED;
-                        break;
-
-                    case PICO_ICMP_UNREACH_NET_PROHIB:
-                    case PICO_ICMP_UNREACH_NET_UNKNOWN:
-                        pico_err = PICO_ERR_ENETUNREACH;
-                        break;
-
-                    default:
-                        pico_err = PICO_ERR_EOPNOTSUPP;
-                    }
+                    pico_transport_error_set_picoerr(code);
                     s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
                     s->wakeup(PICO_SOCK_EV_ERR, s);
-
                 }
 
                 break;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stack/pico_socket_multicast.c	Wed Apr 09 14:31:41 2014 +0200
@@ -0,0 +1,944 @@
+#include <stdint.h>
+#include "pico_socket.h"
+#include "pico_socket_multicast.h"
+#include "pico_tree.h"
+#include "pico_ipv4.h"
+#include "pico_udp.h"
+
+#ifdef PICO_SUPPORT_MCAST
+# define so_mcast_dbg(...) do {} while(0) /* ip_mcast_dbg in pico_ipv4.c */
+/* #define so_mcast_dbg dbg */
+
+/*                       socket
+ *                         |
+ *                    MCASTListen
+ *                    |    |     |
+ *         ------------    |     ------------
+ *         |               |                |
+ *   MCASTSources    MCASTSources     MCASTSources
+ *   |  |  |  |      |  |  |  |       |  |  |  |
+ *   S  S  S  S      S  S  S  S       S  S  S  S
+ *
+ *   MCASTListen: RBTree(mcast_link, mcast_group)
+ *   MCASTSources: RBTree(source)
+ */
+struct pico_mcast_listen
+{
+    uint8_t filter_mode;
+    union pico_address mcast_link;
+    union pico_address mcast_group;
+    struct pico_tree MCASTSources;
+};
+
+static int mcast_listen_link_cmp(struct pico_mcast_listen *a, struct pico_mcast_listen *b)
+{
+    /* TODO: IPv6 */
+    if (a->mcast_link.ip4.addr < b->mcast_link.ip4.addr)
+        return -1;
+
+    /* TODO: IPv6 */
+    if (a->mcast_link.ip4.addr > b->mcast_link.ip4.addr)
+        return 1;
+
+    return 0;
+}
+
+static int mcast_listen_cmp(void *ka, void *kb)
+{
+    struct pico_mcast_listen *a = ka, *b = kb;
+    if (a->mcast_group.ip4.addr < b->mcast_group.ip4.addr)
+        return -1;
+
+    if (a->mcast_group.ip4.addr > b->mcast_group.ip4.addr)
+        return 1;
+
+    return mcast_listen_link_cmp(a, b);
+
+}
+
+static int mcast_sources_cmp(void *ka, void *kb)
+{
+    union pico_address *a = ka, *b = kb;
+    if (a->ip4.addr < b->ip4.addr)
+        return -1;
+
+    if (a->ip4.addr > b->ip4.addr)
+        return 1;
+
+    return 0;
+}
+
+static int mcast_socket_cmp(void *ka, void *kb)
+{
+    struct pico_socket *a = ka, *b = kb;
+    if (a < b)
+        return -1;
+
+    if (a > b)
+        return 1;
+
+    return 0;
+}
+
+/* gather all multicast sockets to hasten filter aggregation */
+PICO_TREE_DECLARE(MCASTSockets, mcast_socket_cmp);
+
+static int mcast_filter_cmp(void *ka, void *kb)
+{
+    union pico_address *a = ka, *b = kb;
+    if (a->ip4.addr < b->ip4.addr)
+        return -1;
+
+    if (a->ip4.addr > b->ip4.addr)
+        return 1;
+
+    return 0;
+}
+/* gather sources to be filtered */
+PICO_TREE_DECLARE(MCASTFilter, mcast_filter_cmp);
+
+static struct pico_mcast_listen *listen_find(struct pico_socket *s, union pico_address *lnk, union pico_address *grp)
+{
+    struct pico_mcast_listen ltest = {
+        0
+    };
+    ltest.mcast_link.ip4.addr = lnk->ip4.addr;
+    ltest.mcast_group.ip4.addr = grp->ip4.addr;
+    return pico_tree_findKey(s->MCASTListen, &ltest);
+}
+
+static uint8_t pico_mcast_filter_excl_excl(struct pico_mcast_listen *listen)
+{
+    /* filter = intersection of EXCLUDEs */
+    /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
+    /* remove from the interface EXCLUDE filter any source not in the socket EXCLUDE filter */
+    struct pico_tree_node *index = NULL, *_tmp = NULL;
+    union pico_address *source = NULL;
+    pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
+    {
+        source = pico_tree_findKey(&listen->MCASTSources, index->keyValue);
+        if (!source)
+            pico_tree_delete(&MCASTFilter, index->keyValue);
+    }
+    return PICO_IP_MULTICAST_EXCLUDE;
+}
+
+static uint8_t pico_mcast_filter_excl_incl(struct pico_mcast_listen *listen)
+{
+    /* filter = EXCLUDE - INCLUDE */
+    /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
+    /* remove from the interface EXCLUDE filter any source in the socket INCLUDE filter */
+    struct pico_tree_node *index = NULL, *_tmp = NULL;
+    union pico_address *source = NULL;
+    pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
+    {
+        source = pico_tree_findKey(&MCASTFilter, index->keyValue);
+        if (source)
+            pico_tree_delete(&MCASTFilter, source);
+    }
+    return PICO_IP_MULTICAST_EXCLUDE;
+}
+
+static uint8_t pico_mcast_filter_incl_excl(struct pico_mcast_listen *listen)
+{
+    /* filter = EXCLUDE - INCLUDE */
+    /* delete from the interface INCLUDE filter any source NOT in the socket EXCLUDE filter */
+    struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
+    union pico_address *source = NULL;
+    pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
+    {
+        source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
+        if (!source)
+            pico_tree_delete(&MCASTFilter, index2->keyValue);
+    }
+    /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
+
+    /* add to the interface EXCLUDE filter any socket source NOT in the former interface INCLUDE filter */
+    pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
+    {
+        source = pico_tree_insert(&MCASTFilter, index->keyValue);
+        if (source)
+            pico_tree_delete(&MCASTFilter, source);
+    }
+    return PICO_IP_MULTICAST_EXCLUDE;
+}
+
+static uint8_t pico_mcast_filter_incl_incl(struct pico_mcast_listen *listen)
+{
+    /* filter = summation of INCLUDEs */
+    /* mode stays INCLUDE, add all sources to filter */
+    struct pico_tree_node *index = NULL, *_tmp = NULL;
+    union pico_address *source = NULL;
+    pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
+    {
+        source = index->keyValue;
+        pico_tree_insert(&MCASTFilter, source);
+    }
+    return PICO_IP_MULTICAST_INCLUDE;
+}
+
+struct pico_mcast_filter_aggregation
+{
+    uint8_t (*call)(struct pico_mcast_listen *);
+};
+
+static const struct pico_mcast_filter_aggregation mcast_filter_aggr_call[2][2] =
+{
+    {
+        /* EXCL + EXCL */ {.call = pico_mcast_filter_excl_excl},
+        /* EXCL + INCL */ {.call = pico_mcast_filter_excl_incl}
+    },
+
+    {
+        /* INCL + EXCL */ {.call = pico_mcast_filter_incl_excl},
+        /* INCL + INCL */ {.call = pico_mcast_filter_incl_incl}
+    }
+};
+
+static int mcast_aggr_validate(uint8_t fm, struct pico_mcast_listen *l)
+{
+    if (!l)
+        return -1;
+
+    if (fm > 1)
+        return -1;
+
+    if (l->filter_mode > 1)
+        return -1;
+
+    return 0;
+}
+
+
+/* MCASTFilter will be empty if no socket is listening on mcast_group on mcast_link anymore */
+static int pico_socket_aggregate_mcastfilters(union pico_address *mcast_link, union pico_address *mcast_group)
+{
+    uint8_t filter_mode = PICO_IP_MULTICAST_INCLUDE;
+    struct pico_mcast_listen *listen = NULL;
+    struct pico_socket *mcast_sock = NULL;
+    struct pico_tree_node *index = NULL, *_tmp = NULL;
+
+
+    /* cleanup old filter */
+    pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
+    {
+        pico_tree_delete(&MCASTFilter, index->keyValue);
+    }
+
+    /* construct new filter */
+    pico_tree_foreach_safe(index, &MCASTSockets, _tmp)
+    {
+        mcast_sock = index->keyValue;
+        listen = listen_find(mcast_sock, mcast_link, mcast_group);
+        if (listen) {
+            if (mcast_aggr_validate(filter_mode, listen) < 0) {
+                pico_err = PICO_ERR_EINVAL;
+                return -1;
+            }
+
+            if (mcast_filter_aggr_call[filter_mode][listen->filter_mode].call) {
+                filter_mode = mcast_filter_aggr_call[filter_mode][listen->filter_mode].call(listen);
+                if (filter_mode > 1)
+                    return -1;
+            }
+        }
+    }
+    return filter_mode;
+}
+
+static int pico_socket_mcast_filter_include(struct pico_mcast_listen *listen, union pico_address *src)
+{
+    struct pico_tree_node *index = NULL;
+    pico_tree_foreach(index, &listen->MCASTSources)
+    {
+        if (src->ip4.addr == ((union pico_address *)index->keyValue)->ip4.addr) {
+            so_mcast_dbg("MCAST: IP %08X in included socket source list\n", src->ip4.addr);
+            return 0;
+        }
+    }
+    so_mcast_dbg("MCAST: IP %08X NOT in included socket source list\n", src->ip4.addr);
+    return -1;
+
+}
+
+static int pico_socket_mcast_filter_exclude(struct pico_mcast_listen *listen, union pico_address *src)
+{
+    struct pico_tree_node *index = NULL;
+    pico_tree_foreach(index, &listen->MCASTSources)
+    {
+        if (src->ip4.addr == ((union pico_address *)index->keyValue)->ip4.addr) {
+            so_mcast_dbg("MCAST: IP %08X in excluded socket source list\n", src->ip4.addr);
+            return -1;
+        }
+    }
+    so_mcast_dbg("MCAST: IP %08X NOT in excluded socket source list\n", src->ip4.addr);
+    return 0;
+}
+
+static int pico_socket_mcast_source_filtering(struct pico_mcast_listen *listen, union pico_address *src)
+{
+    /* perform source filtering */
+    if (listen->filter_mode == PICO_IP_MULTICAST_INCLUDE)
+        return pico_socket_mcast_filter_include(listen, src);
+
+    if (listen->filter_mode == PICO_IP_MULTICAST_EXCLUDE)
+        return pico_socket_mcast_filter_exclude(listen, src);
+
+    return -1;
+}
+
+static struct pico_ipv4_link *pico_socket_mcast_filter_link_get(struct pico_socket *s)
+{
+    /* check if no multicast enabled on socket */
+    if (!s->MCASTListen)
+        return NULL;
+
+    return pico_ipv4_link_get(&s->local_addr.ip4);
+}
+
+int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src)
+{
+    struct pico_ipv4_link *mcast_link = NULL;
+    struct pico_mcast_listen *listen = NULL;
+
+    mcast_link = pico_socket_mcast_filter_link_get(s);
+    if (!mcast_link)
+        return -1;
+
+    listen = listen_find(s, (union pico_address *)&mcast_link->address, mcast_group);
+    if (!listen)
+        return -1;
+
+    return pico_socket_mcast_source_filtering(listen, src);
+}
+
+static struct pico_ipv4_link *get_mcast_link(union pico_address *a)
+{
+    if (!a->ip4.addr)
+        return pico_ipv4_get_default_mcastlink();
+
+    return pico_ipv4_link_get(&a->ip4);
+}
+
+
+static int pico_socket_setoption_pre_validation(struct pico_ip_mreq *mreq)
+{
+    if (!mreq)
+        return -1;
+
+    if (!mreq->mcast_group_addr.addr)
+        return -1;
+
+    return 0;
+}
+
+static struct pico_ipv4_link *pico_socket_setoption_validate_mreq(struct pico_ip_mreq *mreq)
+{
+    if (pico_socket_setoption_pre_validation(mreq) < 0)
+        return NULL;
+
+    if (pico_ipv4_is_unicast(mreq->mcast_group_addr.addr))
+        return NULL;
+
+    return get_mcast_link((union pico_address *)&mreq->mcast_link_addr);
+}
+
+static int pico_socket_setoption_pre_validation_s(struct pico_ip_mreq_source *mreq)
+{
+    if (!mreq)
+        return -1;
+
+    if (!mreq->mcast_group_addr.addr)
+        return -1;
+
+    return 0;
+}
+
+static struct pico_ipv4_link *pico_socket_setoption_validate_s_mreq(struct pico_ip_mreq_source *mreq)
+{
+    if (pico_socket_setoption_pre_validation_s(mreq) < 0)
+        return NULL;
+
+    if (pico_ipv4_is_unicast(mreq->mcast_group_addr.addr))
+        return NULL;
+
+    if (!pico_ipv4_is_unicast(mreq->mcast_source_addr.addr))
+        return NULL;
+
+    return get_mcast_link((union pico_address *)&mreq->mcast_link_addr);
+}
+
+
+static struct pico_ipv4_link *setop_multicast_link_search(void *value, int bysource)
+{
+
+    struct pico_ip_mreq *mreq = NULL;
+    struct pico_ipv4_link *mcast_link = NULL;
+    struct pico_ip_mreq_source *mreq_src = NULL;
+    if (!bysource) {
+        mreq = (struct pico_ip_mreq *) value;
+        mcast_link = pico_socket_setoption_validate_mreq(mreq);
+        if (!mcast_link)
+            return NULL;
+
+        if (!mreq->mcast_link_addr.addr)
+            mreq->mcast_link_addr.addr = mcast_link->address.addr;
+    } else {
+        mreq_src = (struct pico_ip_mreq_source *) value;
+        if (!mreq_src)
+            return NULL;
+
+        mcast_link = pico_socket_setoption_validate_s_mreq(mreq_src);
+        if (!mcast_link)
+            return NULL;
+
+        if (!mreq_src->mcast_link_addr.addr)
+            mreq_src->mcast_link_addr.addr = mcast_link->address.addr;
+    }
+
+    return mcast_link;
+}
+
+static int setop_verify_listen_tree(struct pico_socket *s, int alloc)
+{
+    if(!alloc)
+        return -1;
+
+    s->MCASTListen = PICO_ZALLOC(sizeof(struct pico_tree));
+    if (!s->MCASTListen) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
+    s->MCASTListen->root = &LEAF;
+    s->MCASTListen->compare = mcast_listen_cmp;
+    return 0;
+}
+
+
+static struct pico_ipv4_link *setopt_multicast_check(struct pico_socket *s, void *value, int alloc, int bysource)
+{
+    struct pico_ipv4_link *mcast_link = NULL;
+
+    if (!value) {
+        pico_err = PICO_ERR_EINVAL;
+        return NULL;
+    }
+
+    mcast_link = setop_multicast_link_search(value, bysource);
+
+    if (!mcast_link) {
+        pico_err = PICO_ERR_EINVAL;
+        return NULL;
+    }
+
+    if (!s->MCASTListen) { /* No RBTree allocated yet */
+        if (setop_verify_listen_tree(s, alloc) < 0)
+            return NULL;
+    }
+
+    return mcast_link;
+}
+
+
+void pico_multicast_delete(struct pico_socket *s)
+{
+    int filter_mode;
+    struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
+    struct pico_mcast_listen *listen = NULL;
+    union pico_address *source = NULL;
+    if (s->MCASTListen) {
+        pico_tree_delete(&MCASTSockets, s);
+        pico_tree_foreach_safe(index, s->MCASTListen, _tmp)
+        {
+            listen = index->keyValue;
+            pico_tree_foreach_safe(index2, &listen->MCASTSources, _tmp2)
+            {
+                source = index->keyValue;
+                pico_tree_delete(&listen->MCASTSources, source);
+                PICO_FREE(source);
+            }
+            filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&listen->mcast_link, (union pico_address *)&listen->mcast_group);
+            if (filter_mode >= 0)
+                pico_ipv4_mcast_leave(&listen->mcast_link.ip4, &listen->mcast_group.ip4, 1, (uint8_t)filter_mode, &MCASTFilter);
+
+            pico_tree_delete(s->MCASTListen, listen);
+            PICO_FREE(listen);
+        }
+        PICO_FREE(s->MCASTListen);
+    }
+}
+
+
+int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value)
+{
+    switch(option) {
+    case PICO_IP_MULTICAST_IF:
+        pico_err = PICO_ERR_EOPNOTSUPP;
+        return -1;
+
+    case PICO_IP_MULTICAST_TTL:
+        if (s->proto->proto_number == PICO_PROTO_UDP) {
+            pico_udp_get_mc_ttl(s, (uint8_t *) value);
+        } else {
+            *(uint8_t *)value = 0;
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+
+        break;
+
+    case PICO_IP_MULTICAST_LOOP:
+        if (s->proto->proto_number == PICO_PROTO_UDP) {
+            *(uint8_t *)value = (uint8_t)PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
+        } else {
+            *(uint8_t *)value = 0;
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+
+        break;
+    default:
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    return 0;
+}
+
+static int mcast_so_loop(struct pico_socket *s, void *value)
+{
+    uint8_t val = (*(uint8_t *)value);
+    if (val == 0u) {
+        PICO_SOCKET_SETOPT_DIS(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
+        return 0;
+    } else if (val == 1u) {
+        PICO_SOCKET_SETOPT_EN(s, PICO_SOCKET_OPT_MULTICAST_LOOP);
+        return 0;
+    }
+
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+}
+
+static int mcast_so_addm(struct pico_socket *s, void *value)
+{
+    int filter_mode;
+    struct pico_mcast_listen *listen;
+    struct pico_ip_mreq *mreq = (struct pico_ip_mreq *)value;
+    struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 1, 0);
+    if (!mcast_link)
+        return -1;
+
+    listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *)&mreq->mcast_group_addr);
+    if (listen) {
+        if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
+            so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        } else {
+            so_mcast_dbg("pico_socket_setoption: ERROR duplicate PICO_IP_ADD_MEMBERSHIP\n");
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+    } else {
+        listen = PICO_ZALLOC(sizeof(struct pico_mcast_listen));
+        if (!listen) {
+            pico_err = PICO_ERR_ENOMEM;
+            return -1;
+        }
+
+        listen->filter_mode = PICO_IP_MULTICAST_EXCLUDE;
+        listen->mcast_link.ip4 = mreq->mcast_link_addr;
+        listen->mcast_group.ip4 = mreq->mcast_group_addr;
+        listen->MCASTSources.root = &LEAF;
+        listen->MCASTSources.compare = mcast_sources_cmp;
+        pico_tree_insert(s->MCASTListen, listen);
+    }
+
+    pico_tree_insert(&MCASTSockets, s);
+    filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
+    if (filter_mode < 0)
+        return -1;
+
+    so_mcast_dbg("PICO_IP_ADD_MEMBERSHIP - success, added %p\n", s);
+    return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
+}
+
+static int mcast_so_dropm(struct pico_socket *s, void *value)
+{
+    int filter_mode = 0;
+    struct pico_mcast_listen *listen;
+    struct pico_ip_mreq *mreq = (struct pico_ip_mreq *)value;
+    union pico_address *source = NULL;
+    struct pico_tree_node *index, *_tmp;
+    struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 0);
+    if (!mcast_link)
+        return -1;
+
+    listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *)&mreq->mcast_group_addr);
+    if (!listen) {
+        so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n");
+        pico_err = PICO_ERR_EADDRNOTAVAIL;
+        return -1;
+    } else {
+        pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
+        {
+            source = index->keyValue;
+            pico_tree_delete(&listen->MCASTSources, source);
+            PICO_FREE(source);
+        }
+        pico_tree_delete(s->MCASTListen, listen);
+        PICO_FREE(listen);
+        if (pico_tree_empty(s->MCASTListen)) {
+            PICO_FREE(s->MCASTListen);
+            s->MCASTListen = NULL;
+            pico_tree_delete(&MCASTSockets, s);
+        }
+    }
+
+    filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
+    if (filter_mode < 0)
+        return -1;
+
+    return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
+}
+
+static int mcast_so_unblock_src(struct pico_socket *s, void *value)
+{
+    int filter_mode = 0;
+    struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
+    struct pico_mcast_listen *listen = NULL;
+    union pico_address *source = NULL, stest;
+    struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
+
+    memset(&stest, 0, sizeof(union pico_address));
+    if (!mcast_link)
+        return -1;
+
+
+    listen = listen_find(s, (union pico_address *) &mreq->mcast_link_addr, (union pico_address *) &mreq->mcast_group_addr);
+    if (!listen) {
+        so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    } else {
+        if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
+            so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+
+        stest.ip4.addr = mreq->mcast_source_addr.addr;
+        source = pico_tree_findKey(&listen->MCASTSources, &stest);
+        if (!source) {
+            so_mcast_dbg("pico_socket_setoption: ERROR address to unblock not in source list\n");
+            pico_err = PICO_ERR_EADDRNOTAVAIL;
+            return -1;
+        } else {
+            pico_tree_delete(&listen->MCASTSources, source);
+            PICO_FREE(source);
+        }
+    }
+
+    filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
+    if (filter_mode < 0)
+        return -1;
+
+    return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
+}
+
+static int mcast_so_block_src(struct pico_socket *s, void *value)
+{
+    int filter_mode = 0;
+    struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
+    struct pico_mcast_listen *listen;
+    union pico_address *source, stest;
+    struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
+    if (!mcast_link)
+        return -1;
+
+    memset(&stest, 0, sizeof(union pico_address));
+
+    listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *)&mreq->mcast_group_addr);
+    if (!listen) {
+        dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    } else {
+        if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
+            so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+
+        stest.ip4.addr = mreq->mcast_source_addr.addr;
+        source = pico_tree_findKey(&listen->MCASTSources, &stest);
+        if (source) {
+            so_mcast_dbg("pico_socket_setoption: ERROR address to block already in source list\n");
+            pico_err = PICO_ERR_EADDRNOTAVAIL;
+            return -1;
+        } else {
+            source = PICO_ZALLOC(sizeof(union pico_address));
+            if (!source) {
+                pico_err = PICO_ERR_ENOMEM;
+                return -1;
+            }
+
+            source->ip4.addr = mreq->mcast_source_addr.addr;
+            pico_tree_insert(&listen->MCASTSources, source);
+        }
+    }
+
+    filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
+    if (filter_mode < 0)
+        return -1;
+
+    return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
+}
+
+static int mcast_so_addsrcm(struct pico_socket *s, void *value)
+{
+    int filter_mode = 0, reference_count = 0;
+    struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
+    struct pico_mcast_listen *listen = NULL;
+    union pico_address *source = NULL, stest;
+    struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 1, 1);
+    if (!mcast_link)
+        return -1;
+
+    memset(&stest, 0, sizeof(union pico_address));
+
+    listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *) &mreq->mcast_group_addr);
+    if (listen) {
+        if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
+            so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+
+        stest.ip4.addr = mreq->mcast_source_addr.addr;
+        source = pico_tree_findKey(&listen->MCASTSources, &stest);
+        if (source) {
+            so_mcast_dbg("pico_socket_setoption: ERROR source address to allow already in source list\n");
+            pico_err = PICO_ERR_EADDRNOTAVAIL;
+            return -1;
+        } else {
+            source = PICO_ZALLOC(sizeof(union pico_address));
+            if (!source) {
+                pico_err = PICO_ERR_ENOMEM;
+                return -1;
+            }
+
+            source->ip4.addr = mreq->mcast_source_addr.addr;
+            pico_tree_insert(&listen->MCASTSources, source);
+        }
+    } else {
+        listen = PICO_ZALLOC(sizeof(struct pico_mcast_listen));
+        if (!listen) {
+            pico_err = PICO_ERR_ENOMEM;
+            return -1;
+        }
+
+        listen->filter_mode = PICO_IP_MULTICAST_INCLUDE;
+        listen->mcast_link.ip4 = mreq->mcast_link_addr;
+        listen->mcast_group.ip4 = mreq->mcast_group_addr;
+        listen->MCASTSources.root = &LEAF;
+        listen->MCASTSources.compare = mcast_sources_cmp;
+        source = PICO_ZALLOC(sizeof(union pico_address));
+        if (!source) {
+            PICO_FREE(listen);
+            pico_err = PICO_ERR_ENOMEM;
+            return -1;
+        }
+
+        source->ip4.addr = mreq->mcast_source_addr.addr;
+        pico_tree_insert(&listen->MCASTSources, source);
+        pico_tree_insert(s->MCASTListen, listen);
+        reference_count = 1;
+    }
+
+    pico_tree_insert(&MCASTSockets, s);
+    filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
+    if (filter_mode < 0)
+        return -1;
+
+    return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
+}
+
+static int mcast_so_dropsrcm(struct pico_socket *s, void *value)
+{
+    int filter_mode = 0, reference_count = 0;
+    struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
+    struct pico_mcast_listen *listen;
+    union pico_address *source, stest;
+    struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
+    if (!mcast_link)
+        return -1;
+
+    memset(&stest, 0, sizeof(union pico_address));
+
+    listen = listen_find(s, (union pico_address *)&mreq->mcast_link_addr, (union pico_address *)&mreq->mcast_group_addr);
+    if (!listen) {
+        so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before PICO_IP_ADD_SOURCE_MEMBERSHIP\n");
+        pico_err = PICO_ERR_EADDRNOTAVAIL;
+        return -1;
+    } else {
+        if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
+            so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+
+        stest.ip4.addr = mreq->mcast_source_addr.addr;
+        source = pico_tree_findKey(&listen->MCASTSources, &stest);
+        if (!source) {
+            so_mcast_dbg("pico_socket_setoption: ERROR address to drop not in source list\n");
+            pico_err = PICO_ERR_EADDRNOTAVAIL;
+            return -1;
+        } else {
+            pico_tree_delete(&listen->MCASTSources, source);
+            PICO_FREE(source);
+            if (pico_tree_empty(&listen->MCASTSources)) { /* 1 if empty, 0 otherwise */
+                reference_count = 1;
+                pico_tree_delete(s->MCASTListen, listen);
+                PICO_FREE(listen);
+                if (pico_tree_empty(s->MCASTListen)) {
+                    PICO_FREE(s->MCASTListen);
+                    s->MCASTListen = NULL;
+                    pico_tree_delete(&MCASTSockets, s);
+                }
+            }
+        }
+    }
+
+    filter_mode = pico_socket_aggregate_mcastfilters((union pico_address *)&mcast_link->address, (union pico_address *)&mreq->mcast_group_addr);
+    if (filter_mode < 0)
+        return -1;
+
+    return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
+}
+
+struct pico_setsockopt_mcast_call
+{
+    int option;
+    int (*call)(struct pico_socket *, void *);
+};
+
+static const struct pico_setsockopt_mcast_call mcast_so_calls[1 + PICO_IP_DROP_SOURCE_MEMBERSHIP - PICO_IP_MULTICAST_IF] =
+{
+    { PICO_IP_MULTICAST_IF,             NULL },
+    { PICO_IP_MULTICAST_TTL,            pico_udp_set_mc_ttl },
+    { PICO_IP_MULTICAST_LOOP,           mcast_so_loop },
+    { PICO_IP_ADD_MEMBERSHIP,           mcast_so_addm },
+    { PICO_IP_DROP_MEMBERSHIP,          mcast_so_dropm },
+    { PICO_IP_UNBLOCK_SOURCE,           mcast_so_unblock_src },
+    { PICO_IP_BLOCK_SOURCE,             mcast_so_block_src },
+    { PICO_IP_ADD_SOURCE_MEMBERSHIP,    mcast_so_addsrcm },
+    { PICO_IP_DROP_SOURCE_MEMBERSHIP,   mcast_so_dropsrcm }
+};
+
+
+static int mcast_so_check_socket(struct pico_socket *s)
+{
+    pico_err = PICO_ERR_EINVAL;
+    if (!s)
+        return -1;
+
+    if (!s->proto)
+        return -1;
+
+    if (s->proto->proto_number != PICO_PROTO_UDP)
+        return -1;
+
+    pico_err = PICO_ERR_NOERR;
+    return 0;
+}
+
+int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value)
+{
+    int arrayn = option - PICO_IP_MULTICAST_IF;
+    if (option < PICO_IP_MULTICAST_IF || option > PICO_IP_DROP_SOURCE_MEMBERSHIP) {
+        pico_err = PICO_ERR_EOPNOTSUPP;
+        return -1;
+    }
+
+    if (mcast_so_check_socket(s) < 0)
+        return -1;
+
+    if (!mcast_so_calls[arrayn].call) {
+        pico_err = PICO_ERR_EOPNOTSUPP;
+        return -1;
+    }
+
+    return (mcast_so_calls[arrayn].call(s, value));
+}
+
+int pico_udp_set_mc_ttl(struct pico_socket *s, void  *_ttl)
+{
+    struct pico_socket_udp *u;
+    uint8_t ttl = *(uint8_t *)_ttl;
+    if(!s) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    u = (struct pico_socket_udp *) s;
+    u->mc_ttl = ttl;
+    return 0;
+}
+
+int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl)
+{
+    struct pico_socket_udp *u;
+    if(!s)
+        return -1;
+
+    u = (struct pico_socket_udp *) s;
+    *ttl = u->mc_ttl;
+    return 0;
+}
+#else
+int pico_udp_set_mc_ttl(struct pico_socket *s, void  *_ttl)
+{
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl)
+{
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+int pico_socket_mcast_filter(struct pico_socket *s, union pico_address *mcast_group, union pico_address *src)
+{
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+void pico_multicast_delete(struct pico_socket *s)
+{
+    (void)s;
+}
+
+int pico_getsockopt_mcast(struct pico_socket *s, int option, void *value)
+{
+    (void)s;
+    (void)option;
+    (void)value;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+int pico_setsockopt_mcast(struct pico_socket *s, int option, void *value)
+{
+    (void)s;
+    (void)option;
+    (void)value;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+
+}
+#endif /* PICO_SUPPORT_MCAST */
+
--- a/stack/pico_stack.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/stack/pico_stack.c	Wed Apr 09 14:31:41 2014 +0200
@@ -21,6 +21,7 @@
 #include "pico_ipv4.h"
 #include "pico_ipv6.h"
 #include "pico_icmp4.h"
+#include "pico_icmp6.h"
 #include "pico_igmp.h"
 #include "pico_udp.h"
 #include "pico_tcp.h"
@@ -29,11 +30,23 @@
 
 #define IS_LIMITED_BCAST(f) (((struct pico_ipv4_hdr *) f->net_hdr)->dst.addr == PICO_IP4_BCAST)
 
+const uint8_t PICO_ETHADDR_ALL[6] = {
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
 # define PICO_SIZE_MCAST 3
 const uint8_t PICO_ETHADDR_MCAST[6] = {
     0x01, 0x00, 0x5e, 0x00, 0x00, 0x00
 };
 
+#ifdef PICO_SUPPORT_IPV6
+# define PICO_SIZE_MCAST6 2
+const uint8_t PICO_ETHADDR_MCAST6[6] = {
+    0x33, 0x33, 0x00, 0x00, 0x00, 0x00
+};
+#endif
+
+
 volatile pico_time pico_tick;
 volatile pico_err_t pico_err;
 
@@ -140,6 +153,13 @@
         break;
 #endif
 
+#ifdef PICO_SUPPORT_ICMP6
+    case PICO_PROTO_ICMP6:
+        ret = pico_enqueue(pico_proto_icmp6.q_in, f);
+        break;
+#endif
+
+
 #ifdef PICO_SUPPORT_IGMP
     case PICO_PROTO_IGMP:
         ret = pico_enqueue(pico_proto_igmp.q_in, f);
@@ -168,16 +188,6 @@
     return ret;
 }
 
-int32_t pico_transport_send(struct pico_frame *f)
-{
-    if (!f || !f->sock || !f->sock->proto) {
-        pico_frame_discard(f);
-        return -1;
-    }
-
-    return f->sock->proto->push(f->sock->net, f);
-}
-
 int32_t pico_network_receive(struct pico_frame *f)
 {
     if (0) {}
@@ -212,24 +222,6 @@
     return f->sock->net->push(f->sock->net, f);
 }
 
-int pico_destination_is_local(struct pico_frame *f)
-{
-    if (0) { }
-
-#ifdef PICO_SUPPORT_IPV4
-    else if (IS_IPV4(f)) {
-        struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
-        if (pico_ipv4_link_find(&hdr->dst))
-            return 1;
-    }
-#endif
-#ifdef PICO_SUPPORT_IPV6
-    else if (IS_IPV6(f)) {
-    }
-#endif
-    return 0;
-}
-
 int pico_source_is_local(struct pico_frame *f)
 {
     if (0) { }
@@ -268,10 +260,16 @@
 {
     struct pico_eth_hdr *hdr = (struct pico_eth_hdr *) f->datalink_hdr;
     f->net_hdr = f->datalink_hdr + sizeof(struct pico_eth_hdr);
-    if (hdr->proto == PICO_IDETH_ARP)
+    if (0) { }
+
+#if (defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_ETH)
+    else if (hdr->proto == PICO_IDETH_ARP)
         return pico_arp_receive(f);
+#endif
+#if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6)
     else if ((hdr->proto == PICO_IDETH_IPV4) || (hdr->proto == PICO_IDETH_IPV6))
         return pico_network_receive(f);
+#endif
     else {
         pico_frame_discard(f);
         return -1;
@@ -298,6 +296,9 @@
     hdr = (struct pico_eth_hdr *) f->datalink_hdr;
     if ((memcmp(hdr->daddr, f->dev->eth->mac.addr, PICO_SIZE_ETH) != 0) &&
         (memcmp(hdr->daddr, PICO_ETHADDR_MCAST, PICO_SIZE_MCAST) != 0) &&
+#ifdef PICO_SUPPORT_IPV6
+        (memcmp(hdr->daddr, PICO_ETHADDR_MCAST6, PICO_SIZE_MCAST6) != 0) &&
+#endif
         (memcmp(hdr->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH) != 0))
     {
         pico_frame_discard(f);
@@ -329,20 +330,25 @@
 
 static int destination_is_mcast(struct pico_frame *f)
 {
+    int ret = 0;
     if (!f)
         return 0;
 
-    if (IS_IPV6(f))
-        return 0;
+#ifdef PICO_SUPPORT_IPV6
+    if (IS_IPV6(f)) {
+        struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *) f->net_hdr;
+        ret = pico_ipv6_is_multicast(hdr->dst.addr);
+    }
 
+#endif
 #ifdef PICO_SUPPORT_IPV4
     else {
         struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
-        return pico_ipv4_is_multicast(hdr->dst.addr);
+        ret = pico_ipv4_is_multicast(hdr->dst.addr);
     }
-#else
-    return 0;
 #endif
+
+    return ret;
 }
 
 static struct pico_eth *pico_ethernet_mcast_translate(struct pico_frame *f, uint8_t *pico_mcast_mac)
@@ -350,21 +356,47 @@
     struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
 
     /* place 23 lower bits of IP in lower 23 bits of MAC */
-    pico_mcast_mac[5] = (long_be(hdr->dst.addr) & 0x000000FF);
-    pico_mcast_mac[4] = (uint8_t)((long_be(hdr->dst.addr) & 0x0000FF00) >> 8);
-    pico_mcast_mac[3] = (uint8_t)((long_be(hdr->dst.addr) & 0x007F0000) >> 16);
+    pico_mcast_mac[5] = (long_be(hdr->dst.addr) & 0x000000FFu);
+    pico_mcast_mac[4] = (uint8_t)((long_be(hdr->dst.addr) & 0x0000FF00u) >> 8u);
+    pico_mcast_mac[3] = (uint8_t)((long_be(hdr->dst.addr) & 0x007F0000u) >> 16u);
 
     return (struct pico_eth *)pico_mcast_mac;
 }
 
 
-
+#ifdef PICO_SUPPORT_IPV6
+static struct pico_eth *pico_ethernet_mcast6_translate(struct pico_frame *f, uint8_t *pico_mcast6_mac)
+{
+    struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
 
-int32_t pico_ethernet_send_ipv6(struct pico_frame *f)
+    /* first 2 octets are 0x33, last four are the last four of dst */
+    pico_mcast6_mac[5] = hdr->dst.addr[PICO_SIZE_IP6 - 1];
+    pico_mcast6_mac[4] = hdr->dst.addr[PICO_SIZE_IP6 - 2];
+    pico_mcast6_mac[3] = hdr->dst.addr[PICO_SIZE_IP6 - 3];
+    pico_mcast6_mac[2] = hdr->dst.addr[PICO_SIZE_IP6 - 4];
+
+    return (struct pico_eth *)pico_mcast6_mac;
+}
+#endif
+
+struct pico_eth *pico_ethernet_ipv6_dst(struct pico_frame *f)
 {
+    struct pico_eth *dstmac = NULL;
+    #ifdef PICO_SUPPORT_IPV6
+    if (destination_is_mcast(f)) {
+        uint8_t pico_mcast6_mac[6] = {
+            0x33, 0x33, 0x00, 0x00, 0x00, 0x00
+        };
+        dstmac = pico_ethernet_mcast6_translate(f, pico_mcast6_mac);
+    } else {
+        dstmac = pico_nd_get(f);
+    }
+
+    #else
     (void)f;
-    /*TODO: Neighbor solicitation */
-    return -1;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    #endif
+    return dstmac;
 }
 
 
@@ -414,11 +446,17 @@
 {
     const struct pico_eth *dstmac = NULL;
     int32_t ret = -1;
+    uint16_t proto = PICO_IDETH_IPV4;
 
-    if (IS_IPV6(f))
-        return pico_ethernet_send_ipv6(f);
+    if (IS_IPV6(f)) {
+        dstmac = pico_ethernet_ipv6_dst(f);
+        if (!dstmac)
+            return 0;
 
-    if (IS_BCAST(f) || destination_is_bcast(f))
+        proto = PICO_IDETH_IPV6;
+    }
+
+    else if (IS_BCAST(f) || destination_is_bcast(f))
         dstmac = (const struct pico_eth *) PICO_ETHADDR_ALL;
 
     else if (destination_is_mcast(f)) {
@@ -428,9 +466,11 @@
         dstmac = pico_ethernet_mcast_translate(f, pico_mcast_mac);
     }
     else {
+#if (defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_ETH)
         dstmac = pico_arp_get(f);
         if (!dstmac)
-            return 0;
+#endif
+        return 0;
     }
 
     /* This sets destination and source address, then pushes the packet to the device. */
@@ -442,7 +482,7 @@
         hdr = (struct pico_eth_hdr *) f->datalink_hdr;
         memcpy(hdr->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH);
         memcpy(hdr->daddr, dstmac, PICO_SIZE_ETH);
-        hdr->proto = PICO_IDETH_IPV4;
+        hdr->proto = proto;
 
         if (pico_ethsend_local(f, hdr, &ret) || pico_ethsend_bcast(f, &ret) || pico_ethsend_dispatch(f, &ret)) {
             return ret;
@@ -524,6 +564,37 @@
     return ret;
 }
 
+int32_t pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len)
+{
+    struct pico_frame *f;
+    int ret;
+    if (len <= 0)
+        return -1;
+
+    f = pico_frame_alloc_skeleton(len);
+    if (!f)
+    {
+        dbg("Cannot alloc incoming frame!\n");
+        return -1;
+    }
+
+    if (pico_frame_skeleton_set_buffer(f, buffer) < 0)
+    {
+        dbg("Invalid zero-copy buffer!\n");
+        PICO_FREE(f->usage_count);
+        PICO_FREE(f);
+        return -1;
+    }
+
+    f->dev = dev;
+    ret = pico_enqueue(dev->q_in, f);
+    if (ret <= 0) {
+        pico_frame_discard(f);
+    }
+
+    return ret;
+}
+
 int32_t pico_sendto_dev(struct pico_frame *f)
 {
     if (!f->dev) {
@@ -549,9 +620,6 @@
 struct pico_timer_ref
 {
     pico_time expire;
-#ifdef JENKINS_DEBUG
-    void *caller;
-#endif
     struct pico_timer *tmr;
 };
 
@@ -572,7 +640,7 @@
             t->timer(pico_tick, t->arg);
 
         if (t)
-            pico_free(t);
+            PICO_FREE(t);
 
         t = NULL;
         heap_peek(Timers, &tref_unused);
@@ -590,7 +658,7 @@
     for (i = 1; i <= Timers->n; i++) {
         if (tref[i].tmr == t) {
             Timers->top[i].tmr = NULL;
-            pico_free(t);
+            PICO_FREE(t);
             break;
         }
     }
@@ -627,8 +695,8 @@
 
             index[i]++;
 
-            if (ret[i] == 0 && (score[i] << 1 <= PROTO_MAX_SCORE) && ((total + (score[i] << 1)) < max_total)) { /* used all loop score -> increase next score directly */
-                score[i] <<= 1;
+            if (ret[i] == 0 && ((score[i] * 2) <= PROTO_MAX_SCORE) && ((total + (score[i] * 2)) < max_total)) { /* used all loop score -> increase next score directly */
+                score[i] *= 2;
                 total += score[i];
                 continue;
             }
@@ -637,18 +705,18 @@
             for (j = 0; j < PROTO_DEF_AVG_NR; j++)
                 sum += avg[i][j]; /* calculate sum */
 
-            sum >>= 2;          /* divide by 4 to get average used score */
+            sum /= 4;           /* divide by 4 to get average used score */
 
             /* criterion to increase next loop score */
-            if (sum > (score[i] - (score[i] >> 2))  && (score[i] << 1 <= PROTO_MAX_SCORE) && ((total + (score[i] << 1)) < max_total)) { /* > 3/4 */
-                score[i] <<= 1; /* double loop score */
+            if (sum > (score[i] - (score[i] / 4))  && ((score[i] * 2) <= PROTO_MAX_SCORE) && ((total + (score[i] / 2)) < max_total)) { /* > 3/4 */
+                score[i] *= 2; /* double loop score */
                 total += score[i];
                 continue;
             }
 
             /* criterion to decrease next loop score */
-            if (sum < (score[i] >> 2) && (score[i] >> 1 >= PROTO_MIN_SCORE)) { /* < 1/4 */
-                score[i] >>= 1; /* half loop score */
+            if ((sum < (score[i] / 4)) && ((score[i] / 2) >= PROTO_MIN_SCORE)) { /* < 1/4 */
+                score[i] /= 2; /* half loop score */
                 total += score[i];
                 continue;
             }
@@ -673,10 +741,10 @@
             for (j = 0; j < PROTO_DEF_AVG_NR; j++)
                 sum += avg[i][j]; /* calculate sum */
 
-            sum >>= 2;          /* divide by 4 to get average used score */
+            sum /= 2;          /* divide by 4 to get average used score */
 
-            if ((sum == 0) && (score[i] >> 1 >= PROTO_MIN_SCORE)) {
-                score[i] >>= 1; /* half loop score */
+            if ((sum == 0) && ((score[i] / 2) >= PROTO_MIN_SCORE)) {
+                score[i] /= 2; /* half loop score */
                 total += score[i];
                 for (j = 0; j < PROTO_DEF_AVG_NR; j++)
                     avg[i][j] = score[i];
@@ -797,7 +865,7 @@
 
 struct pico_timer *pico_timer_add(pico_time expire, void (*timer)(pico_time, void *), void *arg)
 {
-    struct pico_timer *t = pico_zalloc(sizeof(struct pico_timer));
+    struct pico_timer *t = PICO_ZALLOC(sizeof(struct pico_timer));
     struct pico_timer_ref tref;
     if (!t) {
         pico_err = PICO_ERR_ENOMEM;
@@ -808,30 +876,15 @@
     t->arg = arg;
     t->timer = timer;
     tref.tmr = t;
-    #ifdef JENKINS_DEBUG
-    //jenkins_dbg("pico_timer_add: now have %d \t caller: %p\n", Timers->n, __builtin_return_address(0));
-    tref.caller = __builtin_return_address(0);
-    #endif
     heap_insert(Timers, &tref);
     if (Timers->n > PICO_MAX_TIMERS) {
-        /* dbg("Warning: I have %d timers\n", Timers->n); */
-        #ifdef JENKINS_DEBUG
-        {
-            struct pico_timer_ref *trf = heap_first(Timers);
-            int timer_it = 1; 
-            for (timer_it = 1; timer_it <= Timers->n; timer_it++) 
-            {
-                trf = &Timers->top[timer_it];
-                jenkins_dbg("timer %d [%p] - cb:%p\n",Timers->n - timer_it, trf->tmr, trf->caller,(trf->tmr->timer));    
-            }
-        }
-        #endif
+        dbg("Warning: I have %d timers\n", Timers->n);
     }
 
     return t;
 }
 
-void pico_stack_init(void)
+int pico_stack_init(void)
 {
 
 #ifdef PICO_SUPPORT_IPV4
@@ -846,6 +899,10 @@
     pico_protocol_init(&pico_proto_icmp4);
 #endif
 
+#ifdef PICO_SUPPORT_ICMP6
+    pico_protocol_init(&pico_proto_icmp6);
+#endif
+
 #ifdef PICO_SUPPORT_IGMP
     pico_protocol_init(&pico_proto_igmp);
 #endif
@@ -866,9 +923,21 @@
 
     /* Initialize timer heap */
     Timers = heap_init();
+    if (!Timers)
+        return -1;
+
+#if ((defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_ETH))
+    /* Initialize ARP module */
     pico_arp_init();
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+    /* Initialize Neighbor discovery module */
+    pico_ipv6_nd_init();
+#endif
     pico_stack_tick();
     pico_stack_tick();
     pico_stack_tick();
+    return 0;
 }
 
--- a/stack/pico_tree.c	Tue Mar 11 15:34:51 2014 +0100
+++ b/stack/pico_tree.c	Wed Apr 09 14:31:41 2014 +0200
@@ -8,6 +8,7 @@
 #include "pico_tree.h"
 #include "pico_config.h"
 #include "pico_protocol.h"
+#include "pico_mm.h"
 
 #define RED     0
 #define BLACK 1
@@ -32,12 +33,27 @@
 /*
  * Local Functions
  */
-static struct pico_tree_node *create_node(struct pico_tree *tree, void *key);
+static struct pico_tree_node *create_node(struct pico_tree *tree, void *key, uint8_t allocator);
 static void rotateToLeft(struct pico_tree*tree, struct pico_tree_node*node);
 static void rotateToRight(struct pico_tree*root, struct pico_tree_node*node);
 static void fix_insert_collisions(struct pico_tree*tree, struct pico_tree_node*node);
 static void fix_delete_collisions(struct pico_tree*tree, struct pico_tree_node *node);
 static void switchNodes(struct pico_tree*tree, struct pico_tree_node*nodeA, struct pico_tree_node*nodeB);
+void *pico_tree_insert_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
+void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator);
+
+#ifdef PICO_SUPPORT_MM
+/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has.
+ * These nodes should be placed in the manager page which is in a different memory region then the nodes
+ * which are used for the pico stack in general.
+ * Therefore the following 2 functions are created so that pico_tree can use them to to put these nodes
+ * into the correct memory regions.
+ * If pico_tree_insert is called from the memory manager module, then create_node should use
+ * pico_mem_page0_zalloc to create a node. The same for pico_tree_delete.
+ */
+extern void*pico_mem_page0_zalloc(size_t len);
+extern void pico_mem_page0_free(void*ptr);
+#endif  /* PICO_SUPPORT_MM */
 
 /*
  * Exported functions
@@ -98,9 +114,19 @@
     return node;
 }
 
-void *pico_tree_insert(struct pico_tree*tree, void *key)
+/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has.
+ * These nodes should be placed in the manager page which is in a different memory region then the nodes
+ * which are used for the pico stack in general.
+ * Therefore the following wrapper for pico_tree_insert is created.
+ * The actual implementation can be found in pico_tree_insert_implementation.
+ */
+void *pico_tree_insert(struct pico_tree *tree, void *key)
 {
+    return pico_tree_insert_implementation(tree, key, USE_PICO_ZALLOC);
+}
 
+void *pico_tree_insert_implementation(struct pico_tree*tree, void *key, uint8_t allocator)
+{
     struct pico_tree_node *last_node = INIT_LEAF;
     struct pico_tree_node *temp = tree->root;
     struct pico_tree_node *insert;
@@ -113,7 +139,11 @@
         return LocalKey;
     else
     {
-        insert = create_node(tree, key);
+        if(allocator == USE_PICO_PAGE0_ZALLOC)
+            insert = create_node(tree, key, USE_PICO_PAGE0_ZALLOC);
+        else
+            insert = create_node(tree, key, USE_PICO_ZALLOC);
+
         if(!insert)
         {
             pico_err = PICO_ERR_ENOMEM;
@@ -128,7 +158,7 @@
         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 */
     insert->parent = last_node;
@@ -204,64 +234,98 @@
     return pico_tree_lastNode(tree->root)->keyValue;
 }
 
-void *pico_tree_delete(struct pico_tree *tree, void *key)
+static uint8_t pico_tree_delete_node(struct pico_tree *tree, struct pico_tree_node *d, struct pico_tree_node **temp)
 {
-
-    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 *min;
+    struct pico_tree_node *ltemp = d;
+    uint8_t nodeColor;
+    min = pico_tree_firstNode(d->rightChild);
+    nodeColor = min->color;
 
-    delete = pico_tree_findNode(tree, key);
-    ltemp = delete;
+    *temp = min->rightChild;
+    if(min->parent == ltemp && IS_NOT_LEAF(*temp))
+        (*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, ltemp, min);
+    min->leftChild = ltemp->leftChild;
 
-    /* this key isn't in the tree, bail out */
-    if(!delete)
-        return NULL;
+    if(IS_NOT_LEAF(min->leftChild))
+        min->leftChild->parent = min;
 
-    lkey = delete->keyValue;
-    nodeColor = delete->color;
+    min->color = ltemp->color;
+    return nodeColor;
+}
 
+static uint8_t pico_tree_delete_check_switch(struct pico_tree *tree, struct pico_tree_node *delete, struct pico_tree_node **temp)
+{
+    struct pico_tree_node *ltemp = delete;
+    uint8_t nodeColor = delete->color;
     if(IS_LEAF(delete->leftChild))
     {
-        temp = ltemp->rightChild;
+        *temp = ltemp->rightChild;
         switchNodes(tree, ltemp, ltemp->rightChild);
     }
     else
     if(IS_LEAF(delete->rightChild))
     {
         struct pico_tree_node *_ltemp = delete;
-        temp = _ltemp->leftChild;
+        *temp = _ltemp->leftChild;
         switchNodes(tree, _ltemp, _ltemp->leftChild);
     }
     else{
-        struct pico_tree_node *min;
-        min = pico_tree_firstNode(delete->rightChild);
-        nodeColor = min->color;
+        nodeColor = pico_tree_delete_node(tree, delete, temp);
+    }
+
+    return nodeColor;
+
+}
+
+/* The memory manager also uses the pico_tree to keep track of all the different slab sizes it has.
+ * These nodes should be placed in the manager page which is in a different memory region then the nodes
+ * which are used for the pico stack in general.
+ * Therefore the following wrapper for pico_tree_delete is created.
+ * The actual implementation can be found in pico_tree_delete_implementation.
+ */
+void *pico_tree_delete(struct pico_tree *tree, void *key)
+{
+    return pico_tree_delete_implementation(tree, key, USE_PICO_ZALLOC);
+}
 
-        temp = min->rightChild;
-        if(min->parent == ltemp && IS_NOT_LEAF(temp))
-            temp->parent = min;
-        else{
-            switchNodes(tree, min, min->rightChild);
-            min->rightChild = ltemp->rightChild;
-            if(IS_NOT_LEAF(min->rightChild)) min->rightChild->parent = min;
-        }
+void *pico_tree_delete_implementation(struct pico_tree *tree, void *key, uint8_t allocator)
+{
+    struct pico_tree_node *temp;
+    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 */
 
-        switchNodes(tree, ltemp, min);
-        min->leftChild = ltemp->leftChild;
-        if(IS_NOT_LEAF(min->leftChild)) min->leftChild->parent = min;
+    if (!key)
+        return NULL;
+
+    delete = pico_tree_findNode(tree, key);
 
-        min->color = ltemp->color;
-    }
+    /* this key isn't in the tree, bail out */
+    if(!delete)
+        return NULL;
+
+    lkey = delete->keyValue;
+    nodeColor = pico_tree_delete_check_switch(tree, delete, &temp);
 
     /* deleted node is black, this will mess up the black path property */
     if(nodeColor == BLACK)
         fix_delete_collisions(tree, temp);
 
-    pico_free(delete);
+    if(allocator == USE_PICO_ZALLOC)
+        PICO_FREE(delete);
 
+#ifdef PICO_SUPPORT_MM
+    else
+        pico_mem_page0_free(delete);
+#endif
     return lkey;
 }
 
@@ -328,11 +392,17 @@
     return;
 }
 
-static struct pico_tree_node *create_node(struct pico_tree *tree, void*key)
+static struct pico_tree_node *create_node(struct pico_tree *tree, void*key, uint8_t allocator)
 {
-    struct pico_tree_node *temp;
+    struct pico_tree_node *temp = NULL;
     IGNORE_PARAMETER(tree);
-    temp = (struct pico_tree_node *)pico_zalloc(sizeof(struct pico_tree_node));
+    if(allocator == USE_PICO_ZALLOC)
+        temp = (struct pico_tree_node *)PICO_ZALLOC(sizeof(struct pico_tree_node));
+
+#ifdef PICO_SUPPORT_MM
+    else
+        temp = (struct pico_tree_node *)pico_mem_page0_zalloc(sizeof(struct pico_tree_node));
+#endif
 
     if(!temp)
         return NULL;