mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [RFC v2 00/16] barebox picotcp integration (2015.07.19)
@ 2015-07-19 20:07 Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 01/16] net_udp_bind(): use uint16_t type for source port Antony Pavlov
                   ` (16 more replies)
  0 siblings, 17 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

I have just published latest picotcp-enabled barebox.
Please see my 20150719.picotcp branch in my github barebox repo
(https://github.com/frantony/barebox/tree/20150719.picotcp).

This version is based on the latest barebox-next and picotcp v1.5.0
(there is also picotcp v1.5.1, but is has no interested
for barebox changes since v1.5.0).


Changes since 2015.07.15 (see http://lists.infradead.org/pipermail/barebox/2015-June/024174.html):

    * net: UDP API changed to satisfy the picotcp integration needs;
    * nfs, tftp and dns subsystems have no picotcp-related stuff anymore.
    * netconsole works on top of picotcp with no additional changes.


Here are some notes:

  1. just now tftp/nfs file transfer on top of picotcp is slower than
     the same transfer on top of legacy network stack;

  2. there is no $<current network interface> anymore,
     so dhcp, tftp and ifup commands don't work on top of picotcp.
     The ifconfig command is used for network interfaces setup.

     N.B. There is an old patch for dhcp support on top of picotcp
        https://github.com/frantony/barebox/commit/94021b6d7bb933cd50b7ea9e2c55725b5c404205

  3. The picoping command is used insted of traditional ping command.



Antony Pavlov (16):
  net_udp_bind(): use uint16_t type for source port
  fs/tftp.c: drop unused server_port variable
  fs/nfs.c: use uint16_t for port numbers
  fs/nfs.c: use SUNRPC_PORT remote port by default
  net: change UDP handler function API
  net: change net_udp_send() API
  net: introduce setudppeerport()
  net: import picotcp from github
  picotcp: add barebox target support
  picotcp: switch to Kbuild
  net: add initial picotcp support
  net: picotcp: add test_picotcp command
  net: picotcp: add ifconfig command
  net: picotcp: add ping command
  net: picotcp: add route command
  sandbox_defconfig: switch to picotcp

 Makefile                                    |    1 +
 arch/sandbox/configs/sandbox_defconfig      |    8 +-
 commands/Kconfig                            |    4 +
 fs/nfs.c                                    |   14 +-
 fs/tftp.c                                   |   30 +-
 include/net.h                               |   61 +-
 include/pico_defines.h                      |    0
 include/stdint.h                            |    1 +
 net/Kconfig                                 |   16 +
 net/Makefile                                |    8 +
 net/dhcp.c                                  |   12 +-
 net/dns.c                                   |    9 +-
 net/eth.c                                   |   71 +
 net/net.c                                   |   95 +-
 net/netconsole.c                            |    7 +-
 net/nfs.c                                   |    6 +-
 net/picotcp.c                               |   20 +
 net/picotcp/.gitignore                      |   25 +
 net/picotcp/COPYING                         |    8 +
 net/picotcp/Kconfig                         |   56 +
 net/picotcp/LICENSE                         |  339 ++++
 net/picotcp/Makefile                        |   30 +
 net/picotcp/README.md                       |   33 +
 net/picotcp/include/arch/pico_barebox.h     |   76 +
 net/picotcp/include/heap.h                  |   83 +
 net/picotcp/include/pico_addressing.h       |   52 +
 net/picotcp/include/pico_config.h           |  231 +++
 net/picotcp/include/pico_constants.h        |   54 +
 net/picotcp/include/pico_device.h           |   54 +
 net/picotcp/include/pico_eth.h              |   21 +
 net/picotcp/include/pico_frame.h            |  122 ++
 net/picotcp/include/pico_module_eth.h       |   33 +
 net/picotcp/include/pico_protocol.h         |   95 ++
 net/picotcp/include/pico_queue.h            |  166 ++
 net/picotcp/include/pico_socket.h           |  268 ++++
 net/picotcp/include/pico_socket_multicast.h |   10 +
 net/picotcp/include/pico_stack.h            |   87 ++
 net/picotcp/include/pico_tree.h             |   93 ++
 net/picotcp/modules/Makefile                |    8 +
 net/picotcp/modules/pico_aodv.h             |  131 ++
 net/picotcp/modules/pico_arp.c              |  531 +++++++
 net/picotcp/modules/pico_arp.h              |   32 +
 net/picotcp/modules/pico_dev_loop.c         |   66 +
 net/picotcp/modules/pico_dev_loop.h         |   15 +
 net/picotcp/modules/pico_dev_mock.h         |   47 +
 net/picotcp/modules/pico_dev_null.c         |   60 +
 net/picotcp/modules/pico_dev_null.h         |   15 +
 net/picotcp/modules/pico_dhcp_client.c      |  960 ++++++++++++
 net/picotcp/modules/pico_dhcp_client.h      |   30 +
 net/picotcp/modules/pico_dhcp_common.c      |  189 +++
 net/picotcp/modules/pico_dhcp_common.h      |  186 +++
 net/picotcp/modules/pico_dns_client.h       |   46 +
 net/picotcp/modules/pico_dns_common.h       |  521 +++++++
 net/picotcp/modules/pico_dns_sd.h           |   90 ++
 net/picotcp/modules/pico_fragments.c        |  345 +++++
 net/picotcp/modules/pico_fragments.h        |   11 +
 net/picotcp/modules/pico_icmp4.c            |  395 +++++
 net/picotcp/modules/pico_icmp4.h            |  162 ++
 net/picotcp/modules/pico_icmp6.h            |  259 ++++
 net/picotcp/modules/pico_igmp.h             |   26 +
 net/picotcp/modules/pico_ipfilter.h         |   29 +
 net/picotcp/modules/pico_ipv4.c             | 1574 +++++++++++++++++++
 net/picotcp/modules/pico_ipv4.h             |  124 ++
 net/picotcp/modules/pico_ipv6.h             |  153 ++
 net/picotcp/modules/pico_ipv6_nd.h          |   26 +
 net/picotcp/modules/pico_mm.h               |   98 ++
 net/picotcp/modules/pico_nat.h              |   90 ++
 net/picotcp/modules/pico_olsr.h             |   32 +
 net/picotcp/modules/pico_socket_tcp.h       |   33 +
 net/picotcp/modules/pico_socket_udp.c       |  250 +++
 net/picotcp/modules/pico_socket_udp.h       |   19 +
 net/picotcp/modules/pico_tcp.h              |  102 ++
 net/picotcp/modules/pico_udp.c              |  216 +++
 net/picotcp/modules/pico_udp.h              |   45 +
 net/picotcp/stack/Makefile                  |    7 +
 net/picotcp/stack/pico_device.c             |  408 +++++
 net/picotcp/stack/pico_frame.c              |  286 ++++
 net/picotcp/stack/pico_protocol.c           |  214 +++
 net/picotcp/stack/pico_socket.c             | 2213 +++++++++++++++++++++++++++
 net/picotcp/stack/pico_socket_multicast.c   |  956 ++++++++++++
 net/picotcp/stack/pico_stack.c              | 1157 ++++++++++++++
 net/picotcp/stack/pico_tree.c               |  575 +++++++
 net/picotcp_ifconfig.c                      |  116 ++
 net/picotcp_ping.c                          |   85 +
 net/picotcp_route.c                         |   36 +
 net/picotcp_test_ipv4.c                     |   96 ++
 86 files changed, 15306 insertions(+), 58 deletions(-)
 create mode 100644 include/pico_defines.h
 create mode 100644 include/stdint.h
 create mode 100644 net/picotcp.c
 create mode 100644 net/picotcp/.gitignore
 create mode 100644 net/picotcp/COPYING
 create mode 100644 net/picotcp/Kconfig
 create mode 100644 net/picotcp/LICENSE
 create mode 100644 net/picotcp/Makefile
 create mode 100644 net/picotcp/README.md
 create mode 100644 net/picotcp/include/arch/pico_barebox.h
 create mode 100644 net/picotcp/include/heap.h
 create mode 100644 net/picotcp/include/pico_addressing.h
 create mode 100644 net/picotcp/include/pico_config.h
 create mode 100644 net/picotcp/include/pico_constants.h
 create mode 100644 net/picotcp/include/pico_device.h
 create mode 100644 net/picotcp/include/pico_eth.h
 create mode 100644 net/picotcp/include/pico_frame.h
 create mode 100644 net/picotcp/include/pico_module_eth.h
 create mode 100644 net/picotcp/include/pico_protocol.h
 create mode 100644 net/picotcp/include/pico_queue.h
 create mode 100644 net/picotcp/include/pico_socket.h
 create mode 100644 net/picotcp/include/pico_socket_multicast.h
 create mode 100644 net/picotcp/include/pico_stack.h
 create mode 100644 net/picotcp/include/pico_tree.h
 create mode 100644 net/picotcp/modules/Makefile
 create mode 100644 net/picotcp/modules/pico_aodv.h
 create mode 100644 net/picotcp/modules/pico_arp.c
 create mode 100644 net/picotcp/modules/pico_arp.h
 create mode 100644 net/picotcp/modules/pico_dev_loop.c
 create mode 100644 net/picotcp/modules/pico_dev_loop.h
 create mode 100644 net/picotcp/modules/pico_dev_mock.h
 create mode 100644 net/picotcp/modules/pico_dev_null.c
 create mode 100644 net/picotcp/modules/pico_dev_null.h
 create mode 100644 net/picotcp/modules/pico_dhcp_client.c
 create mode 100644 net/picotcp/modules/pico_dhcp_client.h
 create mode 100644 net/picotcp/modules/pico_dhcp_common.c
 create mode 100644 net/picotcp/modules/pico_dhcp_common.h
 create mode 100644 net/picotcp/modules/pico_dns_client.h
 create mode 100644 net/picotcp/modules/pico_dns_common.h
 create mode 100644 net/picotcp/modules/pico_dns_sd.h
 create mode 100644 net/picotcp/modules/pico_fragments.c
 create mode 100644 net/picotcp/modules/pico_fragments.h
 create mode 100644 net/picotcp/modules/pico_icmp4.c
 create mode 100644 net/picotcp/modules/pico_icmp4.h
 create mode 100644 net/picotcp/modules/pico_icmp6.h
 create mode 100644 net/picotcp/modules/pico_igmp.h
 create mode 100644 net/picotcp/modules/pico_ipfilter.h
 create mode 100644 net/picotcp/modules/pico_ipv4.c
 create mode 100644 net/picotcp/modules/pico_ipv4.h
 create mode 100644 net/picotcp/modules/pico_ipv6.h
 create mode 100644 net/picotcp/modules/pico_ipv6_nd.h
 create mode 100644 net/picotcp/modules/pico_mm.h
 create mode 100644 net/picotcp/modules/pico_nat.h
 create mode 100644 net/picotcp/modules/pico_olsr.h
 create mode 100644 net/picotcp/modules/pico_socket_tcp.h
 create mode 100644 net/picotcp/modules/pico_socket_udp.c
 create mode 100644 net/picotcp/modules/pico_socket_udp.h
 create mode 100644 net/picotcp/modules/pico_tcp.h
 create mode 100644 net/picotcp/modules/pico_udp.c
 create mode 100644 net/picotcp/modules/pico_udp.h
 create mode 100644 net/picotcp/stack/Makefile
 create mode 100644 net/picotcp/stack/pico_device.c
 create mode 100644 net/picotcp/stack/pico_frame.c
 create mode 100644 net/picotcp/stack/pico_protocol.c
 create mode 100644 net/picotcp/stack/pico_socket.c
 create mode 100644 net/picotcp/stack/pico_socket_multicast.c
 create mode 100644 net/picotcp/stack/pico_stack.c
 create mode 100644 net/picotcp/stack/pico_tree.c
 create mode 100644 net/picotcp_ifconfig.c
 create mode 100644 net/picotcp_ping.c
 create mode 100644 net/picotcp_route.c
 create mode 100644 net/picotcp_test_ipv4.c

-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 01/16] net_udp_bind(): use uint16_t type for source port
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 02/16] fs/tftp.c: drop unused server_port variable Antony Pavlov
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 include/net.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/net.h b/include/net.h
index b93e264..d7a4751 100644
--- a/include/net.h
+++ b/include/net.h
@@ -445,7 +445,7 @@ struct net_connection *net_icmp_new(IPaddr_t dest, rx_handler_f *handler,
 
 void net_unregister(struct net_connection *con);
 
-static inline int net_udp_bind(struct net_connection *con, int sport)
+static inline int net_udp_bind(struct net_connection *con, uint16_t sport)
 {
 	con->udp->uh_sport = ntohs(sport);
 	return 0;
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 02/16] fs/tftp.c: drop unused server_port variable
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 01/16] net_udp_bind(): use uint16_t type for source port Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 03/16] fs/nfs.c: use uint16_t for port numbers Antony Pavlov
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 fs/tftp.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/fs/tftp.c b/fs/tftp.c
index 0de215e..56d4365 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -75,7 +75,6 @@ struct file_priv {
 	uint16_t last_block;
 	int state;
 	int err;
-	int server_port;
 	const char *filename;
 	int filesize;
 	uint64_t resend_timeout;
@@ -299,7 +298,6 @@ static void tftp_recv(struct file_priv *priv,
 
 	case TFTP_OACK:
 		tftp_parse_oack(priv, pkt, len);
-		priv->server_port = ntohs(uh_sport);
 		priv->tftp_con->udp->uh_dport = uh_sport;
 
 		if (priv->push) {
@@ -322,7 +320,6 @@ static void tftp_recv(struct file_priv *priv,
 			/* first block received */
 			priv->state = STATE_RDATA;
 			priv->tftp_con->udp->uh_dport = uh_sport;
-			priv->server_port = ntohs(uh_sport);
 			priv->last_block = 0;
 
 			if (priv->block != 1) {	/* Assertion */
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 03/16] fs/nfs.c: use uint16_t for port numbers
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 01/16] net_udp_bind(): use uint16_t type for source port Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 02/16] fs/tftp.c: drop unused server_port variable Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 04/16] fs/nfs.c: use SUNRPC_PORT remote port by default Antony Pavlov
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 fs/nfs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 5bff54a..0269814 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -132,8 +132,8 @@ struct nfs_priv {
 	struct net_connection *con;
 	IPaddr_t server;
 	char *path;
-	unsigned short mount_port;
-	unsigned short nfs_port;
+	uint16_t mount_port;
+	uint16_t nfs_port;
 	uint32_t rpc_id;
 	uint32_t rootfh_len;
 	char rootfh[NFS3_FHSIZE];
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 04/16] fs/nfs.c: use SUNRPC_PORT remote port by default
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (2 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 03/16] fs/nfs.c: use uint16_t for port numbers Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 05/16] net: change UDP handler function API Antony Pavlov
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

pico_socket_connect() needs remote_port != 0.

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 fs/nfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 0269814..3824752 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -1350,7 +1350,7 @@ static int nfs_probe(struct device_d *dev)
 
 	debug("nfs: server: %s path: %s\n", tmp, npriv->path);
 
-	npriv->con = net_udp_new(npriv->server, 0, nfs_handler, npriv);
+	npriv->con = net_udp_new(npriv->server, SUNRPC_PORT, nfs_handler, npriv);
 	if (IS_ERR(npriv->con)) {
 		ret = PTR_ERR(npriv->con);
 		goto err1;
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 05/16] net: change UDP handler function API
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (3 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 04/16] fs/nfs.c: use SUNRPC_PORT remote port by default Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 06/16] net: change net_udp_send() API Antony Pavlov
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 fs/nfs.c         |  4 +---
 fs/tftp.c        |  9 +++------
 include/net.h    | 15 +++++++++++++--
 net/dhcp.c       |  8 ++------
 net/dns.c        |  7 +++----
 net/net.c        | 12 ++++++++----
 net/netconsole.c |  5 ++---
 net/nfs.c        |  3 +--
 8 files changed, 33 insertions(+), 30 deletions(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 3824752..6c649c6 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -943,10 +943,8 @@ static int nfs_read_req(struct file_priv *priv, uint64_t offset,
 	return 0;
 }
 
-static void nfs_handler(void *ctx, char *packet, unsigned len)
+static void nfs_handler(struct net_connection *con, char *pkt, unsigned len)
 {
-	char *pkt = net_eth_to_udp_payload(packet);
-
 	nfs_state = STATE_DONE;
 	nfs_packet = pkt;
 	nfs_len = len;
diff --git a/fs/tftp.c b/fs/tftp.c
index 56d4365..c854da5 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -368,14 +368,11 @@ static void tftp_recv(struct file_priv *priv,
 	}
 }
 
-static void tftp_handler(void *ctx, char *packet, unsigned len)
+static void tftp_handler(struct net_connection *con, char *packet, unsigned len)
 {
-	struct file_priv *priv = ctx;
-	char *pkt = net_eth_to_udp_payload(packet);
-	struct udphdr *udp = net_eth_to_udphdr(packet);
+	struct file_priv *priv = con->priv;
 
-	(void)len;
-	tftp_recv(priv, pkt, net_eth_to_udplen(packet), udp->uh_sport);
+	tftp_recv(priv, packet, len, getudppeerport(con));
 }
 
 static struct file_priv *tftp_do_open(struct device_d *dev,
diff --git a/include/net.h b/include/net.h
index d7a4751..fa2777e 100644
--- a/include/net.h
+++ b/include/net.h
@@ -405,6 +405,8 @@ static inline int is_valid_ether_addr(const u8 *addr)
 }
 
 typedef void rx_handler_f(void *ctx, char *packet, unsigned int len);
+struct net_connection;
+typedef void udp_rx_handler_f(struct net_connection *con, char *packet, unsigned int len);
 
 void eth_set_current(struct eth_device *eth);
 struct eth_device *eth_get_current(void);
@@ -426,8 +428,9 @@ struct net_connection {
 	struct eth_device *edev;
 	struct icmphdr *icmp;
 	unsigned char *packet;
+	unsigned char *rpacket;
 	struct list_head list;
-	rx_handler_f *handler;
+	void *handler;
 	int proto;
 	void *priv;
 };
@@ -438,7 +441,7 @@ static inline char *net_alloc_packet(void)
 }
 
 struct net_connection *net_udp_new(IPaddr_t dest, uint16_t dport,
-		rx_handler_f *handler, void *ctx);
+		udp_rx_handler_f *handler, void *ctx);
 
 struct net_connection *net_icmp_new(IPaddr_t dest, rx_handler_f *handler,
 		void *ctx);
@@ -467,4 +470,12 @@ void led_trigger_network(enum led_trigger trigger);
 int ifup(const char *name, unsigned flags);
 int ifup_all(unsigned flags);
 
+/* NB! return port in network byte order */
+static inline uint16_t getudppeerport(struct net_connection *con)
+{
+	struct udphdr *udp = net_eth_to_udphdr(con->rpacket);
+
+	return udp->uh_sport;
+}
+
 #endif /* __NET_H__ */
diff --git a/net/dhcp.c b/net/dhcp.c
index e1625ec..d8b6bf7 100644
--- a/net/dhcp.c
+++ b/net/dhcp.c
@@ -588,18 +588,14 @@ static void dhcp_send_request_packet(struct bootp *bp_offer)
 /*
  *	Handle DHCP received packets.
  */
-static void dhcp_handler(void *ctx, char *packet, unsigned int len)
+static void dhcp_handler(struct net_connection *con, char *pkt, unsigned int len)
 {
-	char *pkt = net_eth_to_udp_payload(packet);
-	struct udphdr *udp = net_eth_to_udphdr(packet);
 	struct bootp *bp = (struct bootp *)pkt;
 
-	len = net_eth_to_udplen(packet);
-
 	debug("DHCPHandler: got packet: (len=%d) state: %d\n",
 		len, dhcp_state);
 
-	if (bootp_check_packet(pkt, ntohs(udp->uh_sport), len)) /* Filter out pkts we don't want */
+	if (bootp_check_packet(pkt, ntohs(getudppeerport(con)), len)) /* Filter out pkts we don't want */
 		return;
 
 	switch (dhcp_state) {
diff --git a/net/dns.c b/net/dns.c
index 0e16ea2..05106c6 100644
--- a/net/dns.c
+++ b/net/dns.c
@@ -192,11 +192,10 @@ static void dns_recv(struct header *header, unsigned len)
 	}
 }
 
-static void dns_handler(void *ctx, char *packet, unsigned len)
+static void dns_handler(struct net_connection *con, char *packet, unsigned len)
 {
-	(void)ctx;
-	dns_recv((struct header *)net_eth_to_udp_payload(packet),
-		net_eth_to_udplen(packet));
+	(void)con;
+	dns_recv((struct header *)packet, len);
 }
 
 IPaddr_t resolv(char *host)
diff --git a/net/net.c b/net/net.c
index e5bd9bb..8461caf 100644
--- a/net/net.c
+++ b/net/net.c
@@ -255,7 +255,7 @@ void net_set_gateway(IPaddr_t gw)
 
 static LIST_HEAD(connection_list);
 
-static struct net_connection *net_new(IPaddr_t dest, rx_handler_f *handler,
+static struct net_connection *net_new(IPaddr_t dest, void *handler,
 		void *ctx)
 {
 	struct eth_device *edev = eth_get_current();
@@ -317,7 +317,7 @@ out:
 }
 
 struct net_connection *net_udp_new(IPaddr_t dest, uint16_t dport,
-		rx_handler_f *handler, void *ctx)
+		udp_rx_handler_f *handler, void *ctx)
 {
 	struct net_connection *con = net_new(dest, handler, ctx);
 
@@ -480,7 +480,10 @@ static int net_handle_udp(unsigned char *pkt, int len)
 	port = ntohs(udp->uh_dport);
 	list_for_each_entry(con, &connection_list, list) {
 		if (con->proto == IPPROTO_UDP && port == ntohs(con->udp->uh_sport)) {
-			con->handler(con->priv, pkt, len);
+			udp_rx_handler_f *handler = con->handler;
+			con->rpacket = pkt;
+			handler(con, net_eth_to_udp_payload(pkt),
+						net_eth_to_udplen(pkt));
 			return 0;
 		}
 	}
@@ -495,7 +498,8 @@ static int net_handle_icmp(unsigned char *pkt, int len)
 
 	list_for_each_entry(con, &connection_list, list) {
 		if (con->proto == IPPROTO_ICMP) {
-			con->handler(con->priv, pkt, len);
+			rx_handler_f *handler = con->handler;
+			handler(con->priv, pkt, len);
 			return 0;
 		}
 	}
diff --git a/net/netconsole.c b/net/netconsole.c
index 0ee6a76..e7c722f 100644
--- a/net/netconsole.c
+++ b/net/netconsole.c
@@ -44,12 +44,11 @@ struct nc_priv {
 
 static struct nc_priv *g_priv;
 
-static void nc_handler(void *ctx, char *pkt, unsigned len)
+static void nc_handler(struct net_connection *con, char *pkt, unsigned len)
 {
 	struct nc_priv *priv = g_priv;
-	unsigned char *packet = net_eth_to_udp_payload(pkt);
 
-	kfifo_put(priv->fifo, packet, net_eth_to_udplen(pkt));
+	kfifo_put(priv->fifo, pkt, len);
 }
 
 static int nc_getc(struct console_device *cdev)
diff --git a/net/nfs.c b/net/nfs.c
index 0a30219..5a907d5 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -562,9 +562,8 @@ static int nfs_read_reply(unsigned char *pkt, unsigned len)
 Interfaces of barebox
 **************************************************************************/
 
-static void nfs_handler(void *ctx, char *packet, unsigned len)
+static void nfs_handler(struct net_connection *con, char *pkt, unsigned len)
 {
-	char *pkt = net_eth_to_udp_payload(packet);
 	int ret;
 
 	debug("%s\n", __func__);
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 06/16] net: change net_udp_send() API
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (4 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 05/16] net: change UDP handler function API Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 07/16] net: introduce setudppeerport() Antony Pavlov
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 fs/nfs.c         | 2 +-
 fs/tftp.c        | 9 +++++----
 include/net.h    | 2 +-
 net/dhcp.c       | 4 ++--
 net/dns.c        | 2 +-
 net/net.c        | 2 +-
 net/netconsole.c | 2 +-
 net/nfs.c        | 3 ++-
 8 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 6c649c6..6c55b42 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -414,7 +414,7 @@ static int rpc_req(struct nfs_priv *npriv, int rpc_prog, int rpc_proc,
 	npriv->con->udp->uh_dport = hton16(dport);
 
 again:
-	ret = net_udp_send(npriv->con,
+	ret = net_udp_send(npriv->con, payload,
 			sizeof(pkt) + datalen * sizeof(uint32_t));
 
 	nfs_timer_start = get_time_ns();
diff --git a/fs/tftp.c b/fs/tftp.c
index c854da5..11a10de 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -119,7 +119,8 @@ static int tftp_send(struct file_priv *priv)
 	unsigned char *xp;
 	int len = 0;
 	uint16_t *s;
-	unsigned char *pkt = net_udp_get_payload(priv->tftp_con);
+	uint8_t *payload = net_udp_get_payload(priv->tftp_con);
+	uint8_t *pkt = payload;
 	int ret;
 
 	debug("%s: state %d\n", __func__, priv->state);
@@ -168,7 +169,7 @@ static int tftp_send(struct file_priv *priv)
 		break;
 	}
 
-	ret = net_udp_send(priv->tftp_con, len);
+	ret = net_udp_send(priv->tftp_con, payload, len);
 
 	return ret;
 }
@@ -187,7 +188,7 @@ static int tftp_send_write(struct file_priv *priv, void *buf, int len)
 		priv->state = STATE_LAST;
 	len += 4;
 
-	ret = net_udp_send(priv->tftp_con, len);
+	ret = net_udp_send(priv->tftp_con, pkt, len);
 	priv->last_block = priv->block;
 	priv->state = STATE_WAITACK;
 
@@ -501,7 +502,7 @@ static int tftp_do_close(struct file_priv *priv)
 		*pkt++ = htons(TFTP_ERROR);
 		*pkt++ = 0;
 		*pkt++ = 0;
-		net_udp_send(priv->tftp_con, 6);
+		net_udp_send(priv->tftp_con, (char *)pkt, 6);
 	}
 
 	net_unregister(priv->tftp_con);
diff --git a/include/net.h b/include/net.h
index fa2777e..90cbb09 100644
--- a/include/net.h
+++ b/include/net.h
@@ -460,7 +460,7 @@ static inline void *net_udp_get_payload(struct net_connection *con)
 		sizeof(struct udphdr);
 }
 
-int net_udp_send(struct net_connection *con, int len);
+int net_udp_send(struct net_connection *con, char *payload, int len);
 int net_icmp_send(struct net_connection *con, int len);
 
 void led_trigger_network(enum led_trigger trigger);
diff --git a/net/dhcp.c b/net/dhcp.c
index d8b6bf7..e26acdc 100644
--- a/net/dhcp.c
+++ b/net/dhcp.c
@@ -487,7 +487,7 @@ static int bootp_request(void)
 
 	dhcp_state = SELECTING;
 
-	ret = net_udp_send(dhcp_con, sizeof(*bp) + ext_len);
+	ret = net_udp_send(dhcp_con, payload, sizeof(*bp) + ext_len);
 
 	return ret;
 }
@@ -582,7 +582,7 @@ static void dhcp_send_request_packet(struct bootp *bp_offer)
 				OfferedIP);
 
 	debug("Transmitting DHCPREQUEST packet\n");
-	net_udp_send(dhcp_con, sizeof(*bp) + extlen);
+	net_udp_send(dhcp_con, payload, sizeof(*bp) + extlen);
 }
 
 /*
diff --git a/net/dns.c b/net/dns.c
index 05106c6..7bb664c 100644
--- a/net/dns.c
+++ b/net/dns.c
@@ -109,7 +109,7 @@ static int dns_send(char *name)
 	*p++ = 0;
 	*p++ = 1;				/* Class: inet, 0x0001 */
 
-	ret = net_udp_send(dns_con, p - packet);
+	ret = net_udp_send(dns_con, packet, p - packet);
 
 	free(fullname);
 
diff --git a/net/net.c b/net/net.c
index 8461caf..23a9173 100644
--- a/net/net.c
+++ b/net/net.c
@@ -363,7 +363,7 @@ static int net_ip_send(struct net_connection *con, int len)
 	return eth_send(con->edev, con->packet, ETHER_HDR_SIZE + sizeof(struct iphdr) + len);
 }
 
-int net_udp_send(struct net_connection *con, int len)
+int net_udp_send(struct net_connection *con, char *payload, int len)
 {
 	con->udp->uh_ulen = htons(len + 8);
 	con->udp->uh_sum = 0;
diff --git a/net/netconsole.c b/net/netconsole.c
index e7c722f..11a6d30 100644
--- a/net/netconsole.c
+++ b/net/netconsole.c
@@ -100,7 +100,7 @@ static void nc_putc(struct console_device *cdev, char c)
 	*packet = c;
 
 	priv->busy = 1;
-	net_udp_send(priv->con, 1);
+	net_udp_send(priv->con, packet, 1);
 	priv->busy = 0;
 }
 
diff --git a/net/nfs.c b/net/nfs.c
index 5a907d5..41ad197 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -225,7 +225,8 @@ static int rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
 		sport = nfs_server_nfs_port;
 
 	nfs_con->udp->uh_dport = htons(sport);
-	ret = net_udp_send(nfs_con, sizeof(pkt) + datalen * sizeof(uint32_t));
+	ret = net_udp_send(nfs_con, payload,
+				sizeof(pkt) + datalen * sizeof(uint32_t));
 
 	return ret;
 }
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 07/16] net: introduce setudppeerport()
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (5 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 06/16] net: change net_udp_send() API Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 08/16] net: import picotcp from github Antony Pavlov
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 fs/nfs.c      | 2 +-
 fs/tftp.c     | 9 +++++----
 include/net.h | 7 +++++++
 3 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 6c55b42..8910fd1 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -411,7 +411,7 @@ static int rpc_req(struct nfs_priv *npriv, int rpc_prog, int rpc_proc,
 	memcpy(payload, &pkt, sizeof(pkt));
 	memcpy(payload + sizeof(pkt), data, datalen * sizeof(uint32_t));
 
-	npriv->con->udp->uh_dport = hton16(dport);
+	setudppeerport(npriv->con, htons(dport));
 
 again:
 	ret = net_udp_send(npriv->con, payload,
diff --git a/fs/tftp.c b/fs/tftp.c
index 11a10de..575f064 100644
--- a/fs/tftp.c
+++ b/fs/tftp.c
@@ -177,7 +177,7 @@ static int tftp_send(struct file_priv *priv)
 static int tftp_send_write(struct file_priv *priv, void *buf, int len)
 {
 	uint16_t *s;
-	unsigned char *pkt = net_udp_get_payload(priv->tftp_con);
+	uint8_t *pkt = net_udp_get_payload(priv->tftp_con);
 	int ret;
 
 	s = (uint16_t *)pkt;
@@ -293,13 +293,14 @@ static void tftp_recv(struct file_priv *priv,
 			priv->state = STATE_DONE;
 			break;
 		}
-		priv->tftp_con->udp->uh_dport = uh_sport;
+		setudppeerport(priv->tftp_con, uh_sport);
+
 		priv->state = STATE_WDATA;
 		break;
 
 	case TFTP_OACK:
 		tftp_parse_oack(priv, pkt, len);
-		priv->tftp_con->udp->uh_dport = uh_sport;
+		setudppeerport(priv->tftp_con, uh_sport);
 
 		if (priv->push) {
 			/* send first block */
@@ -320,7 +321,7 @@ static void tftp_recv(struct file_priv *priv,
 		if (priv->state == STATE_RRQ || priv->state == STATE_OACK) {
 			/* first block received */
 			priv->state = STATE_RDATA;
-			priv->tftp_con->udp->uh_dport = uh_sport;
+			setudppeerport(priv->tftp_con, uh_sport);
 			priv->last_block = 0;
 
 			if (priv->block != 1) {	/* Assertion */
diff --git a/include/net.h b/include/net.h
index 90cbb09..ed63d3c 100644
--- a/include/net.h
+++ b/include/net.h
@@ -478,4 +478,11 @@ static inline uint16_t getudppeerport(struct net_connection *con)
 	return udp->uh_sport;
 }
 
+#include <byteorder.h>
+
+static inline void setudppeerport(struct net_connection *con, uint16_t dport)
+{
+	con->udp->uh_dport = dport;
+}
+
 #endif /* __NET_H__ */
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 08/16] net: import picotcp from github
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (6 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 07/16] net: introduce setudppeerport() Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 09/16] picotcp: add barebox target support Antony Pavlov
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Original repo: https://github.com/tass-belgium/picotcp

The last original repo commit is v1.5.0

    commit f6d139147d86d74f9a53ba3c02b2a5b276858d95
    Author: laurens <laurens@localhost.localdomain>
    Date:   Thu Jun 25 12:54:38 2015 +0100

        Remove old check from fragments module

from development branch

Import mini-howto:

    $ cd barebox.git
    $ rm -rf net/picotcp
    $ git clone --branch ${branch_name} ${PICOTCP_REPO} net/picotcp
    $ rm -rf net/picotcp/*
    $ ( cd net/picotcp; git checkout .gitignore COPYING LICENSE README.md )
    $ ( cd net/picotcp; mkdir include modules stack )
    $ ( cd net/picotcp/include; git checkout heap.h pico_addressing.h pico_config.h pico_constants.h pico_device.h pico_eth.h pico_frame.h pico_module_eth.h pico_protocol.h pico_queue.h pico_socket.h pico_socket_multicast.h pico_stack.h pico_tree.h )
    $ ( cd net/picotcp/modules; git checkout pico_aodv.h pico_arp.c pico_arp.h pico_dev_loop.c pico_dev_loop.h pico_dev_mock.h pico_dev_null.c pico_dev_null.h pico_dhcp_client.c pico_dhcp_client.h pico_dhcp_common.c pico_dhcp_common.h pico_dns_client.h pico_dns_common.h pico_dns_sd.h pico_fragments.c pico_fragments.h pico_icmp4.c pico_icmp4.h pico_icmp6.h pico_igmp.h pico_ipfilter.h pico_ipv4.c pico_ipv4.h pico_ipv6.h pico_ipv6_nd.h pico_mm.h pico_nat.h pico_olsr.h pico_socket_tcp.h pico_socket_udp.c pico_socket_udp.h pico_tcp.h pico_udp.c pico_udp.h )
    $ ( cd net/picotcp/stack; git checkout pico_device.c pico_frame.c pico_protocol.c pico_socket.c pico_socket_multicast.c pico_stack.c pico_tree.c )
    $ rm -rf net/picotcp/.git
    $ git add net/picotcp/
    $ git commit -s

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 net/picotcp/.gitignore                      |   24 +
 net/picotcp/COPYING                         |    8 +
 net/picotcp/LICENSE                         |  339 ++++
 net/picotcp/README.md                       |   33 +
 net/picotcp/include/heap.h                  |   83 +
 net/picotcp/include/pico_addressing.h       |   52 +
 net/picotcp/include/pico_config.h           |  229 +++
 net/picotcp/include/pico_constants.h        |   54 +
 net/picotcp/include/pico_device.h           |   54 +
 net/picotcp/include/pico_eth.h              |   21 +
 net/picotcp/include/pico_frame.h            |  122 ++
 net/picotcp/include/pico_module_eth.h       |   33 +
 net/picotcp/include/pico_protocol.h         |   95 ++
 net/picotcp/include/pico_queue.h            |  166 ++
 net/picotcp/include/pico_socket.h           |  268 ++++
 net/picotcp/include/pico_socket_multicast.h |   10 +
 net/picotcp/include/pico_stack.h            |   87 ++
 net/picotcp/include/pico_tree.h             |   93 ++
 net/picotcp/modules/pico_aodv.h             |  131 ++
 net/picotcp/modules/pico_arp.c              |  531 +++++++
 net/picotcp/modules/pico_arp.h              |   32 +
 net/picotcp/modules/pico_dev_loop.c         |   66 +
 net/picotcp/modules/pico_dev_loop.h         |   15 +
 net/picotcp/modules/pico_dev_mock.h         |   47 +
 net/picotcp/modules/pico_dev_null.c         |   60 +
 net/picotcp/modules/pico_dev_null.h         |   15 +
 net/picotcp/modules/pico_dhcp_client.c      |  960 ++++++++++++
 net/picotcp/modules/pico_dhcp_client.h      |   30 +
 net/picotcp/modules/pico_dhcp_common.c      |  189 +++
 net/picotcp/modules/pico_dhcp_common.h      |  186 +++
 net/picotcp/modules/pico_dns_client.h       |   46 +
 net/picotcp/modules/pico_dns_common.h       |  521 +++++++
 net/picotcp/modules/pico_dns_sd.h           |   90 ++
 net/picotcp/modules/pico_fragments.c        |  345 +++++
 net/picotcp/modules/pico_fragments.h        |   11 +
 net/picotcp/modules/pico_icmp4.c            |  395 +++++
 net/picotcp/modules/pico_icmp4.h            |  162 ++
 net/picotcp/modules/pico_icmp6.h            |  259 ++++
 net/picotcp/modules/pico_igmp.h             |   26 +
 net/picotcp/modules/pico_ipfilter.h         |   29 +
 net/picotcp/modules/pico_ipv4.c             | 1574 +++++++++++++++++++
 net/picotcp/modules/pico_ipv4.h             |  124 ++
 net/picotcp/modules/pico_ipv6.h             |  153 ++
 net/picotcp/modules/pico_ipv6_nd.h          |   26 +
 net/picotcp/modules/pico_mm.h               |   98 ++
 net/picotcp/modules/pico_nat.h              |   90 ++
 net/picotcp/modules/pico_olsr.h             |   32 +
 net/picotcp/modules/pico_socket_tcp.h       |   33 +
 net/picotcp/modules/pico_socket_udp.c       |  250 +++
 net/picotcp/modules/pico_socket_udp.h       |   19 +
 net/picotcp/modules/pico_tcp.h              |  102 ++
 net/picotcp/modules/pico_udp.c              |  216 +++
 net/picotcp/modules/pico_udp.h              |   45 +
 net/picotcp/stack/pico_device.c             |  408 +++++
 net/picotcp/stack/pico_frame.c              |  286 ++++
 net/picotcp/stack/pico_protocol.c           |  214 +++
 net/picotcp/stack/pico_socket.c             | 2213 +++++++++++++++++++++++++++
 net/picotcp/stack/pico_socket_multicast.c   |  956 ++++++++++++
 net/picotcp/stack/pico_stack.c              | 1157 ++++++++++++++
 net/picotcp/stack/pico_tree.c               |  575 +++++++
 60 files changed, 14488 insertions(+)

diff --git a/net/picotcp/.gitignore b/net/picotcp/.gitignore
new file mode 100644
index 0000000..88593da
--- /dev/null
+++ b/net/picotcp/.gitignore
@@ -0,0 +1,24 @@
+*.d
+*.o
+*.a
+*.out
+*.swp
+tags
+build
+UNIT_*
+core
+core.*
+.DS_Store
+cscope.files
+cscope.out
+*.so
+*.aux
+*.pdf
+*.toc
+*.gz
+*.log
+*.pyc
+*.elf
+*.gcov
+*.gcda
+*.gcno
diff --git a/net/picotcp/COPYING b/net/picotcp/COPYING
new file mode 100644
index 0000000..8a5fe4b
--- /dev/null
+++ b/net/picotcp/COPYING
@@ -0,0 +1,8 @@
+PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems.
+
+Released under the GNU General Public License, version 2.
+See LICENSE for details.
+
+Different licensing models may exist, at the sole discretion of
+the Copyright holders.
+
diff --git a/net/picotcp/LICENSE b/net/picotcp/LICENSE
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/net/picotcp/LICENSE
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/net/picotcp/README.md b/net/picotcp/README.md
new file mode 100644
index 0000000..9e32eb7
--- /dev/null
+++ b/net/picotcp/README.md
@@ -0,0 +1,33 @@
+picoTCP
+
+---------------
+
+Welcome to the one and only <font color=ff00f0>picoTCP repository</font>. 
+
+picoTCP is a small-footprint, modular TCP/IP stack designed for embedded systems and the Internet of Things. It's actively being developed by *[Altran Intelligent Systems](http://intelligent-systems.altran.com/)*.
+
+This code is released under the terms of GNU GPL v2 only. Some rights reserved.
+Other licenses may apply at the sole discretion of the copyright holders.
+
+Learn how to use picoTCP in your project by going through the Getting Started guide on our [GitHub wiki](https://github.com/tass-belgium/picotcp/wiki).
+
+For more information visit the [picoTCP website](http://www.picotcp.com), send us an email or contact us on [Twitter](https://twitter.com/picotcp), [Facebook](https://www.facebook.com/picoTCP) or [Reddit](http://www.reddit.com/r/picotcp/).
+
+Wondering about picoTCP's code quality? Check [our TiCS score](http://tics.picotcp.com:42506/TIOBEPortal/TICS/treeviewer?)
+
+
+---------------
+
+Continuous integration
+
+Jenkins Functional tests: 
+[![Jenkins autotest](http://jenkins.picotcp.com:8080/buildStatus/icon?job=PicoTCP_rel_autotest)](http://jenkins.picotcp.com:8080/job/PicoTCP_rel_autotest)
+
+Jenkins Unit tests      : 
+[![Jenkins unit tests](http://jenkins.picotcp.com:8080/buildStatus/icon?job=PicoTCP_rel_unit_tests)](http://jenkins.picotcp.com:8080/job/PicoTCP_rel_unit_tests)
+
+Jenkins RFC compliance  :
+[![Jenkins RFC Compliance](http://jenkins.picotcp.com:8080/buildStatus/icon?job=PicoTCP_rel_RF_mbed)](http://jenkins.picotcp.com:8080/job/PicoTCP_rel_RF_mbed)
+
+Jenkins TICS quality    :
+[![Jenkins TICS](http://jenkins.picotcp.com:8080/buildStatus/icon?job=PicoTCP_rel_TICS)](http://jenkins.picotcp.com:8080/job/PicoTCP_rel_TICS/)
diff --git a/net/picotcp/include/heap.h b/net/picotcp/include/heap.h
new file mode 100644
index 0000000..88f495d
--- /dev/null
+++ b/net/picotcp/include/heap.h
@@ -0,0 +1,83 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+
+#define DECLARE_HEAP(type, orderby) \
+    struct heap_ ## type {   \
+        uint32_t size;    \
+        uint32_t n;       \
+        type *top;        \
+    }; \
+    typedef struct heap_ ## type heap_ ## type; \
+    static inline int heap_insert(struct heap_ ## type *heap, type * el) \
+    { \
+        uint32_t i; \
+        type *newTop; \
+        if (++heap->n >= heap->size) {                                                \
+            newTop = PICO_ZALLOC((heap->n + 1) * sizeof(type)); \
+            if(!newTop) { \
+                heap->n--; \
+                return -1; \
+            } \
+            if (heap->top)  { \
+                memcpy(newTop, heap->top, heap->n * sizeof(type)); \
+                PICO_FREE(heap->top); \
+            } \
+            heap->top = newTop;             \
+            heap->size++;                                                               \
+        }                                                                             \
+        if (heap->n == 1) {                                                       \
+            memcpy(&heap->top[1], el, sizeof(type));                                    \
+            return 0;                                                                   \
+        }                                                                             \
+        for (i = heap->n; ((i > 1) && (heap->top[i / 2].orderby > el->orderby)); i /= 2) {        \
+            memcpy(&heap->top[i], &heap->top[i / 2], sizeof(type));                     \
+        }             \
+        memcpy(&heap->top[i], el, sizeof(type));                                      \
+        return 0;                                                                     \
+    } \
+    static inline int heap_peek(struct heap_ ## type *heap, type * first) \
+    { \
+        type *last;           \
+        uint32_t i, child;        \
+        if(heap->n == 0) {    \
+            return -1;          \
+        }                     \
+        memcpy(first, &heap->top[1], sizeof(type));   \
+        last = &heap->top[heap->n--];                 \
+        for(i = 1; (i * 2u) <= heap->n; i = child) {   \
+            child = 2u * i;                              \
+            if ((child != heap->n) &&                   \
+                (heap->top[child + 1]).orderby          \
+                < (heap->top[child]).orderby)           \
+                child++;                                \
+            if (last->orderby >                         \
+                heap->top[child].orderby)               \
+                memcpy(&heap->top[i], &heap->top[child], \
+                       sizeof(type));                  \
+            else                                        \
+                break;                                  \
+        }                                             \
+        memcpy(&heap->top[i], last, sizeof(type));    \
+        return 0;                                     \
+    } \
+    static inline type *heap_first(heap_ ## type * heap)  \
+    { \
+        if (heap->n == 0)     \
+            return NULL;        \
+        return &heap->top[1];  \
+    } \
+    static inline heap_ ## type *heap_init(void) \
+    { \
+        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); \
+       } \*/
+
+
diff --git a/net/picotcp/include/pico_addressing.h b/net/picotcp/include/pico_addressing.h
new file mode 100644
index 0000000..de62281
--- /dev/null
+++ b/net/picotcp/include/pico_addressing.h
@@ -0,0 +1,52 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_ADDRESSING
+#define INCLUDE_PICO_ADDRESSING
+
+#include "pico_config.h"
+
+PACKED_STRUCT_DEF pico_ip4
+{
+    uint32_t addr;
+};
+
+PACKED_STRUCT_DEF pico_ip6
+{
+    uint8_t addr[16];
+};
+
+union pico_address
+{
+    struct pico_ip4 ip4;
+    struct pico_ip6 ip6;
+};
+
+PACKED_STRUCT_DEF pico_eth
+{
+    uint8_t addr[6];
+    uint8_t padding[2];
+};
+
+extern const uint8_t PICO_ETHADDR_ALL[];
+
+
+PACKED_STRUCT_DEF pico_trans
+{
+    uint16_t sport;
+    uint16_t dport;
+
+};
+
+/* Here are some protocols. */
+#define PICO_PROTO_IPV4   0
+#define PICO_PROTO_ICMP4  1
+#define PICO_PROTO_IGMP  2
+#define PICO_PROTO_TCP    6
+#define PICO_PROTO_UDP    17
+#define PICO_PROTO_IPV6   41
+#define PICO_PROTO_ICMP6  58
+
+#endif
diff --git a/net/picotcp/include/pico_config.h b/net/picotcp/include/pico_config.h
new file mode 100644
index 0000000..6b9c040
--- /dev/null
+++ b/net/picotcp/include/pico_config.h
@@ -0,0 +1,229 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#include "pico_defines.h"
+#ifndef INCLUDE_PICO_CONFIG
+#define INCLUDE_PICO_CONFIG
+#ifndef __KERNEL__
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#else
+#include <linux/types.h>
+#endif
+
+#if defined __IAR_SYSTEMS_ICC__ || defined ATOP
+#   define PACKED_STRUCT_DEF __packed struct
+#   define PEDANTIC_STRUCT_DEF __packed struct
+#   define PACKED_UNION_DEF  __packed union
+#   define WEAK
+#else
+#   define PACKED_STRUCT_DEF struct __attribute__((packed))
+#   define PEDANTIC_STRUCT_DEF struct
+#   define PACKED_UNION_DEF  union   /* Sane compilers do not require packed unions */
+#   define WEAK __attribute__((weak))
+#   ifdef __GNUC__
+#       define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#       if ((GCC_VERSION >= 40800))
+#           define BYTESWAP_GCC
+#       endif
+#   endif
+#endif
+
+#ifdef PICO_BIGENDIAN
+
+# define PICO_IDETH_IPV4 0x0800
+# define PICO_IDETH_ARP 0x0806
+# define PICO_IDETH_IPV6 0x86DD
+
+# define PICO_ARP_REQUEST 0x0001
+# define PICO_ARP_REPLY   0x0002
+# define PICO_ARP_HTYPE_ETH 0x0001
+
+#define short_be(x) (x)
+#define long_be(x) (x)
+#define long_long_be(x) (x)
+
+static inline uint16_t short_from(void *_p)
+{
+    unsigned char *p = (unsigned char *)_p;
+    uint16_t r, p0, p1;
+    p0 = p[0];
+    p1 = p[1];
+    r = (p0 << 8) + p1;
+    return r;
+}
+
+static inline uint32_t long_from(void *_p)
+{
+    unsigned char *p = (unsigned char *)_p;
+    uint32_t r, p0, p1, p2, p3;
+    p0 = p[0];
+    p1 = p[1];
+    p2 = p[2];
+    p3 = p[3];
+    r = (p0 << 24) + (p1 << 16) + (p2 << 8) + p3;
+    return r;
+}
+
+#else
+
+static inline uint16_t short_from(void *_p)
+{
+    unsigned char *p = (unsigned char *)_p;
+    uint16_t r, _p0, _p1;
+    _p0 = p[0];
+    _p1 = p[1];
+    r = (uint16_t)((_p1 << 8u) + _p0);
+    return r;
+}
+
+static inline uint32_t long_from(void *_p)
+{
+    unsigned char *p = (unsigned char *)_p;
+    uint32_t r, _p0, _p1, _p2, _p3;
+    _p0 = p[0];
+    _p1 = p[1];
+    _p2 = p[2];
+    _p3 = p[3];
+    r = (_p3 << 24) + (_p2 << 16) + (_p1 << 8) + _p0;
+    return r;
+}
+
+
+# define PICO_IDETH_IPV4 0x0008
+# define PICO_IDETH_ARP 0x0608
+# define PICO_IDETH_IPV6 0xDD86
+
+# define PICO_ARP_REQUEST 0x0100
+# define PICO_ARP_REPLY   0x0200
+# define PICO_ARP_HTYPE_ETH 0x0100
+
+#   ifndef BYTESWAP_GCC
+static inline uint16_t short_be(uint16_t le)
+{
+    return (uint16_t)(((le & 0xFFu) << 8) | ((le >> 8u) & 0xFFu));
+}
+
+static inline uint32_t long_be(uint32_t le)
+{
+    uint8_t *b = (uint8_t *)&le;
+    uint32_t be = 0;
+    uint32_t b0, b1, b2;
+    b0 = b[0];
+    b1 = b[1];
+    b2 = b[2];
+    be = b[3] + (b2 << 8) + (b1 << 16) + (b0 << 24);
+    return be;
+}
+static inline uint64_t long_long_be(uint64_t le)
+{
+    uint8_t *b = (uint8_t *)&le;
+    uint64_t be = 0;
+    uint64_t b0, b1, b2, b3, b4, b5, b6;
+    b0 = b[0];
+    b1 = b[1];
+    b2 = b[2];
+    b3 = b[3];
+    b4 = b[4];
+    b5 = b[5];
+    b6 = b[6];
+    be = b[7] + (b6 << 8) + (b5 << 16) + (b4 << 24) + (b3 << 32) + (b2 << 40) + (b1 << 48) + (b0 << 56);
+    return be;
+}
+#   else
+/*
+   extern uint32_t __builtin_bswap32(uint32_t);
+   extern uint16_t __builtin_bswap16(uint16_t);
+   extern uint64_t __builtin_bswap64(uint64_t);
+ */
+
+static inline uint32_t long_be(uint32_t le)
+{
+    return (uint32_t)__builtin_bswap32(le);
+}
+
+static inline uint16_t short_be(uint16_t le)
+{
+    return (uint16_t)__builtin_bswap16(le);
+}
+
+static inline uint64_t long_long_be(uint64_t le)
+{
+    return (uint64_t)__builtin_bswap64(le);
+}
+
+#   endif /* BYTESWAP_GCC */
+#endif
+
+
+/* Mockables */
+#if defined UNIT_TEST
+#   define MOCKABLE __attribute__((weak))
+#else
+#   define MOCKABLE
+#endif
+
+#include "pico_constants.h"
+#include "pico_mm.h"
+
+#define IGNORE_PARAMETER(x)  ((void)x)
+
+#define PICO_MEM_DEFAULT_SLAB_SIZE 1600
+#define PICO_MEM_PAGE_SIZE 4096
+#define PICO_MEM_PAGE_LIFETIME 100
+#define PICO_MIN_HEAP_SIZE 600
+#define PICO_MIN_SLAB_SIZE 1200
+#define PICO_MAX_SLAB_SIZE 1600
+#define PICO_MEM_MINIMUM_OBJECT_SIZE 4
+
+
+/*** *** *** *** *** *** ***
+ *** PLATFORM SPECIFIC   ***
+ *** *** *** *** *** *** ***/
+#if defined PICO_PORT_CUSTOM
+# include "pico_port.h"
+#elif defined CORTEX_M4_HARDFLOAT
+# include "arch/pico_cortex_m.h"
+#elif defined CORTEX_M4_SOFTFLOAT
+# include "arch/pico_cortex_m.h"
+#elif defined CORTEX_M3
+# include "arch/pico_cortex_m.h"
+#elif defined PIC24
+# include "arch/pico_pic24.h"
+#elif defined MSP430
+# include "arch/pico_msp430.h"
+#elif defined MBED_TEST
+# include "arch/pico_mbed.h"
+#elif defined AVR
+# include "arch/pico_avr.h"
+#elif defined ARM9
+# include "arch/pico_arm9.h"
+#elif defined ESP8266
+# include "arch/pico_esp8266.h"
+#elif defined MT7681
+# include "arch/pico_generic_gcc.h"
+#elif defined FAULTY
+# include "../test/pico_faulty.h"
+#elif defined ARCHNONE
+# include "arch/pico_none.h"
+#elif defined GENERIC
+# include "arch/pico_generic_gcc.h"
+#elif defined __KERNEL__
+# include "arch/pico_linux.h"
+/* #elif defined ... */
+#else
+# include "arch/pico_posix.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
diff --git a/net/picotcp/include/pico_constants.h b/net/picotcp/include/pico_constants.h
new file mode 100644
index 0000000..f043408
--- /dev/null
+++ b/net/picotcp/include/pico_constants.h
@@ -0,0 +1,54 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#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;
+
+
+/*** *** *** *** *** *** ***
+ ***     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 */
+#define PICO_ARP_INTERVAL 1000
+
+/* Add well-known host numbers here. (bigendian constants only beyond this point) */
+#define PICO_IP4_ANY (0x00000000U)
+#define PICO_IP4_BCAST (0xffffffffU)
+
+/* defined in modules/pico_ipv6.c */
+#ifdef PICO_SUPPORT_IPV6
+extern const uint8_t PICO_IPV6_ANY[PICO_SIZE_IP6];
+#endif
+
+static inline uint32_t pico_hash(const void *buf, uint32_t size)
+{
+    uint32_t hash = 5381;
+    uint32_t i;
+    const uint8_t *ptr = (const uint8_t *)buf;
+    for(i = 0; i < size; i++)
+        hash = ((hash << 5) + hash) + ptr[i]; /* hash * 33 + char */
+    return hash;
+}
+
+/* Debug */
+/* #define PICO_SUPPORT_DEBUG_MEMORY */
+/* #define PICO_SUPPORT_DEBUG_TOOLS */
+#endif
diff --git a/net/picotcp/include/pico_device.h b/net/picotcp/include/pico_device.h
new file mode 100644
index 0000000..a2d03ec
--- /dev/null
+++ b/net/picotcp/include/pico_device.h
@@ -0,0 +1,54 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_DEVICE
+#define INCLUDE_PICO_DEVICE
+#include "pico_queue.h"
+#include "pico_frame.h"
+#include "pico_addressing.h"
+#include "pico_tree.h"
+extern struct pico_tree Device_tree;
+#include "pico_ipv6_nd.h"
+#define MAX_DEVICE_NAME 16
+
+
+struct pico_ethdev {
+    struct pico_eth mac;
+};
+
+struct pico_device {
+    char name[MAX_DEVICE_NAME];
+    uint32_t hash;
+    uint32_t overhead;
+    uint32_t mtu;
+    struct pico_ethdev *eth; /* Null if non-ethernet */
+    struct pico_queue *q_in;
+    struct pico_queue *q_out;
+    int (*link_state)(struct pico_device *self);
+    int (*send)(struct pico_device *self, void *buf, int len); /* Send function. Return 0 if busy */
+    int (*poll)(struct pico_device *self, int loop_score);
+    void (*destroy)(struct pico_device *self);
+    int (*dsr)(struct pico_device *self, int loop_score);
+    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);
+void pico_device_destroy(struct pico_device *dev);
+int pico_devices_loop(int loop_score, int direction);
+struct pico_device*pico_get_device(const char*name);
+int32_t pico_device_broadcast(struct pico_frame *f);
+int pico_device_link_state(struct pico_device *dev);
+int pico_device_ipv6_random_ll(struct pico_device *dev);
+#ifdef PICO_SUPPORT_IPV6
+struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix);
+#endif
+
+#endif
diff --git a/net/picotcp/include/pico_eth.h b/net/picotcp/include/pico_eth.h
new file mode 100644
index 0000000..89846c7
--- /dev/null
+++ b/net/picotcp/include/pico_eth.h
@@ -0,0 +1,21 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_ETH
+#define INCLUDE_PICO_ETH
+#include "pico_addressing.h"
+#include "pico_ipv4.h"
+#include "pico_ipv6.h"
+
+
+PACKED_STRUCT_DEF pico_eth_hdr {
+    uint8_t daddr[6];
+    uint8_t saddr[6];
+    uint16_t proto;
+};
+
+#define PICO_SIZE_ETHHDR 14
+
+#endif
diff --git a/net/picotcp/include/pico_frame.h b/net/picotcp/include/pico_frame.h
new file mode 100644
index 0000000..feb8f78
--- /dev/null
+++ b/net/picotcp/include/pico_frame.h
@@ -0,0 +1,122 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_FRAME
+#define INCLUDE_PICO_FRAME
+#include "pico_config.h"
+
+
+#define PICO_FRAME_FLAG_BCAST               (0x01)
+#define PICO_FRAME_FLAG_EXT_BUFFER          (0x02)
+#define PICO_FRAME_FLAG_EXT_USAGE_COUNTER   (0x04)
+#define PICO_FRAME_FLAG_SACKED              (0x80)
+#define IS_BCAST(f) ((f->flags & PICO_FRAME_FLAG_BCAST) == PICO_FRAME_FLAG_BCAST)
+
+
+struct pico_socket;
+
+
+struct pico_frame {
+
+    /* Connector for queues */
+    struct pico_frame *next;
+
+    /* Start of the whole buffer, total frame length. */
+    unsigned char *buffer;
+    uint32_t buffer_len;
+
+    /* For outgoing packets: this is the meaningful buffer. */
+    unsigned char *start;
+    uint32_t len;
+
+    /* Pointer to usage counter */
+    uint32_t *usage_count;
+
+    /* Pointer to protocol headers */
+    uint8_t *datalink_hdr;
+
+    uint8_t *net_hdr;
+    uint16_t net_len;
+    uint8_t *transport_hdr;
+    uint16_t transport_len;
+    uint8_t *app_hdr;
+    uint16_t app_len;
+
+    /* Pointer to the phisical device this packet belongs to.
+     * Should be valid in both routing directions
+     */
+    struct pico_device *dev;
+
+    pico_time timestamp;
+
+    /* Failures due to bad datalink addressing. */
+    uint16_t failure_count;
+
+    /* Protocol over IP */
+    uint8_t proto;
+
+    /* PICO_FRAME_FLAG_* */
+    uint8_t flags;
+
+    /* Pointer to payload */
+    unsigned char *payload;
+    uint16_t payload_len;
+
+#ifdef PICO_SUPPORT_IPFRAG
+    /* Payload fragmentation info */
+    uint16_t frag;
+#endif
+
+    /* Pointer to socket */
+    struct pico_socket *sock;
+
+    /* 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*/
+    int8_t priority;
+    uint8_t transport_flags_saved;
+
+    /* Callback to notify listener when the buffer has been discarded */
+    void (*notify_free)(uint8_t *);
+
+    uint8_t send_ttl; /* Special TTL/HOPS value, 0 = auto assign */
+    uint8_t send_tos; /* Type of service */
+};
+
+/** frame alloc/dealloc/copy **/
+void pico_frame_discard(struct pico_frame *f);
+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);
+int pico_frame_grow(struct pico_frame *f, uint32_t size);
+struct pico_frame *pico_frame_alloc_skeleton(uint32_t size, int ext_buffer);
+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);
+
+static inline int pico_is_digit(char c)
+{
+    if (c < '0' || c > '9')
+        return 0;
+
+    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
diff --git a/net/picotcp/include/pico_module_eth.h b/net/picotcp/include/pico_module_eth.h
new file mode 100644
index 0000000..c86680d
--- /dev/null
+++ b/net/picotcp/include/pico_module_eth.h
@@ -0,0 +1,33 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef PICO_MODULE_IPV4_H
+#define PICO_MODULE_IPV4_H
+
+struct pico_arp_entry {
+    struct eth dest;
+#ifdef PICO_CONFIG_IPV4
+    struct ipv4 addr_ipv4;
+#endif
+    RB_ENTRY(pico_arp_entry) node;
+};
+
+/* Configured device */
+struct pico_eth_link {
+    struct pico_device *dev;
+    struct eth address;
+    struct eth netmask;
+    RB_ENTRY(pico_eth_link) node;
+};
+
+#ifndef IS_MODULE_ETH
+# define _mod extern
+#else
+# define _mod
+#endif
+_mod struct pico_module pico_module_eth;
+#undef _mod
+
+#endif
diff --git a/net/picotcp/include/pico_protocol.h b/net/picotcp/include/pico_protocol.h
new file mode 100644
index 0000000..fd7c122
--- /dev/null
+++ b/net/picotcp/include/pico_protocol.h
@@ -0,0 +1,95 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_PROTOCOL
+#define INCLUDE_PICO_PROTOCOL
+#include "pico_config.h"
+#include "pico_queue.h"
+
+#define PICO_LOOP_DIR_IN   1
+#define PICO_LOOP_DIR_OUT  2
+
+enum pico_layer {
+    PICO_LAYER_DATALINK = 2, /* Ethernet only. */
+    PICO_LAYER_NETWORK = 3, /* IPv4, IPv6, ARP. Arp is there because it communicates with L2 */
+    PICO_LAYER_TRANSPORT = 4, /* UDP, TCP, ICMP */
+    PICO_LAYER_SOCKET = 5   /* Socket management */
+};
+
+enum pico_err_e {
+    PICO_ERR_NOERR = 0,
+    PICO_ERR_EPERM = 1,
+    PICO_ERR_ENOENT = 2,
+    /* ... */
+    PICO_ERR_EINTR = 4,
+    PICO_ERR_EIO = 5,
+    PICO_ERR_ENXIO = 6,
+    /* ... */
+    PICO_ERR_EAGAIN = 11,
+    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 = 99,
+    PICO_ERR_ENETDOWN = 100,
+    PICO_ERR_ENETUNREACH = 101,
+    /* ... */
+    PICO_ERR_ECONNRESET = 104,
+    /* ... */
+    PICO_ERR_EISCONN = 106,
+    PICO_ERR_ENOTCONN = 107,
+    PICO_ERR_ESHUTDOWN = 108,
+    /* ... */
+    PICO_ERR_ETIMEDOUT = 110,
+    PICO_ERR_ECONNREFUSED = 111,
+    PICO_ERR_EHOSTDOWN = 112,
+    PICO_ERR_EHOSTUNREACH = 113,
+};
+
+typedef enum pico_err_e pico_err_t;
+extern volatile pico_err_t pico_err;
+
+#define IS_IPV6(f) (f && f->net_hdr && ((((uint8_t *)(f->net_hdr))[0] & 0xf0) == 0x60))
+#define IS_IPV4(f) (f && f->net_hdr && ((((uint8_t *)(f->net_hdr))[0] & 0xf0) == 0x40))
+
+#define MAX_PROTOCOL_NAME 16
+
+struct pico_protocol {
+    char name[MAX_PROTOCOL_NAME];
+    uint32_t hash;
+    enum pico_layer layer;
+    uint16_t proto_number;
+    struct pico_queue *q_in;
+    struct pico_queue *q_out;
+    struct pico_frame *(*alloc)(struct pico_protocol *self, uint16_t size); /* Frame allocation. */
+    int (*push)(struct pico_protocol *self, struct pico_frame *p);    /* Push function, for active outgoing pkts from above */
+    int (*process_out)(struct pico_protocol *self, struct pico_frame *p);  /* Send loop. */
+    int (*process_in)(struct pico_protocol *self, struct pico_frame *p);  /* Recv loop. */
+    uint16_t (*get_mtu)(struct pico_protocol *self);
+};
+
+int pico_protocols_loop(int loop_score);
+void pico_protocol_init(struct pico_protocol *p);
+
+int pico_protocol_datalink_loop(int loop_score, int direction);
+int pico_protocol_network_loop(int loop_score, int direction);
+int pico_protocol_transport_loop(int loop_score, int direction);
+int pico_protocol_socket_loop(int loop_score, int direction);
+
+#endif
diff --git a/net/picotcp/include/pico_queue.h b/net/picotcp/include/pico_queue.h
new file mode 100644
index 0000000..6cbb979
--- /dev/null
+++ b/net/picotcp/include/pico_queue.h
@@ -0,0 +1,166 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_QUEUE
+#define INCLUDE_PICO_QUEUE
+#include "pico_config.h"
+#include "pico_frame.h"
+
+#define Q_LIMIT 0
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+void *pico_mutex_init(void);
+void pico_mutex_deinit(void *mutex);
+void pico_mutex_lock(void *mutex);
+int pico_mutex_lock_timeout(void *mutex, int timeout);
+void pico_mutex_unlock(void *mutex);
+void pico_mutex_unlock_ISR(void *mutex);
+
+struct pico_queue {
+    uint32_t frames;
+    uint32_t size;
+    uint32_t max_frames;
+    uint32_t max_size;
+    struct pico_frame *head;
+    struct pico_frame *tail;
+#ifdef PICO_SUPPORT_MUTEX
+    void *mutex;
+#endif
+    uint8_t shared;
+    uint16_t overhead;
+};
+
+#ifdef PICO_SUPPORT_MUTEX
+#define PICOTCP_MUTEX_LOCK(x) { \
+        if (x == NULL) \
+            x = pico_mutex_init(); \
+        pico_mutex_lock(x); \
+}
+#define PICOTCP_MUTEX_UNLOCK(x) pico_mutex_unlock(x)
+#define PICOTCP_MUTEX_DEL(x) pico_mutex_deinit(x)
+
+#else
+#define PICOTCP_MUTEX_LOCK(x) do {} while(0)
+#define PICOTCP_MUTEX_UNLOCK(x) do {} while(0)
+#define PICOTCP_MUTEX_DEL(x) do {} while(0)
+#endif
+
+#ifdef PICO_SUPPORT_DEBUG_TOOLS
+static void debug_q(struct pico_queue *q)
+{
+    struct pico_frame *p = q->head;
+    dbg("%d: ", q->frames);
+    while(p) {
+        dbg("(%p)-->", p);
+        p = p->next;
+    }
+    dbg("X\n");
+}
+
+#else
+
+#define debug_q(x) do {} while(0)
+#endif
+
+static inline int32_t pico_enqueue(struct pico_queue *q, struct pico_frame *p)
+{
+    if ((q->max_frames) && (q->max_frames <= q->frames))
+        return -1;
+
+#if (Q_LIMIT != 0)
+    if ((Q_LIMIT < p->buffer_len + q->size))
+        return -1;
+
+#endif
+
+    if ((q->max_size) && (q->max_size < (p->buffer_len + q->size)))
+        return -1;
+
+    if (q->shared)
+        PICOTCP_MUTEX_LOCK(q->mutex);
+
+    p->next = NULL;
+    if (!q->head) {
+        q->head = p;
+        q->tail = p;
+        q->size = 0;
+        q->frames = 0;
+    } else {
+        q->tail->next = p;
+        q->tail = p;
+    }
+
+    q->size += p->buffer_len + q->overhead;
+    q->frames++;
+    debug_q(q);
+
+    if (q->shared)
+        PICOTCP_MUTEX_UNLOCK(q->mutex);
+
+    return (int32_t)q->size;
+}
+
+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)
+        PICOTCP_MUTEX_LOCK(q->mutex);
+
+    q->head = p->next;
+    q->frames--;
+    q->size -= p->buffer_len - q->overhead;
+    if (q->head == NULL)
+        q->tail = NULL;
+
+    debug_q(q);
+
+    p->next = NULL;
+    if (q->shared)
+        PICOTCP_MUTEX_UNLOCK(q->mutex);
+
+    return p;
+}
+
+static inline struct pico_frame *pico_queue_peek(struct pico_queue *q)
+{
+    struct pico_frame *p = q->head;
+    if (q->frames < 1)
+        return NULL;
+
+    debug_q(q);
+    return p;
+}
+
+static inline void pico_queue_deinit(struct pico_queue *q)
+{
+    if (q->shared) {
+        PICOTCP_MUTEX_DEL(q->mutex);
+    }
+}
+
+static inline void pico_queue_empty(struct pico_queue *q)
+{
+    struct pico_frame *p = pico_dequeue(q);
+    while(p) {
+        pico_frame_discard(p);
+        p = pico_dequeue(q);
+    }
+}
+
+static inline void pico_queue_protect(struct pico_queue *q)
+{
+    q->shared = 1;
+}
+
+#endif
diff --git a/net/picotcp/include/pico_socket.h b/net/picotcp/include/pico_socket.h
new file mode 100644
index 0000000..a076654
--- /dev/null
+++ b/net/picotcp/include/pico_socket.h
@@ -0,0 +1,268 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#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 */
+#else
+    #define PICO_DEFAULT_SOCKETQ (6 * 1024) /* seems like an acceptable default for small embedded systems */
+#endif
+
+#define PICO_SHUT_RD   1
+#define PICO_SHUT_WR   2
+#define PICO_SHUT_RDWR 3
+
+#ifdef PICO_SUPPORT_IPV4
+# define IS_SOCK_IPV4(s) ((s->net == &pico_proto_ipv4))
+#else
+# define IS_SOCK_IPV4(s) (0)
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+# define IS_SOCK_IPV6(s) ((s->net == &pico_proto_ipv6))
+#else
+# define IS_SOCK_IPV6(s) (0)
+#endif
+
+
+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 pico_address local_addr;
+    union pico_address remote_addr;
+
+    uint16_t local_port;
+    uint16_t remote_port;
+
+    struct pico_queue q_in;
+    struct pico_queue q_out;
+
+    void (*wakeup)(uint16_t ev, struct pico_socket *s);
+
+
+#ifdef PICO_SUPPORT_TCP
+    /* For the TCP backlog queue */
+    struct pico_socket *backlog;
+    struct pico_socket *next;
+    struct pico_socket *parent;
+    uint16_t max_backlog;
+    uint16_t number_of_pending_conn;
+#endif
+#ifdef PICO_SUPPORT_MCAST
+    struct pico_tree *MCASTListen;
+#endif
+    uint16_t ev_pending;
+
+    struct pico_device *dev;
+
+    /* Private field. */
+    int id;
+    uint16_t state;
+    uint16_t opt_flags;
+    pico_time timestamp;
+    void *priv;
+};
+
+struct pico_remote_endpoint {
+    union pico_address remote_addr;
+    uint16_t remote_port;
+};
+
+
+/* request struct for multicast socket opt */
+struct pico_ip_mreq {
+    struct pico_ip4 mcast_group_addr;
+    struct pico_ip4 mcast_link_addr;
+};
+
+struct pico_ip_mreq_source {
+    struct pico_ip4 mcast_group_addr;
+    struct pico_ip4 mcast_source_addr;
+    struct pico_ip4 mcast_link_addr;
+};
+
+#ifdef PICO_SUPPORT_IPV6
+
+/* same as above, but ipv6 */
+struct pico_ipv6_mreq {
+    struct pico_ip6 mcast_group_addr;
+    struct pico_ip6 mcast_link_addr;
+};
+
+struct pico_ipv6_mreq_source {
+    struct pico_ip6 mcast_group_addr;
+    struct pico_ip6 mcast_source_addr;
+    struct pico_ip6 mcast_link_addr;
+};
+
+#endif
+
+#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                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           0x0000u
+
+# define PICO_IP_MULTICAST_EXCLUDE            0
+# define PICO_IP_MULTICAST_INCLUDE            1
+# define PICO_IP_MULTICAST_IF                 32
+# define PICO_IP_MULTICAST_TTL                33
+# define PICO_IP_MULTICAST_LOOP               34
+# define PICO_IP_ADD_MEMBERSHIP               35
+# define PICO_IP_DROP_MEMBERSHIP              36
+# define PICO_IP_UNBLOCK_SOURCE               37
+# define PICO_IP_BLOCK_SOURCE                 38
+# define PICO_IP_ADD_SOURCE_MEMBERSHIP        39
+# define PICO_IP_DROP_SOURCE_MEMBERSHIP       40
+
+# 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 0x01u
+#define PICO_SOCKET_SHUTDOWN_READ  0x02u
+#define TCPSTATE(s) ((s)->state & PICO_SOCKET_STATE_TCP)
+
+#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_msginfo {
+    struct pico_device *dev;
+    uint8_t ttl;
+    uint8_t tos;
+};
+
+struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s));
+
+int pico_socket_read(struct pico_socket *s, void *buf, int len);
+int pico_socket_write(struct pico_socket *s, const void *buf, int len);
+
+int pico_socket_sendto(struct pico_socket *s, const void *buf, int len, void *dst, uint16_t remote_port);
+int pico_socket_sendto_extended(struct pico_socket *s, const void *buf, const int len,
+                                void *dst, uint16_t remote_port, struct pico_msginfo *msginfo);
+
+int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *local_port);
+int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, void *orig,
+                                  uint16_t *remote_port, struct pico_msginfo *msginfo);
+
+int pico_socket_send(struct pico_socket *s, const void *buf, int len);
+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_getpeername(struct pico_socket *s, void *remote_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);
+int8_t pico_socket_del(struct pico_socket *s);
+
+int pico_socket_setoption(struct pico_socket *s, int option, void *value);
+int pico_socket_getoption(struct pico_socket *s, int option, void *value);
+
+int pico_socket_shutdown(struct pico_socket *s, int mode);
+int pico_socket_close(struct pico_socket *s);
+
+struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len);
+
+#ifdef PICO_SUPPORT_IPV4
+# define is_sock_ipv4(x) (x->net == &pico_proto_ipv4)
+#else
+# define is_sock_ipv4(x) (0)
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+# define is_sock_ipv6(x) (x->net == &pico_proto_ipv6)
+#else
+# define is_sock_ipv6(x) (0)
+#endif
+
+#ifdef PICO_SUPPORT_UDP
+# define is_sock_udp(x) (x->proto == &pico_proto_udp)
+#else
+# define is_sock_udp(x) (0)
+#endif
+
+#ifdef PICO_SUPPORT_TCP
+# define is_sock_tcp(x) (x->proto == &pico_proto_tcp)
+#else
+# define is_sock_tcp(x) (0)
+#endif
+
+/* Interface towards transport protocol */
+int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f);
+struct pico_socket *pico_socket_clone(struct pico_socket *facsimile);
+int8_t pico_socket_add(struct pico_socket *s);
+int pico_transport_error(struct pico_frame *f, uint8_t proto, int code);
+
+/* Socket loop */
+int pico_sockets_loop(int loop_score);
+struct pico_socket*pico_sockets_find(uint16_t local, uint16_t remote);
+/* 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);
+
+uint32_t pico_socket_get_mss(struct pico_socket *s);
+int pico_socket_set_family(struct pico_socket *s, uint16_t family);
+
+int pico_count_sockets(uint8_t proto);
+
+#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
diff --git a/net/picotcp/include/pico_socket_multicast.h b/net/picotcp/include/pico_socket_multicast.h
new file mode 100644
index 0000000..44c30c5
--- /dev/null
+++ b/net/picotcp/include/pico_socket_multicast.h
@@ -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
diff --git a/net/picotcp/include/pico_stack.h b/net/picotcp/include/pico_stack.h
new file mode 100644
index 0000000..69b0bf1
--- /dev/null
+++ b/net/picotcp/include/pico_stack.h
@@ -0,0 +1,87 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_STACK
+#define INCLUDE_PICO_STACK
+#include "pico_config.h"
+#include "pico_frame.h"
+
+#define PICO_MAX_TIMERS 20
+
+#define PICO_ETH_MRU (1514u)
+#define PICO_IP_MRU (1500u)
+
+/* ===== RECEIVING FUNCTIONS (from dev up to socket) ===== */
+
+/* TRANSPORT LEVEL */
+/* interface towards network */
+int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto);
+
+/* NETWORK LEVEL */
+/* interface towards ethernet */
+int32_t pico_network_receive(struct pico_frame *f);
+
+
+/* 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);
+int32_t pico_stack_recv_zerocopy_ext_buffer(struct pico_device *dev, uint8_t *buffer, uint32_t len);
+int32_t pico_stack_recv_zerocopy_ext_buffer_notify(struct pico_device *dev, uint8_t *buffer, uint32_t len, void (*notify_free)(uint8_t *buffer));
+
+/* ===== SENDING FUNCTIONS (from socket down to dev) ===== */
+
+int32_t pico_network_send(struct pico_frame *f);
+int32_t pico_sendto_dev(struct pico_frame *f);
+
+#ifdef PICO_SUPPORT_ETH
+int32_t pico_ethernet_send(struct pico_frame *f);
+
+/* The pico_ethernet_receive() function is used by
+ * those devices supporting ETH in order to push packets up
+ * into the stack.
+ */
+/* DATALINK LEVEL */
+int32_t pico_ethernet_receive(struct pico_frame *f);
+#else
+/* When ETH is not supported by the stack... */
+#   define pico_ethernet_send(f)    (-1)
+#   define pico_ethernet_receive(f) (-1)
+#endif
+
+/* ----- Initialization ----- */
+int pico_stack_init(void);
+
+/* ----- Loop Function. ----- */
+void pico_stack_tick(void);
+void pico_stack_loop(void);
+
+/* ---- Notifications for stack errors */
+int pico_notify_socket_unreachable(struct pico_frame *f);
+int pico_notify_proto_unreachable(struct pico_frame *f);
+int pico_notify_dest_unreachable(struct pico_frame *f);
+int pico_notify_ttl_expired(struct pico_frame *f);
+int pico_notify_frag_expired(struct pico_frame *f);
+int pico_notify_pkt_too_big(struct pico_frame *f);
+
+/* Various. */
+struct pico_timer;
+int pico_source_is_local(struct pico_frame *f);
+int pico_frame_dst_is_unicast(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);
+pico_time pico_timer_get_expire(struct pico_timer *t);
+uint32_t pico_rand(void);
+void pico_rand_feed(uint32_t feed);
+void pico_to_lowercase(char *str);
+int pico_address_compare(union pico_address *a, union pico_address *b, uint16_t proto);
+int32_t pico_seq_compare(uint32_t a, uint32_t b);
+
+#endif
diff --git a/net/picotcp/include/pico_tree.h b/net/picotcp/include/pico_tree.h
new file mode 100644
index 0000000..8667a1f
--- /dev/null
+++ b/net/picotcp/include/pico_tree.h
@@ -0,0 +1,93 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Author: Andrei Carp <andrei.carp@tass.be>
+ *********************************************************************/
+
+#ifndef PICO_RBTREE_H
+#define PICO_RBTREE_H
+
+#include "pico_config.h"
+
+/* This is used to declare a new tree, leaf root by default */
+#define PICO_TREE_DECLARE(name, compareFunction) \
+    struct pico_tree name = \
+    { \
+        &LEAF, \
+        compareFunction \
+    }
+
+#define USE_PICO_PAGE0_ZALLOC (1)
+#define USE_PICO_ZALLOC (2)
+
+struct pico_tree_node
+{
+    void*keyValue; /* generic key */
+    struct pico_tree_node*parent;
+    struct pico_tree_node*leftChild;
+    struct pico_tree_node*rightChild;
+    uint8_t color;
+};
+
+struct pico_tree
+{
+    struct pico_tree_node *root;  /* root of the tree */
+
+    /* this function directly provides the keys as parameters not the nodes. */
+    int (*compare)(void*keyA, void*keyB);
+};
+
+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
+ */
+void *pico_tree_insert(struct pico_tree *tree, void *key);
+void *pico_tree_delete(struct pico_tree *tree, void *key);
+void *pico_tree_findKey(struct pico_tree *tree, void *key);
+void    pico_tree_drop(struct pico_tree *tree);
+int     pico_tree_empty(struct pico_tree *tree);
+struct pico_tree_node *pico_tree_findNode(struct pico_tree *tree, void *key);
+
+void *pico_tree_first(struct pico_tree *tree);
+void *pico_tree_last(struct pico_tree *tree);
+/*
+ * Traverse functions
+ */
+struct pico_tree_node *pico_tree_lastNode(struct pico_tree_node *node);
+struct pico_tree_node *pico_tree_firstNode(struct pico_tree_node *node);
+struct pico_tree_node *pico_tree_next(struct pico_tree_node *node);
+struct pico_tree_node *pico_tree_prev(struct pico_tree_node *node);
+
+/*
+ * For each macros
+ */
+
+#define pico_tree_foreach(idx, tree) \
+    for ((idx) = pico_tree_firstNode((tree)->root); \
+         (idx) != &LEAF; \
+         (idx) = pico_tree_next(idx))
+
+#define pico_tree_foreach_reverse(idx, tree) \
+    for ((idx) = pico_tree_lastNode((tree)->root); \
+         (idx) != &LEAF; \
+         (idx) = pico_tree_prev(idx))
+
+#define pico_tree_foreach_safe(idx, tree, idx2) \
+    for ((idx) = pico_tree_firstNode((tree)->root); \
+         ((idx) != &LEAF) && ((idx2) = pico_tree_next(idx), 1); \
+         (idx) = (idx2))
+
+#define pico_tree_foreach_reverse_safe(idx, tree, idx2) \
+    for ((idx) = pico_tree_lastNode((tree)->root); \
+         ((idx) != &LEAF) && ((idx2) = pico_tree_prev(idx), 1); \
+         (idx) = (idx2))
+
+#endif
diff --git a/net/picotcp/modules/pico_aodv.h b/net/picotcp/modules/pico_aodv.h
new file mode 100644
index 0000000..a3e9b66
--- /dev/null
+++ b/net/picotcp/modules/pico_aodv.h
@@ -0,0 +1,131 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Author: Daniele Lacamera <daniele.lacamera@altran.com>
+ *********************************************************************/
+#ifndef PICO_AODV_H_
+#define PICO_AODV_H_
+#include <stdint.h>
+
+/* RFC3561 */
+#define PICO_AODV_PORT (654)
+
+/* RFC3561 $10 */
+#define AODV_ACTIVE_ROUTE_TIMEOUT     (8000u) /* Conservative value for link breakage detection */
+#define AODV_DELETE_PERIOD            (5 * AODV_ACTIVE_ROUTE_TIMEOUT) /* Recommended value K = 5 */
+#define AODV_ALLOWED_HELLO_LOSS       (4) /* conservative */
+#define AODV_NET_DIAMETER             ((uint8_t)(35))
+#define AODV_RREQ_RETRIES             (2)
+#define AODV_NODE_TRAVERSAL_TIME      (40)
+#define AODV_HELLO_INTERVAL           (1000)
+#define AODV_LOCAL_ADD_TTL            2
+#define AODV_RREQ_RATELIMIT           (10)
+#define AODV_TIMEOUT_BUFFER           (2)
+#define AODV_TTL_START                ((uint8_t)(1))
+#define AODV_TTL_INCREMENT            2
+#define AODV_TTL_THRESHOLD            ((uint8_t)(7))
+#define AODV_RERR_RATELIMIT           (10)
+#define AODV_MAX_REPAIR_TTL           ((uint8_t)(AODV_NET_DIAMETER / 3))
+#define AODV_MY_ROUTE_TIMEOUT         (2 * AODV_ACTIVE_ROUTE_TIMEOUT)
+#define AODV_NET_TRAVERSAL_TIME       (2 * AODV_NODE_TRAVERSAL_TIME * AODV_NET_DIAMETER)
+#define AODV_BLACKLIST_TIMEOUT        (AODV_RREQ_RETRIES * AODV_NET_TRAVERSAL_TIME)
+#define AODV_NEXT_HOP_WAIT            (AODV_NODE_TRAVERSAL_TIME + 10)
+#define AODV_PATH_DISCOVERY_TIME      (2 * AODV_NET_TRAVERSAL_TIME)
+#define AODV_RING_TRAVERSAL_TIME(ttl)   (2 * AODV_NODE_TRAVERSAL_TIME * (ttl + AODV_TIMEOUT_BUFFER))
+/* End section RFC3561 $10 */
+
+
+#define AODV_TYPE_RREQ 1
+#define AODV_TYPE_RREP 2
+#define AODV_TYPE_RERR 3
+#define AODV_TYPE_RACK 4
+
+PACKED_STRUCT_DEF pico_aodv_rreq
+{
+    uint8_t type;
+    uint16_t req_flags;
+    uint8_t hop_count;
+    uint32_t rreq_id;
+    uint32_t dest;
+    uint32_t dseq;
+    uint32_t orig;
+    uint32_t oseq;
+};
+
+#define AODV_RREQ_FLAG_J 0x8000
+#define AODV_RREQ_FLAG_R 0x4000
+#define AODV_RREQ_FLAG_G 0x2000
+#define AODV_RREQ_FLAG_D 0x1000
+#define AODV_RREQ_FLAG_U 0x0800
+#define AODV_RREQ_FLAG_RESERVED 0x07FF
+
+PACKED_STRUCT_DEF pico_aodv_rrep
+{
+    uint8_t type;
+    uint8_t rep_flags;
+    uint8_t prefix_sz;
+    uint8_t hop_count;
+    uint32_t dest;
+    uint32_t dseq;
+    uint32_t orig;
+    uint32_t lifetime;
+};
+
+#define AODV_RREP_MAX_PREFIX 0x1F
+#define AODV_RREP_FLAG_R 0x80
+#define AODV_RREP_FLAG_A 0x40
+#define AODV_RREP_FLAG_RESERVED 0x3F
+
+#define PICO_AODV_NODE_NEW          0x0000
+#define PICO_AODV_NODE_SYNC         0x0001
+#define PICO_AODV_NODE_REQUESTING   0x0002
+#define PICO_AODV_NODE_ROUTE_UP     0x0004
+#define PICO_AODV_NODE_ROUTE_DOWN   0x0008
+#define PICO_AODV_NODE_IDLING       0x0010
+#define PICO_AODV_NODE_UNREACH      0x0020
+
+#define PICO_AODV_ACTIVE(node) ((node->flags & PICO_AODV_NODE_ROUTE_UP) && (node->flags & PICO_AODV_NODE_ROUTE_DOWN))
+
+
+struct pico_aodv_node
+{
+    union pico_address dest;
+    pico_time last_seen;
+    pico_time fwd_time;
+    uint32_t dseq;
+    uint16_t flags;
+    uint8_t metric;
+    uint8_t ring_ttl;
+    uint8_t rreq_retry;
+};
+
+PACKED_STRUCT_DEF pico_aodv_unreachable
+{
+    uint32_t addr;
+    uint32_t dseq;
+};
+
+PACKED_STRUCT_DEF pico_aodv_rerr
+{
+    uint8_t type;
+    uint16_t rerr_flags;
+    uint8_t dst_count;
+    uint32_t unreach_addr;
+    uint32_t unreach_dseq;
+    struct pico_aodv_unreachable unreach[1]; /* unrechable nodes: must be at least 1. See dst_count field above */
+};
+
+PACKED_STRUCT_DEF pico_aodv_rack
+{
+    uint8_t type;
+    uint8_t reserved;
+};
+
+int pico_aodv_init(void);
+int pico_aodv_add(struct pico_device *dev);
+int pico_aodv_lookup(const union pico_address *addr);
+void pico_aodv_refresh(const union pico_address *addr);
+#endif
diff --git a/net/picotcp/modules/pico_arp.c b/net/picotcp/modules/pico_arp.c
new file mode 100644
index 0000000..f205bfe
--- /dev/null
+++ b/net/picotcp/modules/pico_arp.c
@@ -0,0 +1,531 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. 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
+#define PICO_ARP_MAX_PENDING 5
+
+#ifdef DEBUG_ARP
+    #define arp_dbg dbg
+#else
+    #define arp_dbg(...) do {} while(0)
+#endif
+
+static int max_arp_reqs = PICO_ARP_MAX_RATE;
+static struct pico_frame *frames_queued[PICO_ARP_MAX_PENDING] = { };
+
+static void pico_arp_queued_trigger(void)
+{
+    int i;
+    struct pico_frame *f;
+    for (i = 0; i < PICO_ARP_MAX_PENDING; i++)
+    {
+        f = frames_queued[i];
+        if (f) {
+            pico_ethernet_send(f);
+            frames_queued[i] = 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;
+    return pico_ipv4_compare(&a->ipv4, &b->ipv4);
+}
+
+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;
+}
+
+static void pico_arp_unreachable(struct pico_ip4 *a)
+{
+    int i;
+    struct pico_frame *f;
+    struct pico_ipv4_hdr *hdr;
+    struct pico_ip4 dst;
+    for (i = 0; i < PICO_ARP_MAX_PENDING; i++)
+    {
+        f = frames_queued[i];
+        if (f) {
+            hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+            dst = pico_ipv4_route_get_gateway(&hdr->dst);
+            if (!dst.addr)
+                dst.addr = hdr->dst.addr;
+
+            if (dst.addr ==  a->addr) {
+                if (!pico_source_is_local(f)) {
+                    pico_notify_dest_unreachable(f);
+                }
+
+                pico_frame_discard(f);
+                frames_queued[i] = NULL;
+            }
+        }
+    }
+}
+
+static 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);
+    } else {
+        pico_arp_unreachable(where);
+    }
+}
+
+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;
+}
+
+
+void pico_arp_postpone(struct pico_frame *f)
+{
+    int i;
+    for (i = 0; i < PICO_ARP_MAX_PENDING; i++)
+    {
+        if (!frames_queued[i]) {
+            frames_queued[i] = pico_frame_copy(f);
+            return;
+        }
+    }
+    /* Not possible to enqueue: caller will discard packet */
+}
+
+
+#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_arp_queued_trigger();
+    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);
+
+}
+
+static 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);
+}
+
diff --git a/net/picotcp/modules/pico_arp.h b/net/picotcp/modules/pico_arp.h
new file mode 100644
index 0000000..18e1f69
--- /dev/null
+++ b/net/picotcp/modules/pico_arp.h
@@ -0,0 +1,32 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. 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_postpone(struct pico_frame *f);
+void pico_arp_init(void);
+#endif
diff --git a/net/picotcp/modules/pico_dev_loop.c b/net/picotcp/modules/pico_dev_loop.c
new file mode 100644
index 0000000..4416d0b
--- /dev/null
+++ b/net/picotcp/modules/pico_dev_loop.c
@@ -0,0 +1,66 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_device.h"
+#include "pico_dev_loop.h"
+#include "pico_stack.h"
+
+
+#define LOOP_MTU 1500
+static uint8_t l_buf[LOOP_MTU];
+static int l_bufsize = 0;
+
+
+static int pico_loop_send(struct pico_device *dev, void *buf, int len)
+{
+    IGNORE_PARAMETER(dev);
+    if (len > LOOP_MTU)
+        return 0;
+
+    if (l_bufsize == 0) {
+        memcpy(l_buf, buf, (size_t)len);
+        l_bufsize += len;
+        return len;
+    }
+
+    return 0;
+}
+
+static int pico_loop_poll(struct pico_device *dev, int loop_score)
+{
+    if (loop_score <= 0)
+        return 0;
+
+    if (l_bufsize > 0) {
+        pico_stack_recv(dev, l_buf, (uint32_t)l_bufsize);
+        l_bufsize = 0;
+        loop_score--;
+    }
+
+    return loop_score;
+}
+
+
+struct pico_device *pico_loop_create(void)
+{
+    struct pico_device *loop = PICO_ZALLOC(sizeof(struct pico_device));
+    if (!loop)
+        return NULL;
+
+    if( 0 != pico_device_init(loop, "loop", NULL)) {
+        dbg ("Loop init failed.\n");
+        pico_device_destroy(loop);
+        return NULL;
+    }
+
+    loop->send = pico_loop_send;
+    loop->poll = pico_loop_poll;
+    dbg("Device %s created.\n", loop->name);
+    return loop;
+}
+
diff --git a/net/picotcp/modules/pico_dev_loop.h b/net/picotcp/modules/pico_dev_loop.h
new file mode 100644
index 0000000..6cb8de1
--- /dev/null
+++ b/net/picotcp/modules/pico_dev_loop.h
@@ -0,0 +1,15 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_LOOP
+#define INCLUDE_PICO_LOOP
+#include "pico_config.h"
+#include "pico_device.h"
+
+void pico_loop_destroy(struct pico_device *loop);
+struct pico_device *pico_loop_create(void);
+
+#endif
+
diff --git a/net/picotcp/modules/pico_dev_mock.h b/net/picotcp/modules/pico_dev_mock.h
new file mode 100644
index 0000000..dfc2cfc
--- /dev/null
+++ b/net/picotcp/modules/pico_dev_mock.h
@@ -0,0 +1,47 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_MOCK
+#define INCLUDE_PICO_MOCK
+#include "pico_config.h"
+#include "pico_device.h"
+
+
+struct mock_frame {
+    uint8_t*buffer;
+    int len;
+    int read;
+
+    struct mock_frame*next;
+};
+
+struct mock_device {
+    struct pico_device*dev;
+    struct mock_frame*in_head;
+    struct mock_frame*in_tail;
+    struct mock_frame*out_head;
+    struct mock_frame*out_tail;
+
+    uint8_t*mac;
+
+};
+
+struct mock_device;
+/* A mockup-device for the purpose of testing. It provides a couple of extra "network"-functions, which represent the network-side of the device. A network_send will result in mock_poll reading something, a network_read will see if the stack has sent anything through our mock-device. */
+void pico_mock_destroy(struct pico_device *dev);
+struct mock_device *pico_mock_create(uint8_t*mac);
+
+int pico_mock_network_read(struct mock_device*mock, void *buf, int len);
+int pico_mock_network_write(struct mock_device*mock, const void *buf, int len);
+
+/* TODO */
+/* we could use a few checking functions, e.g. one to see if it's a valid IP packet, if it's TCP, if the IP-address matches,... */
+/* That would be useful to avoid having to manually create buffers of what you expect, probably with masks for things that are random,... */
+uint32_t mock_get_sender_ip4(struct mock_device*mock, void*buf, int len);
+
+int mock_ip_protocol(struct mock_device*mock, void*buf, int len);
+int mock_icmp_type(struct mock_device*mock, void*buf, int len);
+int mock_icmp_code(struct mock_device*mock, void*buf, int len);
+#endif
diff --git a/net/picotcp/modules/pico_dev_null.c b/net/picotcp/modules/pico_dev_null.c
new file mode 100644
index 0000000..5fed494
--- /dev/null
+++ b/net/picotcp/modules/pico_dev_null.c
@@ -0,0 +1,60 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_device.h"
+#include "pico_dev_null.h"
+#include "pico_stack.h"
+
+struct pico_device_null {
+    struct pico_device dev;
+    int statistics_frames_out;
+};
+
+#define NULL_MTU 0
+
+static int pico_null_send(struct pico_device *dev, void *buf, int len)
+{
+    struct pico_device_null *null = (struct pico_device_null *) dev;
+    IGNORE_PARAMETER(buf);
+
+    /* Increase the statistic count */
+    null->statistics_frames_out++;
+
+    /* Discard the frame content silently. */
+    return len;
+}
+
+static int pico_null_poll(struct pico_device *dev, int loop_score)
+{
+    /* We never have packet to receive, no score is used. */
+    IGNORE_PARAMETER(dev);
+    return loop_score;
+}
+
+/* Public interface: create/destroy. */
+
+
+struct pico_device *pico_null_create(char *name)
+{
+    struct pico_device_null *null = PICO_ZALLOC(sizeof(struct pico_device_null));
+
+    if (!null)
+        return NULL;
+
+    if( 0 != pico_device_init((struct pico_device *)null, name, NULL)) {
+        return NULL;
+    }
+
+    null->dev.overhead = 0;
+    null->statistics_frames_out = 0;
+    null->dev.send = pico_null_send;
+    null->dev.poll = pico_null_poll;
+    dbg("Device %s created.\n", null->dev.name);
+    return (struct pico_device *)null;
+}
+
diff --git a/net/picotcp/modules/pico_dev_null.h b/net/picotcp/modules/pico_dev_null.h
new file mode 100644
index 0000000..a0eb98e
--- /dev/null
+++ b/net/picotcp/modules/pico_dev_null.h
@@ -0,0 +1,15 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_NULL
+#define INCLUDE_PICO_NULL
+#include "pico_config.h"
+#include "pico_device.h"
+
+void pico_null_destroy(struct pico_device *null);
+struct pico_device *pico_null_create(char *name);
+
+#endif
+
diff --git a/net/picotcp/modules/pico_dhcp_client.c b/net/picotcp/modules/pico_dhcp_client.c
new file mode 100644
index 0000000..7f8df7f
--- /dev/null
+++ b/net/picotcp/modules/pico_dhcp_client.c
@@ -0,0 +1,960 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Authors: Kristof Roelants, Frederik Van Slycken
+ *********************************************************************/
+
+
+#include "pico_dhcp_client.h"
+#include "pico_stack.h"
+#include "pico_config.h"
+#include "pico_device.h"
+#include "pico_ipv4.h"
+#include "pico_socket.h"
+#include "pico_eth.h"
+
+#if (defined PICO_SUPPORT_DHCPC && defined PICO_SUPPORT_UDP)
+#define dhcpc_dbg(...) do {} while(0)
+/* #define dhcpc_dbg dbg */
+
+/* timer values */
+#define DHCP_CLIENT_REINIT             6000 /* msec */
+#define DHCP_CLIENT_RETRANS            4 /* sec */
+#define DHCP_CLIENT_RETRIES            3
+
+#define DHCP_CLIENT_TIMER_STOPPED      0
+#define DHCP_CLIENT_TIMER_STARTED      1
+
+/* maximum size of a DHCP message */
+#define DHCP_CLIENT_MAXMSGZISE         (PICO_IP_MRU - PICO_SIZE_IP4HDR)
+
+enum dhcp_client_state {
+    DHCP_CLIENT_STATE_INIT_REBOOT = 0,
+    DHCP_CLIENT_STATE_REBOOTING,
+    DHCP_CLIENT_STATE_INIT,
+    DHCP_CLIENT_STATE_SELECTING,
+    DHCP_CLIENT_STATE_REQUESTING,
+    DHCP_CLIENT_STATE_BOUND,
+    DHCP_CLIENT_STATE_RENEWING,
+    DHCP_CLIENT_STATE_REBINDING
+};
+
+
+#define PICO_DHCPC_TIMER_INIT    0
+#define PICO_DHCPC_TIMER_REQUEST 1
+#define PICO_DHCPC_TIMER_RENEW   2
+#define PICO_DHCPC_TIMER_REBIND  3
+#define PICO_DHCPC_TIMER_T1      4
+#define PICO_DHCPC_TIMER_T2      5
+#define PICO_DHCPC_TIMER_LEASE   6
+#define PICO_DHCPC_TIMER_ARRAY_SIZE 7
+
+struct dhcp_client_timer
+{
+    uint8_t state;
+    unsigned int type;
+    uint32_t xid;
+};
+
+struct pico_dhcp_client_cookie
+{
+    uint8_t event;
+    uint8_t retry;
+    uint32_t xid;
+    uint32_t *uid;
+    enum dhcp_client_state state;
+    void (*cb)(void*dhcpc, int code);
+    pico_time init_timestamp;
+    struct pico_socket *s;
+    struct pico_ip4 address;
+    struct pico_ip4 netmask;
+    struct pico_ip4 gateway;
+    struct pico_ip4 nameserver[2];
+    struct pico_ip4 server_id;
+    struct pico_device *dev;
+    struct dhcp_client_timer *timer[PICO_DHCPC_TIMER_ARRAY_SIZE];
+    uint32_t t1_time;
+    uint32_t t2_time;
+    uint32_t lease_time;
+    uint32_t renew_time;
+    uint32_t rebind_time;
+};
+
+static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc);
+static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+static int8_t pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type);
+static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s);
+static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+
+static const struct pico_ip4 bcast = {
+    .addr = 0xFFFFFFFF
+};
+
+static const struct pico_ip4 bcast_netmask = {
+    .addr = 0xFFFFFFFF
+};
+
+static struct pico_ip4 inaddr_any = {
+    0
+};
+
+
+static int dhcp_cookies_cmp(void *ka, void *kb)
+{
+    struct pico_dhcp_client_cookie *a = ka, *b = kb;
+    if (a->xid == b->xid)
+        return 0;
+
+    return (a->xid < b->xid) ? (-1) : (1);
+}
+PICO_TREE_DECLARE(DHCPCookies, dhcp_cookies_cmp);
+
+static struct pico_dhcp_client_cookie *pico_dhcp_client_add_cookie(uint32_t xid, struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid)
+{
+    struct pico_dhcp_client_cookie *dhcpc = NULL, *found = NULL, test = {
+        0
+    };
+
+    test.xid = xid;
+    found = pico_tree_findKey(&DHCPCookies, &test);
+    if (found) {
+        pico_err = PICO_ERR_EAGAIN;
+        return NULL;
+    }
+
+    dhcpc = PICO_ZALLOC(sizeof(struct pico_dhcp_client_cookie));
+    if (!dhcpc) {
+        pico_err = PICO_ERR_ENOMEM;
+        return NULL;
+    }
+
+    dhcpc->state = DHCP_CLIENT_STATE_INIT;
+    dhcpc->xid = xid;
+    dhcpc->uid = uid;
+    *(dhcpc->uid) = 0;
+    dhcpc->cb = cb;
+    dhcpc->dev = dev;
+
+    pico_tree_insert(&DHCPCookies, dhcpc);
+    return dhcpc;
+}
+
+static void pico_dhcp_client_stop_timers(struct pico_dhcp_client_cookie *dhcpc);
+static int pico_dhcp_client_del_cookie(uint32_t xid)
+{
+    struct pico_dhcp_client_cookie test = {
+        0
+    }, *found = NULL;
+
+    test.xid = xid;
+    found = pico_tree_findKey(&DHCPCookies, &test);
+    if (!found)
+        return -1;
+
+    pico_dhcp_client_stop_timers(found);
+    pico_socket_close(found->s);
+    found->s = NULL;
+    pico_ipv4_link_del(found->dev, found->address);
+    pico_tree_delete(&DHCPCookies, found);
+    PICO_FREE(found);
+    return 0;
+}
+
+static struct pico_dhcp_client_cookie *pico_dhcp_client_find_cookie(uint32_t xid)
+{
+    struct pico_dhcp_client_cookie test = {
+        0
+    }, *found = NULL;
+
+    test.xid = xid;
+    found = pico_tree_findKey(&DHCPCookies, &test);
+    if (found)
+        return found;
+    else
+        return NULL;
+}
+
+static void pico_dhcp_client_timer_handler(pico_time now, void *arg);
+static void pico_dhcp_client_reinit(pico_time now, void *arg);
+static struct dhcp_client_timer *pico_dhcp_timer_add(uint8_t type, uint32_t time, struct pico_dhcp_client_cookie *ck)
+{
+    struct dhcp_client_timer *t;
+
+    t = PICO_ZALLOC(sizeof(struct dhcp_client_timer));
+    if (!t)
+        return NULL;
+
+    t->state = DHCP_CLIENT_TIMER_STARTED;
+    t->xid = ck->xid;
+    t->type = type;
+    pico_timer_add(time, pico_dhcp_client_timer_handler, t);
+    if (ck->timer[type]) {
+        ck->timer[type]->state = DHCP_CLIENT_TIMER_STOPPED;
+    }
+
+    ck->timer[type] = t;
+    return t;
+}
+
+static int dhcp_get_timer_event(struct pico_dhcp_client_cookie *dhcpc, unsigned int type)
+{
+    const int events[PICO_DHCPC_TIMER_ARRAY_SIZE] =
+    {
+        PICO_DHCP_EVENT_RETRANSMIT,
+        PICO_DHCP_EVENT_RETRANSMIT,
+        PICO_DHCP_EVENT_RETRANSMIT,
+        PICO_DHCP_EVENT_RETRANSMIT,
+        PICO_DHCP_EVENT_T1,
+        PICO_DHCP_EVENT_T2,
+        PICO_DHCP_EVENT_LEASE
+    };
+
+    if (type == PICO_DHCPC_TIMER_REQUEST) {
+        if (++dhcpc->retry > DHCP_CLIENT_RETRIES) {
+            reset(dhcpc, NULL);
+            return PICO_DHCP_EVENT_NONE;
+        }
+    } else if (type < PICO_DHCPC_TIMER_T1) {
+        dhcpc->retry++;
+    }
+
+    return events[type];
+}
+
+static void pico_dhcp_client_timer_handler(pico_time now, void *arg)
+{
+    struct dhcp_client_timer *t = (struct dhcp_client_timer *)arg;
+    struct pico_dhcp_client_cookie *dhcpc;
+
+    if (!t)
+        return;
+
+    (void) now;
+    if (t->state != DHCP_CLIENT_TIMER_STOPPED) {
+        dhcpc = pico_dhcp_client_find_cookie(t->xid);
+        if (dhcpc && dhcpc->timer) {
+            t->state = DHCP_CLIENT_TIMER_STOPPED;
+            if ((t->type == PICO_DHCPC_TIMER_INIT) && (dhcpc->state < DHCP_CLIENT_STATE_SELECTING)) {
+                pico_dhcp_client_reinit(now, dhcpc);
+            } else if (t->type != PICO_DHCPC_TIMER_INIT) {
+                dhcpc->event = (uint8_t)dhcp_get_timer_event(dhcpc, t->type);
+                if (dhcpc->event != PICO_DHCP_EVENT_NONE)
+                    pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
+            }
+        }
+    }
+}
+
+static void pico_dhcp_client_timer_stop(struct pico_dhcp_client_cookie *dhcpc, int type)
+{
+    if (dhcpc->timer[type]) {
+        dhcpc->timer[type]->state = DHCP_CLIENT_TIMER_STOPPED;
+    }
+
+}
+
+
+static void pico_dhcp_client_reinit(pico_time now, void *arg)
+{
+    struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
+    (void) now;
+
+    if (dhcpc->s) {
+        pico_socket_close(dhcpc->s);
+        dhcpc->s = NULL;
+    }
+
+    if (++dhcpc->retry > DHCP_CLIENT_RETRIES) {
+        pico_err = PICO_ERR_EAGAIN;
+        if (dhcpc->cb)
+            dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
+
+        pico_dhcp_client_del_cookie(dhcpc->xid);
+        return;
+    }
+
+    pico_dhcp_client_init(dhcpc);
+    return;
+}
+
+
+static void pico_dhcp_client_stop_timers(struct pico_dhcp_client_cookie *dhcpc)
+{
+    int i;
+    dhcpc->retry = 0;
+    for (i = 0; i < PICO_DHCPC_TIMER_ARRAY_SIZE; i++)
+        pico_dhcp_client_timer_stop(dhcpc, i);
+}
+
+static void pico_dhcp_client_start_init_timer(struct pico_dhcp_client_cookie *dhcpc)
+{
+    uint32_t time = 0;
+    /* timer value is doubled with every retry (exponential backoff) */
+    time = (uint32_t) (DHCP_CLIENT_RETRANS << dhcpc->retry);
+    pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, time * 1000, dhcpc);
+}
+
+static void pico_dhcp_client_start_requesting_timer(struct pico_dhcp_client_cookie *dhcpc)
+{
+    uint32_t time = 0;
+
+    /* timer value is doubled with every retry (exponential backoff) */
+    time = (uint32_t)(DHCP_CLIENT_RETRANS << dhcpc->retry);
+    pico_dhcp_timer_add(PICO_DHCPC_TIMER_REQUEST, time * 1000, dhcpc);
+}
+
+static void pico_dhcp_client_start_renewing_timer(struct pico_dhcp_client_cookie *dhcpc)
+{
+    uint32_t halftime = 0;
+
+    /* wait one-half of the remaining time until T2, down to a minimum of 60 seconds */
+    /* (dhcpc->retry + 1): initial -> divide by 2, 1st retry -> divide by 4, 2nd retry -> divide by 8, etc */
+    pico_dhcp_client_stop_timers(dhcpc);
+    halftime = dhcpc->renew_time >> (dhcpc->retry + 1);
+    if (halftime < 60)
+        halftime = 60;
+
+    pico_dhcp_timer_add(PICO_DHCPC_TIMER_RENEW, halftime * 1000, dhcpc);
+
+    return;
+}
+
+static void pico_dhcp_client_start_rebinding_timer(struct pico_dhcp_client_cookie *dhcpc)
+{
+    uint32_t halftime = 0;
+
+    pico_dhcp_client_stop_timers(dhcpc);
+    halftime = dhcpc->rebind_time >> (dhcpc->retry + 1);
+    if (halftime < 60)
+        halftime = 60;
+
+    pico_dhcp_timer_add(PICO_DHCPC_TIMER_REBIND, halftime * 1000, dhcpc);
+
+    return;
+}
+
+static void pico_dhcp_client_start_reacquisition_timers(struct pico_dhcp_client_cookie *dhcpc)
+{
+
+    pico_dhcp_client_stop_timers(dhcpc);
+    pico_dhcp_timer_add(PICO_DHCPC_TIMER_T1, dhcpc->t1_time * 1000, dhcpc);
+    pico_dhcp_timer_add(PICO_DHCPC_TIMER_T2, dhcpc->t2_time * 1000, dhcpc);
+    pico_dhcp_timer_add(PICO_DHCPC_TIMER_LEASE, dhcpc->lease_time * 1000, dhcpc);
+}
+
+static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc)
+{
+    uint16_t port = PICO_DHCP_CLIENT_PORT;
+    if (!dhcpc)
+        return -1;
+
+    /* adding a link with address 0.0.0.0 and netmask 0.0.0.0,
+     * automatically adds a route for a global broadcast */
+    pico_ipv4_link_add(dhcpc->dev, inaddr_any, bcast_netmask);
+    if (!dhcpc->s)
+        dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup);
+
+    if (!dhcpc->s) {
+        pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc);
+        return 0;
+    }
+
+    dhcpc->s->dev = dhcpc->dev;
+    if (pico_socket_bind(dhcpc->s, &inaddr_any, &port) < 0) {
+        pico_socket_close(dhcpc->s);
+        dhcpc->s = NULL;
+        pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc);
+        return 0;
+    }
+
+    if (pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER) < 0) {
+        pico_socket_close(dhcpc->s);
+        dhcpc->s = NULL;
+        pico_dhcp_timer_add(PICO_DHCPC_TIMER_INIT, DHCP_CLIENT_REINIT, dhcpc);
+        return 0;
+    }
+
+    dhcpc->retry = 0;
+    dhcpc->init_timestamp = PICO_TIME_MS();
+    pico_dhcp_client_start_init_timer(dhcpc);
+    return 0;
+}
+
+int pico_dhcp_initiate_negotiation(struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid)
+{
+    uint8_t retry = 32;
+    uint32_t xid = 0;
+    struct pico_dhcp_client_cookie *dhcpc = NULL;
+
+    if (!dev || !cb || !uid) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    if (!dev->eth) {
+        pico_err = PICO_ERR_EOPNOTSUPP;
+        return -1;
+    }
+
+    /* attempt to generate a correct xid, else fail */
+    do {
+        xid = pico_rand();
+    } while (!xid && --retry);
+
+    if (!xid) {
+        pico_err = PICO_ERR_EAGAIN;
+        return -1;
+    }
+
+    dhcpc = pico_dhcp_client_add_cookie(xid, dev, cb, uid);
+    if (!dhcpc)
+        return -1;
+
+    dhcpc_dbg("DHCP client: cookie with xid %u\n", dhcpc->xid);
+    *uid = xid;
+    return pico_dhcp_client_init(dhcpc);
+}
+
+static void pico_dhcp_client_recv_params(struct pico_dhcp_client_cookie *dhcpc, struct pico_dhcp_opt *opt)
+{
+    do {
+        switch (opt->code)
+        {
+        case PICO_DHCP_OPT_PAD:
+            break;
+
+        case PICO_DHCP_OPT_END:
+            break;
+
+        case PICO_DHCP_OPT_MSGTYPE:
+            dhcpc->event = opt->ext.msg_type.type;
+            dhcpc_dbg("DHCP client: message type %u\n", dhcpc->event);
+            break;
+
+        case PICO_DHCP_OPT_LEASETIME:
+            dhcpc->lease_time = long_be(opt->ext.lease_time.time);
+            dhcpc_dbg("DHCP client: lease time %u\n", dhcpc->lease_time);
+            break;
+
+        case PICO_DHCP_OPT_RENEWALTIME:
+            dhcpc->t1_time = long_be(opt->ext.renewal_time.time);
+            dhcpc_dbg("DHCP client: renewal time %u\n", dhcpc->t1_time);
+            break;
+
+        case PICO_DHCP_OPT_REBINDINGTIME:
+            dhcpc->t2_time = long_be(opt->ext.rebinding_time.time);
+            dhcpc_dbg("DHCP client: rebinding time %u\n", dhcpc->t2_time);
+            break;
+
+        case PICO_DHCP_OPT_ROUTER:
+            dhcpc->gateway = opt->ext.router.ip;
+            dhcpc_dbg("DHCP client: router %08X\n", dhcpc->gateway.addr);
+            break;
+
+        case PICO_DHCP_OPT_DNS:
+            dhcpc->nameserver[0] = opt->ext.dns1.ip;
+            dhcpc_dbg("DHCP client: dns1 %08X\n", dhcpc->nameserver[0].addr);
+            if (opt->len >= 8) {
+                dhcpc->nameserver[1] = opt->ext.dns2.ip;
+                dhcpc_dbg("DHCP client: dns1 %08X\n", dhcpc->nameserver[1].addr);
+            }
+
+            break;
+
+        case PICO_DHCP_OPT_NETMASK:
+            dhcpc->netmask = opt->ext.netmask.ip;
+            dhcpc_dbg("DHCP client: netmask %08X\n", dhcpc->netmask.addr);
+            break;
+
+        case PICO_DHCP_OPT_SERVERID:
+            dhcpc->server_id = opt->ext.server_id.ip;
+            dhcpc_dbg("DHCP client: server ID %08X\n", dhcpc->server_id.addr);
+            break;
+
+        case PICO_DHCP_OPT_OPTOVERLOAD:
+            dhcpc_dbg("DHCP client: WARNING option overload present (not processed)");
+            break;
+
+        default:
+            dhcpc_dbg("DHCP client: WARNING unsupported option %u\n", opt->code);
+            break;
+        }
+    } while (pico_dhcp_next_option(&opt));
+
+    /* default values for T1 and T2 when not provided */
+    if (!dhcpc->t1_time)
+        dhcpc->t1_time = dhcpc->lease_time >> 1;
+
+    if (!dhcpc->t2_time)
+        dhcpc->t2_time = (dhcpc->lease_time * 875) / 1000;
+
+    return;
+}
+
+static int recv_offer(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+    struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)hdr->options;
+
+    pico_dhcp_client_recv_params(dhcpc, opt);
+    if ((dhcpc->event != PICO_DHCP_MSG_OFFER) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_time)
+        return -1;
+
+    dhcpc->address.addr = hdr->yiaddr;
+
+    /* we skip state SELECTING, process first offer received */
+    dhcpc->state = DHCP_CLIENT_STATE_REQUESTING;
+    dhcpc->retry = 0;
+    pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+    pico_dhcp_client_start_requesting_timer(dhcpc);
+    return 0;
+}
+
+static int recv_ack(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+    struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)hdr->options;
+    struct pico_ip4 address = {
+        0
+    };
+    struct pico_ip4 any_address = {
+        0
+    };
+
+    struct pico_ipv4_link *l;
+
+    pico_dhcp_client_recv_params(dhcpc, opt);
+    if ((dhcpc->event != PICO_DHCP_MSG_ACK) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_time)
+        return -1;
+
+    /* Issue #20 the server can transmit on ACK a different IP than the one in OFFER */
+    /* RFC2131 ch 4.3.2 ... The client SHOULD use the parameters in the DHCPACK message for configuration */
+    if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING)
+        dhcpc->address.addr = hdr->yiaddr;
+
+
+    /* close the socket used for address (re)acquisition */
+    pico_socket_close(dhcpc->s);
+    dhcpc->s = NULL;
+
+    /* Delete all the links before adding the address */
+    pico_ipv4_link_del(dhcpc->dev, address);
+    l = pico_ipv4_link_by_dev(dhcpc->dev);
+    while(l) {
+        pico_ipv4_link_del(dhcpc->dev, l->address);
+        l = pico_ipv4_link_by_dev_next(dhcpc->dev, l);
+    }
+    pico_ipv4_link_add(dhcpc->dev, dhcpc->address, dhcpc->netmask);
+
+    dbg("DHCP client: renewal time (T1) %u\n", (unsigned int)dhcpc->t1_time);
+    dbg("DHCP client: rebinding time (T2) %u\n", (unsigned int)dhcpc->t2_time);
+    dbg("DHCP client: lease time %u\n", (unsigned int)dhcpc->lease_time);
+
+    /* If router option is received, use it as default gateway */
+    if (dhcpc->gateway.addr != 0U) {
+        pico_ipv4_route_add(any_address, any_address, dhcpc->gateway, 1, NULL);
+    }
+
+    dhcpc->retry = 0;
+    dhcpc->renew_time = dhcpc->t2_time - dhcpc->t1_time;
+    dhcpc->rebind_time = dhcpc->lease_time - dhcpc->t2_time;
+    pico_dhcp_client_start_reacquisition_timers(dhcpc);
+
+    *(dhcpc->uid) = dhcpc->xid;
+    if (dhcpc->cb)
+        dhcpc->cb(dhcpc, PICO_DHCP_SUCCESS);
+
+    dhcpc->state = DHCP_CLIENT_STATE_BOUND;
+    return 0;
+}
+
+static int renew(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+    uint16_t port = PICO_DHCP_CLIENT_PORT;
+    (void) buf;
+    dhcpc->state = DHCP_CLIENT_STATE_RENEWING;
+    dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup);
+    if (!dhcpc->s) {
+        dhcpc_dbg("DHCP client ERROR: failure opening socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
+        if (dhcpc->cb)
+            dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
+
+        return -1;
+    }
+
+    if (pico_socket_bind(dhcpc->s, &dhcpc->address, &port) != 0) {
+        dhcpc_dbg("DHCP client ERROR: failure binding socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
+        pico_socket_close(dhcpc->s);
+        dhcpc->s = NULL;
+        if (dhcpc->cb)
+            dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
+
+        return -1;
+    }
+
+    dhcpc->retry = 0;
+    pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+    pico_dhcp_client_start_renewing_timer(dhcpc);
+
+    return 0;
+}
+
+static int rebind(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+    (void) buf;
+
+    dhcpc->state = DHCP_CLIENT_STATE_REBINDING;
+    dhcpc->retry = 0;
+    pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+    pico_dhcp_client_start_rebinding_timer(dhcpc);
+
+    return 0;
+}
+
+static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+    struct pico_ip4 address = {
+        0
+    };
+    (void) buf;
+
+    if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING)
+        address.addr = PICO_IP4_ANY;
+    else
+        address.addr = dhcpc->address.addr;
+
+    /* close the socket used for address (re)acquisition */
+    pico_socket_close(dhcpc->s);
+    dhcpc->s = NULL;
+    /* delete the link with the currently in use address */
+    pico_ipv4_link_del(dhcpc->dev, address);
+
+    if (dhcpc->cb)
+        dhcpc->cb(dhcpc, PICO_DHCP_RESET);
+
+    if (dhcpc->state < DHCP_CLIENT_STATE_BOUND)
+    {
+        /* pico_dhcp_client_timer_stop(dhcpc, PICO_DHCPC_TIMER_INIT); */
+    }
+
+
+    dhcpc->state = DHCP_CLIENT_STATE_INIT;
+    pico_dhcp_client_stop_timers(dhcpc);
+    pico_dhcp_client_init(dhcpc);
+    return 0;
+}
+
+static int retransmit(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+    (void) buf;
+    switch (dhcpc->state)
+    {
+    case DHCP_CLIENT_STATE_INIT:
+        pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
+        pico_dhcp_client_start_init_timer(dhcpc);
+        break;
+
+    case DHCP_CLIENT_STATE_REQUESTING:
+        pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+        pico_dhcp_client_start_requesting_timer(dhcpc);
+        break;
+
+    case DHCP_CLIENT_STATE_RENEWING:
+        pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
+        pico_dhcp_client_start_renewing_timer(dhcpc);
+        break;
+
+    case DHCP_CLIENT_STATE_REBINDING:
+        pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
+        pico_dhcp_client_start_rebinding_timer(dhcpc);
+        break;
+
+    default:
+        dhcpc_dbg("DHCP client WARNING: retransmit in incorrect state (%u)!\n", dhcpc->state);
+        return -1;
+    }
+    return 0;
+}
+
+struct dhcp_action_entry {
+    int (*offer)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+    int (*ack)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+    int (*nak)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+    int (*timer1)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+    int (*timer2)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+    int (*timer_lease)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+    int (*timer_retransmit)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
+};
+
+static struct dhcp_action_entry dhcp_fsm[] =
+{ /* event                |offer      |ack      |nak    |T1    |T2     |lease  |retransmit */
+/* state init-reboot */
+    { NULL,       NULL,     NULL,   NULL,  NULL,   NULL,  NULL       },
+/* state rebooting   */ { NULL,       NULL,     NULL,   NULL,  NULL,   NULL,  NULL       },
+/* state init        */ { recv_offer, NULL,     NULL,   NULL,  NULL,   NULL,  retransmit },
+/* state selecting   */ { NULL,       NULL,     NULL,   NULL,  NULL,   NULL,  NULL       },
+/* state requesting  */ { NULL,       recv_ack, reset,  NULL,  NULL,   NULL,  retransmit },
+/* state bound       */ { NULL,       NULL,     NULL,   renew, NULL,   NULL,  NULL       },
+/* state renewing    */ { NULL,       recv_ack, reset,  NULL,  rebind, NULL,  retransmit },
+/* state rebinding   */ { NULL,       recv_ack, reset,  NULL,  NULL,   reset, retransmit },
+};
+
+/* TIMERS REMARK:
+ * In state bound we have T1, T2 and the lease timer running. If T1 goes off, we attempt to renew.
+ * If the renew succeeds a new T1, T2 and lease timer is started. The former T2 and lease timer is
+ * still running though. This poses no concerns as the T2 and lease event in state bound have a NULL
+ * pointer in the fsm. If the former T2 or lease timer goes off, nothing happens. Same situation
+ * applies for T2 and a succesfull rebind. */
+
+static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
+{
+    switch (event)
+    {
+    case PICO_DHCP_MSG_OFFER:
+        dhcpc_dbg("DHCP client: received OFFER\n");
+        if (dhcp_fsm[dhcpc->state].offer)
+            dhcp_fsm[dhcpc->state].offer(dhcpc, buf);
+
+        break;
+
+    case PICO_DHCP_MSG_ACK:
+        dhcpc_dbg("DHCP client: received ACK\n");
+        if (dhcp_fsm[dhcpc->state].ack)
+            dhcp_fsm[dhcpc->state].ack(dhcpc, buf);
+
+        break;
+
+    case PICO_DHCP_MSG_NAK:
+        dhcpc_dbg("DHCP client: received NAK\n");
+        if (dhcp_fsm[dhcpc->state].nak)
+            dhcp_fsm[dhcpc->state].nak(dhcpc, buf);
+
+        break;
+
+    case PICO_DHCP_EVENT_T1:
+        dhcpc_dbg("DHCP client: received T1 timeout\n");
+        if (dhcp_fsm[dhcpc->state].timer1)
+            dhcp_fsm[dhcpc->state].timer1(dhcpc, NULL);
+
+        break;
+
+    case PICO_DHCP_EVENT_T2:
+        dhcpc_dbg("DHCP client: received T2 timeout\n");
+        if (dhcp_fsm[dhcpc->state].timer2)
+            dhcp_fsm[dhcpc->state].timer2(dhcpc, NULL);
+
+        break;
+
+    case PICO_DHCP_EVENT_LEASE:
+        dhcpc_dbg("DHCP client: received LEASE timeout\n");
+        if (dhcp_fsm[dhcpc->state].timer_lease)
+            dhcp_fsm[dhcpc->state].timer_lease(dhcpc, NULL);
+
+        break;
+
+    case PICO_DHCP_EVENT_RETRANSMIT:
+        dhcpc_dbg("DHCP client: received RETRANSMIT timeout\n");
+        if (dhcp_fsm[dhcpc->state].timer_retransmit)
+            dhcp_fsm[dhcpc->state].timer_retransmit(dhcpc, NULL);
+
+        break;
+
+    default:
+        dhcpc_dbg("DHCP client WARNING: unrecognized event (%u)!\n", dhcpc->event);
+        return;
+    }
+    return;
+}
+
+static int16_t pico_dhcp_client_opt_parse(void *ptr, uint16_t len)
+{
+    uint32_t optlen = len - (uint32_t)sizeof(struct pico_dhcp_hdr);
+    struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)ptr;
+    struct pico_dhcp_opt *opt = NULL;
+
+    if (hdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE)
+        return -1;
+
+    if (!pico_dhcp_are_options_valid(hdr->options, (int32_t)optlen))
+        return -1;
+
+    opt = (struct pico_dhcp_opt *)hdr->options;
+    do {
+        if (opt->code == PICO_DHCP_OPT_MSGTYPE)
+            return opt->ext.msg_type.type;
+    } while (pico_dhcp_next_option(&opt));
+
+    return -1;
+}
+
+static int8_t pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type)
+{
+    int32_t r = 0;
+    uint16_t optlen = 0, offset = 0;
+    struct pico_ip4 destination = {
+        .addr = 0xFFFFFFFF
+    };
+    struct pico_dhcp_hdr *hdr = NULL;
+
+
+    /* RFC 2131 3.1.3: Request is always BROADCAST */
+
+    /* Set again default route for the bcast request */
+    pico_ipv4_route_set_bcast_link(pico_ipv4_link_by_dev(dhcpc->dev));
+
+    switch (msg_type)
+    {
+    case PICO_DHCP_MSG_DISCOVER:
+        dhcpc_dbg("DHCP client: sent DHCPDISCOVER\n");
+        optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_END;
+        hdr = PICO_ZALLOC((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;
+
+    case PICO_DHCP_MSG_REQUEST:
+        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);
+        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) {
+            offset = (uint16_t)(offset + pico_dhcp_opt_reqip(&hdr->options[offset], &dhcpc->address));
+            offset = (uint16_t)(offset + pico_dhcp_opt_serverid(&hdr->options[offset], &dhcpc->server_id));
+        }
+
+        break;
+
+    default:
+        return -1;
+    }
+
+    /* common options */
+    offset = (uint16_t)(offset + pico_dhcp_opt_msgtype(&hdr->options[offset], msg_type));
+    offset = (uint16_t)(offset + pico_dhcp_opt_paramlist(&hdr->options[offset]));
+    offset = (uint16_t)(offset + pico_dhcp_opt_end(&hdr->options[offset]));
+
+    switch (dhcpc->state)
+    {
+    case DHCP_CLIENT_STATE_BOUND:
+        destination.addr = dhcpc->server_id.addr;
+        hdr->ciaddr = dhcpc->address.addr;
+        break;
+
+    case DHCP_CLIENT_STATE_RENEWING:
+        destination.addr = dhcpc->server_id.addr;
+        hdr->ciaddr = dhcpc->address.addr;
+        break;
+
+    case DHCP_CLIENT_STATE_REBINDING:
+        hdr->ciaddr = dhcpc->address.addr;
+        break;
+
+    default:
+        /* do nothing */
+        break;
+    }
+
+    /* header information */
+    hdr->op = PICO_DHCP_OP_REQUEST;
+    hdr->htype = PICO_DHCP_HTYPE_ETH;
+    hdr->hlen = PICO_SIZE_ETH;
+    hdr->xid = dhcpc->xid;
+    /* hdr->flags = short_be(PICO_DHCP_FLAG_BROADCAST); / * 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);
+
+    if (destination.addr == PICO_IP4_BCAST)
+        pico_ipv4_route_set_bcast_link(pico_ipv4_link_get(&dhcpc->address));
+
+    r = pico_socket_sendto(dhcpc->s, hdr, (int)(sizeof(struct pico_dhcp_hdr) + optlen), &destination, PICO_DHCPD_PORT);
+    PICO_FREE(hdr);
+    if (r < 0)
+        return -1;
+
+    return 0;
+}
+
+static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s)
+{
+
+    uint8_t *buf;
+    int r = 0;
+    struct pico_dhcp_hdr *hdr = NULL;
+    struct pico_dhcp_client_cookie *dhcpc = NULL;
+
+    if ((ev & PICO_SOCK_EV_RD) == 0)
+        return;
+
+    buf = PICO_ZALLOC(DHCP_CLIENT_MAXMSGZISE);
+    if (!buf) {
+        return;
+    }
+
+    r = pico_socket_recvfrom(s, buf, DHCP_CLIENT_MAXMSGZISE, NULL, NULL);
+    if (r < 0)
+        goto out_discard_buf;
+
+    /* If the 'xid' of an arriving message does not match the 'xid'
+     * of the most recent transmitted message, the message must be
+     * silently discarded. */
+    hdr = (struct pico_dhcp_hdr *)buf;
+    dhcpc = pico_dhcp_client_find_cookie(hdr->xid);
+    if (!dhcpc)
+        goto out_discard_buf;
+
+    dhcpc->event = (uint8_t)pico_dhcp_client_opt_parse(buf, (uint16_t)r);
+    pico_dhcp_state_machine(dhcpc->event, dhcpc, buf);
+
+out_discard_buf:
+    PICO_FREE(buf);
+}
+
+void *pico_dhcp_get_identifier(uint32_t xid)
+{
+    return (void *)pico_dhcp_client_find_cookie(xid);
+}
+
+struct pico_ip4 pico_dhcp_get_address(void*dhcpc)
+{
+    return ((struct pico_dhcp_client_cookie*)dhcpc)->address;
+}
+
+struct pico_ip4 pico_dhcp_get_gateway(void*dhcpc)
+{
+    return ((struct pico_dhcp_client_cookie*)dhcpc)->gateway;
+}
+
+struct pico_ip4 pico_dhcp_get_netmask(void *dhcpc)
+{
+    return ((struct pico_dhcp_client_cookie*)dhcpc)->netmask;
+}
+
+struct pico_ip4 pico_dhcp_get_nameserver(void*dhcpc, int index)
+{
+    struct pico_ip4 fault = {
+        .addr = 0xFFFFFFFFU
+    };
+    if ((index != 0) && (index != 1))
+        return fault;
+
+    return ((struct pico_dhcp_client_cookie*)dhcpc)->nameserver[index];
+}
+
+int pico_dhcp_client_abort(uint32_t xid)
+{
+    return pico_dhcp_client_del_cookie(xid);
+}
+#endif
diff --git a/net/picotcp/modules/pico_dhcp_client.h b/net/picotcp/modules/pico_dhcp_client.h
new file mode 100644
index 0000000..2b5bbf9
--- /dev/null
+++ b/net/picotcp/modules/pico_dhcp_client.h
@@ -0,0 +1,30 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_DHCP_CLIENT
+#define INCLUDE_PICO_DHCP_CLIENT
+#include "pico_defines.h"
+#ifdef PICO_SUPPORT_UDP
+#include "pico_dhcp_common.h"
+#include "pico_addressing.h"
+#include "pico_protocol.h"
+
+int pico_dhcp_initiate_negotiation(struct pico_device *device, void (*callback)(void*cli, int code), uint32_t *xid);
+void *pico_dhcp_get_identifier(uint32_t xid);
+struct pico_ip4 pico_dhcp_get_address(void *cli);
+struct pico_ip4 pico_dhcp_get_gateway(void *cli);
+struct pico_ip4 pico_dhcp_get_netmask(void *cli);
+struct pico_ip4 pico_dhcp_get_nameserver(void*cli, int index);
+int pico_dhcp_client_abort(uint32_t xid);
+
+/* possible codes for the callback */
+#define PICO_DHCP_SUCCESS 0
+#define PICO_DHCP_ERROR   1
+#define PICO_DHCP_RESET   2
+
+#endif
+#endif
diff --git a/net/picotcp/modules/pico_dhcp_common.c b/net/picotcp/modules/pico_dhcp_common.c
new file mode 100644
index 0000000..99701ba
--- /dev/null
+++ b/net/picotcp/modules/pico_dhcp_common.c
@@ -0,0 +1,189 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Frederik Van Slycken
+ *********************************************************************/
+
+#include "pico_config.h"
+#include "pico_stack.h"
+#include "pico_dhcp_common.h"
+
+#if defined (PICO_SUPPORT_DHCPC) || defined (PICO_SUPPORT_DHCPD)
+/* pico_dhcp_are_options_valid needs to be called first to prevent illegal memory access */
+/* The argument pointer is moved forward to the next option */
+struct pico_dhcp_opt *pico_dhcp_next_option(struct pico_dhcp_opt **ptr)
+{
+    uint8_t **p = (uint8_t **)ptr;
+    struct pico_dhcp_opt *opt = *ptr;
+
+    if (opt->code == PICO_DHCP_OPT_END)
+        return NULL;
+
+    if (opt->code == PICO_DHCP_OPT_PAD) {
+        *p += 1;
+        return *ptr;
+    }
+
+    *p += (opt->len + 2); /* (len + 2) to account for code and len octet */
+    return *ptr;
+}
+
+uint8_t pico_dhcp_are_options_valid(void *ptr, int32_t len)
+{
+    uint8_t optlen = 0, *p = ptr;
+
+    while (len > 0) {
+        switch (*p)
+        {
+        case PICO_DHCP_OPT_END:
+            return 1;
+
+        case PICO_DHCP_OPT_PAD:
+            p++;
+            len--;
+            break;
+
+        default:
+            p++; /* move pointer from code octet to len octet */
+            len--;
+            if ((len <= 0) || (len - (*p + 1) < 0)) /* (*p + 1) to account for len octet */
+                return 0;
+
+            optlen = *p;
+            p += optlen + 1;
+            len -= optlen;
+            break;
+        }
+    }
+    return 0;
+}
+
+uint8_t pico_dhcp_opt_netmask(void *ptr, struct pico_ip4 *ip)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: netmask */
+    opt->code = PICO_DHCP_OPT_NETMASK;
+    opt->len = PICO_DHCP_OPTLEN_NETMASK - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.netmask.ip = *ip;
+    return PICO_DHCP_OPTLEN_NETMASK;
+}
+
+uint8_t pico_dhcp_opt_router(void *ptr, struct pico_ip4 *ip)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: router */
+    opt->code = PICO_DHCP_OPT_ROUTER;
+    opt->len = PICO_DHCP_OPTLEN_ROUTER - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.router.ip = *ip;
+    return PICO_DHCP_OPTLEN_ROUTER;
+}
+
+uint8_t pico_dhcp_opt_dns(void *ptr, struct pico_ip4 *ip)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: dns */
+    opt->code = PICO_DHCP_OPT_DNS;
+    opt->len = PICO_DHCP_OPTLEN_DNS - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.dns1.ip = *ip;
+    return PICO_DHCP_OPTLEN_DNS;
+}
+
+uint8_t pico_dhcp_opt_broadcast(void *ptr, struct pico_ip4 *ip)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: broadcast */
+    opt->code = PICO_DHCP_OPT_BROADCAST;
+    opt->len = PICO_DHCP_OPTLEN_BROADCAST - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.broadcast.ip = *ip;
+    return PICO_DHCP_OPTLEN_BROADCAST;
+}
+
+uint8_t pico_dhcp_opt_reqip(void *ptr, struct pico_ip4 *ip)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: request IP address */
+    opt->code = PICO_DHCP_OPT_REQIP;
+    opt->len = PICO_DHCP_OPTLEN_REQIP - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.req_ip.ip = *ip;
+    return PICO_DHCP_OPTLEN_REQIP;
+}
+
+uint8_t pico_dhcp_opt_leasetime(void *ptr, uint32_t time)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: lease time */
+    opt->code = PICO_DHCP_OPT_LEASETIME;
+    opt->len = PICO_DHCP_OPTLEN_LEASETIME - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.lease_time.time = time;
+    return PICO_DHCP_OPTLEN_LEASETIME;
+}
+
+uint8_t pico_dhcp_opt_msgtype(void *ptr, uint8_t type)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: message type */
+    opt->code = PICO_DHCP_OPT_MSGTYPE;
+    opt->len = PICO_DHCP_OPTLEN_MSGTYPE - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.msg_type.type = type;
+    return PICO_DHCP_OPTLEN_MSGTYPE;
+}
+
+uint8_t pico_dhcp_opt_serverid(void *ptr, struct pico_ip4 *ip)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: server identifier */
+    opt->code = PICO_DHCP_OPT_SERVERID;
+    opt->len = PICO_DHCP_OPTLEN_SERVERID - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.server_id.ip = *ip;
+    return PICO_DHCP_OPTLEN_SERVERID;
+}
+
+uint8_t pico_dhcp_opt_paramlist(void *ptr)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: parameter list */
+    opt->code = PICO_DHCP_OPT_PARAMLIST;
+    opt->len = PICO_DHCP_OPTLEN_PARAMLIST - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.param_list.code[0] = PICO_DHCP_OPT_NETMASK;
+    opt->ext.param_list.code[1] = PICO_DHCP_OPT_TIME;
+    opt->ext.param_list.code[2] = PICO_DHCP_OPT_ROUTER;
+    opt->ext.param_list.code[3] = PICO_DHCP_OPT_HOSTNAME;
+    opt->ext.param_list.code[4] = PICO_DHCP_OPT_RENEWALTIME;
+    opt->ext.param_list.code[5] = PICO_DHCP_OPT_REBINDINGTIME;
+    opt->ext.param_list.code[6] = PICO_DHCP_OPT_DNS;
+    return PICO_DHCP_OPTLEN_PARAMLIST;
+}
+
+uint8_t pico_dhcp_opt_maxmsgsize(void *ptr, uint16_t size)
+{
+    struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)ptr;
+
+    /* option: maximum message size */
+    opt->code = PICO_DHCP_OPT_MAXMSGSIZE;
+    opt->len = PICO_DHCP_OPTLEN_MAXMSGSIZE - PICO_DHCP_OPTLEN_HDR;
+    opt->ext.max_msg_size.size = short_be(size);
+    return PICO_DHCP_OPTLEN_MAXMSGSIZE;
+}
+
+uint8_t pico_dhcp_opt_end(void *ptr)
+{
+    uint8_t *opt = (uint8_t *)ptr;
+
+    /* option: end of options */
+    *opt = PICO_DHCP_OPT_END;
+    return PICO_DHCP_OPTLEN_END;
+}
+
+#endif
diff --git a/net/picotcp/modules/pico_dhcp_common.h b/net/picotcp/modules/pico_dhcp_common.h
new file mode 100644
index 0000000..cdf1bd1
--- /dev/null
+++ b/net/picotcp/modules/pico_dhcp_common.h
@@ -0,0 +1,186 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+ *********************************************************************/
+#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))
+#define PICO_DHCP_CLIENT_PORT (short_be(68))
+#define PICO_DHCPD_MAGIC_COOKIE (long_be(0x63825363))
+#define PICO_DHCP_HTYPE_ETH 1
+
+/* flags */
+#define PICO_DHCP_FLAG_BROADCAST        0x8000
+
+/* options */
+#define PICO_DHCP_OPT_PAD               0x00
+#define PICO_DHCP_OPT_NETMASK           0x01
+#define PICO_DHCP_OPT_TIME              0x02
+#define PICO_DHCP_OPT_ROUTER            0x03
+#define PICO_DHCP_OPT_DNS               0x06
+#define PICO_DHCP_OPT_HOSTNAME          0x0c
+#define PICO_DHCP_OPT_DOMAINNAME        0x0f
+#define PICO_DHCP_OPT_MTU               0x1a
+#define PICO_DHCP_OPT_BROADCAST         0x1c
+#define PICO_DHCP_OPT_NETBIOSNS         0x2c
+#define PICO_DHCP_OPT_NETBIOSSCOPE      0x2f
+#define PICO_DHCP_OPT_REQIP             0x32
+#define PICO_DHCP_OPT_LEASETIME         0x33
+#define PICO_DHCP_OPT_OPTOVERLOAD       0x34
+#define PICO_DHCP_OPT_MSGTYPE           0x35
+#define PICO_DHCP_OPT_SERVERID          0x36
+#define PICO_DHCP_OPT_PARAMLIST         0x37
+#define PICO_DHCP_OPT_MESSAGE           0x38
+#define PICO_DHCP_OPT_MAXMSGSIZE        0x39
+#define PICO_DHCP_OPT_RENEWALTIME       0x3a
+#define PICO_DHCP_OPT_REBINDINGTIME     0x3b
+#define PICO_DHCP_OPT_VENDORID          0x3c
+#define PICO_DHCP_OPT_CLIENTID          0x3d
+#define PICO_DHCP_OPT_DOMAINSEARCH      0x77
+#define PICO_DHCP_OPT_STATICROUTE       0x79
+#define PICO_DHCP_OPT_END               0xFF
+
+/* options len */
+#define PICO_DHCP_OPTLEN_HDR            2 /* account for code and len field */
+#define PICO_DHCP_OPTLEN_NETMASK        6
+#define PICO_DHCP_OPTLEN_ROUTER         6
+#define PICO_DHCP_OPTLEN_DNS            6
+#define PICO_DHCP_OPTLEN_BROADCAST      6
+#define PICO_DHCP_OPTLEN_REQIP          6
+#define PICO_DHCP_OPTLEN_LEASETIME      6
+#define PICO_DHCP_OPTLEN_OPTOVERLOAD    3
+#define PICO_DHCP_OPTLEN_MSGTYPE        3
+#define PICO_DHCP_OPTLEN_SERVERID       6
+#define PICO_DHCP_OPTLEN_PARAMLIST      9 /* PicoTCP specific */
+#define PICO_DHCP_OPTLEN_MAXMSGSIZE     4
+#define PICO_DHCP_OPTLEN_RENEWALTIME    6
+#define PICO_DHCP_OPTLEN_REBINDINGTIME  6
+#define PICO_DHCP_OPTLEN_END            1
+
+/* op codes */
+#define PICO_DHCP_OP_REQUEST            1
+#define PICO_DHCP_OP_REPLY              2
+
+/* rfc message types */
+#define PICO_DHCP_MSG_DISCOVER          1
+#define PICO_DHCP_MSG_OFFER             2
+#define PICO_DHCP_MSG_REQUEST           3
+#define PICO_DHCP_MSG_DECLINE           4
+#define PICO_DHCP_MSG_ACK               5
+#define PICO_DHCP_MSG_NAK               6
+#define PICO_DHCP_MSG_RELEASE           7
+#define PICO_DHCP_MSG_INFORM            8
+
+/* custom message types */
+#define PICO_DHCP_EVENT_T1              9
+#define PICO_DHCP_EVENT_T2              10
+#define PICO_DHCP_EVENT_LEASE           11
+#define PICO_DHCP_EVENT_RETRANSMIT      12
+#define PICO_DHCP_EVENT_NONE            0xff
+
+PACKED_STRUCT_DEF pico_dhcp_hdr
+{
+    uint8_t op;
+    uint8_t htype;
+    uint8_t hlen;
+    uint8_t hops; /* zero */
+    uint32_t xid; /* store this in the request */
+    uint16_t secs; /* ignore */
+    uint16_t flags;
+    uint32_t ciaddr; /* client address - if asking for renewal */
+    uint32_t yiaddr; /* your address (client) */
+    uint32_t siaddr; /* dhcp offered address */
+    uint32_t giaddr; /* relay agent, bootp. */
+    uint8_t hwaddr[6];
+    uint8_t hwaddr_padding[10];
+    char hostname[64];
+    char bootp_filename[128];
+    uint32_t dhcp_magic;
+    uint8_t options[0];
+};
+
+PACKED_STRUCT_DEF pico_dhcp_opt
+{
+    uint8_t code;
+    uint8_t len;
+    PACKED_UNION_DEF dhcp_opt_ext_u {
+        PEDANTIC_STRUCT_DEF netmask_s {
+            struct pico_ip4 ip;
+        } netmask;
+        PEDANTIC_STRUCT_DEF router_s {
+            struct pico_ip4 ip;
+        } router;
+        PEDANTIC_STRUCT_DEF dns_s {
+            struct pico_ip4 ip;
+        } dns1;
+        struct dns_s dns2;
+        PEDANTIC_STRUCT_DEF broadcast_s {
+            struct pico_ip4 ip;
+        } broadcast;
+        PEDANTIC_STRUCT_DEF req_ip_s {
+            struct pico_ip4 ip;
+        } req_ip;
+        PEDANTIC_STRUCT_DEF lease_time_s {
+            uint32_t time;
+        } lease_time;
+        PEDANTIC_STRUCT_DEF opt_overload_s {
+            uint8_t value;
+        } opt_overload;
+        PEDANTIC_STRUCT_DEF tftp_server_s {
+            char name[1];
+        } tftp_server;
+        PEDANTIC_STRUCT_DEF bootfile_s {
+            char name[1];
+        } bootfile;
+        PEDANTIC_STRUCT_DEF msg_type_s {
+            uint8_t type;
+        } msg_type;
+        PEDANTIC_STRUCT_DEF server_id_s {
+            struct pico_ip4 ip;
+        } server_id;
+        PEDANTIC_STRUCT_DEF param_list_s {
+            uint8_t code[1];
+        } param_list;
+        PEDANTIC_STRUCT_DEF message_s {
+            char error[1];
+        } message;
+        PEDANTIC_STRUCT_DEF max_msg_size_s {
+            uint16_t size;
+        } max_msg_size;
+        PEDANTIC_STRUCT_DEF renewal_time_s {
+            uint32_t time;
+        } renewal_time;
+        PEDANTIC_STRUCT_DEF rebinding_time_s {
+            uint32_t time;
+        } rebinding_time;
+        PEDANTIC_STRUCT_DEF vendor_id_s {
+            uint8_t id[1];
+        } vendor_id;
+        PEDANTIC_STRUCT_DEF client_id_s {
+            uint8_t id[1];
+        } client_id;
+    } ext;
+};
+
+uint8_t dhcp_get_next_option(uint8_t *begin, uint8_t *data, int *len, uint8_t **nextopt);
+struct pico_dhcp_opt *pico_dhcp_next_option(struct pico_dhcp_opt **ptr);
+uint8_t pico_dhcp_are_options_valid(void *ptr, int32_t len);
+
+uint8_t pico_dhcp_opt_netmask(void *ptr, struct pico_ip4 *ip);
+uint8_t pico_dhcp_opt_router(void *ptr, struct pico_ip4 *ip);
+uint8_t pico_dhcp_opt_dns(void *ptr, struct pico_ip4 *ip);
+uint8_t pico_dhcp_opt_broadcast(void *ptr, struct pico_ip4 *ip);
+uint8_t pico_dhcp_opt_reqip(void *ptr, struct pico_ip4 *ip);
+uint8_t pico_dhcp_opt_leasetime(void *ptr, uint32_t time);
+uint8_t pico_dhcp_opt_msgtype(void *ptr, uint8_t type);
+uint8_t pico_dhcp_opt_serverid(void *ptr, struct pico_ip4 *ip);
+uint8_t pico_dhcp_opt_paramlist(void *ptr);
+uint8_t pico_dhcp_opt_maxmsgsize(void *ptr, uint16_t size);
+uint8_t pico_dhcp_opt_end(void *ptr);
+#endif
diff --git a/net/picotcp/modules/pico_dns_client.h b/net/picotcp/modules/pico_dns_client.h
new file mode 100644
index 0000000..910cc92
--- /dev/null
+++ b/net/picotcp/modules/pico_dns_client.h
@@ -0,0 +1,46 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Kristof Roelants
+ *********************************************************************/
+
+#ifndef INCLUDE_PICO_DNS_CLIENT
+#define INCLUDE_PICO_DNS_CLIENT
+
+#define PICO_DNS_NS_DEL 0
+#define PICO_DNS_NS_ADD 1
+#include "pico_config.h"
+
+/* Compression values */
+#define PICO_DNS_LABEL 0
+#define PICO_DNS_POINTER 3
+
+/* Label len */
+#define PICO_DNS_LABEL_INITIAL 1u
+#define PICO_DNS_LABEL_ROOT 1
+
+/* TTL values */
+#define PICO_DNS_MAX_TTL 604800 /* one week */
+
+/* Len of an IPv4 address string */
+#define PICO_DNS_IPV4_ADDR_LEN 16
+#define PICO_DNS_IPV6_ADDR_LEN 54
+
+/* Default nameservers + port */
+#define PICO_DNS_NS_DEFAULT "208.67.222.222"
+#define PICO_DNS_NS_PORT 53
+
+int pico_dns_client_init(void);
+/* flag is PICO_DNS_NS_DEL or PICO_DNS_NS_ADD */
+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 */
diff --git a/net/picotcp/modules/pico_dns_common.h b/net/picotcp/modules/pico_dns_common.h
new file mode 100644
index 0000000..9172696
--- /dev/null
+++ b/net/picotcp/modules/pico_dns_common.h
@@ -0,0 +1,521 @@
+
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+   See LICENSE and COPYING for usage.
+   .
+   Authors: Toon Stegen, Jelle De Vleeschouwer
+ *********************************************************************/
+
+#ifndef INCLUDE_PICO_DNS_COMMON
+#define INCLUDE_PICO_DNS_COMMON
+
+#include "pico_config.h"
+#include "pico_tree.h"
+
+/* TYPE values */
+#define PICO_DNS_TYPE_A 1
+#define PICO_DNS_TYPE_CNAME 5
+#define PICO_DNS_TYPE_PTR 12
+#define PICO_DNS_TYPE_TXT 16
+#define PICO_DNS_TYPE_AAAA 28
+#define PICO_DNS_TYPE_SRV 33
+#define PICO_DNS_TYPE_NSEC 47
+#define PICO_DNS_TYPE_ANY 255
+
+/* CLASS values */
+#define PICO_DNS_CLASS_IN 1
+
+/* FLAG values */
+#define PICO_DNS_QR_QUERY 0
+#define PICO_DNS_QR_RESPONSE 1
+#define PICO_DNS_OPCODE_QUERY 0
+#define PICO_DNS_OPCODE_IQUERY 1
+#define PICO_DNS_OPCODE_STATUS 2
+#define PICO_DNS_AA_NO_AUTHORITY 0
+#define PICO_DNS_AA_IS_AUTHORITY 1
+#define PICO_DNS_TC_NO_TRUNCATION 0
+#define PICO_DNS_TC_IS_TRUNCATED 1
+#define PICO_DNS_RD_NO_DESIRE 0
+#define PICO_DNS_RD_IS_DESIRED 1
+#define PICO_DNS_RA_NO_SUPPORT 0
+#define PICO_DNS_RA_IS_SUPPORTED 1
+#define PICO_DNS_RCODE_NO_ERROR 0
+#define PICO_DNS_RCODE_EFORMAT 1
+#define PICO_DNS_RCODE_ESERVER 2
+#define PICO_DNS_RCODE_ENAME 3
+#define PICO_DNS_RCODE_ENOIMP 4
+#define PICO_DNS_RCODE_EREFUSED 5
+
+#define PICO_ARPA_IPV4_SUFFIX ".in-addr.arpa"
+
+#ifdef PICO_SUPPORT_IPV6
+#define STRLEN_PTR_IP6 63
+#define PICO_ARPA_IPV6_SUFFIX ".IP6.ARPA"
+#endif
+
+#define PICO_DNS_NAMEBUF_SIZE (256)
+
+enum pico_dns_arpa
+{
+    PICO_DNS_ARPA4,
+    PICO_DNS_ARPA6,
+    PICO_DNS_NO_ARPA,
+};
+
+/* flags split in 2x uint8 due to endianness */
+PACKED_STRUCT_DEF pico_dns_header
+{
+    uint16_t id;        /* Packet id */
+    uint8_t rd : 1;     /* Recursion Desired */
+    uint8_t tc : 1;     /* TrunCation */
+    uint8_t aa : 1;     /* Authoritative Answer */
+    uint8_t opcode : 4; /* Opcode */
+    uint8_t qr : 1;     /* Query/Response */
+    uint8_t rcode : 4;  /* Response code */
+    uint8_t z : 3;      /* Zero */
+    uint8_t ra : 1;     /* Recursion Available */
+    uint16_t qdcount;   /* Question count */
+    uint16_t ancount;   /* Answer count */
+    uint16_t nscount;   /* Authority count */
+    uint16_t arcount;   /* Additional count */
+};
+typedef struct pico_dns_header pico_dns_packet;
+
+/* Question fixed-sized fields */
+PACKED_STRUCT_DEF pico_dns_question_suffix
+{
+    uint16_t qtype;
+    uint16_t qclass;
+};
+
+/* Resource record fixed-sized fields */
+PACKED_STRUCT_DEF pico_dns_record_suffix
+{
+    uint16_t rtype;
+    uint16_t rclass;
+    uint32_t rttl;
+    uint16_t rdlength;
+};
+
+/* DNS QUESTION */
+struct pico_dns_question
+{
+    char *qname;
+    struct pico_dns_question_suffix *qsuffix;
+    uint16_t qname_length;
+    uint8_t proto;
+};
+
+/* DNS RECORD */
+struct pico_dns_record
+{
+    char *rname;
+    struct pico_dns_record_suffix *rsuffix;
+    uint8_t *rdata;
+    uint16_t rname_length;
+};
+
+/* MARK: v NAME & IP FUNCTIONS */
+
+/* ****************************************************************************
+ *  Checks if the DNS name doesn't exceed 256 bytes including zero-byte.
+ *
+ *  @param namelen Length of the DNS name-string including zero-byte
+ *  @return 0 when the length is correct
+ * ****************************************************************************/
+int
+pico_dns_check_namelen( uint16_t namelen );
+
+/* ****************************************************************************
+ *  Returns the length of a name in a DNS-packet as if DNS name compression
+ *  would be applied to the packet. If there's no compression present this
+ *	returns the strlen. If there's compression present this returns the length
+ *	until the compression-pointer + 1.
+ *
+ *  @param name Compressed name you want the calculate the strlen from
+ *  @return Returns strlen of a compressed name, takes the first byte of compr-
+ *			ession pointer into account but not the second byte, which acts
+ *			like a trailing zero-byte.
+ * ****************************************************************************/
+uint16_t
+pico_dns_namelen_comp( char *name );
+
+/* ****************************************************************************
+ *  Returns the uncompressed name in DNS name format when DNS name compression
+ *  is applied to the packet-buffer.
+ *
+ *  @param name   Compressed name, should be in the bounds of the actual packet
+ *  @param packet Packet that contains the compressed name
+ *  @return Returns the decompressed name, NULL on failure.
+ * ****************************************************************************/
+char *
+pico_dns_decompress_name( char *name, pico_dns_packet *packet );
+
+/* ****************************************************************************
+ *  Converts a DNS name in DNS name format to a name in URL format. Provides
+ *  space for the name in URL format as well. PICO_FREE() should be called on
+ *  the returned string buffer that contains the name in URL format.
+ *
+ *  @param qname DNS name in DNS name format to convert
+ *  @return Returns a pointer to a string-buffer with the URL name on success.
+ * ****************************************************************************/
+char *
+pico_dns_qname_to_url( const char *qname );
+
+/* ****************************************************************************
+ *  Converts a DNS name in URL format to name in DNS name format. Provides
+ *  space for the DNS name as well. PICO_FREE() should be called on the returned
+ *  string buffer that contains the DNS name.
+ *
+ *  @param url DNS name in URL format to convert
+ *  @return Returns a pointer to a string-buffer with the DNS name on success.
+ * ****************************************************************************/
+char *
+pico_dns_url_to_qname( const char *url );
+
+/* ****************************************************************************
+ *  @param url String-buffer
+ *  @return Length of string-buffer in an uint16_t
+ * ****************************************************************************/
+uint16_t
+pico_dns_strlen( const char *url );
+
+/* ****************************************************************************
+ *  Replaces .'s in a DNS name in URL format by the label lengths. So it
+ *  actually converts a name in URL format to a name in DNS name format.
+ *  f.e. "*www.google.be" => "3www6google2be0"
+ *
+ *  @param url    Location to buffer with name in URL format. The URL needs to
+ *                be +1 byte offset in the actual buffer. Size is should be
+ *                strlen(url) + 2.
+ *  @param maxlen Maximum length of buffer so it doesn't cause a buffer overflow
+ *  @return 0 on success, something else on failure.
+ * ****************************************************************************/
+int pico_dns_name_to_dns_notation( char *url, unsigned int maxlen );
+
+/* ****************************************************************************
+ *  Replaces the label lengths in a DNS-name by .'s. So it actually converts a
+ *  name in DNS format to a name in URL format.
+ *  f.e. 3www6google2be0 => .www.google.be
+ *
+ *  @param ptr    Location to buffer with name in DNS name format
+ *  @param maxlen Maximum length of buffer so it doesn't cause a buffer overflow
+ *  @return 0 on success, something else on failure.
+ * ****************************************************************************/
+int pico_dns_notation_to_name( char *ptr, unsigned int maxlen );
+
+/* ****************************************************************************
+ *  Determines the length of the first label of a DNS name in URL-format
+ *
+ *  @param url DNS name in URL-format
+ *  @return Length of the first label of DNS name in URL-format
+ * ****************************************************************************/
+uint16_t
+pico_dns_first_label_length( const char *url );
+
+/* ****************************************************************************
+ *  Mirrors a dotted IPv4-address string.
+ *	f.e. 192.168.0.1 => 1.0.168.192
+ *
+ *  @param ptr
+ *  @return 0 on success, something else on failure.
+ * ****************************************************************************/
+int
+pico_dns_mirror_addr( char *ptr );
+
+/* ****************************************************************************
+ *  Convert an IPv6-address in string-format to a IPv6-address in nibble-format.
+ *	Doesn't add a IPv6 ARPA-suffix though.
+ *
+ *  @param ip  IPv6-address stored as a string
+ *  @param dst Destination to store IPv6-address in nibble-format
+ * ****************************************************************************/
+void
+pico_dns_ipv6_set_ptr( const char *ip, char *dst );
+
+/* MARK: QUESTION FUNCTIONS */
+
+/* ****************************************************************************
+ *  Deletes a single DNS Question.
+ *
+ *  @param question Void-pointer to DNS Question. Can be used with pico_tree_-
+ *					destroy.
+ *  @return Returns 0 on success, something else on failure.
+ * ****************************************************************************/
+int
+pico_dns_question_delete( void **question);
+
+/* ****************************************************************************
+ *  Fills in the DNS question suffix-fields with the correct values.
+ *
+ *  todo: Update pico_dns_client to make the same mechanism possible as with
+ *        filling DNS Resource Record-suffixes. This function shouldn't be an
+ *		  API-function.
+ *
+ *  @param suf    Pointer to the suffix member of the DNS question.
+ *  @param qtype  DNS type of the DNS question to be.
+ *  @param qclass DNS class of the DNS question to be.
+ *  @return Returns 0 on success, something else on failure.
+ * ****************************************************************************/
+int
+pico_dns_question_fill_suffix( struct pico_dns_question_suffix *suf,
+                               uint16_t qtype,
+                               uint16_t qclass );
+
+/* ****************************************************************************
+ *  Creates a standalone DNS Question with a given name and type.
+ *
+ *  @param url     DNS question name in URL format. Will be converted to DNS
+ *				   name notation format.
+ *  @param len     Will be filled with the total length of the DNS question.
+ *  @param proto   Protocol for which you want to create a question. Can be
+ *				   either PICO_PROTO_IPV4 or PICO_PROTO_IPV6.
+ *  @param qtype   DNS type of the question to be.
+ *  @param qclass  DNS class of the question to be.
+ *  @param reverse When this is true, a reverse resolution name will be gene-
+ *				   from the URL
+ *  @return Returns pointer to the created DNS Question on success, NULL on
+ *			failure.
+ * ****************************************************************************/
+struct pico_dns_question *
+pico_dns_question_create( const char *url,
+                          uint16_t *len,
+                          uint8_t proto,
+                          uint16_t qtype,
+                          uint16_t qclass,
+                          uint8_t reverse );
+
+/* ****************************************************************************
+ *  Decompresses the name of a single DNS question.
+ *
+ *  @param question Question you want to decompress the name of
+ *  @param packet   Packet in which the DNS question is contained.
+ *  @return Pointer to original name of the DNS question before decompressing.
+ * ****************************************************************************/
+char *
+pico_dns_question_decompress( struct pico_dns_question *question,
+                              pico_dns_packet *packet );
+
+/* MARK: RESOURCE RECORD FUNCTIONS */
+
+/* ****************************************************************************
+ *  Deletes a single DNS resource record.
+ *
+ *  @param record Void-pointer to DNS record. Can be used with pico_tree_destroy
+ *  @return Returns 0 on success, something else on failure.
+ * ****************************************************************************/
+int
+pico_dns_record_delete( void **record );
+
+/* ****************************************************************************
+ *  Just makes a hardcopy from a single DNS Resource Record
+ *
+ *  @param record DNS record you want to copy
+ *  @return Pointer to copy of DNS record.
+ * ****************************************************************************/
+struct pico_dns_record *
+pico_dns_record_copy( struct pico_dns_record *record );
+
+/* ****************************************************************************
+ *  Create a standalone DNS Resource Record with given name, type and data.
+ *
+ *  @param url     DNS rrecord name in URL format. Will be converted to DNS
+ *                 name notation format.
+ *  @param _rdata  Memory buffer with data to insert in the resource record. If
+ *				   data of record should contain a DNS name, the name in the
+ *				   databuffer needs to be in URL-format.
+ *  @param datalen The exact length in bytes of the _rdata-buffer. If data of
+ *				   record should contain a DNS name, datalen needs to be
+ *				   pico_dns_strlen(_rdata).
+ *  @param len     Will be filled with the total length of the DNS rrecord.
+ *  @param rtype   DNS type of the resource record to be.
+ *  @param rclass  DNS class of the resource record to be.
+ *  @param rttl    DNS ttl of the resource record to be.
+ *  @return Returns pointer to the created DNS Resource Record
+ * ****************************************************************************/
+struct pico_dns_record *
+pico_dns_record_create( const char *url,
+                        void *_rdata,
+                        uint16_t datalen,
+                        uint16_t *len,
+                        uint16_t rtype,
+                        uint16_t rclass,
+                        uint32_t rttl );
+
+/* ****************************************************************************
+ *  Decompresses the name of single DNS record.
+ *
+ *  @param record DNS record to decompress the name of.
+ *  @param packet Packet in which is DNS record is present
+ *  @return Pointer to original name of the DNS record before decompressing.
+ * ****************************************************************************/
+char *
+pico_dns_record_decompress( struct pico_dns_record *record,
+                            pico_dns_packet *packet );
+
+/* MARK: COMPARING */
+
+/* ****************************************************************************
+ *  Compares two databuffers against each other.
+ *
+ *  @param a          1st Memory buffer to compare
+ *  @param b          2nd Memory buffer to compare
+ *  @param rdlength_a Length of 1st memory buffer
+ *  @param rdlength_b Length of 2nd memory buffer
+ *  @return 0 when the buffers are equal, returns difference when they're not.
+ * ****************************************************************************/
+int
+pico_dns_rdata_cmp( uint8_t *a, uint8_t *b,
+                    uint16_t rdlength_a, uint16_t rdlength_b );
+
+/* ****************************************************************************
+ *  Compares 2 DNS questions
+ *
+ *  @param qa DNS question A as a void-pointer (for pico_tree)
+ *  @param qb DNS question A as a void-pointer (for pico_tree)
+ *  @return 0 when questions are equal, returns difference when they're not.
+ * ****************************************************************************/
+int
+pico_dns_question_cmp( void *qa,
+                       void *qb );
+
+/* ****************************************************************************
+ *  Compares 2 DNS records by type and name only
+ *
+ *  @param ra DNS record A as a void-pointer (for pico_tree)
+ *  @param rb DNS record B as a void-pointer (for pico_tree)
+ *  @return 0 when name and type of records are equal, returns difference when
+ *			they're not.
+ * ****************************************************************************/
+int
+pico_dns_record_cmp_name_type( void *ra,
+                               void *rb );
+
+/* ****************************************************************************
+ *  Compares 2 DNS records by type, name AND rdata for a truly unique result
+ *
+ *  @param ra DNS record A as a void-pointer (for pico_tree)
+ *  @param rb DNS record B as a void-pointer (for pico_tree)
+ *  @return 0 when records are equal, returns difference when they're not
+ * ****************************************************************************/
+int
+pico_dns_record_cmp( void *ra,
+                     void *rb );
+
+/* MARK: PICO_TREE */
+
+/* ****************************************************************************
+ *  Erases a pico_tree entirely.
+ *
+ *  @param tree        Pointer to a pico_tree-instance
+ *  @param node_delete Helper-function for type-specific deleting.
+ *  @return Returns 0 on success, something else on failure.
+ * ****************************************************************************/
+int
+pico_tree_destroy( struct pico_tree *tree, int (*node_delete)(void **));
+
+/* ****************************************************************************
+ *  Determines the amount of nodes in a pico_tree
+ *
+ *  @param tree Pointer to pico_tree-instance
+ *  @return Amount of items in the tree.
+ * ****************************************************************************/
+uint16_t
+pico_tree_count( struct pico_tree *tree );
+
+/* ****************************************************************************
+ *  Definition of DNS question tree
+ * ****************************************************************************/
+typedef struct pico_tree pico_dns_qtree;
+#define PICO_DNS_QTREE_DECLARE(name) \
+    pico_dns_qtree (name) = {&LEAF, pico_dns_question_cmp}
+#define PICO_DNS_QTREE_DESTROY(qtree) \
+    pico_tree_destroy(qtree, pico_dns_question_delete)
+
+/* ****************************************************************************
+ *  Deletes all the questions with given DNS name from a pico_tree
+ *
+ *  @param qtree Pointer to pico_tree-instance which contains DNS questions
+ *  @param name  Name of the questions you want to delete
+ *  @return Returns 0 on success, something else on failure.
+ * ****************************************************************************/
+int
+pico_dns_qtree_del_name( struct pico_tree *qtree,
+                         const char *name );
+
+/* ****************************************************************************
+ *  Checks whether a question with given name is in the tree or not.
+ *
+ *  @param qtree Pointer to pico_tree-instance which contains DNS questions
+ *  @param name  Name you want to check for
+ *  @return 1 when the name is present in the qtree, 0 when it's not.
+ * ****************************************************************************/
+int
+pico_dns_qtree_find_name( struct pico_tree *qtree,
+                          const char *name );
+
+/* ****************************************************************************
+ *  Definition of DNS record tree
+ * ****************************************************************************/
+typedef struct pico_tree pico_dns_rtree;
+#define PICO_DNS_RTREE_DECLARE(name) \
+    pico_dns_rtree (name) = {&LEAF, pico_dns_record_cmp}
+#define PICO_DNS_RTREE_DESTROY(rtree) \
+    pico_tree_destroy((rtree), pico_dns_record_delete)
+
+/* MARK: DNS PACKET FUNCTIONS */
+
+/* ****************************************************************************
+ *  Fills the header section of a DNS packet with the correct flags and section
+ *  -counts.
+ *
+ *  @param hdr     Header to fill in.
+ *  @param qdcount Amount of questions added to the packet
+ *  @param ancount Amount of answer records added to the packet
+ *  @param nscount Amount of authority records added to the packet
+ *  @param arcount Amount of additional records added to the packet
+ * ****************************************************************************/
+void
+pico_dns_fill_packet_header( struct pico_dns_header *hdr,
+                             uint16_t qdcount,
+                             uint16_t ancount,
+                             uint16_t authcount,
+                             uint16_t addcount );
+
+/* ****************************************************************************
+ *  Creates a DNS Query packet with given question and resource records to put
+ *  the Resource Record Sections. If a NULL-pointer is provided for a certain
+ *  tree, no records will be added to that particular section of the packet.
+ *
+ *  @param qtree  DNS Questions to put in the Question Section
+ *  @param antree DNS Records to put in the Answer Section
+ *  @param nstree DNS Records to put in the Authority Section
+ *  @param artree DNS Records to put in the Additional Section
+ *  @param len    Will get filled with the entire size of the packet
+ *  @return Pointer to created DNS packet
+ * ****************************************************************************/
+pico_dns_packet *
+pico_dns_query_create( struct pico_tree *qtree,
+                       struct pico_tree *antree,
+                       struct pico_tree *nstree,
+                       struct pico_tree *artree,
+                       uint16_t *len );
+
+/* ****************************************************************************
+ *  Creates a DNS Answer packet with given resource records to put in the
+ *  Resource Record Sections. If a NULL-pointer is provided for a certain tree,
+ *  no records will be added to that particular section of the packet.
+ *
+ *  @param antree DNS Records to put in the Answer Section
+ *  @param nstree DNS Records to put in the Authority Section
+ *  @param artree DNS Records to put in the Additional Section
+ *  @param len    Will get filled with the entire size of the packet
+ *  @return Pointer to created DNS packet.
+ * ****************************************************************************/
+pico_dns_packet *
+pico_dns_answer_create( struct pico_tree *antree,
+                        struct pico_tree *nstree,
+                        struct pico_tree *artree,
+                        uint16_t *len );
+
+#endif /* _INCLUDE_PICO_DNS_COMMON */
diff --git a/net/picotcp/modules/pico_dns_sd.h b/net/picotcp/modules/pico_dns_sd.h
new file mode 100644
index 0000000..77f8ef2
--- /dev/null
+++ b/net/picotcp/modules/pico_dns_sd.h
@@ -0,0 +1,90 @@
+/* ****************************************************************************
+ *  PicoTCP. Copyright (c) 2014 TASS Belgium NV. Some rights reserved.
+ *  See LICENSE and COPYING for usage.
+ *  .
+ *  Author: Jelle De Vleeschouwer
+ * ****************************************************************************/
+#ifndef INCLUDE_PICO_DNS_SD
+#define INCLUDE_PICO_DNS_SD
+
+#include "pico_mdns.h"
+
+typedef struct
+{
+    char *key;
+    char *value;
+} key_value_pair_t;
+
+typedef struct
+{
+    key_value_pair_t **pairs;
+    uint16_t count;
+} kv_vector;
+
+#define PICO_DNS_SD_KV_VECTOR_DECLARE(name) \
+    kv_vector (name) = {0}
+
+/* ****************************************************************************
+ *  Just calls pico_mdns_init in it's turn to initialise the mDNS-module.
+ *  See pico_mdns.h for description.
+ * ****************************************************************************/
+int
+pico_dns_sd_init( const char *_hostname,
+                  struct pico_ip4 address,
+                  void (*callback)(pico_mdns_rtree *,
+                                   char *,
+                                   void *),
+                  void *arg );
+
+/* ****************************************************************************
+ *  Register a DNS-SD service via Multicast DNS on the local network.
+ *
+ *  @param name     Instance Name of the service, f.e. "Printer 2nd Floor".
+ *  @param type     ServiceType of the service, f.e. "_http._tcp".
+ *  @param port     Port number on which the service runs.
+ *  @param txt_data TXT data to create TXT record with, need kv_vector-type,
+ *                  Declare such a type with PICO_DNS_SD_KV_VECTOR_DECLARE(*) &
+ *                  add key-value pairs with pico_dns_sd_kv_vector_add().
+ *  @param ttl      TTL
+ *  @param callback Callback-function to call when the service is registered.
+ *  @return
+ * ****************************************************************************/
+int
+pico_dns_sd_register_service( const char *name,
+                              const char *type,
+                              uint16_t port,
+                              kv_vector *txt_data,
+                              uint16_t ttl,
+                              void (*callback)(pico_mdns_rtree *,
+                                               char *,
+                                               void *),
+                              void *arg);
+
+/* ****************************************************************************
+ *  Does nothing for now.
+ *
+ *  @param type     Type to browse for.
+ *  @param callback Callback to call when something particular happens.
+ *  @return When the module successfully started browsing the servicetype.
+ * ****************************************************************************/
+int
+pico_dns_sd_browse_service( const char *type,
+                            void (*callback)(pico_mdns_rtree *,
+                                             char *,
+                                             void *),
+                            void *arg );
+
+/* ****************************************************************************
+ *  Add a key-value pair the a key-value pair vector.
+ *
+ *  @param vector Vector to add the pair to.
+ *  @param key    Key of the pair, cannot be NULL.
+ *  @param value  Value of the pair, can be NULL, empty ("") or filled ("qkejq")
+ *  @return Returns 0 when the pair is added successfully, something else on
+ *			failure.
+ * ****************************************************************************/
+int
+pico_dns_sd_kv_vector_add( kv_vector *vector, char *key, char *value );
+
+
+#endif /* _INCLUDE_PICO_DNS_SD */
\ No newline at end of file
diff --git a/net/picotcp/modules/pico_fragments.c b/net/picotcp/modules/pico_fragments.c
new file mode 100644
index 0000000..e6fe44b
--- /dev/null
+++ b/net/picotcp/modules/pico_fragments.c
@@ -0,0 +1,345 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Authors: Laurens Miers, Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_config.h"
+#ifdef PICO_SUPPORT_IPV6
+#include "pico_ipv6.h"
+#include "pico_icmp6.h"
+#endif
+#ifdef PICO_SUPPORT_IPV4
+#include "pico_ipv4.h"
+#include "pico_icmp4.h"
+#endif
+#include "pico_stack.h"
+#include "pico_eth.h"
+#include "pico_udp.h"
+#include "pico_tcp.h"
+#include "pico_socket.h"
+#include "pico_device.h"
+#include "pico_tree.h"
+#include "pico_constants.h"
+#include "pico_fragments.h"
+#define frag_dbg(...) do {} while(0)
+
+#define IP6_FRAG_OFF(x)         ((x & 0xFFF8u))
+#define IP6_FRAG_MORE(x)        ((x & 0x0001))
+#define IP6_FRAG_ID(x)          ((uint32_t)((x->ext.frag.id[0] << 24) + (x->ext.frag.id[1] << 16) + \
+                                            (x->ext.frag.id[2] << 8) + x->ext.frag.id[3]))
+
+#define IP4_FRAG_OFF(frag)      (((uint32_t)frag & PICO_IPV4_FRAG_MASK) << 3ul)
+#define IP4_FRAG_MORE(frag)     ((frag & PICO_IPV4_MOREFRAG) ? 1 : 0)
+#define IP4_FRAG_ID(hdr)        (hdr->id)
+
+#define FRAG_OFF(net, frag)     ((net == PICO_PROTO_IPV4) ? (IP4_FRAG_OFF(frag)) : (IP6_FRAG_OFF(frag)))
+#define FRAG_MORE(net, frag)    ((net == PICO_PROTO_IPV4) ? (IP4_FRAG_MORE(frag)) : (IP6_FRAG_MORE(frag)))
+
+#define PICO_IPV6_FRAG_TIMEOUT   60000
+#define PICO_IPV4_FRAG_TIMEOUT   15000
+
+static int pico_ipv6_frag_compare(void *ka, void *kb);
+static int pico_ipv4_frag_compare(void *ka, void *kb);
+static void pico_ipv6_fragments_complete(unsigned int len, uint8_t proto);
+static void pico_ipv4_fragments_complete(unsigned int len, uint8_t proto);
+static void pico_fragments_complete(unsigned int bookmark, uint8_t proto, uint8_t net);
+static int pico_fragments_check_complete(uint8_t proto, uint8_t net);
+static void pico_frag_expire(pico_time now, void *arg);
+static void pico_ipv6_frag_timer_on(void);
+static void pico_ipv4_frag_timer_on(void);
+static int pico_ipv6_frag_match(struct pico_frame *a, struct pico_frame *b);
+static int pico_ipv4_frag_match(struct pico_frame *a, struct pico_frame *b);
+
+static uint32_t ipv6_cur_frag_id = 0u;
+static uint32_t ipv4_cur_frag_id = 0u;
+
+static int pico_ipv6_frag_compare(void *ka, void *kb)
+{
+    struct pico_frame *a = ka, *b = kb;
+    if (IP6_FRAG_OFF(a->frag) > IP6_FRAG_OFF(b->frag))
+        return 1;
+
+    if (IP6_FRAG_OFF(a->frag) < IP6_FRAG_OFF(b->frag))
+        return -1;
+
+    return 0;
+}
+PICO_TREE_DECLARE(ipv6_fragments, pico_ipv6_frag_compare);
+
+struct pico_timer *ipv6_fragments_timer = NULL;
+
+static int pico_ipv4_frag_compare(void *ka, void *kb)
+{
+    struct pico_frame *a = ka, *b = kb;
+    if (IP4_FRAG_OFF(a->frag) > IP4_FRAG_OFF(b->frag))
+        return 1;
+
+    if (IP4_FRAG_OFF(a->frag) < IP4_FRAG_OFF(b->frag))
+        return -1;
+
+    return 0;
+}
+PICO_TREE_DECLARE(ipv4_fragments, pico_ipv4_frag_compare);
+
+struct pico_timer *ipv4_fragments_timer = NULL;
+
+static void pico_ipv6_fragments_complete(unsigned int len, uint8_t proto)
+{
+    struct pico_tree_node *index, *tmp;
+    struct pico_frame *f;
+    unsigned int bookmark = 0;
+    struct pico_frame *full = NULL;
+    struct pico_frame *first = pico_tree_first(&ipv6_fragments);
+
+    full = pico_frame_alloc((uint16_t)(PICO_SIZE_IP6HDR + len));
+    if (full) {
+        full->net_hdr = full->buffer;
+        full->net_len = PICO_SIZE_IP6HDR;
+        memcpy(full->net_hdr, first->net_hdr, full->net_len);
+        full->transport_hdr = full->net_hdr + full->net_len;
+        full->transport_len = (uint16_t)len;
+        full->dev = first->dev;
+        pico_tree_foreach_safe(index, &ipv6_fragments, tmp) {
+            f = index->keyValue;
+            memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len);
+            bookmark += f->transport_len;
+            pico_tree_delete(&ipv6_fragments, f);
+            pico_frame_discard(f);
+        }
+        pico_transport_receive(full, proto);
+        if (ipv6_fragments_timer) {
+            pico_timer_cancel(ipv6_fragments_timer);
+            ipv6_fragments_timer = NULL;
+        }
+    }
+}
+
+static void pico_ipv4_fragments_complete(unsigned int len, uint8_t proto)
+{
+    struct pico_tree_node *index, *tmp;
+    struct pico_frame *f;
+    unsigned int bookmark = 0;
+    struct pico_frame *full = NULL;
+    struct pico_frame *first = pico_tree_first(&ipv4_fragments);
+
+    full = pico_frame_alloc((uint16_t)(PICO_SIZE_IP4HDR + len));
+    if (full) {
+        full->net_hdr = full->buffer;
+        full->net_len = PICO_SIZE_IP4HDR;
+        memcpy(full->net_hdr, first->net_hdr, full->net_len);
+        full->transport_hdr = full->net_hdr + full->net_len;
+        full->transport_len = (uint16_t)len;
+        full->dev = first->dev;
+        pico_tree_foreach_safe(index, &ipv4_fragments, tmp) {
+            f = index->keyValue;
+            memcpy(full->transport_hdr + bookmark, f->transport_hdr, f->transport_len);
+            bookmark += f->transport_len;
+            pico_tree_delete(&ipv4_fragments, f);
+            pico_frame_discard(f);
+        }
+        pico_transport_receive(full, proto);
+        if (ipv4_fragments_timer) {
+            pico_timer_cancel(ipv4_fragments_timer);
+            ipv4_fragments_timer = NULL;
+        }
+    }
+}
+
+static void pico_fragments_complete(unsigned int bookmark, uint8_t proto, uint8_t net)
+{
+    if (net == PICO_PROTO_IPV4)
+    {
+        pico_ipv4_fragments_complete(bookmark, proto);
+    }
+    else
+    {
+        pico_ipv6_fragments_complete(bookmark, proto);
+    }
+}
+
+static int pico_fragments_check_complete(uint8_t proto, uint8_t net)
+{
+    struct pico_tree_node *index, *temp;
+    struct pico_frame *cur;
+    unsigned int bookmark = 0;
+    struct pico_tree *tree = NULL;
+
+    if (net == PICO_PROTO_IPV4)
+    {
+        tree = &ipv4_fragments;
+    }
+    else
+    {
+        tree = &ipv6_fragments;
+    }
+
+
+    pico_tree_foreach_safe(index, tree, temp) {
+        cur = index->keyValue;
+        if (FRAG_OFF(net, cur->frag) != bookmark)
+            return 0;
+
+        bookmark += cur->transport_len;
+        if (!FRAG_MORE(net, cur->frag)) {
+            pico_fragments_complete(bookmark, proto, net);
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static void pico_frag_expire(pico_time now, void *arg)
+{
+    struct pico_tree_node *index, *tmp;
+    struct pico_frame *f = NULL;
+    struct pico_tree *tree = (struct pico_tree *) arg;
+    struct pico_frame *first = NULL;
+    uint8_t net = 0;
+    (void)now;
+
+    if (!tree)
+    {
+        frag_dbg("Expired packet but no tree supplied!\n");
+        return;
+    }
+
+    first = pico_tree_first(tree);
+
+    if (!first) {
+        frag_dbg("not first - not sending notify\n");
+        return;
+    }
+
+    if (IS_IPV4(first))
+    {
+        net = PICO_PROTO_IPV4;
+        frag_dbg("Packet expired! ID:%hu\n", ipv4_cur_frag_id);
+    }
+    else
+    {
+        net = PICO_PROTO_IPV6;
+        frag_dbg("Packet expired! ID:%hu\n", ipv6_cur_frag_id);
+    }
+
+    /* Empty the tree */
+    pico_tree_foreach_safe(index, tree, tmp) {
+        f = index->keyValue;
+        pico_tree_delete(tree, f);
+        if (f != first)
+            pico_frame_discard(f); /* Later, after ICMP notification...*/
+
+    }
+
+    if (((FRAG_OFF(net, first->frag) == 0) && (pico_frame_dst_is_unicast(first))))
+    {
+        frag_dbg("sending notify\n");
+        pico_notify_frag_expired(first);
+    }
+
+    if (f)
+        pico_tree_delete(tree, f);
+
+    pico_frame_discard(first);
+}
+
+static void pico_ipv6_frag_timer_on(void)
+{
+    ipv6_fragments_timer = pico_timer_add(PICO_IPV6_FRAG_TIMEOUT, pico_frag_expire, &ipv6_fragments);
+}
+
+static void pico_ipv4_frag_timer_on(void)
+{
+    ipv4_fragments_timer = pico_timer_add( PICO_IPV4_FRAG_TIMEOUT, pico_frag_expire, &ipv4_fragments);
+}
+
+
+static int pico_ipv6_frag_match(struct pico_frame *a, struct pico_frame *b)
+{
+    struct pico_ipv6_hdr *ha, *hb;
+    if (!a || !b)
+        return 0;
+
+    ha = (struct pico_ipv6_hdr *)a->net_hdr;
+    hb = (struct pico_ipv6_hdr *)b->net_hdr;
+    if (!ha || !hb)
+        return 0;
+
+    if (memcmp(ha->src.addr, hb->src.addr, PICO_SIZE_IP6) != 0)
+        return 0;
+
+    if (memcmp(ha->dst.addr, hb->dst.addr, PICO_SIZE_IP6) != 0)
+        return 0;
+
+    return 1;
+}
+
+static int pico_ipv4_frag_match(struct pico_frame *a, struct pico_frame *b)
+{
+    struct pico_ipv4_hdr *ha, *hb;
+    if (!a || !b)
+        return 0;
+
+    ha = (struct pico_ipv4_hdr *)a->net_hdr;
+    hb = (struct pico_ipv4_hdr *)b->net_hdr;
+    if (!ha || !hb)
+        return 0;
+
+    if (memcmp(&(ha->src.addr), &(hb->src.addr), PICO_SIZE_IP4) != 0)
+        return 0;
+
+    if (memcmp(&(ha->dst.addr), &(hb->dst.addr), PICO_SIZE_IP4) != 0)
+        return 0;
+
+    return 1;
+}
+
+
+void pico_ipv6_process_frag(struct pico_ipv6_exthdr *frag, struct pico_frame *f, uint8_t proto)
+{
+    struct pico_frame *first = pico_tree_first(&ipv6_fragments);
+
+    if (!first) {
+        if (ipv6_cur_frag_id && (IP6_FRAG_ID(frag) == ipv6_cur_frag_id)) {
+            /* Discard late arrivals, without firing the timer.
+             */
+            frag_dbg("discarded late arrival, exp:%hu found:%hu\n", ipv6_cur_frag_id, IP6_FRAG_ID(frag));
+            return;
+        }
+
+        pico_ipv6_frag_timer_on();
+        ipv6_cur_frag_id = IP6_FRAG_ID(frag);
+        frag_dbg("Started new reassembly, ID:%hu\n", ipv6_cur_frag_id);
+    }
+
+    if (!first || (pico_ipv6_frag_match(f, first) && (IP6_FRAG_ID(frag) == ipv6_cur_frag_id))) {
+        pico_tree_insert(&ipv6_fragments, pico_frame_copy(f));
+    }
+
+    pico_fragments_check_complete(proto, PICO_PROTO_IPV6);
+}
+
+void pico_ipv4_process_frag(struct pico_ipv4_hdr *hdr, struct pico_frame *f, uint8_t proto)
+{
+    struct pico_frame *first = pico_tree_first(&ipv4_fragments);
+
+    f->frag = short_be(hdr->frag);
+    if (!first) {
+        if (ipv4_cur_frag_id && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id)) {
+            /* Discard late arrivals, without firing the timer,
+             */
+            return;
+        }
+
+        pico_ipv4_frag_timer_on();
+        ipv4_cur_frag_id = IP4_FRAG_ID(hdr);
+    }
+
+    if (!first || (pico_ipv4_frag_match(f, first) && (IP4_FRAG_ID(hdr) == ipv4_cur_frag_id))) {
+        pico_tree_insert(&ipv4_fragments, pico_frame_copy(f));
+    }
+
+    pico_fragments_check_complete(proto, PICO_PROTO_IPV4);
+}
diff --git a/net/picotcp/modules/pico_fragments.h b/net/picotcp/modules/pico_fragments.h
new file mode 100644
index 0000000..e51ec44
--- /dev/null
+++ b/net/picotcp/modules/pico_fragments.h
@@ -0,0 +1,11 @@
+#ifndef PICO_FRAGMENTS_H
+#define PICO_FRAGMENTS_H
+#include "pico_ipv4.h"
+#include "pico_ipv6.h"
+#include "pico_addressing.h"
+#include "pico_frame.h"
+
+void pico_ipv6_process_frag(struct pico_ipv6_exthdr *frag, struct pico_frame *f, uint8_t proto);
+void pico_ipv4_process_frag(struct pico_ipv4_hdr *hdr, struct pico_frame *f, uint8_t proto);
+
+#endif
diff --git a/net/picotcp/modules/pico_icmp4.c b/net/picotcp/modules/pico_icmp4.c
new file mode 100644
index 0000000..da3d89c
--- /dev/null
+++ b/net/picotcp/modules/pico_icmp4.c
@@ -0,0 +1,395 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_icmp4.h"
+#include "pico_config.h"
+#include "pico_ipv4.h"
+#include "pico_eth.h"
+#include "pico_device.h"
+#include "pico_stack.h"
+#include "pico_tree.h"
+
+/* Queues */
+static struct pico_queue icmp_in = {
+    0
+};
+static struct pico_queue icmp_out = {
+    0
+};
+
+
+/* Functions */
+
+static int pico_icmp4_checksum(struct pico_frame *f)
+{
+    struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
+    if (!hdr) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    hdr->crc = 0;
+    hdr->crc = short_be(pico_checksum(hdr, f->transport_len));
+    return 0;
+}
+
+#ifdef PICO_SUPPORT_PING
+static void ping_recv_reply(struct pico_frame *f);
+#endif
+
+static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *f)
+{
+    struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
+    static int firstpkt = 1;
+    static uint16_t last_id = 0;
+    static uint16_t last_seq = 0;
+    IGNORE_PARAMETER(self);
+
+    if (hdr->type == PICO_ICMP_ECHO) {
+        hdr->type = PICO_ICMP_ECHOREPLY;
+        /* outgoing frames require a f->len without the ethernet header len */
+        if (f->dev && f->dev->eth)
+            f->len -= PICO_SIZE_ETHHDR;
+
+        if (!firstpkt && (hdr->hun.ih_idseq.idseq_id ==  last_id) && (last_seq == hdr->hun.ih_idseq.idseq_seq)) {
+            /* The network duplicated the echo. Do not reply. */
+            pico_frame_discard(f);
+            return 0;
+        }
+
+        firstpkt = 0;
+        last_id = hdr->hun.ih_idseq.idseq_id;
+        last_seq = hdr->hun.ih_idseq.idseq_seq;
+        pico_icmp4_checksum(f);
+        pico_ipv4_rebound(f);
+    } else if (hdr->type == PICO_ICMP_UNREACH) {
+        f->net_hdr = f->transport_hdr + PICO_ICMPHDR_UN_SIZE;
+        pico_ipv4_unreachable(f, hdr->code);
+    } else if (hdr->type == PICO_ICMP_ECHOREPLY) {
+#ifdef PICO_SUPPORT_PING
+        ping_recv_reply(f);
+#endif
+        pico_frame_discard(f);
+    } else {
+        pico_frame_discard(f);
+    }
+
+    return 0;
+}
+
+static int pico_icmp4_process_out(struct pico_protocol *self, struct pico_frame *f)
+{
+    IGNORE_PARAMETER(self);
+    IGNORE_PARAMETER(f);
+    dbg("Called %s\n", __FUNCTION__);
+    return 0;
+}
+
+/* Interface: protocol definition */
+struct pico_protocol pico_proto_icmp4 = {
+    .name = "icmp4",
+    .proto_number = PICO_PROTO_ICMP4,
+    .layer = PICO_LAYER_TRANSPORT,
+    .process_in = pico_icmp4_process_in,
+    .process_out = pico_icmp4_process_out,
+    .q_in = &icmp_in,
+    .q_out = &icmp_out,
+};
+
+static int pico_icmp4_notify(struct pico_frame *f, uint8_t type, uint8_t code)
+{
+    struct pico_frame *reply;
+    struct pico_icmp4_hdr *hdr;
+    struct pico_ipv4_hdr *info;
+    uint16_t f_tot_len;
+
+    f_tot_len = short_be(((struct pico_ipv4_hdr *)f->net_hdr)->len);
+
+    if (f_tot_len < (sizeof(struct pico_ipv4_hdr)))
+        return -1;
+
+    /* Truncate tot len to be at most 8 bytes + iphdr */
+    if (f_tot_len > (sizeof(struct pico_ipv4_hdr) + 8u)) {
+        f_tot_len = (sizeof(struct pico_ipv4_hdr) + 8u);
+    }
+
+    if (f == NULL) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    reply = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t) (f_tot_len + PICO_ICMPHDR_UN_SIZE));
+    info = (struct pico_ipv4_hdr*)(f->net_hdr);
+    hdr = (struct pico_icmp4_hdr *) reply->transport_hdr;
+    hdr->type = type;
+    hdr->code = code;
+    hdr->hun.ih_pmtu.ipm_nmtu = short_be(1500);
+    hdr->hun.ih_pmtu.ipm_void = 0;
+    reply->transport_len = (uint16_t)(f_tot_len +  PICO_ICMPHDR_UN_SIZE);
+    reply->payload = reply->transport_hdr + PICO_ICMPHDR_UN_SIZE;
+    memcpy(reply->payload, f->net_hdr, f_tot_len);
+    pico_icmp4_checksum(reply);
+    pico_ipv4_frame_push(reply, &info->src, PICO_PROTO_ICMP4);
+    return 0;
+}
+
+int pico_icmp4_port_unreachable(struct pico_frame *f)
+{
+    /*Parameter check executed in pico_icmp4_notify*/
+    return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PORT);
+}
+
+int pico_icmp4_proto_unreachable(struct pico_frame *f)
+{
+    /*Parameter check executed in pico_icmp4_notify*/
+    return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PROTOCOL);
+}
+
+int pico_icmp4_dest_unreachable(struct pico_frame *f)
+{
+    /*Parameter check executed in pico_icmp4_notify*/
+    return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_HOST);
+}
+
+int pico_icmp4_ttl_expired(struct pico_frame *f)
+{
+    /*Parameter check executed in pico_icmp4_notify*/
+    return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_INTRANS);
+}
+
+MOCKABLE int pico_icmp4_frag_expired(struct pico_frame *f)
+{
+    /*Parameter check executed in pico_icmp4_notify*/
+    return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_REASS);
+}
+
+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*/
+    /*Packet Filtered: type 3, code 13 (Communication Administratively Prohibited)*/
+    return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_FILTER_PROHIB);
+}
+
+int pico_icmp4_param_problem(struct pico_frame *f, uint8_t code)
+{
+    return pico_icmp4_notify(f, PICO_ICMP_PARAMPROB, code);
+}
+
+/***********************/
+/* Ping implementation */
+/***********************/
+/***********************/
+/***********************/
+/***********************/
+
+
+#ifdef PICO_SUPPORT_PING
+
+
+struct pico_icmp4_ping_cookie
+{
+    struct pico_ip4 dst;
+    uint16_t err;
+    uint16_t id;
+    uint16_t seq;
+    uint16_t size;
+    int count;
+    pico_time timestamp;
+    int interval;
+    int timeout;
+    void (*cb)(struct pico_icmp4_stats*);
+};
+
+static int cookie_compare(void *ka, void *kb)
+{
+    struct pico_icmp4_ping_cookie *a = ka, *b = kb;
+    if (a->id < b->id)
+        return -1;
+
+    if (a->id > b->id)
+        return 1;
+
+    return (a->seq - b->seq);
+}
+
+PICO_TREE_DECLARE(Pings, cookie_compare);
+
+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;
+
+    hdr->type = PICO_ICMP_ECHO;
+    hdr->code = 0;
+    hdr->hun.ih_idseq.idseq_id = short_be(cookie->id);
+    hdr->hun.ih_idseq.idseq_seq = short_be(cookie->seq);
+    echo->transport_len = (uint16_t)(PICO_ICMPHDR_UN_SIZE + cookie->size);
+    echo->payload = echo->transport_hdr + PICO_ICMPHDR_UN_SIZE;
+    echo->payload_len = cookie->size;
+    /* XXX: Fill payload */
+    pico_icmp4_checksum(echo);
+    pico_ipv4_frame_push(echo, &cookie->dst, PICO_PROTO_ICMP4);
+    return 0;
+}
+
+
+static void ping_timeout(pico_time now, void *arg)
+{
+    struct pico_icmp4_ping_cookie *cookie = (struct pico_icmp4_ping_cookie *)arg;
+    IGNORE_PARAMETER(now);
+
+    if(pico_tree_findKey(&Pings, cookie)) {
+        if (cookie->err == PICO_PING_ERR_PENDING) {
+            struct pico_icmp4_stats stats;
+            stats.dst = cookie->dst;
+            stats.seq = cookie->seq;
+            stats.time = 0;
+            stats.size = cookie->size;
+            stats.err = PICO_PING_ERR_TIMEOUT;
+            dbg(" ---- Ping timeout!!!\n");
+            cookie->cb(&stats);
+        }
+
+        pico_tree_delete(&Pings, cookie);
+        PICO_FREE(cookie);
+    }
+}
+
+static void next_ping(pico_time now, void *arg);
+static inline void send_ping(struct pico_icmp4_ping_cookie *cookie)
+{
+    pico_icmp4_send_echo(cookie);
+    cookie->timestamp = pico_tick;
+    pico_timer_add((uint32_t)cookie->timeout, ping_timeout, cookie);
+    if (cookie->seq < (uint16_t)cookie->count)
+        pico_timer_add((uint32_t)cookie->interval, next_ping, cookie);
+}
+
+static void next_ping(pico_time now, void *arg)
+{
+    struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg;
+    IGNORE_PARAMETER(now);
+
+    if(pico_tree_findKey(&Pings, cookie)) {
+        if (cookie->err == PICO_PING_ERR_ABORTED)
+            return;
+
+        if (cookie->seq < (uint16_t)cookie->count) {
+            newcookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie));
+            if (!newcookie)
+                return;
+
+            memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie));
+            newcookie->seq++;
+
+            pico_tree_insert(&Pings, newcookie);
+            send_ping(newcookie);
+        }
+    }
+}
+
+
+static void ping_recv_reply(struct pico_frame *f)
+{
+    struct pico_icmp4_ping_cookie test, *cookie;
+    struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr;
+    test.id  = short_be(hdr->hun.ih_idseq.idseq_id );
+    test.seq = short_be(hdr->hun.ih_idseq.idseq_seq);
+
+    cookie = pico_tree_findKey(&Pings, &test);
+    if (cookie) {
+        struct pico_icmp4_stats stats;
+        if (cookie->err == PICO_PING_ERR_ABORTED)
+            return;
+
+        cookie->err = PICO_PING_ERR_REPLIED;
+        stats.dst = ((struct pico_ipv4_hdr *)f->net_hdr)->src;
+        stats.seq = cookie->seq;
+        stats.size = cookie->size;
+        stats.time = pico_tick - cookie->timestamp;
+        stats.err = cookie->err;
+        stats.ttl = ((struct pico_ipv4_hdr *)f->net_hdr)->ttl;
+        if(cookie->cb != NULL)
+            cookie->cb(&stats);
+    } else {
+        dbg("Reply for seq=%d, not found.\n", test.seq);
+    }
+}
+
+int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *))
+{
+    static uint16_t next_id = 0x91c0;
+    struct pico_icmp4_ping_cookie *cookie;
+
+    if((dst == NULL) || (interval == 0) || (timeout == 0) || (count == 0)) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    cookie = PICO_ZALLOC(sizeof(struct pico_icmp4_ping_cookie));
+    if (!cookie) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
+    if (pico_string_to_ipv4(dst, (uint32_t *)&cookie->dst.addr) < 0) {
+        pico_err = PICO_ERR_EINVAL;
+        PICO_FREE(cookie);
+        return -1;
+    }
+
+    cookie->seq = 1;
+    cookie->id = next_id++;
+    cookie->err = PICO_PING_ERR_PENDING;
+    cookie->size = (uint16_t)size;
+    cookie->interval = interval;
+    cookie->timeout = timeout;
+    cookie->cb = cb;
+    cookie->count = count;
+
+    pico_tree_insert(&Pings, cookie);
+    send_ping(cookie);
+
+    return cookie->id;
+
+}
+
+int pico_icmp4_ping_abort(int id)
+{
+    struct pico_tree_node *node;
+    int found = 0;
+    pico_tree_foreach(node, &Pings)
+    {
+        struct pico_icmp4_ping_cookie *ck =
+            (struct pico_icmp4_ping_cookie *) node->keyValue;
+        if (ck->id == (uint16_t)id) {
+            ck->err = PICO_PING_ERR_ABORTED;
+            found++;
+        }
+    }
+    if (found > 0)
+        return 0; /* OK if at least one pending ping has been canceled */
+
+    pico_err = PICO_ERR_ENOENT;
+    return -1;
+}
+
+#endif
diff --git a/net/picotcp/modules/pico_icmp4.h b/net/picotcp/modules/pico_icmp4.h
new file mode 100644
index 0000000..45f0a62
--- /dev/null
+++ b/net/picotcp/modules/pico_icmp4.h
@@ -0,0 +1,162 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+ *********************************************************************/
+#ifndef INCLUDE_PICO_ICMP4
+#define INCLUDE_PICO_ICMP4
+#include "pico_defines.h"
+#include "pico_addressing.h"
+#include "pico_protocol.h"
+
+
+extern struct pico_protocol pico_proto_icmp4;
+
+PACKED_STRUCT_DEF pico_icmp4_hdr {
+    uint8_t type;
+    uint8_t code;
+    uint16_t crc;
+
+    /* hun */
+    PACKED_UNION_DEF hun_u {
+        uint8_t ih_pptr;
+        struct pico_ip4 ih_gwaddr;
+        PEDANTIC_STRUCT_DEF ih_idseq_s {
+            uint16_t idseq_id;
+            uint16_t idseq_seq;
+        } ih_idseq;
+        uint32_t ih_void;
+        PEDANTIC_STRUCT_DEF ih_pmtu_s {
+            uint16_t ipm_void;
+            uint16_t ipm_nmtu;
+        } ih_pmtu;
+        PEDANTIC_STRUCT_DEF ih_rta_s {
+            uint8_t rta_numgw;
+            uint8_t rta_wpa;
+            uint16_t rta_lifetime;
+        } ih_rta;
+    } hun;
+
+    /* dun */
+    PACKED_UNION_DEF dun_u {
+        PEDANTIC_STRUCT_DEF id_ts_s {
+            uint32_t ts_otime;
+            uint32_t ts_rtime;
+            uint32_t ts_ttime;
+        } id_ts;
+        PEDANTIC_STRUCT_DEF id_ip_s {
+            uint32_t ip_options;
+            uint32_t ip_data_hi;
+            uint32_t ip_data_lo;
+        } id_ip;
+        PEDANTIC_STRUCT_DEF id_ra_s {
+            uint32_t ira_addr;
+            uint32_t ira_pref;
+        } id_ra;
+        uint32_t id_mask;
+        uint8_t id_data[1];
+    } dun;
+};
+
+#define PICO_ICMPHDR_DRY_SIZE  4
+#define PICO_ICMPHDR_UN_SIZE  8u
+
+#define PICO_ICMP_ECHOREPLY    0
+#define PICO_ICMP_DEST_UNREACH 3
+#define PICO_ICMP_SOURCE_QUENCH  4
+#define PICO_ICMP_REDIRECT   5
+#define PICO_ICMP_ECHO   8
+#define PICO_ICMP_TIME_EXCEEDED  11
+#define PICO_ICMP_PARAMETERPROB  12
+#define PICO_ICMP_TIMESTAMP    13
+#define PICO_ICMP_TIMESTAMPREPLY 14
+#define PICO_ICMP_INFO_REQUEST 15
+#define PICO_ICMP_INFO_REPLY   16
+#define PICO_ICMP_ADDRESS    17
+#define PICO_ICMP_ADDRESSREPLY 18
+
+
+#define  PICO_ICMP_UNREACH    3
+#define  PICO_ICMP_SOURCEQUENCH  4
+#define  PICO_ICMP_ROUTERADVERT  9
+#define  PICO_ICMP_ROUTERSOLICIT  10
+#define  PICO_ICMP_TIMXCEED    11
+#define  PICO_ICMP_PARAMPROB    12
+#define  PICO_ICMP_TSTAMP    13
+#define  PICO_ICMP_TSTAMPREPLY  14
+#define  PICO_ICMP_IREQ    15
+#define  PICO_ICMP_IREQREPLY    16
+#define  PICO_ICMP_MASKREQ    17
+#define  PICO_ICMP_MASKREPLY    18
+
+#define  PICO_ICMP_MAXTYPE    18
+
+
+#define  PICO_ICMP_UNREACH_NET          0
+#define  PICO_ICMP_UNREACH_HOST          1
+#define  PICO_ICMP_UNREACH_PROTOCOL          2
+#define  PICO_ICMP_UNREACH_PORT          3
+#define  PICO_ICMP_UNREACH_NEEDFRAG          4
+#define  PICO_ICMP_UNREACH_SRCFAIL          5
+#define  PICO_ICMP_UNREACH_NET_UNKNOWN        6
+#define  PICO_ICMP_UNREACH_HOST_UNKNOWN       7
+#define  PICO_ICMP_UNREACH_ISOLATED          8
+#define  PICO_ICMP_UNREACH_NET_PROHIB          9
+#define  PICO_ICMP_UNREACH_HOST_PROHIB        10
+#define  PICO_ICMP_UNREACH_TOSNET          11
+#define  PICO_ICMP_UNREACH_TOSHOST          12
+#define  PICO_ICMP_UNREACH_FILTER_PROHIB      13
+#define  PICO_ICMP_UNREACH_HOST_PRECEDENCE    14
+#define  PICO_ICMP_UNREACH_PRECEDENCE_CUTOFF  15
+
+
+#define  PICO_ICMP_REDIRECT_NET  0
+#define  PICO_ICMP_REDIRECT_HOST  1
+#define  PICO_ICMP_REDIRECT_TOSNET  2
+#define  PICO_ICMP_REDIRECT_TOSHOST  3
+
+
+#define  PICO_ICMP_TIMXCEED_INTRANS  0
+#define  PICO_ICMP_TIMXCEED_REASS  1
+
+
+#define  PICO_ICMP_PARAMPROB_OPTABSENT 1
+
+#define PICO_SIZE_ICMP4HDR ((sizeof(struct pico_icmp4_hdr)))
+
+struct pico_icmp4_stats
+{
+    struct pico_ip4 dst;
+    unsigned long size;
+    unsigned long seq;
+    pico_time time;
+    unsigned long ttl;
+    int err;
+};
+
+int pico_icmp4_port_unreachable(struct pico_frame *f);
+int pico_icmp4_proto_unreachable(struct pico_frame *f);
+int pico_icmp4_dest_unreachable(struct pico_frame *f);
+int pico_icmp4_mtu_exceeded(struct pico_frame *f);
+int pico_icmp4_ttl_expired(struct pico_frame *f);
+int pico_icmp4_frag_expired(struct pico_frame *f);
+int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *));
+int pico_icmp4_ping_abort(int id);
+
+#ifdef PICO_SUPPORT_ICMP4
+int pico_icmp4_packet_filtered(struct pico_frame *f);
+int pico_icmp4_param_problem(struct pico_frame *f, uint8_t code);
+#else
+# define pico_icmp4_packet_filtered(f) (-1)
+# define pico_icmp4_param_problem(f, c) (-1)
+#endif /* PICO_SUPPORT_ICMP4 */
+
+#define PICO_PING_ERR_REPLIED 0
+#define PICO_PING_ERR_TIMEOUT 1
+#define PICO_PING_ERR_UNREACH 2
+#define PICO_PING_ERR_ABORTED 3
+#define PICO_PING_ERR_PENDING 0xFFFF
+
+#endif
diff --git a/net/picotcp/modules/pico_icmp6.h b/net/picotcp/modules/pico_icmp6.h
new file mode 100644
index 0000000..90e8223
--- /dev/null
+++ b/net/picotcp/modules/pico_icmp6.h
@@ -0,0 +1,259 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. 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_PARAM_PROBLEM_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_ABORTED         3
+#define PICO_PING6_ERR_PENDING         0xFFFF
+
+/* ND configuration */
+#define PICO_ND_MAX_FRAMES_QUEUED      4 /* max frames queued while awaiting address resolution */
+
+/* ND RFC constants */
+#define PICO_ND_MAX_SOLICIT            3
+#define PICO_ND_MAX_NEIGHBOR_ADVERT    3
+#define PICO_ND_DELAY_INCOMPLETE       1000 /* msec */
+#define PICO_ND_DELAY_FIRST_PROBE_TIME 5000 /* msec */
+
+/* neighbor discovery options */
+#define PICO_ND_OPT_LLADDR_SRC         1
+#define PICO_ND_OPT_LLADDR_TGT         2
+#define PICO_ND_OPT_PREFIX             3
+#define PICO_ND_OPT_REDIRECT           4
+#define PICO_ND_OPT_MTU                5
+#define PICO_ND_OPT_RDNSS             25 /* RFC 5006 */
+
+/* ND advertisement flags */
+#define PICO_ND_ROUTER             0x80000000
+#define PICO_ND_SOLICITED          0x40000000
+#define PICO_ND_OVERRIDE           0x20000000
+#define IS_ROUTER(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_ROUTER))           /* router flag set? */
+#define IS_SOLICITED(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_SOLICITED))     /* solicited flag set? */
+#define IS_OVERRIDE(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_OVERRIDE))   /* override flag set? */
+
+#define PICO_ND_PREFIX_LIFETIME_INF    0xFFFFFFFFu
+/* #define PICO_ND_DESTINATION_LRU_TIME   600000u / * msecs (10min) * / */
+
+/* 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)))
+#define PICO_ICMP6_OPT_LLADDR_SIZE (8)
+
+extern struct pico_protocol pico_proto_icmp6;
+
+PACKED_STRUCT_DEF pico_icmp6_hdr {
+    uint8_t type;
+    uint8_t code;
+    uint16_t crc;
+
+    PACKED_UNION_DEF icmp6_msg_u {
+        /* error messages */
+        PACKED_UNION_DEF icmp6_err_u {
+            PEDANTIC_STRUCT_DEF dest_unreach_s {
+                uint32_t unused;
+                uint8_t data[0];
+            } dest_unreach;
+            PEDANTIC_STRUCT_DEF pkt_too_big_s {
+                uint32_t mtu;
+                uint8_t data[0];
+            } pkt_too_big;
+            PEDANTIC_STRUCT_DEF time_exceeded_s {
+                uint32_t unused;
+                uint8_t data[0];
+            } time_exceeded;
+            PEDANTIC_STRUCT_DEF param_problem_s {
+                uint32_t ptr;
+                uint8_t data[0];
+            } param_problem;
+        } err;
+
+        /* informational messages */
+        PACKED_UNION_DEF icmp6_info_u {
+            PEDANTIC_STRUCT_DEF echo_request_s {
+                uint16_t id;
+                uint16_t seq;
+                uint8_t data[0];
+            } echo_request;
+            PEDANTIC_STRUCT_DEF echo_reply_s {
+                uint16_t id;
+                uint16_t seq;
+                uint8_t data[0];
+            } echo_reply;
+            PEDANTIC_STRUCT_DEF router_sol_s {
+                uint32_t unused;
+                uint8_t options[0];
+            } router_sol;
+            PEDANTIC_STRUCT_DEF router_adv_s {
+                uint8_t hop;
+                uint8_t mor;
+                uint16_t life_time;
+                uint32_t reachable_time;
+                uint32_t retrans_time;
+                uint8_t options[0];
+            } router_adv;
+            PEDANTIC_STRUCT_DEF neigh_sol_s {
+                uint32_t unused;
+                struct pico_ip6 target;
+                uint8_t options[0];
+            } neigh_sol;
+            PEDANTIC_STRUCT_DEF neigh_adv_s {
+                uint32_t rsor;
+                struct pico_ip6 target;
+                uint8_t options[0];
+            } neigh_adv;
+            PEDANTIC_STRUCT_DEF redirect_s {
+                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;
+    PACKED_UNION_DEF 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_rdnss
+{
+    uint8_t type;
+    uint8_t len;
+    uint16_t res0;
+    uint32_t lifetime;
+    struct pico_ip6 addr[];
+};
+
+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 *), struct pico_device *dev);
+int pico_icmp6_ping_abort(int id);
+
+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);
+int pico_icmp6_parameter_problem(struct pico_frame *f, uint8_t problem, uint32_t ptr);
+int pico_icmp6_pkt_too_big(struct pico_frame *f);
+int pico_icmp6_frag_expired(struct pico_frame *f);
+
+uint16_t pico_icmp6_checksum(struct pico_frame *f);
+int pico_icmp6_router_advertisement(struct pico_device *dev, struct pico_ip6 *dst);
+
+#endif
diff --git a/net/picotcp/modules/pico_igmp.h b/net/picotcp/modules/pico_igmp.h
new file mode 100644
index 0000000..03d6102
--- /dev/null
+++ b/net/picotcp/modules/pico_igmp.h
@@ -0,0 +1,26 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Kristof Roelants, Simon Maes, Brecht Van Cauwenberghe
+ *********************************************************************/
+
+#ifndef INCLUDE_PICO_IGMP
+#define INCLUDE_PICO_IGMP
+
+#define PICO_IGMPV1               1
+#define PICO_IGMPV2               2
+#define PICO_IGMPV3               3
+
+#define PICO_IGMP_STATE_CREATE    1
+#define PICO_IGMP_STATE_UPDATE    2
+#define PICO_IGMP_STATE_DELETE    3
+
+#define PICO_IGMP_QUERY_INTERVAL  125
+
+extern struct pico_protocol pico_proto_igmp;
+
+int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *MCASTFilter, uint8_t state);
+#endif /* _INCLUDE_PICO_IGMP */
diff --git a/net/picotcp/modules/pico_ipfilter.h b/net/picotcp/modules/pico_ipfilter.h
new file mode 100644
index 0000000..fb92e67
--- /dev/null
+++ b/net/picotcp/modules/pico_ipfilter.h
@@ -0,0 +1,29 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Authors: Simon Maes
+ *********************************************************************/
+#ifndef INCLUDE_PICO_IPFILTER
+#define INCLUDE_PICO_IPFILTER
+
+#include "pico_device.h"
+
+enum filter_action {
+    FILTER_PRIORITY = 0,
+    FILTER_REJECT,
+    FILTER_DROP,
+    FILTER_COUNT
+};
+
+uint32_t pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto,
+                              struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask, struct pico_ip4 *in_addr,
+                              struct pico_ip4 *in_addr_netmask, uint16_t out_port, uint16_t in_port,
+                              int8_t priority, uint8_t tos, enum filter_action action);
+
+int pico_ipv4_filter_del(uint32_t filter_id);
+
+int ipfilter(struct pico_frame *f);
+
+#endif /* _INCLUDE_PICO_IPFILTER */
+
diff --git a/net/picotcp/modules/pico_ipv4.c b/net/picotcp/modules/pico_ipv4.c
new file mode 100644
index 0000000..f94d6e6
--- /dev/null
+++ b/net/picotcp/modules/pico_ipv4.c
@@ -0,0 +1,1574 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Authors: Daniele Lacamera, Markian Yskout
+ *********************************************************************/
+
+
+#include "pico_config.h"
+#include "pico_ipfilter.h"
+#include "pico_ipv4.h"
+#include "pico_icmp4.h"
+#include "pico_stack.h"
+#include "pico_eth.h"
+#include "pico_udp.h"
+#include "pico_tcp.h"
+#include "pico_socket.h"
+#include "pico_device.h"
+#include "pico_nat.h"
+#include "pico_igmp.h"
+#include "pico_tree.h"
+#include "pico_aodv.h"
+#include "pico_socket_multicast.h"
+#include "pico_fragments.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
+
+/* Queues */
+static struct pico_queue in = {
+    0
+};
+static struct pico_queue out = {
+    0
+};
+
+/* 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_compare(struct pico_ip4 *a, struct pico_ip4 *b)
+{
+    if (a->addr < b->addr)
+        return -1;
+
+    if (a->addr > b->addr)
+        return 1;
+
+    return 0;
+}
+
+int pico_ipv4_to_string(char *ipbuf, const uint32_t ip)
+{
+    const unsigned char *addr = (const unsigned char *) &ip;
+    int i;
+
+    if (!ipbuf) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    for(i = 0; i < 4; i++)
+    {
+        if (addr[i] > 99) {
+            *ipbuf++ = (char)('0' + (addr[i] / 100));
+            *ipbuf++ = (char)('0' + ((addr[i] % 100) / 10));
+            *ipbuf++ = (char)('0' + ((addr[i] % 100) % 10));
+        } else if (addr[i] > 9) {
+            *ipbuf++ = (char)('0' + (addr[i] / 10));
+            *ipbuf++ = (char)('0' + (addr[i] % 10));
+        } else {
+            *ipbuf++ = (char)('0' + addr[i]);
+        }
+
+        if (i < 3)
+            *ipbuf++ = '.';
+    }
+    *ipbuf = '\0';
+
+    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[PICO_SIZE_IP4] = {
+        0
+    };
+    int cnt = 0;
+    char p;
+
+    if (pico_string_check_null_args(ipstr, ip) < 0)
+        return -1;
+
+    while((p = *ipstr++) != 0 && cnt < PICO_SIZE_IP4)
+    {
+        if (pico_is_digit(p)) {
+            buf[cnt] = (uint8_t)((10 * buf[cnt]) + (p - '0'));
+        } else if (p == '.') {
+            cnt++;
+        } else {
+            return -1;
+        }
+    }
+    /* Handle short notation */
+    if (cnt == 1) {
+        buf[3] = buf[1];
+        buf[1] = 0;
+        buf[2] = 0;
+    } else if (cnt == 2) {
+        buf[3] = buf[2];
+        buf[2] = 0;
+    } else if (cnt != 3) {
+        /* String could not be parsed, return error */
+        return -1;
+    }
+
+    *ip = long_from(buf);
+
+    return 0;
+}
+
+int pico_ipv4_valid_netmask(uint32_t mask)
+{
+    int cnt = 0;
+    int end = 0;
+    int i;
+    uint32_t mask_swap = long_be(mask);
+
+    /*
+     * Swap bytes for convenient parsing
+     * e.g. 0x..f8ff will become 0xfff8..
+     * Then, we count the consecutive bits
+     *
+     * */
+
+    for(i = 0; i < 32; i++) {
+        if ((mask_swap << i) & 0x80000000) {
+            if (end) {
+                pico_err = PICO_ERR_EINVAL;
+                return -1;
+            }
+
+            cnt++;
+        } else {
+            end = 1;
+        }
+    }
+    return cnt;
+}
+
+int pico_ipv4_is_unicast(uint32_t address)
+{
+    const unsigned char *addr = (unsigned char *) &address;
+    if ((addr[0] & 0xe0) == 0xe0)
+        return 0; /* multicast */
+
+    return 1;
+}
+
+int pico_ipv4_is_multicast(uint32_t address)
+{
+    const unsigned char *addr = (unsigned char *) &address;
+    if ((addr[0] != 0xff) && ((addr[0] & 0xe0) == 0xe0))
+        return 1; /* multicast */
+
+    return 0;
+}
+
+int pico_ipv4_is_loopback(uint32_t address)
+{
+    const unsigned char *addr = (unsigned char *) &address;
+    if (addr[0] == 0x7f)
+        return 1;
+
+    return 0;
+}
+
+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");
+        return 0;
+    } else if ( pico_ipv4_is_multicast(address)) {
+        dbg("Source is a multicast address, discard packet\n");
+        return 0;
+    } else if (pico_ipv4_is_invalid_loopback(address, dev)) {
+        dbg("Source is a loopback address, discard packet\n");
+        return 0;
+    } else {
+#ifdef PICO_SUPPORT_AODV
+        union pico_address src;
+        src.ip4.addr = address;
+        pico_aodv_refresh(&src);
+#endif
+        return 1;
+    }
+}
+
+static int pico_ipv4_checksum(struct pico_frame *f)
+{
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    if (!hdr)
+        return -1;
+
+    hdr->crc = 0;
+    hdr->crc = short_be(pico_checksum(hdr, f->net_len));
+    return 0;
+}
+
+
+#ifdef PICO_SUPPORT_CRC
+static inline int pico_ipv4_crc_check(struct pico_frame *f)
+{
+    uint16_t checksum_invalid = 1;
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+
+    checksum_invalid = short_be(pico_checksum(hdr, f->net_len));
+    if (checksum_invalid) {
+        dbg("IP: checksum failed!\n");
+        pico_frame_discard(f);
+        return 0;
+    }
+
+    return 1;
+}
+#else
+static inline int pico_ipv4_crc_check(struct pico_frame *f)
+{
+    IGNORE_PARAMETER(f);
+    return 1;
+}
+#endif /* PICO_SUPPORT_CRC */
+
+static int pico_ipv4_forward(struct pico_frame *f);
+#ifdef PICO_SUPPORT_MCAST
+static int pico_ipv4_mcast_filter(struct pico_frame *f);
+#endif
+
+static int ipv4_link_compare(void *ka, void *kb)
+{
+    struct pico_ipv4_link *a = ka, *b = kb;
+    int cmp = pico_ipv4_compare(&a->address, &b->address);
+    if (cmp)
+        return cmp;
+
+    /* zero can be assigned multiple times (e.g. for DHCP) */
+    if (a->dev != NULL && b->dev != NULL && a->address.addr == PICO_IP4_ANY && b->address.addr == PICO_IP4_ANY) {
+        if (a->dev < b->dev)
+            return -1;
+
+        if (a->dev > b->dev)
+            return 1;
+    }
+
+    return 0;
+}
+
+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;
+    }
+
+#endif
+
+#ifdef PICO_SUPPORT_ICMP4
+    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;
+    uint16_t max_allowed = (uint16_t) ((int)f->buffer_len - (f->net_hdr - f->buffer) - (int)PICO_SIZE_IP4HDR);
+    uint16_t flag = short_be(hdr->frag);
+
+    (void)self;
+    /* NAT needs transport header information */
+    if (((hdr->vhl) & 0x0F) > 5) {
+        option_len =  (uint8_t)(4 * (((hdr->vhl) & 0x0F) - 5));
+    }
+
+    f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR + option_len;
+    f->transport_len = (uint16_t)(short_be(hdr->len) - PICO_SIZE_IP4HDR - option_len);
+    f->net_len = (uint16_t)(PICO_SIZE_IP4HDR + option_len);
+
+    if (f->transport_len > max_allowed) {
+        pico_frame_discard(f);
+        return 0; /* Packet is discarded due to unfeasible length */
+    }
+
+#ifdef PICO_SUPPORT_IPFILTER
+    if (ipfilter(f)) {
+        /*pico_frame is discarded as result of the filtering*/
+        return 0;
+    }
+
+#endif
+
+
+    /* ret == 1 indicates to continue the function */
+    ret = pico_ipv4_crc_check(f);
+    if (ret < 1)
+        return ret;
+
+    /* Validate source IP address. Discard quietly if invalid */
+    if (!pico_ipv4_is_valid_src(hdr->src.addr, f->dev)) {
+        pico_frame_discard(f);
+        return 0;
+    }
+
+    if (hdr->frag & short_be(PICO_IPV4_EVIL)) {
+        (void)pico_icmp4_param_problem(f, 0);
+        pico_frame_discard(f); /* RFC 3514 */
+        return 0;
+    }
+
+    if ((hdr->vhl & 0x0f) < 5) {
+        /* RFC 791: IHL minimum value is 5 */
+        (void)pico_icmp4_param_problem(f, 0);
+        pico_frame_discard(f);
+        return 0;
+    }
+
+    if ((flag & PICO_IPV4_MOREFRAG) || (flag & PICO_IPV4_FRAG_MASK))
+    {
+#ifdef PICO_SUPPORT_IPFRAG
+        pico_ipv4_process_frag(hdr, f, hdr ? hdr->proto : 0 );
+        /* Frame can be discarded, frag will handle its own copy */
+#endif
+        /* We do not support fragmentation, discard frame quietly */
+        pico_frame_discard(f);
+        return 0;
+    }
+
+    if (pico_ipv4_process_bcast_in(f) > 0)
+        return 0;
+
+    if (pico_ipv4_process_mcast_in(f) > 0)
+        return 0;
+
+    if (pico_ipv4_process_local_unicast_in(f) > 0)
+        return 0;
+
+    pico_ipv4_process_finally_try_forward(f);
+
+    return 0;
+}
+
+PICO_TREE_DECLARE(Routes, ipv4_route_compare);
+
+
+static int pico_ipv4_process_out(struct pico_protocol *self, struct pico_frame *f)
+{
+    IGNORE_PARAMETER(self);
+    f->start = (uint8_t*) f->net_hdr;
+#ifdef PICO_SUPPORT_IPFILTER
+    if (ipfilter(f)) {
+        /*pico_frame is discarded as result of the filtering*/
+        return 0;
+    }
+
+#endif
+    return pico_sendto_dev(f);
+}
+
+
+static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, uint16_t size)
+{
+    struct pico_frame *f =  pico_frame_alloc(size + PICO_SIZE_IP4HDR + PICO_SIZE_ETHHDR);
+    IGNORE_PARAMETER(self);
+
+    if (!f)
+        return NULL;
+
+    f->datalink_hdr = f->buffer;
+    f->net_hdr = f->buffer + PICO_SIZE_ETHHDR;
+    f->net_len = PICO_SIZE_IP4HDR;
+    f->transport_hdr = f->net_hdr + PICO_SIZE_IP4HDR;
+    f->transport_len = size;
+    f->len =  size + PICO_SIZE_IP4HDR;
+    return f;
+}
+
+static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f);
+
+/* Interface: protocol definition */
+struct pico_protocol pico_proto_ipv4 = {
+    .name = "ipv4",
+    .proto_number = PICO_PROTO_IPV4,
+    .layer = PICO_LAYER_NETWORK,
+    .alloc = pico_ipv4_alloc,
+    .process_in = pico_ipv4_process_in,
+    .process_out = pico_ipv4_process_out,
+    .push = pico_ipv4_frame_sock_push,
+    .q_in = &in,
+    .q_out = &out,
+};
+
+
+static int ipv4_route_compare(void *ka, void *kb)
+{
+    struct pico_ipv4_route *a = ka, *b = kb;
+    uint32_t a_nm, b_nm;
+    int cmp;
+
+    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 (a_nm < b_nm)
+        return -1;
+
+    if (b_nm < a_nm)
+        return 1;
+
+    cmp = pico_ipv4_compare(&a->dest, &b->dest);
+    if (cmp)
+        return cmp;
+
+    if (a->metric < b->metric)
+        return -1;
+
+    if (a->metric > b->metric)
+        return 1;
+
+    return 0;
+}
+
+
+static struct pico_ipv4_route default_bcast_route = {
+    .dest = {PICO_IP4_BCAST},
+    .netmask = {PICO_IP4_BCAST},
+    .gateway  = { 0 },
+    .link = NULL,
+    .metric = 1000
+};
+
+static struct pico_ipv4_route *route_find_default_bcast(void)
+{
+    return &default_bcast_route;
+}
+
+
+static struct pico_ipv4_route *route_find(const struct pico_ip4 *addr)
+{
+    struct pico_ipv4_route *r;
+    struct pico_tree_node *index;
+
+    if (addr->addr != PICO_IP4_BCAST) {
+        pico_tree_foreach_reverse(index, &Routes) {
+            r = index->keyValue;
+            if ((addr->addr & (r->netmask.addr)) == (r->dest.addr)) {
+                return r;
+            }
+        }
+        return NULL;
+    }
+
+    return route_find_default_bcast();
+}
+
+struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr)
+{
+    struct pico_ip4 nullip;
+    struct pico_ipv4_route *route;
+    nullip.addr = 0U;
+
+    if (!addr) {
+        pico_err = PICO_ERR_EINVAL;
+        return nullip;
+    }
+
+    route = route_find(addr);
+    if (!route) {
+        pico_err = PICO_ERR_EHOSTUNREACH;
+        return nullip;
+    }
+    else
+        return route->gateway;
+}
+
+struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst)
+{
+    struct pico_ip4 *myself = NULL;
+    struct pico_ipv4_route *rt;
+#ifdef PICO_SUPPORT_AODV
+    union pico_address node_address;
+    node_address.ip4.addr = dst->addr;
+    if (dst->addr && pico_ipv4_is_unicast(dst->addr))
+        pico_aodv_lookup(&node_address);
+
+#endif
+
+    if (!dst) {
+        pico_err = PICO_ERR_EINVAL;
+        return NULL;
+    }
+
+    rt = route_find(dst);
+    if (rt && rt->link) {
+        myself = &rt->link->address;
+    } else {
+        pico_err = PICO_ERR_EHOSTUNREACH;
+    }
+
+    return myself;
+}
+
+struct pico_device *pico_ipv4_source_dev_find(const struct pico_ip4 *dst)
+{
+    struct pico_device *dev = NULL;
+    struct pico_ipv4_route *rt;
+
+    if (!dst) {
+        pico_err = PICO_ERR_EINVAL;
+        return NULL;
+    }
+
+    rt = route_find(dst);
+    if (rt && rt->link) {
+        dev = rt->link->dev;
+    } else {
+        pico_err = PICO_ERR_EHOSTUNREACH;
+    }
+
+    return dev;
+}
+
+
+#ifdef PICO_SUPPORT_MCAST
+/*                        link
+ *                         |
+ *                    MCASTGroups
+ *                    |    |     |
+ *         ------------    |     ------------
+ *         |               |                |
+ *   MCASTSources    MCASTSources     MCASTSources
+ *   |  |  |  |      |  |  |  |       |  |  |  |
+ *   S  S  S  S      S  S  S  S       S  S  S  S
+ *
+ *   MCASTGroups: RBTree(mcast_group)
+ *   MCASTSources: RBTree(source)
+ */
+static int ipv4_mcast_groups_cmp(void *ka, void *kb)
+{
+    struct pico_mcast_group *a = ka, *b = kb;
+    return pico_ipv4_compare(&a->mcast_addr, &b->mcast_addr);
+}
+
+static int ipv4_mcast_sources_cmp(void *ka, void *kb)
+{
+    struct pico_ip4 *a = ka, *b = kb;
+    return pico_ipv4_compare(a, b);
+}
+
+static void pico_ipv4_mcast_print_groups(struct pico_ipv4_link *mcast_link)
+{
+    uint16_t i = 0;
+    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);
+    ip_mcast_dbg("+---------------------------------------------------------------------------------+\n");
+    ip_mcast_dbg("+  nr  |    interface     | host group | reference count | filter mode |  source  +\n");
+    ip_mcast_dbg("+---------------------------------------------------------------------------------+\n");
+
+    pico_tree_foreach(index, mcast_link->MCASTGroups) {
+        g = index->keyValue;
+        ip_mcast_dbg("+ %04d | %16s |  %08X  |      %05u      |      %u      | %8s +\n", i, mcast_link->dev->name, g->mcast_addr.addr, g->reference_count, g->filter_mode, "");
+        pico_tree_foreach(index2, &g->MCASTSources) {
+            source = index2->keyValue;
+            ip_mcast_dbg("+ %4s | %16s |  %8s  |      %5s      |      %s      | %08X +\n", "", "", "", "", "", source->addr);
+        }
+        i++;
+    }
+    ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+}
+
+static int mcast_group_update(struct pico_mcast_group *g, struct pico_tree *MCASTFilter, uint8_t filter_mode)
+{
+    struct pico_tree_node *index = NULL, *_tmp = NULL;
+    struct pico_ip4 *source = NULL;
+    /* cleanup filter */
+    pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) {
+        source = index->keyValue;
+        pico_tree_delete(&g->MCASTSources, source);
+        PICO_FREE(source);
+    }
+    /* insert new filter */
+    if (MCASTFilter) {
+        pico_tree_foreach(index, MCASTFilter) {
+            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);
+            }
+        }
+    }
+
+    g->filter_mode = filter_mode;
+    return 0;
+}
+
+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)
+{
+    struct pico_mcast_group *g = NULL, test = {
+        0
+    };
+    struct pico_ipv4_link *link = NULL;
+
+    if (mcast_link)
+        link = pico_ipv4_link_get(mcast_link);
+
+    if (!link)
+        link = mcast_default_link;
+
+    test.mcast_addr = *mcast_group;
+    g = pico_tree_findKey(link->MCASTGroups, &test);
+    if (g) {
+        if (reference_count)
+            g->reference_count++;
+
+        pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE);
+    } else {
+        g = PICO_ZALLOC(sizeof(struct pico_mcast_group));
+        if (!g) {
+            pico_err = PICO_ERR_ENOMEM;
+            return -1;
+        }
+
+        /* "non-existent" state of filter mode INCLUDE and empty source list */
+        g->filter_mode = PICO_IP_MULTICAST_INCLUDE;
+        g->reference_count = 1;
+        g->mcast_addr = *mcast_group;
+        g->MCASTSources.root = &LEAF;
+        g->MCASTSources.compare = ipv4_mcast_sources_cmp;
+        pico_tree_insert(link->MCASTGroups, g);
+        pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_CREATE);
+    }
+
+    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;
+}
+
+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_mcast_group *g = NULL, test = {
+        0
+    };
+    struct pico_ipv4_link *link = NULL;
+    struct pico_tree_node *index = NULL, *_tmp = NULL;
+    struct pico_ip4 *source = NULL;
+
+    if (mcast_link)
+        link = pico_ipv4_link_get(mcast_link);
+
+    if (!link)
+        link = mcast_default_link;
+
+    test.mcast_addr = *mcast_group;
+    g = pico_tree_findKey(link->MCASTGroups, &test);
+    if (!g) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    } else {
+        if (reference_count && (--(g->reference_count) < 1)) {
+            pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_DELETE);
+            /* cleanup filter */
+            pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) {
+                source = index->keyValue;
+                pico_tree_delete(&g->MCASTSources, source);
+                PICO_FREE(source);
+            }
+            pico_tree_delete(link->MCASTGroups, 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)
+                return -1;
+        }
+    }
+
+    pico_ipv4_mcast_print_groups(link);
+    return 0;
+}
+
+struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void)
+{
+    return mcast_default_link;
+}
+
+static int pico_ipv4_mcast_filter(struct pico_frame *f)
+{
+    struct pico_ipv4_link *link = NULL;
+    struct pico_tree_node *index = NULL, *index2 = NULL;
+    struct pico_mcast_group *g = NULL, test = {
+        0
+    };
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+
+    test.mcast_addr = hdr->dst;
+
+    pico_tree_foreach(index, &Tree_dev_link) {
+        link = index->keyValue;
+        g = pico_tree_findKey(link->MCASTGroups, &test);
+        if (g) {
+            if (f->dev == link->dev) {
+                ip_mcast_dbg("MCAST: IP %08X is group member of current link %s\n", hdr->dst.addr, f->dev->name);
+                /* perform source filtering */
+                switch (g->filter_mode) {
+                case PICO_IP_MULTICAST_INCLUDE:
+                    pico_tree_foreach(index2, &g->MCASTSources) {
+                        if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) {
+                            ip_mcast_dbg("MCAST: IP %08X in included interface source list\n", hdr->src.addr);
+                            return 0;
+                        }
+                    }
+                    ip_mcast_dbg("MCAST: IP %08X NOT in included interface source list\n", hdr->src.addr);
+                    return -1;
+
+                case PICO_IP_MULTICAST_EXCLUDE:
+                    pico_tree_foreach(index2, &g->MCASTSources) {
+                        if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) {
+                            ip_mcast_dbg("MCAST: IP %08X in excluded interface source list\n", hdr->src.addr);
+                            return -1;
+                        }
+                    }
+                    ip_mcast_dbg("MCAST: IP %08X NOT in excluded interface source list\n", hdr->src.addr);
+                    return 0;
+
+                default:
+                    return -1;
+                }
+            } else {
+                ip_mcast_dbg("MCAST: IP %08X is group member of different link %s\n", hdr->dst.addr, link->dev->name);
+            }
+        } else {
+            ip_mcast_dbg("MCAST: IP %08X is not a group member of link %s\n", hdr->dst.addr, f->dev->name);
+        }
+    }
+    return -1;
+}
+
+#else
+
+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)
+{
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+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)
+{
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void)
+{
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return NULL;
+}
+#endif /* PICO_SUPPORT_MCAST */
+
+/* #define DEBUG_ROUTE */
+#ifdef DEBUG_ROUTE
+void dbg_route(void)
+{
+    struct pico_ipv4_route *r;
+    struct pico_tree_node *index;
+    int count_hosts = 0;
+    dbg("==== ROUTING TABLE =====\n");
+    pico_tree_foreach(index, &Routes) {
+        r = index->keyValue;
+        dbg("Route to %08x/%08x, gw %08x, dev: %s, metric: %d\n", r->dest.addr, r->netmask.addr, r->gateway.addr, r->link->dev->name, r->metric);
+        if (r->netmask.addr == 0xFFFFFFFF)
+            count_hosts++;
+    }
+    dbg("================ total HOST nodes: %d ======\n\n\n", count_hosts);
+}
+#else
+#define dbg_route() do { } while(0)
+#endif
+
+int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto)
+{
+
+    struct pico_ipv4_route *route;
+    struct pico_ipv4_link *link;
+    struct pico_ipv4_hdr *hdr;
+    uint8_t ttl = PICO_IPV4_DEFAULT_TTL;
+    uint8_t vhl = 0x45; /* version 4, header length 20 */
+    static uint16_t ipv4_progressive_id = 0x91c0;
+#ifdef PICO_SUPPORT_MCAST
+    struct pico_tree_node *index;
+#endif
+
+    if (!f || !dst) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+
+    hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    if (!hdr) {
+        dbg("IP header error\n");
+        pico_err = PICO_ERR_EINVAL;
+        goto drop;
+    }
+
+    if (dst->addr == 0) {
+        dbg("IP destination addr error\n");
+        pico_err = PICO_ERR_EINVAL;
+        goto drop;
+    }
+
+    route = route_find(dst);
+    if (!route) {
+        /* dbg("Route to %08x not found.\n", long_be(dst->addr)); */
+
+
+        pico_err = PICO_ERR_EHOSTUNREACH;
+        goto drop;
+    } else {
+        link = route->link;
+#ifdef PICO_SUPPORT_MCAST
+        if (pico_ipv4_is_multicast(dst->addr)) { /* if multicast */
+            switch (proto) {
+            case PICO_PROTO_UDP:
+                if (pico_udp_get_mc_ttl(f->sock, &ttl) < 0)
+                    ttl = PICO_IP_DEFAULT_MULTICAST_TTL;
+
+                break;
+            case PICO_PROTO_IGMP:
+                vhl = 0x46; /* header length 24 */
+                ttl = 1;
+                /* router alert (RFC 2113) */
+                hdr->options[0] = 0x94;
+                hdr->options[1] = 0x04;
+                hdr->options[2] = 0x00;
+                hdr->options[3] = 0x00;
+                if (f->dev && link->dev != f->dev) { /* default link is not requested link */
+                    pico_tree_foreach(index, &Tree_dev_link) {
+                        link = index->keyValue;
+                        if (link->dev == f->dev)
+                            break;
+                    }
+                }
+
+                break;
+            default:
+                ttl = PICO_IPV4_DEFAULT_TTL;
+            }
+        }
+
+#endif
+    }
+
+    hdr->vhl = vhl;
+    hdr->len = short_be((uint16_t)(f->transport_len + f->net_len));
+    if ((f->transport_hdr != f->payload)  &&
+#ifdef PICO_SUPPORT_IPFRAG
+        (0 == (f->frag & PICO_IPV4_MOREFRAG)) &&
+        (0 == (f->frag & PICO_IPV4_FRAG_MASK)) &&
+#endif
+        1 )
+        ipv4_progressive_id++;
+
+    if (f->send_ttl > 0) {
+        ttl = f->send_ttl;
+    }
+
+    hdr->id = short_be(ipv4_progressive_id);
+    hdr->dst.addr = dst->addr;
+    hdr->src.addr = link->address.addr;
+    hdr->ttl = ttl;
+    hdr->tos = f->send_tos;
+    hdr->proto = proto;
+    hdr->frag = short_be(PICO_IPV4_DONTFRAG);
+
+#ifdef PICO_SUPPORT_IPFRAG
+#  ifdef PICO_SUPPORT_UDP
+    if (proto == PICO_PROTO_UDP) {
+        /* first fragment, can not use transport_len to calculate IP length */
+        if (f->transport_hdr != f->payload)
+            hdr->len = short_be((uint16_t)(f->payload_len + sizeof(struct pico_udp_hdr) + f->net_len));
+
+        /* set fragmentation flags and offset calculated in socket layer */
+        hdr->frag = short_be(f->frag);
+    }
+
+    if (proto == PICO_PROTO_ICMP4)
+    {
+        hdr->frag = short_be(f->frag);
+    }
+
+#   endif
+#endif /* PICO_SUPPORT_IPFRAG */
+    pico_ipv4_checksum(f);
+
+    if (f->sock && f->sock->dev) {
+        /* if the socket has its device set, use that (currently used for DHCP) */
+        f->dev = f->sock->dev;
+    } else {
+        f->dev = link->dev;
+        if (f->sock)
+            f->sock->dev = f->dev;
+    }
+
+#ifdef PICO_SUPPORT_MCAST
+    if (pico_ipv4_is_multicast(hdr->dst.addr)) {
+        struct pico_frame *cpy;
+        /* Sending UDP multicast datagram, am I member? If so, loopback copy */
+        if ((proto != PICO_PROTO_IGMP) && (pico_ipv4_mcast_filter(f) == 0)) {
+            ip_mcast_dbg("MCAST: sender is member of group, loopback copy\n");
+            cpy = pico_frame_copy(f);
+            pico_enqueue(&in, cpy);
+        }
+    }
+
+#endif
+
+/* #ifdef PICO_SUPPORT_AODV */
+#if 0
+    {
+        union pico_address node_address;
+        node_address.ip4.addr = hdr->dst.addr;
+        if(hdr->dst.addr && pico_ipv4_is_unicast(hdr->dst.addr))
+            pico_aodv_lookup(&node_address);
+    }
+#endif
+
+    if (pico_ipv4_link_get(&hdr->dst)) {
+        /* it's our own IP */
+        return pico_enqueue(&in, f);
+    } else{
+        /* TODO: Check if there are members subscribed here */
+        return pico_enqueue(&out, f);
+    }
+
+drop:
+    pico_frame_discard(f);
+    return -1;
+}
+
+
+static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f)
+{
+    struct pico_ip4 *dst;
+    struct pico_remote_endpoint *remote_endpoint = (struct pico_remote_endpoint *) f->info;
+    IGNORE_PARAMETER(self);
+
+    if (!f->sock) {
+        pico_frame_discard(f);
+        return -1;
+    }
+
+    if (remote_endpoint) {
+        dst = &remote_endpoint->remote_addr.ip4;
+    } else {
+        dst = &f->sock->remote_addr.ip4;
+    }
+
+    return pico_ipv4_frame_push(f, dst, (uint8_t)f->sock->proto->proto_number);
+}
+
+
+int MOCKABLE pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link)
+{
+    struct pico_ipv4_route test, *new;
+    test.dest.addr = address.addr;
+    test.netmask.addr = netmask.addr;
+    test.metric = (uint32_t)metric;
+
+    if (pico_tree_findKey(&Routes, &test)) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    new = PICO_ZALLOC(sizeof(struct pico_ipv4_route));
+    if (!new) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
+    new->dest.addr = address.addr;
+    new->netmask.addr = netmask.addr;
+    new->gateway.addr = gateway.addr;
+    new->metric = (uint32_t)metric;
+    if (gateway.addr == 0) {
+        /* No gateway provided, use the link */
+        new->link = link;
+    } else {
+        struct pico_ipv4_route *r = route_find(&gateway);
+        if (!r ) { /* Specified Gateway is unreachable */
+            pico_err = PICO_ERR_EHOSTUNREACH;
+            PICO_FREE(new);
+            return -1;
+        }
+
+        if (r->gateway.addr) { /* Specified Gateway is not a neighbor */
+            pico_err = PICO_ERR_ENETUNREACH;
+            PICO_FREE(new);
+            return -1;
+        }
+
+        new->link = r->link;
+    }
+
+    if (!new->link) {
+        pico_err = PICO_ERR_EINVAL;
+        PICO_FREE(new);
+        return -1;
+    }
+
+    pico_tree_insert(&Routes, new);
+    dbg_route();
+    return 0;
+}
+
+int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, int metric)
+{
+    struct pico_ipv4_route test, *found;
+
+    test.dest.addr = address.addr;
+    test.netmask.addr = netmask.addr;
+    test.metric = (uint32_t)metric;
+
+    found = pico_tree_findKey(&Routes, &test);
+    if (found) {
+
+        pico_tree_delete(&Routes, found);
+        PICO_FREE(found);
+
+        dbg_route();
+        return 0;
+    }
+
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+}
+
+
+int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask)
+{
+    struct pico_ipv4_link test, *new;
+    struct pico_ip4 network, gateway;
+    char ipstr[30];
+
+    if (!dev) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    test.address.addr = address.addr;
+    test.netmask.addr = netmask.addr;
+    test.dev = dev;
+    /** XXX: Valid netmask / unicast address test **/
+
+    if (pico_tree_findKey(&Tree_dev_link, &test)) {
+        pico_err = PICO_ERR_EADDRINUSE;
+        return -1;
+    }
+
+    /** 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));
+    if (!new) {
+        dbg("IPv4: Out of memory!\n");
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
+    new->address.addr = address.addr;
+    new->netmask.addr = netmask.addr;
+    new->dev = dev;
+#ifdef PICO_SUPPORT_MCAST
+    new->MCASTGroups = PICO_ZALLOC(sizeof(struct pico_tree));
+    if (!new->MCASTGroups) {
+        PICO_FREE(new);
+        dbg("IPv4: Out of memory!\n");
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
+    new->MCASTGroups->root = &LEAF;
+    new->MCASTGroups->compare = ipv4_mcast_groups_cmp;
+    new->mcast_compatibility = PICO_IGMPV3; /* default RFC 3376 $7.2.1 */
+    new->mcast_last_query_interval = PICO_IGMP_QUERY_INTERVAL;
+#endif
+
+    pico_tree_insert(&Tree_dev_link, new);
+#ifdef PICO_SUPPORT_MCAST
+    do {
+        struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm, mcast_gw;
+        if (!mcast_default_link) {
+            mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */
+            mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */
+            mcast_gw.addr = long_be(0x00000000);
+            mcast_default_link = new;
+            pico_ipv4_route_add(mcast_addr, mcast_nm, mcast_gw, 1, new);
+        }
+
+        mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS;
+        pico_ipv4_mcast_join(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL);
+    } while(0);
+#endif
+
+    network.addr = address.addr & netmask.addr;
+    gateway.addr = 0U;
+    pico_ipv4_route_add(network, netmask, gateway, 1, new);
+    pico_ipv4_to_string(ipstr, new->address.addr);
+    dbg("Assigned ipv4 %s to device %s\n", ipstr, new->dev->name);
+    if (default_bcast_route.link == NULL)
+        default_bcast_route.link = new;
+
+    return 0;
+}
+
+static int pico_ipv4_cleanup_routes(struct pico_ipv4_link *link)
+{
+    struct pico_tree_node *index = NULL, *tmp = NULL;
+    struct pico_ipv4_route *route = NULL;
+
+    pico_tree_foreach_safe(index, &Routes, tmp) {
+        route = index->keyValue;
+        if (link == route->link)
+            pico_ipv4_route_del(route->dest, route->netmask, (int)route->metric);
+    }
+    return 0;
+}
+
+void MOCKABLE pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link)
+{
+    if (link)
+        default_bcast_route.link = link;
+}
+
+int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address)
+{
+    struct pico_ipv4_link test, *found;
+
+    if (!dev) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    test.address.addr = address.addr;
+    test.dev = dev;
+    found = pico_tree_findKey(&Tree_dev_link, &test);
+    if (!found) {
+        pico_err = PICO_ERR_ENXIO;
+        return -1;
+    }
+
+#ifdef PICO_SUPPORT_MCAST
+    do {
+        struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm;
+        struct pico_mcast_group *g = NULL;
+        struct pico_tree_node *index, *_tmp;
+        if (found == mcast_default_link) {
+            mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */
+            mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */
+            mcast_default_link = NULL;
+            pico_ipv4_route_del(mcast_addr, mcast_nm, 1);
+        }
+
+        mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS;
+        pico_ipv4_mcast_leave(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL);
+        pico_tree_foreach_safe(index, found->MCASTGroups, _tmp) {
+            g = index->keyValue;
+            pico_tree_delete(found->MCASTGroups, g);
+            PICO_FREE(g);
+        }
+    } while(0);
+#endif
+
+    pico_ipv4_cleanup_routes(found);
+    pico_tree_delete(&Tree_dev_link, found);
+    if (default_bcast_route.link == found)
+        default_bcast_route.link = NULL;
+
+    PICO_FREE(found);
+
+    return 0;
+}
+
+
+struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address)
+{
+    struct pico_ipv4_link test = {
+        0
+    }, *found = NULL;
+    test.address.addr = address->addr;
+
+    found = pico_tree_findKey(&Tree_dev_link, &test);
+    if (!found)
+        return NULL;
+    else
+        return found;
+}
+
+struct pico_ipv4_link *MOCKABLE pico_ipv4_link_by_dev(struct pico_device *dev)
+{
+    struct pico_tree_node *index = NULL;
+    struct pico_ipv4_link *link = NULL;
+
+    pico_tree_foreach(index, &Tree_dev_link) {
+        link = index->keyValue;
+        if (link->dev == dev)
+            return link;
+    }
+    return NULL;
+}
+
+struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struct pico_ipv4_link *last)
+{
+    struct pico_tree_node *index = NULL;
+    struct pico_ipv4_link *link = NULL;
+    int valid = 0;
+
+    if (last == NULL)
+        valid = 1;
+
+    pico_tree_foreach(index, &Tree_dev_link) {
+        link = index->keyValue;
+        if (link->dev == dev) {
+            if (last == link)
+                valid = 1;
+            else if (valid > 0)
+                return link;
+        }
+    }
+    return NULL;
+}
+
+struct pico_device *MOCKABLE pico_ipv4_link_find(struct pico_ip4 *address)
+{
+    struct pico_ipv4_link test, *found;
+    if (!address) {
+        pico_err = PICO_ERR_EINVAL;
+        return NULL;
+    }
+
+    test.dev = NULL;
+    test.address.addr = address->addr;
+    found = pico_tree_findKey(&Tree_dev_link, &test);
+    if (!found) {
+        pico_err = PICO_ERR_ENXIO;
+        return NULL;
+    }
+
+    return found->dev;
+}
+
+
+static int pico_ipv4_rebound_large(struct pico_frame *f)
+{
+#ifdef PICO_SUPPORT_IPFRAG
+    uint16_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;
+
+    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 |= PICO_IPV4_MOREFRAG;
+        }
+        else
+        {
+            fr->frag &= PICO_IPV4_FRAG_MASK;
+        }
+
+        fr->frag = (((total_payload_written) >> 3u) & 0xffffu) | fr->frag;
+
+        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 = (uint16_t)((uint16_t)fr->transport_len + total_payload_written);
+        } else {
+            pico_frame_discard(fr);
+            break;
+        }
+    } /* while() */
+    return (int)total_payload_written;
+#else
+    (void)f;
+    return -1;
+#endif
+}
+
+int pico_ipv4_rebound(struct pico_frame *f)
+{
+    struct pico_ip4 dst;
+    struct pico_ipv4_hdr *hdr;
+    if (!f) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    if (!hdr) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    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);
+}
+
+static int pico_ipv4_pre_forward_checks(struct pico_frame *f)
+{
+    static uint16_t last_id = 0;
+    static uint16_t last_proto = 0;
+    static struct pico_ip4 last_src = {
+        0
+    };
+    static struct pico_ip4 last_dst = {
+        0
+    };
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
+
+    /* Decrease TTL, check if expired */
+    hdr->ttl = (uint8_t)(hdr->ttl - 1);
+    if (hdr->ttl < 1) {
+        pico_notify_ttl_expired(f);
+        dbg(" ------------------- TTL EXPIRED\n");
+        return -1;
+    }
+
+    /* HACK: increase crc to compensate decreased TTL */
+    hdr->crc++;
+
+    /* If source is local, discard anyway (packets bouncing back and forth) */
+    if (pico_ipv4_link_get(&hdr->src))
+        return -1;
+
+    /* If this was the last forwarded packet, silently discard to prevent duplications */
+    if ((last_src.addr == hdr->src.addr) && (last_id == hdr->id)
+        && (last_dst.addr == hdr->dst.addr) && (last_proto == hdr->proto)) {
+        return -1;
+    } else {
+        last_src.addr = hdr->src.addr;
+        last_dst.addr = hdr->dst.addr;
+        last_id = hdr->id;
+        last_proto = hdr->proto;
+    }
+
+    return 0;
+}
+
+static int pico_ipv4_forward_check_dev(struct pico_frame *f)
+{
+    if (f->dev->eth != NULL)
+        f->len -= PICO_SIZE_ETHHDR;
+
+    if (f->len > f->dev->mtu) {
+        pico_notify_pkt_too_big(f);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int pico_ipv4_forward(struct pico_frame *f)
+{
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
+    struct pico_ipv4_route *rt;
+    if (!hdr) {
+        return -1;
+    }
+
+    rt = route_find(&hdr->dst);
+    if (!rt) {
+        pico_notify_dest_unreachable(f);
+        return -1;
+    }
+
+    f->dev = rt->link->dev;
+
+    if (pico_ipv4_pre_forward_checks(f) < 0)
+        return -1;
+
+    pico_ipv4_nat_outbound(f, &rt->link->address);
+
+    f->start = f->net_hdr;
+
+    if (pico_ipv4_forward_check_dev(f) < 0)
+        return -1;
+
+    pico_sendto_dev(f);
+    return 0;
+
+}
+
+int pico_ipv4_is_broadcast(uint32_t addr)
+{
+    struct pico_ipv4_link *link;
+    struct pico_tree_node *index;
+    if (addr == PICO_IP4_BCAST)
+        return 1;
+
+    pico_tree_foreach(index, &Tree_dev_link) {
+        link = index->keyValue;
+        if ((link->address.addr | (~link->netmask.addr)) == addr)
+            return 1;
+    }
+    return 0;
+}
+
+void pico_ipv4_unreachable(struct pico_frame *f, int err)
+{
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+#if defined PICO_SUPPORT_TCP || defined PICO_SUPPORT_UDP
+    f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR;
+    pico_transport_error(f, hdr->proto, err);
+#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
diff --git a/net/picotcp/modules/pico_ipv4.h b/net/picotcp/modules/pico_ipv4.h
new file mode 100644
index 0000000..2429815
--- /dev/null
+++ b/net/picotcp/modules/pico_ipv4.h
@@ -0,0 +1,124 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+ *********************************************************************/
+#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 0x4000U
+#define PICO_IPV4_MOREFRAG 0x2000U
+#define PICO_IPV4_EVIL      0x8000U
+#define PICO_IPV4_FRAG_MASK 0x1FFFU
+#define PICO_IPV4_DEFAULT_TTL 64
+#ifndef MBED
+    #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;
+
+PACKED_STRUCT_DEF pico_ipv4_hdr {
+    uint8_t vhl;
+    uint8_t tos;
+    uint16_t len;
+    uint16_t id;
+    uint16_t frag;
+    uint8_t ttl;
+    uint8_t proto;
+    uint16_t crc;
+    struct pico_ip4 src;
+    struct pico_ip4 dst;
+    uint8_t options[];
+};
+
+PACKED_STRUCT_DEF pico_ipv4_pseudo_hdr
+{
+    struct pico_ip4 src;
+    struct pico_ip4 dst;
+    uint8_t zeros;
+    uint8_t proto;
+    uint16_t len;
+};
+
+/* Interface: link to device */
+struct pico_mcast_list;
+
+struct pico_ipv4_link
+{
+    struct pico_device *dev;
+    struct pico_ip4 address;
+    struct pico_ip4 netmask;
+#ifdef PICO_SUPPORT_MCAST
+    struct pico_tree *MCASTGroups;
+    uint8_t mcast_compatibility;
+    uint8_t mcast_last_query_interval;
+#endif
+};
+
+#ifdef PICO_SUPPORT_MCAST
+struct pico_mcast_group {
+    uint8_t filter_mode;
+    uint16_t reference_count;
+    struct pico_ip4 mcast_addr;
+    struct pico_tree MCASTSources;
+};
+#endif
+
+struct pico_ipv4_route
+{
+    struct pico_ip4 dest;
+    struct pico_ip4 netmask;
+    struct pico_ip4 gateway;
+    struct pico_ipv4_link *link;
+    uint32_t metric;
+};
+
+extern struct pico_tree Routes;
+
+
+int pico_ipv4_compare(struct pico_ip4 *a, struct pico_ip4 *b);
+int pico_ipv4_to_string(char *ipbuf, const uint32_t ip);
+int pico_string_to_ipv4(const char *ipstr, uint32_t *ip);
+int pico_ipv4_valid_netmask(uint32_t mask);
+int pico_ipv4_is_unicast(uint32_t address);
+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, 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);
+int pico_ipv4_rebound(struct pico_frame *f);
+
+int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto);
+struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address);
+struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev);
+struct pico_ipv4_link *pico_ipv4_link_by_dev_next(struct pico_device *dev, struct pico_ipv4_link *last);
+struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address);
+struct pico_ip4 *pico_ipv4_source_find(const struct pico_ip4 *dst);
+struct pico_device *pico_ipv4_source_dev_find(const struct pico_ip4 *dst);
+int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link);
+int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, int metric);
+struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr);
+void pico_ipv4_route_set_bcast_link(struct pico_ipv4_link *link);
+void pico_ipv4_unreachable(struct pico_frame *f, int err);
+
+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 */
diff --git a/net/picotcp/modules/pico_ipv6.h b/net/picotcp/modules/pico_ipv6.h
new file mode 100644
index 0000000..a753531
--- /dev/null
+++ b/net/picotcp/modules/pico_ipv6.h
@@ -0,0 +1,153 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+ *********************************************************************/
+#ifndef _INCLUDE_PICO_IPV6
+#define _INCLUDE_PICO_IPV6
+#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
+
+
+#define PICO_IPV6_EXTHDR_HOPBYHOP 0
+#define PICO_IPV6_EXTHDR_ROUTING 43
+#define PICO_IPV6_EXTHDR_FRAG 44
+#define PICO_IPV6_EXTHDR_ESP 50
+#define PICO_IPV6_EXTHDR_AUTH 51
+#define PICO_IPV6_EXTHDR_NONE 59
+#define PICO_IPV6_EXTHDR_DESTOPT 60
+
+
+
+
+extern const uint8_t PICO_IP6_ANY[PICO_SIZE_IP6];
+extern struct pico_protocol pico_proto_ipv6;
+extern struct pico_tree IPV6Routes;
+
+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];
+};
+
+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;
+    struct pico_timer *dad_timer;
+    uint16_t dup_detect_retrans;
+    pico_time expire_time;
+};
+
+struct pico_ipv6_hbhoption {
+    uint8_t type;
+    uint8_t len;
+    uint8_t options[0];
+};
+
+struct pico_ipv6_destoption {
+    uint8_t type;
+    uint8_t len;
+    uint8_t options[0];
+};
+
+struct pico_ipv6_route
+{
+    struct pico_ip6 dest;
+    struct pico_ip6 netmask;
+    struct pico_ip6 gateway;
+    struct pico_ipv6_link *link;
+    uint32_t metric;
+};
+
+PACKED_STRUCT_DEF pico_ipv6_exthdr {
+    uint8_t nxthdr;
+
+    PACKED_UNION_DEF ipv6_ext_u {
+        PEDANTIC_STRUCT_DEF hopbyhop_s {
+            uint8_t len;
+            uint8_t options[0];
+        } hopbyhop;
+
+        PEDANTIC_STRUCT_DEF destopt_s {
+            uint8_t len;
+            uint8_t options[0];
+        } destopt;
+
+        PEDANTIC_STRUCT_DEF routing_s {
+            uint8_t len;
+            uint8_t routtype;
+            uint8_t segleft;
+        } routing;
+
+        PEDANTIC_STRUCT_DEF fragmentation_s {
+            uint8_t res;
+            uint8_t om[2];
+            uint8_t id[4];
+        } frag;
+    } ext;
+};
+
+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_allhosts_multicast(const uint8_t addr[PICO_SIZE_IP6]);
+int pico_ipv6_is_solnode_multicast(const uint8_t addr[PICO_SIZE_IP6], struct pico_device *dev);
+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]);
+int pico_ipv6_is_localhost(const uint8_t addr[PICO_SIZE_IP6]);
+
+int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *src, struct pico_ip6 *dst, uint8_t proto, int is_dad);
+int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link);
+int pico_ipv6_route_del(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);
+
+struct pico_ipv6_link *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_device *pico_ipv6_source_dev_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);
+struct pico_ipv6_link *pico_ipv6_global_get(struct pico_device *dev);
+struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev);
+struct pico_ipv6_link *pico_ipv6_sitelocal_get(struct pico_device *dev);
+struct pico_ipv6_link *pico_ipv6_prefix_configured(struct pico_ip6 *prefix);
+int pico_ipv6_lifetime_set(struct pico_ipv6_link *l, pico_time expire);
+void pico_ipv6_check_lifetime_expired(pico_time now, void *arg);
+int pico_ipv6_dev_routing_enable(struct pico_device *dev);
+int pico_ipv6_dev_routing_disable(struct pico_device *dev);
+void pico_ipv6_router_down(struct pico_ip6 *address);
+#endif
diff --git a/net/picotcp/modules/pico_ipv6_nd.h b/net/picotcp/modules/pico_ipv6_nd.h
new file mode 100644
index 0000000..f709b1e
--- /dev/null
+++ b/net/picotcp/modules/pico_ipv6_nd.h
@@ -0,0 +1,26 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. 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 {
+    uint8_t routing;
+    uint8_t hoplimit;
+    pico_time basetime;
+    pico_time reachabletime;
+    pico_time retranstime;
+};
+
+void pico_ipv6_nd_init(void);
+struct pico_eth *pico_ipv6_get_neighbor(struct pico_frame *f);
+void pico_ipv6_nd_postpone(struct pico_frame *f);
+int pico_ipv6_nd_recv(struct pico_frame *f);
+#endif
diff --git a/net/picotcp/modules/pico_mm.h b/net/picotcp/modules/pico_mm.h
new file mode 100644
index 0000000..29366d0
--- /dev/null
+++ b/net/picotcp/modules/pico_mm.h
@@ -0,0 +1,98 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. 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 "pico_config.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(void);
+/*
+ * 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(void);
+
+/*
+ * 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(void);
+
+/*
+ * 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(void);
+
+/*
+ * 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 */
diff --git a/net/picotcp/modules/pico_nat.h b/net/picotcp/modules/pico_nat.h
new file mode 100644
index 0000000..5237501
--- /dev/null
+++ b/net/picotcp/modules/pico_nat.h
@@ -0,0 +1,90 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Kristof Roelants, Simon Maes, Brecht Van Cauwenberghe
+ *********************************************************************/
+
+#ifndef INCLUDE_PICO_NAT
+#define INCLUDE_PICO_NAT
+#include "pico_frame.h"
+
+#define PICO_NAT_PORT_FORWARD_DEL 0
+#define PICO_NAT_PORT_FORWARD_ADD 1
+
+#ifdef PICO_SUPPORT_NAT
+void pico_ipv4_nat_print_table(void);
+int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto);
+int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag);
+
+int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr);
+int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr);
+int pico_ipv4_nat_enable(struct pico_ipv4_link *link);
+int pico_ipv4_nat_disable(void);
+int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr);
+#else
+
+#define pico_ipv4_nat_print_table() do {} while(0)
+static inline int pico_ipv4_nat_inbound(struct pico_frame *f, struct pico_ip4 *link_addr)
+{
+    (void)f;
+    (void)link_addr;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+static inline int pico_ipv4_nat_outbound(struct pico_frame *f, struct pico_ip4 *link_addr)
+{
+    (void)f;
+    (void)link_addr;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+static inline int pico_ipv4_nat_enable(struct pico_ipv4_link *link)
+{
+    (void)link;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+static inline int pico_ipv4_nat_disable(void)
+{
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+static inline int pico_ipv4_nat_is_enabled(struct pico_ip4 *link_addr)
+{
+    (void)link_addr;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+static inline int pico_ipv4_nat_find(uint16_t nat_port, struct pico_ip4 *src_addr, uint16_t src_port, uint8_t proto)
+{
+    (void)nat_port;
+    (void)src_addr;
+    (void)src_port;
+    (void)proto;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+static inline int pico_ipv4_port_forward(struct pico_ip4 nat_addr, uint16_t nat_port, struct pico_ip4 src_addr, uint16_t src_port, uint8_t proto, uint8_t flag)
+{
+    (void)nat_addr;
+    (void)nat_port;
+    (void)src_addr;
+    (void)src_port;
+    (void)proto;
+    (void)flag;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+#endif
+
+#endif /* _INCLUDE_PICO_NAT */
+
diff --git a/net/picotcp/modules/pico_olsr.h b/net/picotcp/modules/pico_olsr.h
new file mode 100644
index 0000000..11c3bf0
--- /dev/null
+++ b/net/picotcp/modules/pico_olsr.h
@@ -0,0 +1,32 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+#ifndef PICO_OLSR_H
+#define PICO_OLSR_H
+
+
+/* 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;
+};
+
+
+void pico_olsr_init(void);
+int pico_olsr_add(struct pico_device *dev);
+struct olsr_route_entry *olsr_get_ethentry(struct pico_device *vif);
+#endif
diff --git a/net/picotcp/modules/pico_socket_tcp.h b/net/picotcp/modules/pico_socket_tcp.h
new file mode 100644
index 0000000..6479103
--- /dev/null
+++ b/net/picotcp/modules/pico_socket_tcp.h
@@ -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
diff --git a/net/picotcp/modules/pico_socket_udp.c b/net/picotcp/modules/pico_socket_udp.c
new file mode 100644
index 0000000..ea7e9e1
--- /dev/null
+++ b/net/picotcp/modules/pico_socket_udp.c
@@ -0,0 +1,250 @@
+#include "pico_config.h"
+#include "pico_socket.h"
+#include "pico_udp.h"
+#include "pico_socket_multicast.h"
+#include "pico_ipv4.h"
+#include "pico_ipv6.h"
+#include "pico_socket_udp.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 = UDP_FRAME_OVERHEAD;
+    s->q_out.overhead = UDP_FRAME_OVERHEAD;
+#endif
+    return s;
+}
+
+
+#ifdef PICO_SUPPORT_IPV4
+static inline int pico_socket_udp_deliver_ipv4_mcast_initial_checks(struct pico_socket *s, struct pico_frame *f)
+{
+    struct pico_ip4 p_dst;
+    struct pico_ipv4_hdr *ip4hdr;
+
+    ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
+    p_dst.addr = ip4hdr->dst.addr;
+    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 ((pico_ipv4_link_get(&ip4hdr->src)) && (PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP) == 0u)) {
+        /* Datagram from ourselves, Loop disabled, discarding. */
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int pico_socket_udp_deliver_ipv4_mcast(struct pico_socket *s, struct pico_frame *f)
+{
+    struct pico_ip4 s_local;
+    struct pico_frame *cpy;
+    struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);
+
+    s_local.addr = s->local_addr.ip4.addr;
+
+    if (pico_socket_udp_deliver_ipv4_mcast_initial_checks(s, f) < 0)
+        return 0;
+
+
+
+    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);
+    }
+
+    return 0;
+}
+
+static int pico_socket_udp_deliver_ipv4_unicast(struct pico_socket *s, struct pico_frame *f)
+{
+    struct pico_frame *cpy;
+    /* 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);
+    }
+
+    return 0;
+}
+
+
+static int pico_socket_udp_deliver_ipv4(struct pico_socket *s, struct pico_frame *f)
+{
+    int ret = 0;
+    struct pico_ip4 s_local, p_dst;
+    struct pico_ipv4_hdr *ip4hdr;
+    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)) {
+        ret = pico_socket_udp_deliver_ipv4_mcast(s, f);
+    } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr)) {
+        ret = pico_socket_udp_deliver_ipv4_unicast(s, f);
+    }
+
+    pico_frame_discard(f);
+    return ret;
+}
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+static inline int pico_socket_udp_deliver_ipv6_mcast(struct pico_socket *s, struct pico_frame *f)
+{
+    struct pico_ipv6_hdr *ip6hdr;
+    struct pico_frame *cpy;
+    struct pico_device *dev = pico_ipv6_link_find(&s->local_addr.ip6);
+
+    ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
+
+    if ((pico_ipv6_link_get(&ip6hdr->src)) && (PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP) == 0u)) {
+        /* Datagram from ourselves, Loop disabled, discarding. */
+        return 0;
+    }
+
+
+    if (pico_ipv6_is_unspecified(s->local_addr.ip6.addr) || /* 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);
+    }
+
+    return 0;
+}
+
+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))) {
+        return pico_socket_udp_deliver_ipv6_mcast(s, f);
+    } 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 if (IS_IPV6(f)) {
+#ifdef PICO_SUPPORT_IPV6
+            return pico_socket_udp_deliver_ipv6(s, f);
+#endif
+        } else {
+            /* something wrong in the packet header*/
+        }
+    } /* 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
+}
+
diff --git a/net/picotcp/modules/pico_socket_udp.h b/net/picotcp/modules/pico_socket_udp.h
new file mode 100644
index 0000000..6b3a4c9
--- /dev/null
+++ b/net/picotcp/modules/pico_socket_udp.h
@@ -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, NULL)
+#else
+#   define pico_socket_udp_recv(...) (0)
+#   define pico_getsockopt_udp(...) (-1)
+#   define pico_setsockopt_udp(...) (-1)
+#endif
+
+
+#endif
diff --git a/net/picotcp/modules/pico_tcp.h b/net/picotcp/modules/pico_tcp.h
new file mode 100644
index 0000000..d5003a8
--- /dev/null
+++ b/net/picotcp/modules/pico_tcp.h
@@ -0,0 +1,102 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+ *********************************************************************/
+#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;
+
+PACKED_STRUCT_DEF pico_tcp_hdr {
+    struct pico_trans trans;
+    uint32_t seq;
+    uint32_t ack;
+    uint8_t len;
+    uint8_t flags;
+    uint16_t rwnd;
+    uint16_t crc;
+    uint16_t urgent;
+};
+
+PACKED_STRUCT_DEF tcp_pseudo_hdr_ipv4
+{
+    struct pico_ip4 src;
+    struct pico_ip4 dst;
+    uint16_t tcp_len;
+    uint8_t res;
+    uint8_t proto;
+};
+
+#define PICO_TCPHDR_SIZE 20
+#define PICO_SIZE_TCPOPT_SYN 20
+#define PICO_SIZE_TCPHDR (uint32_t)(sizeof(struct pico_tcp_hdr))
+
+/* TCP options */
+#define PICO_TCP_OPTION_END         0x00
+#define PICO_TCPOPTLEN_END        1u
+#define PICO_TCP_OPTION_NOOP        0x01
+#define PICO_TCPOPTLEN_NOOP       1
+#define PICO_TCP_OPTION_MSS         0x02
+#define PICO_TCPOPTLEN_MSS        4
+#define PICO_TCP_OPTION_WS          0x03
+#define PICO_TCPOPTLEN_WS         3u
+#define PICO_TCP_OPTION_SACK_OK        0x04
+#define PICO_TCPOPTLEN_SACK_OK       2
+#define PICO_TCP_OPTION_SACK        0x05
+#define PICO_TCPOPTLEN_SACK       2 /* Plus the block */
+#define PICO_TCP_OPTION_TIMESTAMP   0x08
+#define PICO_TCPOPTLEN_TIMESTAMP  10u
+
+/* TCP flags */
+#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
+
+#define PICO_TCP_SYNACK    (PICO_TCP_SYN | PICO_TCP_ACK)
+#define PICO_TCP_PSHACK    (PICO_TCP_PSH | PICO_TCP_ACK)
+#define PICO_TCP_FINACK    (PICO_TCP_FIN | PICO_TCP_ACK)
+#define PICO_TCP_FINPSHACK (PICO_TCP_FIN | PICO_TCP_PSH | PICO_TCP_ACK)
+#define PICO_TCP_RSTACK    (PICO_TCP_RST | PICO_TCP_ACK)
+
+
+PACKED_STRUCT_DEF pico_tcp_option
+{
+    uint8_t kind;
+    uint8_t len;
+};
+
+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 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_mss(struct pico_socket *s);
+int pico_tcp_check_listen_close(struct pico_socket *s);
+
+#endif
diff --git a/net/picotcp/modules/pico_udp.c b/net/picotcp/modules/pico_udp.c
new file mode 100644
index 0000000..b7c61e4
--- /dev/null
+++ b/net/picotcp/modules/pico_udp.c
@@ -0,0 +1,216 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_udp.h"
+#include "pico_config.h"
+#include "pico_eth.h"
+#include "pico_socket.h"
+#include "pico_stack.h"
+
+#define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame))
+#define udp_dbg(...) do {} while(0)
+
+/* Queues */
+static struct pico_queue udp_in = {
+    0
+};
+static struct pico_queue udp_out = {
+    0
+};
+
+
+/* Functions */
+
+uint16_t pico_udp_checksum_ipv4(struct pico_frame *f)
+{
+    struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
+    struct pico_socket *s = f->sock;
+    struct pico_ipv4_pseudo_hdr pseudo;
+
+    if (s) {
+        /* Case of outgoing frame */
+        udp_dbg("UDP CRC: on outgoing frame\n");
+        pseudo.src.addr = s->local_addr.ip4.addr;
+        pseudo.dst.addr = s->remote_addr.ip4.addr;
+    } else {
+        /* Case of incomming frame */
+        udp_dbg("UDP CRC: on incomming frame\n");
+        pseudo.src.addr = hdr->src.addr;
+        pseudo.dst.addr = hdr->dst.addr;
+    }
+
+    pseudo.zeros = 0;
+    pseudo.proto = PICO_PROTO_UDP;
+    pseudo.len = short_be(f->transport_len);
+
+    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 = {
+        .src = {{0}}, .dst = {{0}}, .len = 0, .zero = {0}, .nxthdr = 0
+    };
+    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 (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_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_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
+         */
+        hdr->crc = 0;
+    }
+
+    if (pico_enqueue(self->q_out, f) > 0) {
+        return f->payload_len;
+    } else {
+        return 0;
+    }
+}
+
+/* Interface: protocol definition */
+struct pico_protocol pico_proto_udp = {
+    .name = "udp",
+    .proto_number = PICO_PROTO_UDP,
+    .layer = PICO_LAYER_TRANSPORT,
+    .process_in = pico_transport_process_in,
+    .process_out = pico_udp_process_out,
+    .push = pico_udp_push,
+    .q_in = &udp_in,
+    .q_out = &udp_out,
+};
+
+
+
+struct pico_socket *pico_udp_open(void)
+{
+    struct pico_socket_udp *u = PICO_ZALLOC(sizeof(struct pico_socket_udp));
+    if (!u)
+        return NULL;
+
+    u->mode = PICO_UDP_MODE_UNICAST;
+
+#ifdef PICO_SUPPORT_MCAST
+    u->mc_ttl = PICO_IP_DEFAULT_MULTICAST_TTL;
+    /* enable multicast loopback by default */
+    u->sock.opt_flags |= (1 << PICO_SOCKET_OPT_MULTICAST_LOOP);
+#endif
+
+    return &u->sock;
+}
+
+static void pico_udp_get_msginfo(struct pico_frame *f, struct pico_msginfo *msginfo)
+{
+    msginfo->dev = f->dev;
+    if (!msginfo || !f->net_hdr)
+        return;
+
+    if (IS_IPV4(f)) { /* IPV4 */
+#ifdef PICO_SUPPORT_IPV4
+        struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)(f->net_hdr);
+        msginfo->ttl = hdr->ttl;
+        msginfo->tos = hdr->tos;
+#endif
+    } else {
+#ifdef PICO_SUPPORT_IPV6
+        struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr);
+        msginfo->ttl = hdr->hop;
+        msginfo->tos = (hdr->vtf >> 20) & 0xFF; /* IPv6 traffic class */
+#endif
+    }
+}
+
+uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port, struct pico_msginfo *msginfo)
+{
+    struct pico_frame *f = pico_queue_peek(&s->q_in);
+    if (f) {
+        if(!f->payload_len) {
+            f->payload = f->transport_hdr + sizeof(struct pico_udp_hdr);
+            f->payload_len = (uint16_t)(f->transport_len - sizeof(struct pico_udp_hdr));
+        }
+
+        udp_dbg("expected: %d, got: %d\n", len, f->payload_len);
+        if (src)
+            pico_store_network_origin(src, f);
+
+        if (port) {
+            struct pico_trans *hdr = (struct pico_trans *)f->transport_hdr;
+            *port = hdr->sport;
+        }
+
+        if (msginfo) {
+            pico_udp_get_msginfo(f, msginfo);
+        }
+
+        if (f->payload_len > len) {
+            memcpy(buf, f->payload, len);
+            f->payload += len;
+            f->payload_len = (uint16_t)(f->payload_len - len);
+            return len;
+        } else {
+            uint16_t ret = f->payload_len;
+            memcpy(buf, f->payload, f->payload_len);
+            f = pico_dequeue(&s->q_in);
+            pico_frame_discard(f);
+            return ret;
+        }
+    } else return 0;
+}
+
diff --git a/net/picotcp/modules/pico_udp.h b/net/picotcp/modules/pico_udp.h
new file mode 100644
index 0000000..80b97a9
--- /dev/null
+++ b/net/picotcp/modules/pico_udp.h
@@ -0,0 +1,45 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+ *********************************************************************/
+#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;
+
+PACKED_STRUCT_DEF pico_udp_hdr {
+    struct pico_trans trans;
+    uint16_t len;
+    uint16_t crc;
+};
+#define PICO_UDPHDR_SIZE 8
+
+struct pico_socket *pico_udp_open(void);
+uint16_t pico_udp_recv(struct pico_socket *s, void *buf, uint16_t len, void *src, uint16_t *port, struct pico_msginfo *msginfo);
+uint16_t pico_udp_checksum_ipv4(struct pico_frame *f);
+
+#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
diff --git a/net/picotcp/stack/pico_device.c b/net/picotcp/stack/pico_device.c
new file mode 100644
index 0000000..224b37f
--- /dev/null
+++ b/net/picotcp/stack/pico_device.c
@@ -0,0 +1,408 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+#include "pico_config.h"
+#include "pico_device.h"
+#include "pico_stack.h"
+#include "pico_protocol.h"
+#include "pico_tree.h"
+#include "pico_ipv6.h"
+#include "pico_ipv4.h"
+#include "pico_icmp6.h"
+#include "pico_eth.h"
+#define PICO_DEVICE_DEFAULT_MTU (1500)
+
+struct pico_devices_rr_info {
+    struct pico_tree_node *node_in, *node_out;
+};
+
+static struct pico_devices_rr_info Devices_rr_info = {
+    NULL, NULL
+};
+
+static int pico_dev_cmp(void *ka, void *kb)
+{
+    struct pico_device *a = ka, *b = kb;
+    if (a->hash < b->hash)
+        return -1;
+
+    if (a->hash > b->hash)
+        return 1;
+
+    return 0;
+}
+
+PICO_TREE_DECLARE(Device_tree, pico_dev_cmp);
+
+#ifdef PICO_SUPPORT_IPV6
+static void device_init_ipv6_final(struct pico_device *dev, struct pico_ip6 *linklocal)
+{
+    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;
+}
+
+struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix)
+{
+    struct pico_ip6 newaddr;
+    struct pico_ip6 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+    struct pico_ipv6_link *link;
+    memcpy(newaddr.addr, prefix->addr, PICO_SIZE_IP6);
+    /* modified EUI-64 + invert universal/local bit */
+    newaddr.addr[8] = (dev->eth->mac.addr[0] ^ 0x02);
+    newaddr.addr[9] = dev->eth->mac.addr[1];
+    newaddr.addr[10] = dev->eth->mac.addr[2];
+    newaddr.addr[11] = 0xff;
+    newaddr.addr[12] = 0xfe;
+    newaddr.addr[13] = dev->eth->mac.addr[3];
+    newaddr.addr[14] = dev->eth->mac.addr[4];
+    newaddr.addr[15] = dev->eth->mac.addr[5];
+    link = pico_ipv6_link_add(dev, newaddr, netmask64);
+    if (link) {
+        device_init_ipv6_final(dev, &newaddr);
+    }
+
+    return link;
+}
+#endif
+
+static int device_init_mac(struct pico_device *dev, 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}};
+    #endif
+    dev->eth = PICO_ZALLOC(sizeof(struct pico_ethdev));
+    if (dev->eth) {
+        memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH);
+        #ifdef PICO_SUPPORT_IPV6
+        if (pico_ipv6_link_add_local(dev, &linklocal) == NULL) {
+            PICO_FREE(dev->q_in);
+            PICO_FREE(dev->q_out);
+            PICO_FREE(dev->eth);
+            return -1;
+        }
+
+        #endif
+    } else {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
+    return 0;
+}
+
+int pico_device_ipv6_random_ll(struct pico_device *dev)
+{
+    #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}};
+    uint32_t len = (uint32_t)strlen(dev->name);
+    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) == NULL) {
+            return -1;
+        }
+    }
+
+    #endif
+    return 0;
+}
+
+static int device_init_nomac(struct pico_device *dev)
+{
+    if (pico_device_ipv6_random_ll(dev) < 0) {
+        PICO_FREE(dev->q_in);
+        PICO_FREE(dev->q_out);
+        return -1;
+    }
+
+    dev->eth = NULL;
+    return 0;
+}
+
+int pico_device_init(struct pico_device *dev, const char *name, uint8_t *mac)
+{
+
+    uint32_t len = (uint32_t)strlen(name);
+    int ret = 0;
+    if(len > MAX_DEVICE_NAME)
+        len = MAX_DEVICE_NAME;
+
+    memcpy(dev->name, name, len);
+    dev->hash = pico_hash(dev->name, len);
+
+    Devices_rr_info.node_in  = NULL;
+    Devices_rr_info.node_out = NULL;
+    dev->q_in = PICO_ZALLOC(sizeof(struct pico_queue));
+    if (!dev->q_in)
+        return -1;
+
+    dev->q_out = PICO_ZALLOC(sizeof(struct pico_queue));
+    if (!dev->q_out) {
+        PICO_FREE(dev->q_in);
+        return -1;
+    }
+
+    pico_tree_insert(&Device_tree, dev);
+    if (!dev->mtu)
+        dev->mtu = PICO_DEVICE_DEFAULT_MTU;
+
+    if (mac) {
+        ret = device_init_mac(dev, mac);
+    } else {
+        ret = device_init_nomac(dev);
+    }
+
+    return ret;
+}
+
+static void pico_queue_destroy(struct pico_queue *q)
+{
+    if (q) {
+        pico_queue_empty(q);
+        PICO_FREE(q);
+    }
+}
+
+void pico_device_destroy(struct pico_device *dev)
+{
+    if (dev->destroy)
+        dev->destroy(dev);
+
+    pico_queue_destroy(dev->q_in);
+    pico_queue_destroy(dev->q_out);
+
+    if (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);
+
+    Devices_rr_info.node_in  = NULL;
+    Devices_rr_info.node_out = NULL;
+    PICO_FREE(dev);
+}
+
+static int check_dev_serve_interrupt(struct pico_device *dev, int loop_score)
+{
+    if ((dev->__serving_interrupt) && (dev->dsr)) {
+        /* call dsr routine */
+        loop_score = dev->dsr(dev, loop_score);
+    }
+
+    return loop_score;
+}
+
+static int check_dev_serve_polling(struct pico_device *dev, int loop_score)
+{
+    if (dev->poll) {
+        loop_score = dev->poll(dev, loop_score);
+    }
+
+    return loop_score;
+}
+
+static int devloop_in(struct pico_device *dev, int loop_score)
+{
+    struct pico_frame *f;
+    while(loop_score > 0) {
+        if (dev->q_in->frames <= 0)
+            break;
+
+        /* Receive */
+        f = pico_dequeue(dev->q_in);
+        if (f) {
+            if (dev->eth) {
+                f->datalink_hdr = f->buffer;
+                (void)pico_ethernet_receive(f);
+            } else {
+                f->net_hdr = f->buffer;
+                pico_network_receive(f);
+            }
+
+            loop_score--;
+        }
+    }
+    return loop_score;
+}
+
+static int devloop_sendto_dev(struct pico_device *dev, struct pico_frame *f)
+{
+
+    if (dev->eth) {
+        /* Ethernet: pass management of the frame to the pico_ethernet_send() rdv function */
+        return pico_ethernet_send(f);
+    } else {
+        /* non-ethernet: no post-processing needed */
+        return (dev->send(dev, f->start, (int)f->len) <= 0); /* Return 0 upon success, which is dev->send() > 0 */
+    }
+}
+
+static int devloop_out(struct pico_device *dev, int loop_score)
+{
+    struct pico_frame *f;
+    while(loop_score > 0) {
+        if (dev->q_out->frames <= 0)
+            break;
+
+        /* Device dequeue + send */
+        f = pico_queue_peek(dev->q_out);
+        if (!f)
+            break;
+
+        if (devloop_sendto_dev(dev, f) == 0) { /* success. */
+            f = pico_dequeue(dev->q_out);
+            pico_frame_discard(f); /* SINGLE POINT OF DISCARD for OUTGOING FRAMES */
+            loop_score--;
+        } else
+            break; /* Don't discard */
+
+    }
+    return loop_score;
+}
+
+static int devloop(struct pico_device *dev, int loop_score, int direction)
+{
+    /* If device supports interrupts, read the value of the condition and trigger the dsr */
+    loop_score = check_dev_serve_interrupt(dev, loop_score);
+
+    /* If device supports polling, give control. Loop score is managed internally,
+     * remaining loop points are returned. */
+    loop_score = check_dev_serve_polling(dev, loop_score);
+
+    if (direction == PICO_LOOP_DIR_OUT)
+        loop_score = devloop_out(dev, loop_score);
+    else
+        loop_score = devloop_in(dev, loop_score);
+
+    return loop_score;
+}
+
+
+static struct pico_tree_node *pico_dev_roundrobin_start(int direction)
+{
+    if (Devices_rr_info.node_in == NULL)
+        Devices_rr_info.node_in = pico_tree_firstNode(Device_tree.root);
+
+    if (Devices_rr_info.node_out == NULL)
+        Devices_rr_info.node_out = pico_tree_firstNode(Device_tree.root);
+
+    if (direction == PICO_LOOP_DIR_IN)
+        return Devices_rr_info.node_in;
+    else
+        return Devices_rr_info.node_out;
+}
+
+static void pico_dev_roundrobin_end(int direction, struct pico_tree_node *last)
+{
+    if (direction == PICO_LOOP_DIR_IN)
+        Devices_rr_info.node_in = last;
+    else
+        Devices_rr_info.node_out = last;
+}
+
+#define DEV_LOOP_MIN  16
+
+int pico_devices_loop(int loop_score, int direction)
+{
+    struct pico_device *start, *next;
+    struct pico_tree_node *next_node  = pico_dev_roundrobin_start(direction);
+
+    if (!next_node)
+        return loop_score;
+
+    next = next_node->keyValue;
+    start = next;
+
+    /* round-robin all devices, break if traversed all devices */
+    while ((loop_score > DEV_LOOP_MIN) && (next != NULL)) {
+        loop_score = devloop(next, loop_score, direction);
+        next_node = pico_tree_next(next_node);
+        next = next_node->keyValue;
+        if (next == NULL)
+        {
+            next_node = pico_tree_firstNode(Device_tree.root);
+            next = next_node->keyValue;
+        }
+
+        if (next == start)
+            break;
+    }
+    pico_dev_roundrobin_end(direction, next_node);
+    return loop_score;
+}
+
+struct pico_device *pico_get_device(const char*name)
+{
+    struct pico_device *dev;
+    struct pico_tree_node *index;
+    pico_tree_foreach(index, &Device_tree){
+        dev = index->keyValue;
+        if(strcmp(name, dev->name) == 0)
+            return dev;
+    }
+    return NULL;
+}
+
+int32_t pico_device_broadcast(struct pico_frame *f)
+{
+    struct pico_tree_node *index;
+    int32_t ret = -1;
+
+    pico_tree_foreach(index, &Device_tree)
+    {
+        struct pico_device *dev = index->keyValue;
+        if(dev != f->dev)
+        {
+            struct pico_frame *copy = pico_frame_copy(f);
+
+            if(!copy)
+                break;
+
+            copy->dev = dev;
+            copy->dev->send(copy->dev, copy->start, (int)copy->len);
+            pico_frame_discard(copy);
+        }
+        else
+        {
+            ret = f->dev->send(f->dev, f->start, (int)f->len);
+        }
+    }
+    return ret;
+}
+
+int pico_device_link_state(struct pico_device *dev)
+{
+    if (!dev->link_state)
+        return 1; /* Not supported, assuming link is always up */
+
+    return dev->link_state(dev);
+}
diff --git a/net/picotcp/stack/pico_frame.c b/net/picotcp/stack/pico_frame.c
new file mode 100644
index 0000000..482edfe
--- /dev/null
+++ b/net/picotcp/stack/pico_frame.c
@@ -0,0 +1,286 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_config.h"
+#include "pico_frame.h"
+#include "pico_protocol.h"
+#include "pico_stack.h"
+
+#ifdef PICO_SUPPORT_DEBUG_MEMORY
+static int n_frames_allocated;
+#endif
+
+/** frame alloc/dealloc/copy **/
+void pico_frame_discard(struct pico_frame *f)
+{
+    if (!f)
+        return;
+
+    (*f->usage_count)--;
+    if (*f->usage_count <= 0) {
+        if (f->flags & PICO_FRAME_FLAG_EXT_USAGE_COUNTER)
+            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
+        if (!(f->flags & PICO_FRAME_FLAG_EXT_BUFFER))
+            PICO_FREE(f->buffer);
+        else if (f->notify_free)
+            f->notify_free(f->buffer);
+
+        if (f->info)
+            PICO_FREE(f->info);
+    }
+
+#ifdef PICO_SUPPORT_DEBUG_MEMORY
+    else {
+        dbg("Removed frame @%p(copy), usage count now: %d\n", f, *f->usage_count);
+    }
+#endif
+    PICO_FREE(f);
+}
+
+struct pico_frame *pico_frame_copy(struct pico_frame *f)
+{
+    struct pico_frame *new = PICO_ZALLOC(sizeof(struct pico_frame));
+    if (!new)
+        return NULL;
+
+    memcpy(new, f, sizeof(struct pico_frame));
+    *(new->usage_count) += 1;
+#ifdef PICO_SUPPORT_DEBUG_MEMORY
+    dbg("Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count);
+#endif
+    new->next = NULL;
+    return new;
+}
+
+
+static struct pico_frame *pico_frame_do_alloc(uint32_t size, int zerocopy, int ext_buffer)
+{
+    struct pico_frame *p = PICO_ZALLOC(sizeof(struct pico_frame));
+    uint32_t frame_buffer_size = size;
+    if (!p)
+        return NULL;
+
+    if (ext_buffer && !zerocopy) {
+        /* external buffer implies zerocopy flag! */
+        PICO_FREE(p);
+        return NULL;
+    }
+
+    if (!zerocopy) {
+        unsigned int align = size % sizeof(uint32_t);
+        /* Ensure that usage_count starts on an aligned address */
+        if (align) {
+            frame_buffer_size += (uint32_t)sizeof(uint32_t) - align;
+        }
+
+        p->buffer = PICO_ZALLOC(frame_buffer_size + sizeof(uint32_t));
+        if (!p->buffer) {
+            PICO_FREE(p);
+            return NULL;
+        }
+
+        p->usage_count = (uint32_t *)(((uint8_t*)p->buffer) + frame_buffer_size);
+    } else {
+        p->buffer = NULL;
+        p->flags |= PICO_FRAME_FLAG_EXT_USAGE_COUNTER;
+        p->usage_count = PICO_ZALLOC(sizeof(uint32_t));
+        if (!p->usage_count) {
+            PICO_FREE(p);
+            return NULL;
+        }
+    }
+
+
+    p->buffer_len = size;
+
+    /* By default, frame content is the full buffer. */
+    p->start = p->buffer;
+    p->len = p->buffer_len;
+    *p->usage_count = 1;
+
+    if (ext_buffer)
+        p->flags |= PICO_FRAME_FLAG_EXT_BUFFER;
+
+#ifdef PICO_SUPPORT_DEBUG_MEMORY
+    dbg("Allocated buffer @%p, len= %d caller: %p\n", p->buffer, p->buffer_len, __builtin_return_address(2));
+    dbg("DEBUG MEMORY: %d frames in use.\n", ++n_frames_allocated);
+#endif
+    return p;
+}
+
+struct pico_frame *pico_frame_alloc(uint32_t size)
+{
+    return pico_frame_do_alloc(size, 0, 0);
+}
+
+int pico_frame_grow(struct pico_frame *f, uint32_t size)
+{
+    uint8_t *oldbuf;
+    uint32_t usage_count, *p_old_usage;
+    uint32_t frame_buffer_size;
+    uint32_t oldsize;
+    unsigned int align;
+    int addr_diff = 0;
+
+    if (!f || (size < f->buffer_len)) {
+        return -1;
+    }
+
+    align = size % sizeof(uint32_t);
+    frame_buffer_size = size;
+    if (align) {
+        frame_buffer_size += (uint32_t)sizeof(uint32_t) - align;
+    }
+
+    oldbuf = f->buffer;
+    oldsize = f->buffer_len;
+    usage_count = *(f->usage_count);
+    p_old_usage = f->usage_count;
+    f->buffer = PICO_ZALLOC(frame_buffer_size + sizeof(uint32_t));
+    if (!f->buffer) {
+        f->buffer = oldbuf;
+        return -1;
+    }
+
+    f->usage_count = (uint32_t *)(((uint8_t*)f->buffer) + frame_buffer_size);
+    *f->usage_count = usage_count;
+    f->buffer_len = size;
+    memcpy(f->buffer, oldbuf, oldsize);
+
+    /* Update hdr fields to new buffer*/
+    addr_diff = (int)(f->buffer - oldbuf);
+    f->net_hdr += addr_diff;
+    f->datalink_hdr += addr_diff;
+    f->transport_hdr += addr_diff;
+    f->app_hdr += addr_diff;
+    f->start += addr_diff;
+    f->payload += addr_diff;
+
+    if (f->flags & PICO_FRAME_FLAG_EXT_USAGE_COUNTER)
+        PICO_FREE(p_old_usage);
+
+    if (!(f->flags & PICO_FRAME_FLAG_EXT_BUFFER))
+        PICO_FREE(oldbuf);
+    else if (f->notify_free)
+        f->notify_free(oldbuf);
+
+    f->flags = 0;
+    /* Now, the frame is not zerocopy anymore, and the usage counter has been moved within it */
+    return 0;
+}
+
+struct pico_frame *pico_frame_alloc_skeleton(uint32_t size, int ext_buffer)
+{
+    return pico_frame_do_alloc(size, 1, ext_buffer);
+}
+
+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);
+    int addr_diff;
+    unsigned char *buf;
+    uint32_t *uc;
+    if (!new)
+        return NULL;
+
+    /* Save the two key pointers... */
+    buf = new->buffer;
+    uc  = new->usage_count;
+
+    /* Overwrite all fields with originals */
+    memcpy(new, f, sizeof(struct pico_frame));
+
+    /* ...restore the two key pointers */
+    new->buffer = buf;
+    new->usage_count = uc;
+
+    /* Update in-buffer pointers with offset */
+    addr_diff = (int)(new->buffer - f->buffer);
+    new->datalink_hdr += addr_diff;
+    new->net_hdr += addr_diff;
+    new->transport_hdr += addr_diff;
+    new->app_hdr += addr_diff;
+    new->start += addr_diff;
+    new->payload += addr_diff;
+
+#ifdef PICO_SUPPORT_DEBUG_MEMORY
+    dbg("Deep-Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count);
+#endif
+    new->next = NULL;
+    return new;
+}
+
+
+static inline uint32_t pico_checksum_adder(uint32_t sum, void *data, uint32_t len)
+{
+    uint16_t *buf = (uint16_t *)data;
+    uint16_t *stop;
+
+    if (len & 0x01) {
+        --len;
+#ifdef PICO_BIGENDIAN
+        sum += (((uint8_t *)data)[len]) << 8;
+#else
+        sum += ((uint8_t *)data)[len];
+#endif
+    }
+
+    stop = (uint16_t *)(((uint8_t *)data) + len);
+
+    while (buf < stop) {
+        sum += *buf++;
+    }
+    return sum;
+}
+
+static inline uint16_t pico_checksum_finalize(uint32_t sum)
+{
+    while (sum >> 16) { /* a second carry is possible! */
+        sum = (sum & 0x0000FFFF) + (sum >> 16);
+    }
+    return short_be((uint16_t) ~sum);
+}
+
+/**
+ * Calculate checksum of a given string
+ */
+uint16_t pico_checksum(void *inbuf, uint32_t len)
+{
+    uint32_t sum;
+
+    sum = pico_checksum_adder(0, inbuf, len);
+    return pico_checksum_finalize(sum);
+}
+
+/* WARNING: len1 MUST be an EVEN number */
+uint16_t pico_dualbuffer_checksum(void *inbuf1, uint32_t len1, void *inbuf2, uint32_t len2)
+{
+    uint32_t sum;
+
+    sum = pico_checksum_adder(0, inbuf1, len1);
+    sum = pico_checksum_adder(sum, inbuf2, len2);
+    return pico_checksum_finalize(sum);
+}
+
diff --git a/net/picotcp/stack/pico_protocol.c b/net/picotcp/stack/pico_protocol.c
new file mode 100644
index 0000000..98d2a20
--- /dev/null
+++ b/net/picotcp/stack/pico_protocol.c
@@ -0,0 +1,214 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_protocol.h"
+#include "pico_tree.h"
+
+struct pico_proto_rr
+{
+    struct pico_tree *t;
+    struct pico_tree_node *node_in, *node_out;
+};
+
+
+static int pico_proto_cmp(void *ka, void *kb)
+{
+    struct pico_protocol *a = ka, *b = kb;
+    if (a->hash < b->hash)
+        return -1;
+
+    if (a->hash > b->hash)
+        return 1;
+
+    return 0;
+}
+
+PICO_TREE_DECLARE(Datalink_proto_tree, pico_proto_cmp);
+PICO_TREE_DECLARE(Network_proto_tree, pico_proto_cmp);
+PICO_TREE_DECLARE(Transport_proto_tree, pico_proto_cmp);
+PICO_TREE_DECLARE(Socket_proto_tree, pico_proto_cmp);
+
+/* Static variables to keep track of the round robin loop */
+static struct pico_proto_rr proto_rr_datalink   = {
+    &Datalink_proto_tree,     NULL, NULL
+};
+static struct pico_proto_rr proto_rr_network    = {
+    &Network_proto_tree,      NULL, NULL
+};
+static struct pico_proto_rr proto_rr_transport  = {
+    &Transport_proto_tree,    NULL, NULL
+};
+static struct pico_proto_rr proto_rr_socket     = {
+    &Socket_proto_tree,       NULL, NULL
+};
+
+static int proto_loop_in(struct pico_protocol *proto, int loop_score)
+{
+    struct pico_frame *f;
+    while(loop_score > 0) {
+        if (proto->q_in->frames <= 0)
+            break;
+
+        f = pico_dequeue(proto->q_in);
+        if ((f) && (proto->process_in(proto, f) > 0)) {
+            loop_score--;
+        }
+    }
+    return loop_score;
+}
+
+static int proto_loop_out(struct pico_protocol *proto, int loop_score)
+{
+    struct pico_frame *f;
+    while(loop_score > 0) {
+        if (proto->q_out->frames <= 0)
+            break;
+
+        f = pico_dequeue(proto->q_out);
+        if ((f) && (proto->process_out(proto, f) > 0)) {
+            loop_score--;
+        }
+    }
+    return loop_score;
+}
+
+static int proto_loop(struct pico_protocol *proto, int loop_score, int direction)
+{
+
+    if (direction == PICO_LOOP_DIR_IN)
+        loop_score = proto_loop_in(proto, loop_score);
+    else if (direction == PICO_LOOP_DIR_OUT)
+        loop_score = proto_loop_out(proto, loop_score);
+
+    return loop_score;
+}
+
+static struct pico_tree_node *roundrobin_init(struct pico_proto_rr *rr, int direction)
+{
+    struct pico_tree_node *next_node = NULL;
+    /* Initialization (takes place only once) */
+    if (rr->node_in == NULL)
+        rr->node_in = pico_tree_firstNode(rr->t->root);
+
+    if (rr->node_out == NULL)
+        rr->node_out = pico_tree_firstNode(rr->t->root);
+
+    if (direction == PICO_LOOP_DIR_IN)
+        next_node = rr->node_in;
+    else
+        next_node = rr->node_out;
+
+    return next_node;
+}
+
+static void roundrobin_end(struct pico_proto_rr *rr, int direction, struct pico_tree_node *last)
+{
+    if (direction == PICO_LOOP_DIR_IN)
+        rr->node_in = last;
+    else
+        rr->node_out = last;
+}
+
+static int pico_protocol_generic_loop(struct pico_proto_rr *rr, int loop_score, int direction)
+{
+    struct pico_protocol *start, *next;
+    struct pico_tree_node *next_node = roundrobin_init(rr, direction);
+
+    if (!next_node)
+        return loop_score;
+
+    next = next_node->keyValue;
+
+    /* init start node */
+    start = next;
+
+    /* round-robin all layer protocols, break if traversed all protocols */
+    while (loop_score > 1 && next != NULL) {
+        loop_score = proto_loop(next, loop_score, direction);
+        next_node = pico_tree_next(next_node);
+        next = next_node->keyValue;
+        if (next == NULL)
+        {
+            next_node = pico_tree_firstNode(rr->t->root);
+            next = next_node->keyValue;
+        }
+
+        if (next == start)
+            break;
+    }
+    roundrobin_end(rr, direction, next_node);
+    return loop_score;
+}
+
+int pico_protocol_datalink_loop(int loop_score, int direction)
+{
+    return pico_protocol_generic_loop(&proto_rr_datalink, loop_score, direction);
+}
+
+int pico_protocol_network_loop(int loop_score, int direction)
+{
+    return pico_protocol_generic_loop(&proto_rr_network, loop_score, direction);
+}
+
+int pico_protocol_transport_loop(int loop_score, int direction)
+{
+    return pico_protocol_generic_loop(&proto_rr_transport, loop_score, direction);
+}
+
+int pico_protocol_socket_loop(int loop_score, int direction)
+{
+    return pico_protocol_generic_loop(&proto_rr_socket, loop_score, direction);
+}
+
+int pico_protocols_loop(int loop_score)
+{
+/*
+   loop_score = pico_protocol_datalink_loop(loop_score);
+   loop_score = pico_protocol_network_loop(loop_score);
+   loop_score = pico_protocol_transport_loop(loop_score);
+   loop_score = pico_protocol_socket_loop(loop_score);
+ */
+    return loop_score;
+}
+
+static void proto_layer_rr_reset(struct pico_proto_rr *rr)
+{
+    rr->node_in = NULL;
+    rr->node_out = NULL;
+}
+
+void pico_protocol_init(struct pico_protocol *p)
+{
+    if (!p)
+        return;
+
+    p->hash = pico_hash(p->name, (uint32_t)strlen(p->name));
+    switch (p->layer) {
+    case PICO_LAYER_DATALINK:
+        pico_tree_insert(&Datalink_proto_tree, p);
+        proto_layer_rr_reset(&proto_rr_datalink);
+        break;
+    case PICO_LAYER_NETWORK:
+        pico_tree_insert(&Network_proto_tree, p);
+        proto_layer_rr_reset(&proto_rr_network);
+        break;
+    case PICO_LAYER_TRANSPORT:
+        pico_tree_insert(&Transport_proto_tree, p);
+        proto_layer_rr_reset(&proto_rr_transport);
+        break;
+    case PICO_LAYER_SOCKET:
+        pico_tree_insert(&Socket_proto_tree, p);
+        proto_layer_rr_reset(&proto_rr_socket);
+        break;
+    }
+    dbg("Protocol %s registered (layer: %d).\n", p->name, p->layer);
+
+}
+
diff --git a/net/picotcp/stack/pico_socket.c b/net/picotcp/stack/pico_socket.c
new file mode 100644
index 0000000..cd0be1e
--- /dev/null
+++ b/net/picotcp/stack/pico_socket.c
@@ -0,0 +1,2213 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_config.h"
+#include "pico_queue.h"
+#include "pico_socket.h"
+#include "pico_ipv4.h"
+#include "pico_ipv6.h"
+#include "pico_udp.h"
+#include "pico_tcp.h"
+#include "pico_stack.h"
+#include "pico_icmp4.h"
+#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 PROTO(s) ((s)->proto->proto_number)
+#define PICO_MIN_MSS (1280)
+#define TCP_STATE(s) (s->state & PICO_SOCKET_STATE_TCP)
+
+#ifdef PICO_SUPPORT_MUTEX
+static void *Mutex = NULL;
+#endif
+
+
+#define PROTO(s) ((s)->proto->proto_number)
+
+#define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
+
+# define frag_dbg(...) do {} while(0)
+
+
+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 int socket_cmp_family(struct pico_socket *a, struct pico_socket *b)
+{
+    uint32_t a_is_ip6 = is_sock_ipv6(a);
+    uint32_t b_is_ip6 = is_sock_ipv6(b);
+    (void)a;
+    (void)b;
+    if (a_is_ip6 < b_is_ip6)
+        return -1;
+
+    if (a_is_ip6 > b_is_ip6)
+        return 1;
+
+    return 0;
+}
+
+
+static int socket_cmp_ipv6(struct pico_socket *a, struct pico_socket *b)
+{
+    int ret = 0;
+    (void)a;
+    (void)b;
+#ifdef PICO_SUPPORT_IPV6
+    if (!is_sock_ipv6(a) || !is_sock_ipv6(b))
+        return 0;
+
+    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
+    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);
+
+    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 (ret == 0)
+        ret = socket_cmp_remotehost(a, b);
+
+    return 0;
+}
+
+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. */
+    if (ret == 0)
+        ret = b->remote_port - a->remote_port;
+
+    return ret;
+}
+
+
+#define INIT_SOCKPORT { {&LEAF, socket_cmp}, 0, 0 }
+
+static int sockport_cmp(void *ka, void *kb)
+{
+    struct pico_sockport *a = ka, *b = kb;
+    if (a->number < b->number)
+        return -1;
+
+    if (a->number > b->number)
+        return 1;
+
+    return 0;
+}
+
+PICO_TREE_DECLARE(UDPTable, sockport_cmp);
+PICO_TREE_DECLARE(TCPTable, sockport_cmp);
+
+struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port)
+{
+    struct pico_sockport test = INIT_SOCKPORT;
+    test.number = port;
+
+    if (proto == PICO_PROTO_UDP)
+        return pico_tree_findKey(&UDPTable, &test);
+
+    else if (proto == PICO_PROTO_TCP)
+        return pico_tree_findKey(&TCPTable, &test);
+
+    else return NULL;
+}
+
+#ifdef PICO_SUPPORT_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");
+        ret = 1;
+    }
+
+#endif
+    return ret;
+}
+
+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;
+        struct pico_socket *s;
+        pico_tree_foreach(idx, &sp->socks) {
+            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 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, void *net)
+{
+#ifdef PICO_SUPPORT_IPV4
+    if (net == &pico_proto_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 (net == &pico_proto_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;
+    sp = pico_get_sockport(proto, port);
+
+    if (pico_generic_port_in_use(proto, port, sp, addr, net))
+        return 0;
+
+    return 1;
+}
+
+static int pico_check_socket(struct pico_socket *s)
+{
+    struct pico_sockport *test;
+    struct pico_socket *found;
+    struct pico_tree_node *index;
+
+    test = pico_get_sockport(PROTO(s), s->local_port);
+
+    if (!test) {
+        return -1;
+    }
+
+    pico_tree_foreach(index, &test->socks){
+        found = index->keyValue;
+        if (s == found) {
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+struct pico_socket *pico_sockets_find(uint16_t local, uint16_t remote)
+{
+    struct pico_socket *sock = NULL;
+    struct pico_tree_node *index = NULL;
+    struct pico_sockport *sp = NULL;
+
+    sp = pico_get_sockport(PICO_PROTO_TCP, local);
+    if(sp)
+    {
+        pico_tree_foreach(index, &sp->socks)
+        {
+            if(((struct pico_socket *)index->keyValue)->remote_port == remote)
+            {
+                sock = (struct pico_socket *)index->keyValue;
+                break;
+            }
+        }
+    }
+
+    return sock;
+}
+
+
+int8_t pico_socket_add(struct pico_socket *s)
+{
+    struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
+    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));
+
+        if (!sp) {
+            pico_err = PICO_ERR_ENOMEM;
+            PICOTCP_MUTEX_UNLOCK(Mutex);
+            return -1;
+        }
+
+        sp->proto = PROTO(s);
+        sp->number = s->local_port;
+        sp->socks.root = &LEAF;
+        sp->socks.compare = socket_cmp;
+
+        if (PROTO(s) == PICO_PROTO_UDP)
+        {
+            pico_tree_insert(&UDPTable, sp);
+        }
+        else if (PROTO(s) == PICO_PROTO_TCP)
+        {
+            pico_tree_insert(&TCPTable, sp);
+        }
+    }
+
+    pico_tree_insert(&sp->socks, s);
+    s->state |= PICO_SOCKET_STATE_BOUND;
+    PICOTCP_MUTEX_UNLOCK(Mutex);
+#ifdef DEBUG_SOCKET_TREE
+    {
+        struct pico_tree_node *index;
+        /* RB_FOREACH(s, socket_tree, &sp->socks) { */
+        pico_tree_foreach(index, &sp->socks){
+            s = index->keyValue;
+            dbg(">>>> List Socket lc=%hu rm=%hu\n", short_be(s->local_port), short_be(s->remote_port));
+        }
+
+    }
+#endif
+    return 0;
+}
+
+
+static void socket_clean_queues(struct pico_socket *sock)
+{
+    struct pico_frame *f_in = pico_dequeue(&sock->q_in);
+    struct pico_frame *f_out = pico_dequeue(&sock->q_out);
+    while(f_in || f_out)
+    {
+        if(f_in)
+        {
+            pico_frame_discard(f_in);
+            f_in = pico_dequeue(&sock->q_in);
+        }
+
+        if(f_out)
+        {
+            pico_frame_discard(f_out);
+            f_out = pico_dequeue(&sock->q_out);
+        }
+    }
+    pico_queue_deinit(&sock->q_in);
+    pico_queue_deinit(&sock->q_out);
+    pico_socket_tcp_cleanup(sock);
+}
+
+static void socket_garbage_collect(pico_time now, void *arg)
+{
+    struct pico_socket *s = (struct pico_socket *) arg;
+    IGNORE_PARAMETER(now);
+
+    socket_clean_queues(s);
+    PICO_FREE(s);
+}
+
+
+static void pico_socket_check_empty_sockport(struct pico_socket *s, struct pico_sockport *sp)
+{
+    if(pico_tree_empty(&sp->socks)) {
+        if (PROTO(s) == PICO_PROTO_UDP)
+        {
+            pico_tree_delete(&UDPTable, sp);
+        }
+        else if (PROTO(s) == PICO_PROTO_TCP)
+        {
+            pico_tree_delete(&TCPTable, sp);
+        }
+
+        if(sp_tcp == sp)
+            sp_tcp = NULL;
+
+        if(sp_udp == sp)
+            sp_udp = NULL;
+
+        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;
+    }
+
+    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);
+    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;
+    if (more_states & PICO_SOCKET_STATE_BOUND)
+        return pico_socket_add(s);
+
+    if (less_states & PICO_SOCKET_STATE_BOUND)
+        return pico_socket_del(s);
+
+    sp = pico_get_sockport(PROTO(s), s->local_port);
+    if (!sp) {
+        pico_err = PICO_ERR_ENXIO;
+        return -1;
+    }
+
+    s->state |= more_states;
+    s->state = (uint16_t)(s->state & (~less_states));
+    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)
+{
+#ifdef PICO_SUPPORT_TCP
+    if (p->proto_number == PICO_PROTO_TCP)
+        return pico_socket_tcp_deliver(sp, f);
+
+#endif
+
+#ifdef PICO_SUPPORT_UDP
+    if (p->proto_number == PICO_PROTO_UDP)
+        return pico_socket_udp_deliver(sp, f);
+
+#endif
+
+    return -1;
+}
+
+
+static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, uint16_t localport)
+{
+    struct pico_sockport *sp = NULL;
+    struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
+
+    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;
+    }
+
+    return pico_socket_transport_deliver(p, sp, f);
+}
+
+int pico_socket_set_family(struct pico_socket *s, uint16_t family)
+{
+    (void) family;
+
+  #ifdef PICO_SUPPORT_IPV4
+    if (family == PICO_PROTO_IPV4)
+        s->net = &pico_proto_ipv4;
+
+  #endif
+
+  #ifdef PICO_SUPPORT_IPV6
+    if (family == PICO_PROTO_IPV6)
+        s->net = &pico_proto_ipv6;
+
+  #endif
+
+    if (s->net == NULL)
+        return -1;
+
+    return 0;
+}
+
+static struct pico_socket *pico_socket_transport_open(uint16_t proto, uint16_t family)
+{
+    struct pico_socket *s = NULL;
+    (void)family;
+#ifdef PICO_SUPPORT_UDP
+    if (proto == PICO_PROTO_UDP)
+        s = pico_socket_udp_open();
+
+#endif
+
+#ifdef PICO_SUPPORT_TCP
+    if (proto == PICO_PROTO_TCP)
+        s = pico_socket_tcp_open(family);
+
+#endif
+
+    return s;
+
+}
+
+struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *))
+{
+
+    struct pico_socket *s = NULL;
+
+    s = pico_socket_transport_open(proto, net);
+
+    if (!s) {
+        pico_err = PICO_ERR_EPROTONOSUPPORT;
+        return NULL;
+    }
+
+    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;
+    return s;
+}
+
+
+static void pico_socket_clone_assign_address(struct pico_socket *s, struct pico_socket *facsimile)
+{
+
+#ifdef PICO_SUPPORT_IPV4
+    if (facsimile->net == &pico_proto_ipv4) {
+        s->net = &pico_proto_ipv4;
+        memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip4));
+        memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip4));
+    }
+
+#endif
+
+#ifdef PICO_SUPPORT_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
+
+}
+
+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_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)
+    {
+        /* make sure cast to uint16_t doesn't give unexpected results */
+        if(len > 0xFFFF) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+
+        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) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    } else {
+        /* check if exists in tree */
+        /* See task #178 */
+        if (pico_check_socket(s) != 0) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+    }
+
+    if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
+        pico_err = PICO_ERR_EIO;
+        return -1;
+    }
+
+    return pico_socket_transport_read(s, buf, 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;
+    }
+
+    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) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    } else {
+        /* check if exists in tree */
+        /* See task #178 */
+        if (pico_check_socket(s) != 0) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+    }
+
+    return pico_socket_write_attempt(s, buf, len);
+}
+
+static uint16_t pico_socket_high_port(uint16_t proto)
+{
+    uint16_t port;
+    if (0 ||
+#ifdef PICO_SUPPORT_TCP
+        (proto == PICO_PROTO_TCP) ||
+#endif
+#ifdef PICO_SUPPORT_UDP
+        (proto == PICO_PROTO_UDP) ||
+#endif
+        0) {
+        do {
+            uint32_t rand = pico_rand();
+            port = (uint16_t) (rand & 0xFFFFU);
+            port = (uint16_t)((port % (65535 - 1024)) + 1024U);
+            if (pico_is_port_free(proto, port, NULL, NULL)) {
+                return short_be(port);
+            }
+        } while(1);
+    }
+    else return 0U;
+}
+
+static void *pico_socket_sendto_get_ip4_src(struct pico_socket *s, struct pico_ip4 *dst)
+{
+    struct pico_ip4 *src4 = NULL;
+
+#ifdef PICO_SUPPORT_IPV4
+    /* 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
+
+    /* 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) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    if (buf == NULL || s == NULL) {
+        pico_err = PICO_ERR_EINVAL;
+        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;
+    }
+
+    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;
+        }
+
+        s->state |= PICO_SOCKET_STATE_BOUND;
+    }
+
+    return s->local_port;
+}
+
+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);
+
+    #endif
+
+    #ifdef PICO_SUPPORT_UDP
+    if (PROTO(s) == PICO_PROTO_UDP)
+        header_offset = sizeof(struct pico_udp_hdr);
+
+    #endif
+    return header_offset;
+}
+
+
+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 = PICO_IPV4_DONTFRAG;
+#else
+    (void)f;
+#endif
+}
+
+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;
+    }
+}
+
+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_msginfo *msginfo)
+{
+    struct pico_frame *f;
+    uint16_t hdr_offset = (uint16_t)pico_socket_sendto_transport_offset(s);
+    int ret = 0;
+    (void)src;
+
+    f = pico_socket_frame_alloc(s, (uint16_t)(len + hdr_offset));
+    if (!f) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+    }
+
+    f->payload += hdr_offset;
+    f->payload_len = (uint16_t)(len);
+    f->sock = s;
+    transport_flags_update(f, s);
+    pico_xmit_frame_set_nofrag(f);
+    if (ep && !f->info) {
+        f->info = pico_socket_set_info(ep);
+        if (!f->info) {
+            pico_frame_discard(f);
+            return -1;
+        }
+    }
+
+    if (msginfo) {
+        f->send_ttl = (uint8_t)msginfo->ttl;
+        f->send_tos = (uint8_t)msginfo->tos;
+        f->dev = msginfo->dev;
+    }
+
+    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);
+
+#ifdef PICO_SUPPORT_IPFRAG
+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);
+    f->frag = PICO_IPV4_MOREFRAG;
+    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 */
+    f->frag = (uint16_t)((total_payload_written + (uint16_t)hdr_offset) >> 3u);
+    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 |= 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 &= 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, struct pico_msginfo *msginfo)
+{
+    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, msginfo);
+    }
+
+#ifdef PICO_SUPPORT_IPV6
+    /* Can't fragment IPv6 */
+    if (is_sock_ipv6(s)) {
+        return pico_socket_xmit_one(s, buf, space, src, ep, msginfo);
+    }
+
+#endif
+
+#ifdef PICO_SUPPORT_IPFRAG
+    while(total_payload_written < len) {
+        /* Always allocate the max space available: space + offset */
+        if (len < space)
+            space = len;
+
+        if (space > len - total_payload_written)
+            space = len - total_payload_written;
+
+        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;
+            }
+        }
+
+        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, msginfo);
+
+#endif
+}
+
+static void get_sock_dev(struct pico_socket *s)
+{
+    if (0) {}
+
+#ifdef PICO_SUPPORT_IPV6
+    else if (is_sock_ipv6(s))
+        s->dev = pico_ipv6_source_dev_find(&s->remote_addr.ip6);
+#endif
+#ifdef PICO_SUPPORT_IPV4
+    else if (is_sock_ipv4(s))
+        s->dev = pico_ipv4_source_dev_find(&s->remote_addr.ip4);
+#endif
+
+}
+
+
+static uint32_t pico_socket_adapt_mss_to_proto(struct pico_socket *s, uint32_t mss)
+{
+#ifdef PICO_SUPPORT_IPV6
+    if (is_sock_ipv6(s))
+        mss -= PICO_SIZE_IP6HDR;
+    else
+#endif
+    mss -= PICO_SIZE_IP4HDR;
+    return mss;
+}
+
+uint32_t pico_socket_get_mss(struct pico_socket *s)
+{
+    uint32_t mss = PICO_MIN_MSS;
+    if (!s)
+        return mss;
+
+    if (!s->dev)
+        get_sock_dev(s);
+
+    if (!s->dev) {
+        mss = PICO_MIN_MSS;
+    } else {
+        mss = s->dev->mtu;
+    }
+
+    return pico_socket_adapt_mss_to_proto(s, mss);
+}
+
+
+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 = (uint16_t)pico_tcp_get_socket_mss(s);
+    } else
+#endif
+    transport_len = (uint16_t)pico_socket_get_mss(s);
+    header_offset = pico_socket_sendto_transport_offset(s);
+    if (header_offset < 0) {
+        pico_err = PICO_ERR_EPROTONOSUPPORT;
+        return -1;
+    }
+
+    transport_len -= pico_socket_sendto_transport_offset(s);
+    return transport_len;
+}
+
+
+static int pico_socket_xmit(struct pico_socket *s, const void *buf, const int len, void *src,
+                            struct pico_remote_endpoint *ep, struct pico_msginfo *msginfo)
+{
+    int space = pico_socket_xmit_avail_space(s);
+    int total_payload_written = 0;
+
+    if (space < 0) {
+        pico_err = PICO_ERR_EPROTONOSUPPORT;
+        pico_endpoint_free(ep);
+        return -1;
+    }
+
+    if ((PROTO(s) == PICO_PROTO_UDP) && (len > space)) {
+        total_payload_written = pico_socket_xmit_fragments(s, buf, len, src, ep, msginfo);
+        /* Implies ep discarding */
+        return total_payload_written;
+    }
+
+    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, msginfo);
+        if (w <= 0) {
+            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;
+    }
+}
+
+
+int MOCKABLE pico_socket_sendto_extended(struct pico_socket *s, const void *buf, const int len,
+                                         void *dst, uint16_t remote_port, struct pico_msginfo *msginfo)
+{
+    struct pico_remote_endpoint *remote_endpoint = NULL;
+    void *src = NULL;
+
+    if(len == 0)
+        return 0;
+
+    if (pico_socket_sendto_initial_checks(s, buf, len, dst, remote_port) < 0)
+        return -1;
+
+
+    src = pico_socket_sendto_get_src(s, dst);
+    if (!src) {
+#ifdef PICO_SUPPORT_IPV6
+        if((s->net->proto_number == PICO_PROTO_IPV6)
+           && msginfo && msginfo->dev
+           && pico_ipv6_is_linklocal(((struct pico_ip6 *)dst)->addr))
+        {
+            src = &(pico_ipv6_linklocal_get(msginfo->dev)->address);
+            if(!src)
+                return -1;
+        }
+        else
+#endif
+        return -1;
+    }
+
+    remote_endpoint = pico_socket_sendto_destination(s, dst, remote_port);
+    if (pico_socket_sendto_set_localport(s) < 0) {
+        pico_endpoint_free(remote_endpoint);
+        return -1;
+    }
+
+    pico_socket_sendto_set_dport(s, remote_port);
+    return pico_socket_xmit(s, buf, len, src, remote_endpoint, msginfo); /* Implies discarding the endpoint */
+}
+
+int MOCKABLE pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port)
+{
+    return pico_socket_sendto_extended(s, buf, len, dst, remote_port, NULL);
+}
+
+int pico_socket_send(struct pico_socket *s, const void *buf, int len)
+{
+    if (!s || buf == NULL) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    } else {
+        /* check if exists in tree */
+        /* See task #178 */
+        if (pico_check_socket(s) != 0) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+    }
+
+    if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
+        pico_err = PICO_ERR_ENOTCONN;
+        return -1;
+    }
+
+    return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
+}
+
+int pico_socket_recvfrom_extended(struct pico_socket *s, void *buf, int len, void *orig,
+                                  uint16_t *remote_port, struct pico_msginfo *msginfo)
+{
+    if (!s || buf == NULL) { /* / || orig == NULL || remote_port == NULL) { */
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    } else {
+        /* check if exists in tree */
+        if (pico_check_socket(s) != 0) {
+            pico_err = PICO_ERR_EINVAL;
+            /* See task #178 */
+            return -1;
+        }
+    }
+
+    if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
+        pico_err = PICO_ERR_EADDRNOTAVAIL;
+        return -1;
+    }
+
+#ifdef PICO_SUPPORT_UDP
+    if (PROTO(s) == PICO_PROTO_UDP) {
+        /* make sure cast to uint16_t doesn't give unexpected results */
+        if(len > 0xFFFF) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+
+        return pico_udp_recv(s, buf, (uint16_t)len, orig, remote_port, msginfo);
+    }
+
+#endif
+#ifdef PICO_SUPPORT_TCP
+    if (PROTO(s) == PICO_PROTO_TCP) {
+        /* check if in shutdown state and if tcpq_in empty */
+        if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
+            pico_err = PICO_ERR_ESHUTDOWN;
+            return -1;
+        } else {
+            /* dbg("socket tcp recv\n"); */
+            return (int)pico_tcp_read(s, buf, (uint32_t)len);
+        }
+    }
+
+#endif
+    /* dbg("socket return 0\n"); */
+    return 0;
+}
+
+int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig,
+                         uint16_t *remote_port)
+{
+    return pico_socket_recvfrom_extended(s, buf, len, orig, remote_port, NULL);
+
+}
+
+int pico_socket_recv(struct pico_socket *s, void *buf, int len)
+{
+    return pico_socket_recvfrom(s, buf, len, NULL, NULL);
+}
+
+
+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_getpeername(struct pico_socket *s, void *remote_addr, uint16_t *port, uint16_t *proto)
+{
+    if (!s || !remote_addr || !port || !proto) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
+        pico_err = PICO_ERR_ENOTCONN;
+        return -1;
+    }
+
+    if (is_sock_ipv4(s)) {
+    #ifdef PICO_SUPPORT_IPV4
+        struct pico_ip4 *ip = (struct pico_ip4 *)remote_addr;
+        ip->addr = s->remote_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 *)remote_addr;
+        memcpy(ip->addr, s->remote_addr.ip6.addr, PICO_SIZE_IP6);
+        *proto = PICO_PROTO_IPV6;
+    #endif
+    } else {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    *port = s->remote_port;
+    return 0;
+
+}
+
+int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port)
+{
+    if (!s || !local_addr || !port) {
+        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;
+        if (ip->addr != PICO_IPV4_INADDR_ANY) {
+            if (!pico_ipv4_link_find(local_addr)) {
+                pico_err = PICO_ERR_EINVAL;
+                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 {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+
+    /* When given port = 0, get a random high port to bind to. */
+    if (*port == 0) {
+        *port = pico_socket_high_port(PROTO(s));
+        if (*port == 0) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+    }
+
+    if (pico_is_port_free(PROTO(s), *port, local_addr, s->net) == 0) {
+        pico_err = PICO_ERR_EADDRINUSE;
+        return -1;
+    }
+
+    s->local_port = *port;
+
+    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;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    if (!s || remote_addr == NULL || remote_port == 0) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    s->remote_port = remote_port;
+
+    if (s->local_port == 0) {
+        s->local_port = pico_socket_high_port(PROTO(s));
+        if (!s->local_port) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+    }
+
+    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) {
+            get_sock_dev(s);
+            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) {
+            get_sock_dev(s);
+            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);
+
+#ifdef PICO_SUPPORT_UDP
+    if (PROTO(s) == PICO_PROTO_UDP) {
+        pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED, 0, 0);
+        pico_err = PICO_ERR_NOERR;
+        ret = 0;
+    }
+
+#endif
+
+#ifdef PICO_SUPPORT_TCP
+    if (PROTO(s) == PICO_PROTO_TCP) {
+        if (pico_tcp_initconn(s) == 0) {
+            pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, PICO_SOCKET_STATE_CLOSED, 0);
+            pico_err = PICO_ERR_NOERR;
+            ret = 0;
+        } else {
+            pico_err = PICO_ERR_EHOSTUNREACH;
+        }
+    }
+
+#endif
+
+    return ret;
+}
+
+
+#ifdef PICO_SUPPORT_TCP
+
+int pico_socket_listen(struct pico_socket *s, int backlog)
+{
+    if (!s || backlog < 1) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    } else {
+        /* check if exists in tree */
+        /* See task #178 */
+        if (pico_check_socket(s) != 0) {
+            pico_err = PICO_ERR_EINVAL;
+            return -1;
+        }
+    }
+
+    if (PROTO(s) == PICO_PROTO_UDP) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
+        pico_err = PICO_ERR_EISCONN;
+        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 = (uint16_t)backlog;
+
+    return 0;
+}
+
+struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port)
+{
+    if (!s || !orig || !port) {
+        pico_err = PICO_ERR_EINVAL;
+        return NULL;
+    }
+
+    pico_err = PICO_ERR_EINVAL;
+
+    if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
+        return NULL;
+    }
+
+    if (PROTO(s) == PICO_PROTO_UDP) {
+        return NULL;
+    }
+
+    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.
+         */
+        pico_err = PICO_ERR_EAGAIN;
+        if (sp) {
+            struct pico_tree_node *index;
+            /* RB_FOREACH(found, socket_tree, &sp->socks) { */
+            pico_tree_foreach(index, &sp->socks){
+                found = index->keyValue;
+                if ((s == found->parent) && ((found->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) {
+                    found->parent = NULL;
+                    pico_err = PICO_ERR_NOERR;
+                    #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;
+                }
+            }
+        }
+    }
+
+    return NULL;
+}
+
+#else
+
+int pico_socket_listen(struct pico_socket *s, int backlog)
+{
+    IGNORE_PARAMETER(s);
+    IGNORE_PARAMETER(backlog);
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+}
+
+struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *local_port)
+{
+    IGNORE_PARAMETER(s);
+    IGNORE_PARAMETER(orig);
+    IGNORE_PARAMETER(local_port);
+    pico_err = PICO_ERR_EINVAL;
+    return NULL;
+}
+
+#endif
+
+
+int pico_socket_setoption(struct pico_socket *s, int option, void *value)
+{
+
+    if (s == NULL) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+
+    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);
+
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+
+int pico_socket_getoption(struct pico_socket *s, int option, void *value)
+{
+    if (s == NULL) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+
+    if (PROTO(s) == PICO_PROTO_TCP)
+        return pico_getsockopt_tcp(s, option, value);
+
+    if (PROTO(s) == PICO_PROTO_UDP)
+        return pico_getsockopt_udp(s, option, value);
+
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    return -1;
+}
+
+
+int pico_socket_shutdown(struct pico_socket *s, int mode)
+{
+    if (!s) {
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+    }
+
+    /* 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
+    if (PROTO(s) == PICO_PROTO_UDP) {
+        if ((mode & PICO_SHUT_RDWR) == PICO_SHUT_RDWR)
+            pico_socket_alter_state(s, PICO_SOCKET_STATE_CLOSED, PICO_SOCKET_STATE_CLOSING | PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED, 0);
+        else if (mode & PICO_SHUT_RD)
+            pico_socket_alter_state(s, 0, PICO_SOCKET_STATE_BOUND, 0);
+    }
+
+#endif
+#ifdef PICO_SUPPORT_TCP
+    if (PROTO(s) == PICO_PROTO_TCP) {
+        if ((mode & PICO_SHUT_RDWR) == PICO_SHUT_RDWR)
+        {
+            pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
+            pico_tcp_notify_closing(s);
+        }
+        else if (mode & PICO_SHUT_WR)
+            pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL, 0, 0);
+        else if (mode & PICO_SHUT_RD)
+            pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
+
+    }
+
+#endif
+    return 0;
+}
+
+int MOCKABLE 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);
+}
+
+#ifdef PICO_SUPPORT_CRC
+static inline int pico_transport_crc_check(struct pico_frame *f)
+{
+    struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+    struct pico_udp_hdr *udp_hdr = NULL;
+    uint16_t checksum_invalid = 1;
+
+    switch (net_hdr->proto)
+    {
+#ifdef PICO_SUPPORT_TCP
+    case PICO_PROTO_TCP:
+        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");
+            pico_frame_discard(f);
+            return 0;
+        }
+
+        break;
+#endif /* PICO_SUPPORT_TCP */
+
+#ifdef PICO_SUPPORT_UDP
+    case PICO_PROTO_UDP:
+        udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
+        if (short_be(udp_hdr->crc)) {
+#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"); */
+                pico_frame_discard(f);
+                return 0;
+            }
+        }
+
+        break;
+#endif /* PICO_SUPPORT_UDP */
+
+    default:
+        /* Do nothing */
+        break;
+    }
+    return 1;
+}
+#else
+static inline int pico_transport_crc_check(struct pico_frame *f)
+{
+    IGNORE_PARAMETER(f);
+    return 1;
+}
+#endif /* PICO_SUPPORT_CRC */
+
+int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f)
+{
+    struct pico_trans *hdr = (struct pico_trans *) f->transport_hdr;
+    int ret = 0;
+
+    if (!hdr) {
+        pico_err = PICO_ERR_EFAULT;
+        return -1;
+    }
+
+    ret = pico_transport_crc_check(f);
+    if (ret < 1)
+        return ret;
+    else
+        ret = 0;
+
+    if ((hdr) && (pico_socket_deliver(self, f, hdr->dport) == 0))
+        return ret;
+
+    if (!IS_BCAST(f)) {
+        dbg("Socket not found... \n");
+        pico_notify_socket_unreachable(f);
+        ret = -1;
+        pico_err = PICO_ERR_ENOENT;
+    }
+
+    pico_frame_discard(f);
+    return ret;
+}
+
+#define SL_LOOP_MIN 1
+
+#ifdef PICO_SUPPORT_TCP
+static int checkSocketSanity(struct pico_socket *s)
+{
+
+    /* checking for pending connections */
+    if(TCP_STATE(s) == PICO_SOCKET_STATE_TCP_SYN_RECV) {
+        if((PICO_TIME_MS() - s->timestamp) >= PICO_SOCKET_BOUND_TIMEOUT)
+            return -1;
+    }
+
+    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;
+    }
+
+    return 0;
+}
+#endif
+
+
+static int pico_sockets_loop_udp(int loop_score)
+{
+
+#ifdef PICO_SUPPORT_UDP
+    static struct pico_tree_node *index_udp;
+    struct pico_sockport *start;
+    struct pico_socket *s;
+    struct pico_frame *f;
+
+    if (sp_udp == NULL)
+    {
+        index_udp = pico_tree_firstNode(UDPTable.root);
+        sp_udp = index_udp->keyValue;
+    }
+
+    /* init start node */
+    start = sp_udp;
+
+    /* round-robin all transport protocols, break if traversed all protocols */
+    while (loop_score > SL_LOOP_MIN && sp_udp != NULL) {
+        struct pico_tree_node *index;
+
+        pico_tree_foreach(index, &sp_udp->socks){
+            s = index->keyValue;
+            f = pico_dequeue(&s->q_out);
+            while (f && (loop_score > 0)) {
+                pico_proto_udp.push(&pico_proto_udp, f);
+                loop_score -= 1;
+                f = pico_dequeue(&s->q_out);
+            }
+        }
+
+        index_udp = pico_tree_next(index_udp);
+        sp_udp = index_udp->keyValue;
+
+        if (sp_udp == NULL)
+        {
+            index_udp = pico_tree_firstNode(UDPTable.root);
+            sp_udp = index_udp->keyValue;
+        }
+
+        if (sp_udp == start)
+            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);
+        sp_tcp = index_tcp->keyValue;
+    }
+
+    /* init start node */
+    start = sp_tcp;
+
+    while (loop_score > SL_LOOP_MIN && sp_tcp != NULL) {
+        struct pico_tree_node *index = NULL, *safe_index = NULL;
+        pico_tree_foreach_safe(index, &sp_tcp->socks, safe_index){
+            s = index->keyValue;
+            loop_score = pico_tcp_output(s, loop_score);
+            if ((s->ev_pending) && s->wakeup) {
+                s->wakeup(s->ev_pending, s);
+                if(!s->parent)
+                    s->ev_pending = 0;
+            }
+
+            if (loop_score <= 0) {
+                loop_score = 0;
+                break;
+            }
+
+            if(checkSocketSanity(s) < 0)
+            {
+                pico_socket_del(s);
+                index_tcp = NULL; /* forcing the restart of loop */
+                sp_tcp = NULL;
+                break;
+            }
+        }
+
+        /* check if RB_FOREACH ended, if not, break to keep the cur sp_tcp */
+        if (!index_tcp || (index && index->keyValue))
+            break;
+
+        index_tcp = pico_tree_next(index_tcp);
+        sp_tcp = index_tcp->keyValue;
+
+        if (sp_tcp == NULL)
+        {
+            index_tcp = pico_tree_firstNode(TCPTable.root);
+            sp_tcp = index_tcp->keyValue;
+        }
+
+        if (sp_tcp == start)
+            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;
+}
+
+int pico_count_sockets(uint8_t proto)
+{
+    struct pico_sockport *sp;
+    struct pico_tree_node *idx_sp, *idx_s;
+    int count = 0;
+
+    if ((proto == 0) || (proto == PICO_PROTO_TCP)) {
+        pico_tree_foreach(idx_sp, &TCPTable) {
+            sp = idx_sp->keyValue;
+            if (sp) {
+                pico_tree_foreach(idx_s, &sp->socks)
+                count++;
+            }
+        }
+    }
+
+    if ((proto == 0) || (proto == PICO_PROTO_UDP)) {
+        pico_tree_foreach(idx_sp, &UDPTable) {
+            sp = idx_sp->keyValue;
+            if (sp) {
+                pico_tree_foreach(idx_s, &sp->socks)
+                count++;
+            }
+        }
+    }
+
+    return count;
+}
+
+
+struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len)
+{
+    struct pico_frame *f = NULL;
+
+#ifdef PICO_SUPPORT_IPV6
+    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, len);
+
+#endif
+    if (!f) {
+        pico_err = PICO_ERR_ENOMEM;
+        return f;
+    }
+
+    f->payload = f->transport_hdr;
+    f->payload_len = len;
+    f->sock = s;
+    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;
+    struct pico_trans *trans = (struct pico_trans*) f->transport_hdr;
+    struct pico_sockport *port = NULL;
+    struct pico_socket *s = NULL;
+    switch (proto) {
+
+
+#ifdef PICO_SUPPORT_UDP
+    case PICO_PROTO_UDP:
+        port = pico_get_sockport(proto, trans->sport);
+        break;
+#endif
+
+#ifdef PICO_SUPPORT_TCP
+    case PICO_PROTO_TCP:
+        port = pico_get_sockport(proto, trans->sport);
+        break;
+#endif
+
+    default:
+        /* Protocol not available */
+        ret = -1;
+    }
+    if (port) {
+        struct pico_tree_node *index;
+        ret = 0;
+
+        pico_tree_foreach(index, &port->socks) {
+            s = index->keyValue;
+            if (trans->dport == s->remote_port) {
+                if (s->wakeup) {
+                    pico_transport_error_set_picoerr(code);
+                    s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
+                    s->wakeup(PICO_SOCK_EV_ERR, s);
+                }
+
+                break;
+            }
+        }
+    }
+
+    pico_frame_discard(f);
+    return ret;
+}
+#endif
+#endif
diff --git a/net/picotcp/stack/pico_socket_multicast.c b/net/picotcp/stack/pico_socket_multicast.c
new file mode 100644
index 0000000..f23327d
--- /dev/null
+++ b/net/picotcp/stack/pico_socket_multicast.c
@@ -0,0 +1,956 @@
+#include "pico_config.h"
+#include "pico_stack.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;
+    uint16_t proto;
+};
+
+static int mcast_listen_link_cmp(struct pico_mcast_listen *a, struct pico_mcast_listen *b)
+{
+
+    if (a->proto < b->proto)
+        return -1;
+
+    if (a->proto > b->proto)
+        return 1;
+
+    return pico_address_compare(&a->mcast_link, &b->mcast_link, a->proto);
+}
+
+static int mcast_listen_grp_cmp(struct pico_mcast_listen *a, struct pico_mcast_listen *b)
+{
+    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_listen_cmp(void *ka, void *kb)
+{
+    struct pico_mcast_listen *a = ka, *b = kb;
+    if (a->proto < b->proto)
+        return -1;
+
+    if (a->proto > b->proto)
+        return 1;
+
+    return mcast_listen_grp_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;
+
+    if (!s->local_addr.ip4.addr)
+        return pico_ipv4_get_default_mcastlink();
+
+    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;
+        listen->proto = s->net->proto_number;
+        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_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);
+        }
+    }
+
+    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);
+            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 */
+
diff --git a/net/picotcp/stack/pico_stack.c b/net/picotcp/stack/pico_stack.c
new file mode 100644
index 0000000..b4fcdd6
--- /dev/null
+++ b/net/picotcp/stack/pico_stack.c
@@ -0,0 +1,1157 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   .
+
+   Authors: Daniele Lacamera
+ *********************************************************************/
+
+
+#include "pico_config.h"
+#include "pico_frame.h"
+#include "pico_device.h"
+#include "pico_protocol.h"
+#include "pico_stack.h"
+#include "pico_addressing.h"
+#include "pico_dns_client.h"
+
+#include "pico_olsr.h"
+#include "pico_aodv.h"
+#include "pico_eth.h"
+#include "pico_arp.h"
+#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"
+#include "pico_socket.h"
+#include "heap.h"
+
+#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;
+
+static uint32_t _rand_seed;
+
+void WEAK pico_rand_feed(uint32_t feed)
+{
+    if (!feed)
+        return;
+
+    _rand_seed *= 1664525;
+    _rand_seed += 1013904223;
+    _rand_seed ^= ~(feed);
+}
+
+uint32_t WEAK pico_rand(void)
+{
+    pico_rand_feed((uint32_t)pico_tick);
+    return _rand_seed;
+}
+
+void pico_to_lowercase(char *str)
+{
+    int i = 0;
+    if (!str)
+        return;
+
+    while(str[i]) {
+        if ((str[i] <= 'Z') && (str[i] >= 'A'))
+            str[i] = (char) (str[i] - (char)('A' - 'a'));
+
+        i++;
+    }
+}
+
+/* NOTIFICATIONS: distributed notifications for stack internal errors.
+ */
+
+int pico_notify_socket_unreachable(struct pico_frame *f)
+{
+    if (0) {}
+
+#ifdef PICO_SUPPORT_ICMP4
+    else if (IS_IPV4(f)) {
+        pico_icmp4_port_unreachable(f);
+    }
+#endif
+#ifdef PICO_SUPPORT_ICMP6
+    else if (IS_IPV6(f)) {
+        pico_icmp6_port_unreachable(f);
+    }
+#endif
+
+    return 0;
+}
+
+int pico_notify_proto_unreachable(struct pico_frame *f)
+{
+    if (0) {}
+
+#ifdef PICO_SUPPORT_ICMP4
+    else if (IS_IPV4(f)) {
+        pico_icmp4_proto_unreachable(f);
+    }
+#endif
+#ifdef PICO_SUPPORT_ICMP6
+    else if (IS_IPV6(f)) {
+        pico_icmp6_proto_unreachable(f);
+    }
+#endif
+    return 0;
+}
+
+int pico_notify_dest_unreachable(struct pico_frame *f)
+{
+    if (0) {}
+
+#ifdef PICO_SUPPORT_ICMP4
+    else if (IS_IPV4(f)) {
+        pico_icmp4_dest_unreachable(f);
+    }
+#endif
+#ifdef PICO_SUPPORT_ICMP6
+    else if (IS_IPV6(f)) {
+        pico_icmp6_dest_unreachable(f);
+    }
+#endif
+    return 0;
+}
+
+int pico_notify_ttl_expired(struct pico_frame *f)
+{
+    if (0) {}
+
+#ifdef PICO_SUPPORT_ICMP4
+    else if (IS_IPV4(f)) {
+        pico_icmp4_ttl_expired(f);
+    }
+#endif
+#ifdef PICO_SUPPORT_ICMP6
+    else if (IS_IPV6(f)) {
+        pico_icmp6_ttl_expired(f);
+    }
+#endif
+    return 0;
+}
+
+int pico_notify_frag_expired(struct pico_frame *f)
+{
+    if (0) {}
+
+#ifdef PICO_SUPPORT_ICMP4
+    else if (IS_IPV4(f)) {
+        pico_icmp4_frag_expired(f);
+    }
+#endif
+#ifdef PICO_SUPPORT_ICMP6
+    else if (IS_IPV6(f)) {
+        pico_icmp6_frag_expired(f);
+    }
+#endif
+    return 0;
+}
+
+int pico_notify_pkt_too_big(struct pico_frame *f)
+{
+    if (0) {}
+
+#ifdef PICO_SUPPORT_ICMP4
+    else if (IS_IPV4(f)) {
+        pico_icmp4_mtu_exceeded(f);
+    }
+#endif
+#ifdef PICO_SUPPORT_ICMP6
+    else if (IS_IPV6(f)) {
+        pico_icmp6_pkt_too_big(f);
+    }
+#endif
+    return 0;
+}
+
+
+/* Transport layer */
+MOCKABLE int32_t pico_transport_receive(struct pico_frame *f, uint8_t proto)
+{
+    int32_t ret = -1;
+    switch (proto) {
+
+#ifdef PICO_SUPPORT_ICMP4
+    case PICO_PROTO_ICMP4:
+        ret = pico_enqueue(pico_proto_icmp4.q_in, f);
+        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);
+        break;
+#endif
+
+#ifdef PICO_SUPPORT_UDP
+    case PICO_PROTO_UDP:
+        ret = pico_enqueue(pico_proto_udp.q_in, f);
+        break;
+#endif
+
+#ifdef PICO_SUPPORT_TCP
+    case PICO_PROTO_TCP:
+        ret = pico_enqueue(pico_proto_tcp.q_in, f);
+        break;
+#endif
+
+    default:
+        /* Protocol not available */
+        dbg("pkt: no such protocol (%d)\n", proto);
+        pico_notify_proto_unreachable(f);
+        pico_frame_discard(f);
+        ret = -1;
+    }
+    return ret;
+}
+
+int32_t pico_network_receive(struct pico_frame *f)
+{
+    if (0) {}
+
+#ifdef PICO_SUPPORT_IPV4
+    else if (IS_IPV4(f)) {
+        pico_enqueue(pico_proto_ipv4.q_in, f);
+    }
+#endif
+#ifdef PICO_SUPPORT_IPV6
+    else if (IS_IPV6(f)) {
+        pico_enqueue(pico_proto_ipv6.q_in, f);
+    }
+#endif
+    else {
+        dbg("Network not found.\n");
+        pico_frame_discard(f);
+        return -1;
+    }
+    return (int32_t)f->buffer_len;
+}
+
+/* Network layer: interface towards socket for frame sending */
+int32_t pico_network_send(struct pico_frame *f)
+{
+    if (!f || !f->sock || !f->sock->net) {
+        pico_frame_discard(f);
+        return -1;
+    }
+
+    return f->sock->net->push(f->sock->net, f);
+}
+
+int pico_source_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 (hdr->src.addr == PICO_IPV4_INADDR_ANY)
+            return 1;
+
+        if (pico_ipv4_link_find(&hdr->src))
+            return 1;
+    }
+#endif
+#ifdef PICO_SUPPORT_IPV6
+    else if (IS_IPV6(f)) {
+        struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
+        if (pico_ipv6_is_unspecified(hdr->src.addr) || pico_ipv6_link_find(&hdr->src))
+            return 1;
+    }
+#endif
+    return 0;
+}
+
+#ifdef PICO_SUPPORT_ETH
+/* DATALINK LEVEL: interface from network to the device
+ * and vice versa.
+ */
+
+/* The pico_ethernet_receive() function is used by
+ * those devices supporting ETH in order to push packets up
+ * into the stack.
+ */
+
+static int destination_is_bcast(struct pico_frame *f)
+{
+    if (!f)
+        return 0;
+
+    if (IS_IPV6(f))
+        return 0;
+
+#ifdef PICO_SUPPORT_IPV4
+    else {
+        struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+        return pico_ipv4_is_broadcast(hdr->dst.addr);
+    }
+#else
+    return 0;
+#endif
+}
+
+static int destination_is_mcast(struct pico_frame *f)
+{
+    int ret = 0;
+    if (!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;
+        ret = pico_ipv4_is_multicast(hdr->dst.addr);
+    }
+#endif
+
+    return ret;
+}
+
+#ifdef PICO_SUPPORT_IPV4
+static int32_t pico_ipv4_ethernet_receive(struct pico_frame *f)
+{
+    if (IS_IPV4(f)) {
+        pico_enqueue(pico_proto_ipv4.q_in, f);
+    } else {
+        (void)pico_icmp4_param_problem(f, 0);
+        pico_frame_discard(f);
+        return -1;
+    }
+
+    return (int32_t)f->buffer_len;
+}
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+static int32_t pico_ipv6_ethernet_receive(struct pico_frame *f)
+{
+    if (IS_IPV6(f)) {
+        pico_enqueue(pico_proto_ipv6.q_in, f);
+    } else {
+        /* Wrong version for link layer type */
+        pico_frame_discard(f);
+        return -1;
+    }
+
+    return (int32_t)f->buffer_len;
+}
+#endif
+
+static int32_t pico_ll_receive(struct pico_frame *f)
+{
+    struct pico_eth_hdr *hdr = (struct pico_eth_hdr *) f->datalink_hdr;
+    f->net_hdr = f->datalink_hdr + sizeof(struct pico_eth_hdr);
+
+#if (defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_ETH)
+    if (hdr->proto == PICO_IDETH_ARP)
+        return pico_arp_receive(f);
+
+#endif
+
+#if defined (PICO_SUPPORT_IPV4)
+    if (hdr->proto == PICO_IDETH_IPV4)
+        return pico_ipv4_ethernet_receive(f);
+
+#endif
+
+#if defined (PICO_SUPPORT_IPV6)
+    if (hdr->proto == PICO_IDETH_IPV6)
+        return pico_ipv6_ethernet_receive(f);
+
+#endif
+
+    pico_frame_discard(f);
+    return -1;
+}
+
+static void pico_ll_check_bcast(struct pico_frame *f)
+{
+    struct pico_eth_hdr *hdr = (struct pico_eth_hdr *) f->datalink_hdr;
+    /* Indicate a link layer broadcast packet */
+    if (memcmp(hdr->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH) == 0)
+        f->flags |= PICO_FRAME_FLAG_BCAST;
+}
+
+int32_t pico_ethernet_receive(struct pico_frame *f)
+{
+    struct pico_eth_hdr *hdr;
+    if (!f || !f->dev || !f->datalink_hdr)
+    {
+        pico_frame_discard(f);
+        return -1;
+    }
+
+    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);
+        return -1;
+    }
+
+    pico_ll_check_bcast(f);
+    return pico_ll_receive(f);
+}
+
+static struct pico_eth *pico_ethernet_mcast_translate(struct pico_frame *f, uint8_t *pico_mcast_mac)
+{
+    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) & 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;
+
+    /* 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
+
+static int pico_ethernet_ipv6_dst(struct pico_frame *f, struct pico_eth *const dstmac)
+{
+    int retval = -1;
+    if (!dstmac)
+        return -1;
+
+    #ifdef PICO_SUPPORT_IPV6
+    if (destination_is_mcast(f)) {
+        uint8_t pico_mcast6_mac[6] = {
+            0x33, 0x33, 0x00, 0x00, 0x00, 0x00
+        };
+        pico_ethernet_mcast6_translate(f, pico_mcast6_mac);
+        memcpy(dstmac, pico_mcast6_mac, PICO_SIZE_ETH);
+        retval = 0;
+    } else {
+        struct pico_eth *neighbor = pico_ipv6_get_neighbor(f);
+        if (neighbor)
+        {
+            memcpy(dstmac, neighbor, PICO_SIZE_ETH);
+            retval = 0;
+        }
+    }
+
+    #else
+    (void)f;
+    pico_err = PICO_ERR_EPROTONOSUPPORT;
+    #endif
+    return retval;
+}
+
+
+/* Ethernet send, first attempt: try our own address.
+ * Returns 0 if the packet is not for us.
+ * Returns 1 if the packet is cloned to our own receive queue, so the caller can discard the original frame.
+ * */
+static int32_t pico_ethsend_local(struct pico_frame *f, struct pico_eth_hdr *hdr)
+{
+    if (!hdr)
+        return 0;
+
+    /* Check own mac */
+    if(!memcmp(hdr->daddr, hdr->saddr, PICO_SIZE_ETH)) {
+        struct pico_frame *clone = pico_frame_copy(f);
+        dbg("sending out packet destined for our own mac\n");
+        (void)pico_ethernet_receive(clone);
+        return 1;
+    }
+
+    return 0;
+}
+
+/* Ethernet send, second attempt: try bcast.
+ * Returns 0 if the packet is not bcast, so it will be handled somewhere else.
+ * Returns 1 if the packet is handled by the pico_device_broadcast() function, so it can be discarded.
+ * */
+static int32_t pico_ethsend_bcast(struct pico_frame *f)
+{
+    if (IS_LIMITED_BCAST(f)) {
+        (void)pico_device_broadcast(f); /* We can discard broadcast even if it's not sent. */
+        return 1;
+    }
+
+    return 0;
+}
+
+/* Ethernet send, third attempt: try unicast.
+ * If the device driver is busy, we return 0, so the stack won't discard the frame.
+ * In case of success, we can safely return 1.
+ */
+static int32_t pico_ethsend_dispatch(struct pico_frame *f)
+{
+    int ret = f->dev->send(f->dev, f->start, (int) f->len);
+    if (ret <= 0)
+        return 0; /* Failure to deliver! */
+    else {
+        return 1; /* Frame is in flight by now. */
+    }
+}
+
+
+
+
+/* This function looks for the destination mac address
+ * in order to send the frame being processed.
+ */
+
+int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f)
+{
+    struct pico_eth dstmac;
+    uint8_t dstmac_valid = 0;
+    uint16_t proto = PICO_IDETH_IPV4;
+
+#ifdef PICO_SUPPORT_IPV6
+    /* Step 1: If the frame has an IPv6 packet,
+     * destination address is taken from the ND tables
+     */
+    if (IS_IPV6(f)) {
+        if (pico_ethernet_ipv6_dst(f, &dstmac) < 0)
+        {
+            pico_ipv6_nd_postpone(f);
+            return 0; /* I don't care if frame was actually postponed. If there is no room in the ND table, discard safely. */
+        }
+
+        dstmac_valid = 1;
+        proto = PICO_IDETH_IPV6;
+    }
+    else
+#endif
+
+    /* In case of broadcast (IPV4 only), dst mac is FF:FF:... */
+    if (IS_BCAST(f) || destination_is_bcast(f))
+    {
+        memcpy(&dstmac, PICO_ETHADDR_ALL, PICO_SIZE_ETH);
+        dstmac_valid = 1;
+    }
+
+    /* In case of multicast, dst mac is translated from the group address */
+    else if (destination_is_mcast(f)) {
+        uint8_t pico_mcast_mac[6] = {
+            0x01, 0x00, 0x5e, 0x00, 0x00, 0x00
+        };
+        pico_ethernet_mcast_translate(f, pico_mcast_mac);
+        memcpy(&dstmac, pico_mcast_mac, PICO_SIZE_ETH);
+        dstmac_valid = 1;
+    }
+
+#if (defined PICO_SUPPORT_IPV4)
+    else {
+        struct pico_eth *arp_get;
+        arp_get = pico_arp_get(f);
+        if (arp_get) {
+            memcpy(&dstmac, arp_get, PICO_SIZE_ETH);
+            dstmac_valid = 1;
+        } else {
+            /* At this point, ARP will discard the frame in any case.
+             * It is safe to return without discarding.
+             */
+            pico_arp_postpone(f);
+            return 0;
+            /* Same case as for IPv6 ... */
+        }
+
+    }
+#endif
+
+    /* This sets destination and source address, then pushes the packet to the device. */
+    if (dstmac_valid) {
+        struct pico_eth_hdr *hdr;
+        hdr = (struct pico_eth_hdr *) f->datalink_hdr;
+        if ((f->start > f->buffer) && ((f->start - f->buffer) >= PICO_SIZE_ETHHDR))
+        {
+            f->start -= PICO_SIZE_ETHHDR;
+            f->len += PICO_SIZE_ETHHDR;
+            f->datalink_hdr = f->start;
+            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 = proto;
+        }
+
+        if (pico_ethsend_local(f, hdr) || pico_ethsend_bcast(f) || pico_ethsend_dispatch(f)) {
+            /* one of the above functions has delivered the frame accordingly. (returned != 0)
+             * It is safe to directly return success.
+             * */
+            return 0;
+        }
+    }
+
+    /* Failure: do not dequeue the frame, keep it for later. */
+    return -1;
+}
+
+#endif /* PICO_SUPPORT_ETH */
+
+
+void pico_store_network_origin(void *src, struct pico_frame *f)
+{
+  #ifdef PICO_SUPPORT_IPV4
+    struct pico_ip4 *ip4;
+  #endif
+
+  #ifdef PICO_SUPPORT_IPV6
+    struct pico_ip6 *ip6;
+  #endif
+
+  #ifdef PICO_SUPPORT_IPV4
+    if (IS_IPV4(f)) {
+        struct pico_ipv4_hdr *hdr;
+        hdr = (struct pico_ipv4_hdr *) f->net_hdr;
+        ip4 = (struct pico_ip4 *) src;
+        ip4->addr = hdr->src.addr;
+    }
+
+  #endif
+  #ifdef PICO_SUPPORT_IPV6
+    if (IS_IPV6(f)) {
+        struct pico_ipv6_hdr *hdr;
+        hdr = (struct pico_ipv6_hdr *) f->net_hdr;
+        ip6 = (struct pico_ip6 *) src;
+        memcpy(ip6->addr, hdr->src.addr, PICO_SIZE_IP6);
+    }
+
+  #endif
+}
+
+int pico_address_compare(union pico_address *a, union pico_address *b, uint16_t proto)
+{
+    #ifdef PICO_SUPPORT_IPV6
+    if (proto == PICO_PROTO_IPV6) {
+        return pico_ipv6_compare(&a->ip6, &b->ip6);
+    }
+
+    #endif
+    #ifdef PICO_SUPPORT_IPV4
+    if (proto == PICO_PROTO_IPV4) {
+        return pico_ipv4_compare(&a->ip4, &b->ip4);
+    }
+
+    #endif
+    return 0;
+
+}
+
+int pico_frame_dst_is_unicast(struct pico_frame *f)
+{
+    if (0) {
+        return 0;
+    }
+
+#ifdef PICO_SUPPORT_IPV4
+    if (IS_IPV4(f)) {
+        struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr;
+        if (pico_ipv4_is_multicast(hdr->dst.addr) || pico_ipv4_is_broadcast(hdr->dst.addr))
+            return 0;
+
+        return 1;
+    }
+
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+    if (IS_IPV6(f)) {
+        struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
+        if (pico_ipv6_is_multicast(hdr->dst.addr) || pico_ipv6_is_unspecified(hdr->dst.addr))
+            return 0;
+
+        return 1;
+    }
+
+#endif
+    else return 0;
+}
+
+
+/* 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.
+ */
+int32_t pico_stack_recv(struct pico_device *dev, uint8_t *buffer, uint32_t len)
+{
+    struct pico_frame *f;
+    int32_t ret;
+    if (len <= 0)
+        return -1;
+
+    f = pico_frame_alloc(len);
+    if (!f)
+    {
+        dbg("Cannot alloc incoming frame!\n");
+        return -1;
+    }
+
+    /* Association to the device that just received the frame. */
+    f->dev = dev;
+
+    /* Setup the start pointer, length. */
+    f->start = f->buffer;
+    f->len = f->buffer_len;
+    if (f->len > 8) {
+        uint32_t rand, mid_frame = (f->buffer_len >> 2) << 1;
+        mid_frame -= (mid_frame % 4);
+        memcpy(&rand, f->buffer + mid_frame, sizeof(uint32_t));
+        pico_rand_feed(rand);
+    }
+
+    memcpy(f->buffer, buffer, len);
+    ret = pico_enqueue(dev->q_in, f);
+    if (ret <= 0) {
+        pico_frame_discard(f);
+    }
+
+    return ret;
+}
+
+static int32_t _pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len, int ext_buffer, void (*notify_free)(uint8_t *))
+{
+    struct pico_frame *f;
+    int ret;
+    if (len <= 0)
+        return -1;
+
+    f = pico_frame_alloc_skeleton(len, ext_buffer);
+    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;
+    }
+
+    if (notify_free) {
+        f->notify_free = notify_free;
+    }
+
+    f->dev = dev;
+    ret = pico_enqueue(dev->q_in, f);
+    if (ret <= 0) {
+        pico_frame_discard(f);
+    }
+
+    return ret;
+}
+
+int32_t pico_stack_recv_zerocopy(struct pico_device *dev, uint8_t *buffer, uint32_t len)
+{
+    return _pico_stack_recv_zerocopy(dev, buffer, len, 0, NULL);
+}
+
+int32_t pico_stack_recv_zerocopy_ext_buffer(struct pico_device *dev, uint8_t *buffer, uint32_t len)
+{
+    return _pico_stack_recv_zerocopy(dev, buffer, len, 1, NULL);
+}
+
+int32_t pico_stack_recv_zerocopy_ext_buffer_notify(struct pico_device *dev, uint8_t *buffer, uint32_t len, void (*notify_free)(uint8_t *buffer))
+{
+    return _pico_stack_recv_zerocopy(dev, buffer, len, 1, notify_free);
+}
+
+int32_t pico_sendto_dev(struct pico_frame *f)
+{
+    if (!f->dev) {
+        pico_frame_discard(f);
+        return -1;
+    } else {
+        if (f->len > 8) {
+            uint32_t rand, mid_frame = (f->buffer_len >> 2) << 1;
+            mid_frame -= (mid_frame % 4);
+            memcpy(&rand, f->buffer + mid_frame, sizeof(uint32_t));
+            pico_rand_feed(rand);
+        }
+
+        return pico_enqueue(f->dev->q_out, f);
+    }
+}
+
+struct pico_timer
+{
+    void *arg;
+    void (*timer)(pico_time timestamp, void *arg);
+};
+
+struct pico_timer_ref
+{
+    pico_time expire;
+    struct pico_timer *tmr;
+};
+
+typedef struct pico_timer_ref pico_timer_ref;
+
+DECLARE_HEAP(pico_timer_ref, expire);
+
+static heap_pico_timer_ref *Timers;
+
+int32_t pico_seq_compare(uint32_t a, uint32_t b)
+{
+    uint32_t thresh = ((uint32_t)(-1)) >> 1;
+
+    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;
+}
+
+static void pico_check_timers(void)
+{
+    struct pico_timer *t;
+    struct pico_timer_ref tref_unused, *tref = heap_first(Timers);
+    pico_tick = PICO_TIME_MS();
+    while((tref) && (tref->expire < pico_tick)) {
+        t = tref->tmr;
+        if (t && t->timer)
+            t->timer(pico_tick, t->arg);
+
+        if (t)
+        {
+            PICO_FREE(t);
+        }
+
+        t = NULL;
+        heap_peek(Timers, &tref_unused);
+        tref = heap_first(Timers);
+    }
+}
+
+void MOCKABLE pico_timer_cancel(struct pico_timer *t)
+{
+    uint32_t i;
+    struct pico_timer_ref *tref = Timers->top;
+    if (!t)
+        return;
+
+    for (i = 1; i <= Timers->n; i++) {
+        if (tref[i].tmr == t) {
+            Timers->top[i].tmr = NULL;
+            PICO_FREE(t);
+            break;
+        }
+    }
+}
+
+#define PROTO_DEF_NR      11
+#define PROTO_DEF_AVG_NR  4
+#define PROTO_DEF_SCORE   32
+#define PROTO_MIN_SCORE   32
+#define PROTO_MAX_SCORE   128
+#define PROTO_LAT_IND     3   /* latency indication 0-3 (lower is better latency performance), x1, x2, x4, x8 */
+#define PROTO_MAX_LOOP    (PROTO_MAX_SCORE << PROTO_LAT_IND) /* max global loop score, so per tick */
+
+static int calc_score(int *score, int *index, int avg[][PROTO_DEF_AVG_NR], int *ret)
+{
+    int temp, i, j, sum;
+    int max_total = PROTO_MAX_LOOP, total = 0;
+
+    /* dbg("USED SCORES> "); */
+
+    for (i = 0; i < PROTO_DEF_NR; i++) {
+
+        /* if used looped score */
+        if (ret[i] < score[i]) {
+            temp = score[i] - ret[i]; /* remaining loop score */
+
+            /* dbg("%3d - ",temp); */
+
+            if (index[i] >= PROTO_DEF_AVG_NR)
+                index[i] = 0;   /* reset index */
+
+            j = index[i];
+            avg[i][j] = temp;
+
+            index[i]++;
+
+            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;
+            }
+
+            sum = 0;
+            for (j = 0; j < PROTO_DEF_AVG_NR; j++)
+                sum += avg[i][j]; /* calculate sum */
+
+            sum /= 4;           /* divide by 4 to get average used score */
+
+            /* criterion to increase next 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] / 4)) && ((score[i] / 2) >= PROTO_MIN_SCORE)) { /* < 1/4 */
+                score[i] /= 2; /* half loop score */
+                total += score[i];
+                continue;
+            }
+
+            /* also add non-changed scores */
+            total += score[i];
+        }
+        else if (ret[i] == score[i]) {
+            /* no used loop score - gradually decrease */
+
+            /*  dbg("%3d - ",0); */
+
+            if (index[i] >= PROTO_DEF_AVG_NR)
+                index[i] = 0;   /* reset index */
+
+            j = index[i];
+            avg[i][j] = 0;
+
+            index[i]++;
+
+            sum = 0;
+            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 */
+
+            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];
+            }
+
+        }
+    }
+    /* dbg("\n"); */
+
+    return 0;
+}
+
+void pico_stack_tick(void)
+{
+    static int score[PROTO_DEF_NR] = {
+        PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE
+    };
+    static int index[PROTO_DEF_NR] = {
+        0, 0, 0, 0, 0, 0
+    };
+    static int avg[PROTO_DEF_NR][PROTO_DEF_AVG_NR];
+    static int ret[PROTO_DEF_NR] = {
+        0
+    };
+
+    pico_check_timers();
+
+    /* dbg("LOOP_SCORES> %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d\n",score[0],score[1],score[2],score[3],score[4],score[5],score[6],score[7],score[8],score[9],score[10]); */
+
+    /* score = pico_protocols_loop(100); */
+
+    ret[0] = pico_devices_loop(score[0], PICO_LOOP_DIR_IN);
+    pico_rand_feed((uint32_t)ret[0]);
+
+    ret[1] = pico_protocol_datalink_loop(score[1], PICO_LOOP_DIR_IN);
+    pico_rand_feed((uint32_t)ret[1]);
+
+    ret[2] = pico_protocol_network_loop(score[2], PICO_LOOP_DIR_IN);
+    pico_rand_feed((uint32_t)ret[2]);
+
+    ret[3] = pico_protocol_transport_loop(score[3], PICO_LOOP_DIR_IN);
+    pico_rand_feed((uint32_t)ret[3]);
+
+
+    ret[5] = score[5];
+#if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6)
+#if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP)
+    ret[5] = pico_sockets_loop(score[5]); /* swapped */
+    pico_rand_feed((uint32_t)ret[5]);
+#endif
+#endif
+
+    ret[4] = pico_protocol_socket_loop(score[4], PICO_LOOP_DIR_IN);
+    pico_rand_feed((uint32_t)ret[4]);
+
+
+    ret[6] = pico_protocol_socket_loop(score[6], PICO_LOOP_DIR_OUT);
+    pico_rand_feed((uint32_t)ret[6]);
+
+    ret[7] = pico_protocol_transport_loop(score[7], PICO_LOOP_DIR_OUT);
+    pico_rand_feed((uint32_t)ret[7]);
+
+    ret[8] = pico_protocol_network_loop(score[8], PICO_LOOP_DIR_OUT);
+    pico_rand_feed((uint32_t)ret[8]);
+
+    ret[9] = pico_protocol_datalink_loop(score[9], PICO_LOOP_DIR_OUT);
+    pico_rand_feed((uint32_t)ret[9]);
+
+    ret[10] = pico_devices_loop(score[10], PICO_LOOP_DIR_OUT);
+    pico_rand_feed((uint32_t)ret[10]);
+
+    /* calculate new loop scores for next iteration */
+    calc_score(score, index, (int (*)[])avg, ret);
+}
+
+void pico_stack_loop(void)
+{
+    while(1) {
+        pico_stack_tick();
+        PICO_IDLE();
+    }
+}
+
+MOCKABLE 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_ref tref;
+    if (!t) {
+        pico_err = PICO_ERR_ENOMEM;
+        return NULL;
+    }
+
+    tref.expire = PICO_TIME_MS() + expire;
+    t->arg = arg;
+    t->timer = timer;
+    tref.tmr = t;
+    heap_insert(Timers, &tref);
+    if (Timers->n > PICO_MAX_TIMERS) {
+        dbg("Warning: I have %d timers\n", (int)Timers->n);
+    }
+
+    return t;
+}
+
+int pico_stack_init(void)
+{
+
+#ifdef PICO_SUPPORT_IPV4
+    pico_protocol_init(&pico_proto_ipv4);
+#endif
+
+#ifdef PICO_SUPPORT_IPV6
+    pico_protocol_init(&pico_proto_ipv6);
+#endif
+
+#ifdef PICO_SUPPORT_ICMP4
+    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
+
+#ifdef PICO_SUPPORT_UDP
+    pico_protocol_init(&pico_proto_udp);
+#endif
+
+#ifdef PICO_SUPPORT_TCP
+    pico_protocol_init(&pico_proto_tcp);
+#endif
+
+#ifdef PICO_SUPPORT_DNS_CLIENT
+    pico_dns_client_init();
+#endif
+
+    pico_rand_feed(123456);
+
+    /* 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
+
+#ifdef PICO_SUPPORT_OLSR
+    pico_olsr_init();
+#endif
+#ifdef PICO_SUPPORT_AODV
+    pico_aodv_init();
+#endif
+
+    pico_stack_tick();
+    pico_stack_tick();
+    pico_stack_tick();
+    return 0;
+}
+
diff --git a/net/picotcp/stack/pico_tree.c b/net/picotcp/stack/pico_tree.c
new file mode 100644
index 0000000..76eaf2f
--- /dev/null
+++ b/net/picotcp/stack/pico_tree.c
@@ -0,0 +1,575 @@
+/*********************************************************************
+   PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
+   See LICENSE and COPYING for usage.
+
+   Author: Andrei Carp <andrei.carp@tass.be>
+ *********************************************************************/
+
+#include "pico_tree.h"
+#include "pico_config.h"
+#include "pico_protocol.h"
+#include "pico_mm.h"
+
+#define RED     0
+#define BLACK 1
+
+/* By default the null leafs are black */
+struct pico_tree_node LEAF = {
+    NULL, /* key */
+    &LEAF, &LEAF, &LEAF, /* parent, left,right */
+    BLACK, /* color */
+};
+
+#define IS_LEAF(x) (x == &LEAF)
+#define IS_NOT_LEAF(x) (x != &LEAF)
+#define INIT_LEAF (&LEAF)
+
+#define AM_I_LEFT_CHILD(x) (x == x->parent->leftChild)
+#define AM_I_RIGHT_CHILD(x) (x == x->parent->rightChild)
+
+#define PARENT(x) (x->parent)
+#define GRANPA(x) (x->parent->parent)
+
+/*
+ * Local Functions
+ */
+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
+ */
+
+struct pico_tree_node *pico_tree_firstNode(struct pico_tree_node *node)
+{
+    while(IS_NOT_LEAF(node->leftChild))
+        node = node->leftChild;
+    return node;
+}
+
+struct pico_tree_node *pico_tree_lastNode(struct pico_tree_node *node)
+{
+    while(IS_NOT_LEAF(node->rightChild))
+        node = node->rightChild;
+    return node;
+}
+
+struct pico_tree_node *pico_tree_next(struct pico_tree_node *node)
+{
+    if(IS_NOT_LEAF(node->rightChild))
+    {
+        node = node->rightChild;
+        while(IS_NOT_LEAF(node->leftChild))
+            node = node->leftChild;
+    }
+    else
+    {
+        if (IS_NOT_LEAF(node->parent) &&  AM_I_LEFT_CHILD(node))
+            node = node->parent;
+        else {
+            while (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node))
+                node = node->parent;
+            node = node->parent;
+        }
+    }
+
+    return node;
+}
+
+struct pico_tree_node *pico_tree_prev(struct pico_tree_node *node)
+{
+    if (IS_NOT_LEAF(node->leftChild)) {
+        node = node->leftChild;
+        while (IS_NOT_LEAF(node->rightChild))
+            node = node->rightChild;
+    } else {
+        if (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node))
+            node = node->parent;
+        else {
+            while (IS_NOT_LEAF(node) && AM_I_LEFT_CHILD(node))
+                node = node->parent;
+            node = node->parent;
+        }
+    }
+
+    return node;
+}
+
+/* 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;
+    void *LocalKey;
+    int result = 0;
+
+    LocalKey = (IS_NOT_LEAF(tree->root) ? pico_tree_findKey(tree, key) : NULL);
+    /* if node already in, bail out */
+    if(LocalKey)
+        return LocalKey;
+    else
+    {
+        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;
+            /* to let the user know that it couldn't insert */
+            return (void *)&LEAF;
+        }
+    }
+
+    /* search for the place to insert the new node */
+    while(IS_NOT_LEAF(temp))
+    {
+        last_node = temp;
+        result = tree->compare(insert->keyValue, temp->keyValue);
+
+        temp = (result < 0) ? (temp->leftChild) : (temp->rightChild);
+    }
+    /* make the needed connections */
+    insert->parent = last_node;
+
+    if(IS_LEAF(last_node))
+        tree->root = insert;
+    else{
+        result = tree->compare(insert->keyValue, last_node->keyValue);
+        if(result < 0)
+            last_node->leftChild = insert;
+        else
+            last_node->rightChild = insert;
+    }
+
+    /* fix colour issues */
+    fix_insert_collisions(tree, insert);
+
+    return NULL;
+}
+
+struct pico_tree_node *pico_tree_findNode(struct pico_tree *tree, void *key)
+{
+    struct pico_tree_node *found;
+
+    found = tree->root;
+
+    while(IS_NOT_LEAF(found))
+    {
+        int result;
+        result = tree->compare(found->keyValue, key);
+        if(result == 0)
+        {
+            return found;
+        }
+        else if(result < 0)
+            found = found->rightChild;
+        else
+            found = found->leftChild;
+    }
+    return NULL;
+}
+
+void *pico_tree_findKey(struct pico_tree *tree, void *key)
+{
+    struct pico_tree_node *found;
+
+
+    found = tree->root;
+
+    while(IS_NOT_LEAF(found))
+    {
+        int result;
+
+        result = tree->compare(found->keyValue, key);
+        if(result == 0)
+            return found->keyValue;
+        else if(result < 0)
+            found = found->rightChild;
+        else
+            found = found->leftChild;
+
+    }
+    return NULL;
+}
+
+void *pico_tree_first(struct pico_tree *tree)
+{
+    return pico_tree_firstNode(tree->root)->keyValue;
+}
+
+void *pico_tree_last(struct pico_tree *tree)
+{
+    return pico_tree_lastNode(tree->root)->keyValue;
+}
+
+static uint8_t pico_tree_delete_node(struct pico_tree *tree, struct pico_tree_node *d, struct pico_tree_node **temp)
+{
+    struct pico_tree_node *min;
+    struct pico_tree_node *ltemp = d;
+    uint8_t nodeColor;
+    min = pico_tree_firstNode(d->rightChild);
+    nodeColor = min->color;
+
+    *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;
+
+    if(IS_NOT_LEAF(min->leftChild))
+        min->leftChild->parent = min;
+
+    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;
+        switchNodes(tree, ltemp, ltemp->rightChild);
+    }
+    else
+    if(IS_LEAF(delete->rightChild))
+    {
+        struct pico_tree_node *_ltemp = delete;
+        *temp = _ltemp->leftChild;
+        switchNodes(tree, _ltemp, _ltemp->leftChild);
+    }
+    else{
+        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);
+}
+
+static inline void if_nodecolor_black_fix_collisions(struct pico_tree *tree, struct pico_tree_node *temp, uint8_t nodeColor)
+{
+    /* deleted node is black, this will mess up the black path property */
+    if(nodeColor == BLACK)
+        fix_delete_collisions(tree, temp);
+
+}
+
+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 */
+
+    if (!key)
+        return NULL;
+
+    delete = pico_tree_findNode(tree, key);
+
+    /* 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);
+
+    if_nodecolor_black_fix_collisions(tree, temp, nodeColor);
+
+    if(allocator == USE_PICO_ZALLOC)
+        PICO_FREE(delete);
+
+#ifdef PICO_SUPPORT_MM
+    else
+        pico_mem_page0_free(delete);
+#endif
+    return lkey;
+}
+
+int pico_tree_empty(struct pico_tree *tree)
+{
+    return (!tree->root || IS_LEAF(tree->root));
+}
+
+/*
+ * Private functions
+ */
+static void rotateToLeft(struct pico_tree*tree, struct pico_tree_node*node)
+{
+    struct pico_tree_node*temp;
+
+    temp = node->rightChild;
+
+    if(temp == &LEAF) return;
+
+    node->rightChild = temp->leftChild;
+
+    if(IS_NOT_LEAF(temp->leftChild))
+        temp->leftChild->parent = node;
+
+    temp->parent = node->parent;
+
+    if(IS_LEAF(node->parent))
+        tree->root = temp;
+    else
+    if(node == node->parent->leftChild)
+        node->parent->leftChild = temp;
+    else
+        node->parent->rightChild = temp;
+
+    temp->leftChild = node;
+    node->parent = temp;
+}
+
+
+static void rotateToRight(struct pico_tree *tree, struct pico_tree_node *node)
+{
+    struct pico_tree_node*temp;
+
+    temp = node->leftChild;
+    node->leftChild = temp->rightChild;
+
+    if(temp == &LEAF) return;
+
+    if(IS_NOT_LEAF(temp->rightChild))
+        temp->rightChild->parent = node;
+
+    temp->parent = node->parent;
+
+    if(IS_LEAF(node->parent))
+        tree->root = temp;
+    else
+    if(node == node->parent->rightChild)
+        node->parent->rightChild = temp;
+    else
+        node->parent->leftChild = temp;
+
+    temp->rightChild = node;
+    node->parent = temp;
+    return;
+}
+
+static struct pico_tree_node *create_node(struct pico_tree *tree, void*key, uint8_t allocator)
+{
+    struct pico_tree_node *temp = NULL;
+    IGNORE_PARAMETER(tree);
+    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;
+
+    temp->keyValue = key;
+    temp->parent = &LEAF;
+    temp->leftChild = &LEAF;
+    temp->rightChild = &LEAF;
+    /* by default every new node is red */
+    temp->color = RED;
+    return temp;
+}
+
+/*
+ * This function fixes the possible collisions in the tree.
+ * Eg. if a node is red his children must be black !
+ */
+static void fix_insert_collisions(struct pico_tree*tree, struct pico_tree_node*node)
+{
+    struct pico_tree_node*temp;
+
+    while(node->parent->color == RED && IS_NOT_LEAF(GRANPA(node)))
+    {
+        if(AM_I_RIGHT_CHILD(node->parent))
+        {
+            temp = GRANPA(node)->leftChild;
+            if(temp->color == RED) {
+                node->parent->color = BLACK;
+                temp->color = BLACK;
+                GRANPA(node)->color = RED;
+                node = GRANPA(node);
+            }
+            else if(temp->color == BLACK) {
+                if(node == node->parent->leftChild) {
+                    node = node->parent;
+                    rotateToRight(tree, node);
+                }
+
+                node->parent->color = BLACK;
+                GRANPA(node)->color = RED;
+                rotateToLeft(tree, GRANPA(node));
+            }
+        }
+        else if(AM_I_LEFT_CHILD(node->parent))
+        {
+            temp = GRANPA(node)->rightChild;
+            if(temp->color == RED) {
+                node->parent->color = BLACK;
+                temp->color = BLACK;
+                GRANPA(node)->color = RED;
+                node = GRANPA(node);
+            }
+            else if(temp->color == BLACK) {
+                if(AM_I_RIGHT_CHILD(node)) {
+                    node = node->parent;
+                    rotateToLeft(tree, node);
+                }
+
+                node->parent->color = BLACK;
+                GRANPA(node)->color = RED;
+                rotateToRight(tree, GRANPA(node));
+            }
+        }
+    }
+    /* make sure that the root of the tree stays black */
+    tree->root->color = BLACK;
+}
+
+static void switchNodes(struct pico_tree*tree, struct pico_tree_node*nodeA, struct pico_tree_node*nodeB)
+{
+
+    if(IS_LEAF(nodeA->parent))
+        tree->root = nodeB;
+    else
+    if(IS_NOT_LEAF(nodeA))
+    {
+        if(AM_I_LEFT_CHILD(nodeA))
+            nodeA->parent->leftChild = nodeB;
+        else
+            nodeA->parent->rightChild = nodeB;
+    }
+
+    if(IS_NOT_LEAF(nodeB)) nodeB->parent = nodeA->parent;
+
+}
+
+/*
+ * This function fixes the possible collisions in the tree.
+ * Eg. if a node is red his children must be black !
+ * In this case the function fixes the constant black path property.
+ */
+static void fix_delete_collisions(struct pico_tree*tree, struct pico_tree_node *node)
+{
+    struct pico_tree_node*temp;
+
+    while( node != tree->root && node->color == BLACK && IS_NOT_LEAF(node))
+    {
+        if(AM_I_LEFT_CHILD(node)) {
+
+            temp = node->parent->rightChild;
+            if(temp->color == RED)
+            {
+                temp->color = BLACK;
+                node->parent->color = RED;
+                rotateToLeft(tree, node->parent);
+                temp = node->parent->rightChild;
+            }
+
+            if(temp->leftChild->color == BLACK && temp->rightChild->color == BLACK)
+            {
+                temp->color = RED;
+                node = node->parent;
+            }
+            else
+            {
+                if(temp->rightChild->color == BLACK)
+                {
+                    temp->leftChild->color = BLACK;
+                    temp->color = RED;
+                    rotateToRight(tree, temp);
+                    temp = temp->parent->rightChild;
+                }
+
+                temp->color = node->parent->color;
+                node->parent->color = BLACK;
+                temp->rightChild->color = BLACK;
+                rotateToLeft(tree, node->parent);
+                node = tree->root;
+            }
+        }
+        else{
+            temp = node->parent->leftChild;
+            if(temp->color == RED)
+            {
+                temp->color = BLACK;
+                node->parent->color = RED;
+                rotateToRight(tree, node->parent);
+                temp = node->parent->leftChild;
+            }
+
+            if(temp->rightChild->color == BLACK && temp->leftChild->color == BLACK)
+            {
+                temp->color = RED;
+                node = node->parent;
+            }
+            else{
+                if(temp->leftChild->color == BLACK)
+                {
+                    temp->rightChild->color = BLACK;
+                    temp->color = RED;
+                    rotateToLeft(tree, temp);
+                    temp = temp->parent->leftChild;
+                }
+
+                temp->color = node->parent->color;
+                node->parent->color = BLACK;
+                temp->leftChild->color = BLACK;
+                rotateToRight(tree, node->parent);
+                node = tree->root;
+            }
+        }
+    }
+    node->color = BLACK;
+}
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 09/16] picotcp: add barebox target support
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (7 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 08/16] net: import picotcp from github Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 10/16] picotcp: switch to Kbuild Antony Pavlov
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 net/picotcp/include/arch/pico_barebox.h | 76 +++++++++++++++++++++++++++++++++
 net/picotcp/include/pico_config.h       |  2 +
 2 files changed, 78 insertions(+)

diff --git a/net/picotcp/include/arch/pico_barebox.h b/net/picotcp/include/arch/pico_barebox.h
new file mode 100644
index 0000000..11e6ed3
--- /dev/null
+++ b/net/picotcp/include/arch/pico_barebox.h
@@ -0,0 +1,76 @@
+#ifndef PICO_SUPPORT_BAREBOX
+#define PICO_SUPPORT_BAREBOX
+
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <clock.h>
+#include <linux/math64.h>
+
+/*
+   #define MEMORY_MEASURE
+ */
+#define dbg printf
+
+#define stack_fill_pattern(...) do {} while(0)
+#define stack_count_free_words(...) do {} while(0)
+#define stack_get_free_words() (0)
+
+/* measure allocated memory */
+#ifdef MEMORY_MEASURE
+extern uint32_t max_mem;
+extern uint32_t cur_mem;
+
+static inline void *pico_zalloc(int x)
+{
+    uint32_t *ptr;
+    if ((cur_mem + x) > (10 * 1024))
+        return NULL;
+
+    ptr = (uint32_t *)calloc(x + 4, 1);
+    *ptr = (uint32_t)x;
+    cur_mem += x;
+    if (cur_mem > max_mem) {
+        max_mem = cur_mem;
+    }
+
+    return (void*)(ptr + 1);
+}
+
+static inline void pico_free(void *x)
+{
+    uint32_t *ptr = (uint32_t*)(((uint8_t *)x) - 4);
+    cur_mem -= *ptr;
+    free(ptr);
+}
+#else
+
+#define pico_zalloc(x) calloc(x, 1)
+#define pico_free(x) free(x)
+#endif
+
+static inline uint32_t PICO_TIME(void)
+{
+    uint64_t time;
+
+    time = get_time_ns();
+    do_div(time, 1000000000);
+
+    return (uint32_t) time;
+}
+
+static inline uint32_t PICO_TIME_MS(void)
+{
+    uint64_t time;
+
+    time = get_time_ns();
+    do_div(time, 1000000);
+
+    return (uint32_t) time;
+}
+
+static inline void PICO_IDLE(void)
+{
+}
+
+#endif /* PICO_SUPPORT_BAREBOX */
diff --git a/net/picotcp/include/pico_config.h b/net/picotcp/include/pico_config.h
index 6b9c040..79aaadc 100644
--- a/net/picotcp/include/pico_config.h
+++ b/net/picotcp/include/pico_config.h
@@ -211,6 +211,8 @@ static inline uint64_t long_long_be(uint64_t le)
 # include "arch/pico_none.h"
 #elif defined GENERIC
 # include "arch/pico_generic_gcc.h"
+#elif defined __BAREBOX__
+# include "arch/pico_barebox.h"
 #elif defined __KERNEL__
 # include "arch/pico_linux.h"
 /* #elif defined ... */
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 10/16] picotcp: switch to Kbuild
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (8 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 09/16] picotcp: add barebox target support Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 11/16] net: add initial picotcp support Antony Pavlov
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 net/picotcp/.gitignore       |  1 +
 net/picotcp/Kconfig          | 34 ++++++++++++++++++++++++++++++++++
 net/picotcp/Makefile         | 30 ++++++++++++++++++++++++++++++
 net/picotcp/modules/Makefile |  8 ++++++++
 net/picotcp/stack/Makefile   |  7 +++++++
 5 files changed, 80 insertions(+)

diff --git a/net/picotcp/.gitignore b/net/picotcp/.gitignore
index 88593da..10f36c8 100644
--- a/net/picotcp/.gitignore
+++ b/net/picotcp/.gitignore
@@ -22,3 +22,4 @@ cscope.out
 *.gcov
 *.gcda
 *.gcno
+*.o.cmd
diff --git a/net/picotcp/Kconfig b/net/picotcp/Kconfig
new file mode 100644
index 0000000..3882984
--- /dev/null
+++ b/net/picotcp/Kconfig
@@ -0,0 +1,34 @@
+if NET_PICOTCP
+
+config NET_PICO_SUPPORT_IPV4
+	bool
+	default y if NET_PICOTCP
+
+config NET_PICO_SUPPORT_IPFRAG
+	bool
+	default y if NET_PICO_SUPPORT_IPV4
+
+config NET_PICO_SUPPORT_ICMP4
+	bool
+	default y if NET_PICO_SUPPORT_IPV4
+
+config NET_PICO_SUPPORT_UDP
+	bool
+	default y if NET_PICO_SUPPORT_IPV4
+
+
+config NET_PICO_SUPPORT_ETH
+	bool
+	default y if NET_PICOTCP
+
+config NET_PICO_SUPPORT_DEVLOOP
+	bool
+	default y if NET_PICOTCP
+
+comment "Misc options"
+
+config NET_PICO_BIGENDIAN
+	bool
+	prompt "bigendian picotcp"
+
+endif # NET_PICOTCP
diff --git a/net/picotcp/Makefile b/net/picotcp/Makefile
new file mode 100644
index 0000000..8127453
--- /dev/null
+++ b/net/picotcp/Makefile
@@ -0,0 +1,30 @@
+ifeq ($(CONFIG_NET_PICO_SUPPORT_IPV4),y)
+CPPFLAGS += -DPICO_SUPPORT_IPV4
+endif
+
+ifeq ($(CONFIG_NET_PICO_SUPPORT_ICMP4),y)
+CPPFLAGS += -DPICO_SUPPORT_ICMP4 -DPICO_SUPPORT_PING
+endif
+
+ifeq ($(CONFIG_NET_PICO_SUPPORT_IPFRAG),y)
+CPPFLAGS += -DPICO_SUPPORT_IPFRAG
+endif
+
+ifeq ($(CONFIG_NET_PICO_SUPPORT_UDP),y)
+CPPFLAGS += -DPICO_SUPPORT_UDP
+endif
+
+ifeq ($(CONFIG_NET_PICO_SUPPORT_ETH),y)
+CPPFLAGS += -DPICO_SUPPORT_ETH
+endif
+
+ifeq ($(CONFIG_NET_PICO_SUPPORT_DEVLOOP),y)
+CPPFLAGS += -DPICO_SUPPORT_DEVLOOP
+endif
+
+ifeq ($(CONFIG_NET_PICO_BIGENDIAN),y)
+CPPFLAGS += -DPICO_BIGENDIAN
+endif
+
+obj-y += modules/
+obj-y += stack/
diff --git a/net/picotcp/modules/Makefile b/net/picotcp/modules/Makefile
new file mode 100644
index 0000000..2fa2261
--- /dev/null
+++ b/net/picotcp/modules/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_NET_PICO_SUPPORT_IPV4) += pico_ipv4.o
+obj-$(CONFIG_NET_PICO_SUPPORT_IPFRAG) += pico_fragments.o
+obj-$(CONFIG_NET_PICO_SUPPORT_ICMP4) += pico_icmp4.o
+obj-$(CONFIG_NET_PICO_SUPPORT_UDP) += pico_udp.o pico_socket_udp.o
+
+obj-$(CONFIG_NET_PICO_SUPPORT_ETH) += pico_arp.o
+obj-$(CONFIG_NET_PICO_SUPPORT_DEVLOOP) += pico_dev_loop.o
+obj-y += pico_dev_null.o
diff --git a/net/picotcp/stack/Makefile b/net/picotcp/stack/Makefile
new file mode 100644
index 0000000..13be8d0
--- /dev/null
+++ b/net/picotcp/stack/Makefile
@@ -0,0 +1,7 @@
+obj-y += pico_device.o
+obj-y += pico_frame.o
+obj-y += pico_protocol.o
+obj-y += pico_socket.o
+obj-y += pico_socket_multicast.o
+obj-y += pico_stack.o
+obj-y += pico_tree.o
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 11/16] net: add initial picotcp support
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (9 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 10/16] picotcp: switch to Kbuild Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 12/16] net: picotcp: add test_picotcp command Antony Pavlov
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox; +Cc: Daniele Lacamera

This commit adds initial picotcp support:

 * build stuff (Kbuild fixes and fake stdint.h);
 * "pico_adapter" code for connecting barebox ethernet interfaces
   to picotcp;
 * picotcp start initialization and necessary poller.

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Daniele Lacamera <daniele.lacamera@tass.be>
---
 Makefile               |  1 +
 commands/Kconfig       |  4 +++
 include/net.h          | 37 ++++++++++++++++++++++-
 include/pico_defines.h |  0
 include/stdint.h       |  1 +
 net/Kconfig            | 16 ++++++++++
 net/Makefile           |  3 ++
 net/eth.c              | 71 +++++++++++++++++++++++++++++++++++++++++++
 net/net.c              | 81 +++++++++++++++++++++++++++++++++++++++++++++++++-
 net/picotcp.c          | 20 +++++++++++++
 10 files changed, 232 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 5a7fd5f..972b5db 100644
--- a/Makefile
+++ b/Makefile
@@ -292,6 +292,7 @@ export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_ve
 # Use LINUXINCLUDE when you must reference the include/ directory.
 # Needed to be compatible with the O= option
 LINUXINCLUDE    := -Iinclude -I$(srctree)/dts/include \
+                   -I$(srctree)/net/picotcp/include -I$(srctree)/net/picotcp/modules \
                    $(if $(KBUILD_SRC), -I$(srctree)/include) \
 		   -I$(srctree)/arch/$(ARCH)/include \
 		   -I$(objtree)/arch/$(ARCH)/include \
diff --git a/commands/Kconfig b/commands/Kconfig
index 5571902..77193cb 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1184,6 +1184,7 @@ menu "Network"
 config CMD_DHCP
 	bool
 	select NET_DHCP
+	depends on NET_LEGACY
 	prompt "dhcp"
 	help
 	  DHCP client to obtain IP or boot params
@@ -1210,6 +1211,7 @@ config CMD_HOST
 config NET_CMD_IFUP
 	bool
 	prompt "ifup"
+	depends on NET_LEGACY
 	help
 	  Bring up network interfaces based on config files.
 
@@ -1237,6 +1239,7 @@ config CMD_MIITOOL
 
 config CMD_PING
 	tristate
+	depends on NET_LEGACY
 	prompt "ping"
 	help
 	  Send ICMP echo requests.
@@ -1245,6 +1248,7 @@ config CMD_PING
 
 config CMD_TFTP
 	depends on FS_TFTP
+	depends on NET_LEGACY
 	tristate
 	prompt "tftp"
 	help
diff --git a/include/net.h b/include/net.h
index ed63d3c..5f2d470 100644
--- a/include/net.h
+++ b/include/net.h
@@ -24,6 +24,10 @@
 #include <linux/string.h>	/* memcpy */
 #include <asm/byteorder.h>	/* for nton* / ntoh* stuff */
 
+#include <pico_stack.h>
+#include <pico_socket.h>
+#include <pico_ipv4.h>
+
 /* How often do we retry to send packages */
 #define PKT_NUM_RETRIES 4
 
@@ -44,6 +48,7 @@ struct eth_device {
 	int  (*get_ethaddr) (struct eth_device*, u8 adr[6]);
 	int  (*set_ethaddr) (struct eth_device*, const unsigned char *adr);
 
+	struct pico_device *picodev;
 	struct eth_device *next;
 	void *priv;
 
@@ -433,6 +438,8 @@ struct net_connection {
 	void *handler;
 	int proto;
 	void *priv;
+	struct pico_socket *sock;
+	uint16_t remote_port;
 };
 
 static inline char *net_alloc_packet(void)
@@ -450,10 +457,28 @@ void net_unregister(struct net_connection *con);
 
 static inline int net_udp_bind(struct net_connection *con, uint16_t sport)
 {
+	if (IS_ENABLED(CONFIG_NET_PICOTCP)) {
+		union pico_address local_address;
+		uint16_t localport;
+
+		/* FIXME: use local_address == PICO_IPV4_INADDR_ANY */
+		memset(&local_address, 0, sizeof(union pico_address));
+
+		localport = ntohs(sport);
+
+		/* FIXME: check pico_socket_bind() return value */
+		pico_socket_bind(con->sock, &local_address, &localport);
+
+		return 0;
+	}
+
 	con->udp->uh_sport = ntohs(sport);
 	return 0;
 }
 
+#define UDP_PAYLOAD_SIZE (PKTSIZE - sizeof(struct ethernet) - sizeof(struct iphdr) - \
+		sizeof(struct udphdr))
+
 static inline void *net_udp_get_payload(struct net_connection *con)
 {
 	return con->packet + sizeof(struct ethernet) + sizeof(struct iphdr) +
@@ -475,6 +500,10 @@ static inline uint16_t getudppeerport(struct net_connection *con)
 {
 	struct udphdr *udp = net_eth_to_udphdr(con->rpacket);
 
+	if (IS_ENABLED(CONFIG_NET_PICOTCP)) {
+		return con->remote_port;
+	}
+
 	return udp->uh_sport;
 }
 
@@ -482,7 +511,13 @@ static inline uint16_t getudppeerport(struct net_connection *con)
 
 static inline void setudppeerport(struct net_connection *con, uint16_t dport)
 {
-	con->udp->uh_dport = dport;
+	if (IS_ENABLED(CONFIG_NET_LEGACY)) {
+		con->udp->uh_dport = dport;
+	} else if (IS_ENABLED(CONFIG_NET_PICOTCP)) {
+		/* FIXME */
+//		pico_socket_connect(npriv->con->sock, &remote_address, dport);
+		con->sock->remote_port = dport;
+	}
 }
 
 #endif /* __NET_H__ */
diff --git a/include/pico_defines.h b/include/pico_defines.h
new file mode 100644
index 0000000..e69de29
diff --git a/include/stdint.h b/include/stdint.h
new file mode 100644
index 0000000..029276e
--- /dev/null
+++ b/include/stdint.h
@@ -0,0 +1 @@
+/* fake stdint.h for picotcp */
diff --git a/net/Kconfig b/net/Kconfig
index a890492..f8f660c 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -3,6 +3,18 @@ menuconfig NET
 
 if NET
 
+choice
+	prompt "network stack implementation"
+
+config NET_LEGACY
+	bool "legacy U-Boot network stack"
+
+config NET_PICOTCP
+	bool "picotcp network stack"
+	select POLLER
+
+endchoice
+
 config NET_NFS
 	bool
 	prompt "nfs support"
@@ -20,10 +32,14 @@ config NET_RESOLV
 
 config NET_IFUP
 	default y
+	depends on NET_LEGACY
 	bool
 
 config NET_DHCP
 	bool
+	depends on NET_LEGACY
 	prompt "dhcp support"
 
+source "net/picotcp/Kconfig"
+
 endif
diff --git a/net/Makefile b/net/Makefile
index 8d564e7..7a4597d 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_CMD_PING)	+= ping.o
 obj-$(CONFIG_NET_RESOLV)+= dns.o
 obj-$(CONFIG_NET_NETCONSOLE) += netconsole.o
 obj-$(CONFIG_NET_IFUP)	+= ifup.o
+
+obj-$(CONFIG_NET_PICOTCP) += picotcp/
+obj-$(CONFIG_NET_PICOTCP) += picotcp.o
diff --git a/net/eth.c b/net/eth.c
index a090961..34358f6 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -328,6 +328,73 @@ static int eth_register_of_fixup(void)
 late_initcall(eth_register_of_fixup);
 #endif
 
+#ifdef CONFIG_NET_PICO_SUPPORT_ETH
+
+#include <pico_stack.h>
+#include <pico_ipv4.h>
+
+struct pico_device_barebox_eth {
+	struct pico_device dev;
+	struct eth_device *edev;
+};
+
+static int pico_adapter_send(struct pico_device *dev, void *buf, int len)
+{
+	struct pico_device_barebox_eth *t = (struct pico_device_barebox_eth *)dev;
+	struct eth_device *edev = t->edev;
+
+	pr_debug("pico_adapter_send barebox eth (len=%d)\n", len);
+	edev->send(edev, buf, len);
+
+	return len;
+}
+
+static int pico_adapter_poll(struct pico_device *dev, int loop_score)
+{
+	struct pico_device_barebox_eth *t = (struct pico_device_barebox_eth *)dev;
+	struct eth_device *edev = t->edev;
+
+	/* pico_stack_recv(dev, buf, len) will be called from net_receive */
+
+	edev->recv(edev);
+
+	return loop_score;
+}
+
+static void pico_adapter_destroy(struct pico_device *dev)
+{
+	printf("pico_adapter_destroy barebox eth\n");
+}
+
+static void pico_adapter_init(struct eth_device *edev)
+{
+	/* FIXME: get macaddr for edev */
+	static unsigned char macaddr0[6] = { 0, 0, 0, 0xa, 0xb, 0xc };
+
+	struct pico_device_barebox_eth *pif = PICO_ZALLOC(sizeof(struct pico_device_barebox_eth));
+
+	struct pico_device *picodev;
+
+	char *name = strdup(edev->dev.name);
+
+	picodev = &pif->dev;
+	if (0 != pico_device_init(picodev, name, macaddr0)) {
+		pr_info("pico_adapter_init failed.\n");
+		pico_adapter_destroy(picodev);
+		return;
+	}
+
+	picodev->send = pico_adapter_send;
+	picodev->poll = pico_adapter_poll;
+	picodev->destroy = pico_adapter_destroy;
+
+	pif->edev = edev;
+	edev->picodev = picodev;
+
+	pr_info("Device %s created.\n", picodev->name);
+}
+#endif /* CONFIG_NET_PICO_SUPPORT_ETH */
+
 int eth_register(struct eth_device *edev)
 {
 	struct device_d *dev = &edev->dev;
@@ -388,6 +455,10 @@ int eth_register(struct eth_device *edev)
 	if (!eth_current)
 		eth_current = edev;
 
+#ifdef CONFIG_NET_PICO_SUPPORT_ETH
+	pico_adapter_init(edev);
+#endif
+
 	return 0;
 }
 
diff --git a/net/net.c b/net/net.c
index 23a9173..f4481f8 100644
--- a/net/net.c
+++ b/net/net.c
@@ -194,9 +194,15 @@ static int arp_request(IPaddr_t dest, unsigned char *ether)
 	return 0;
 }
 
+#include <pico_stack.h>
+
 void net_poll(void)
 {
-	eth_rx();
+	if (IS_ENABLED(CONFIG_NET_LEGACY)) {
+		eth_rx();
+	} else if (IS_ENABLED(CONFIG_NET_PICOTCP)) {
+		pico_stack_tick();
+	}
 }
 
 static uint16_t net_udp_new_localport(void)
@@ -262,6 +268,17 @@ static struct net_connection *net_new(IPaddr_t dest, void *handler,
 	struct net_connection *con;
 	int ret;
 
+	if (IS_ENABLED(CONFIG_NET_PICOTCP)) {
+		con = xzalloc(sizeof(*con));
+		con->handler = handler;
+		con->packet = net_alloc_packet();
+		memset(con->packet, 0, PKTSIZE);
+
+		list_add_tail(&con->list, &connection_list);
+
+		return con;
+	}
+
 	if (!edev)
 		return ERR_PTR(-ENETDOWN);
 
@@ -316,6 +333,27 @@ out:
 	return ERR_PTR(ret);
 }
 
+#include <pico_socket.h>
+#include <pico_ipv4.h>
+
+static void picotcp_udp_cb(uint16_t ev, struct pico_socket *sock)
+{
+	struct net_connection *con = sock->priv;
+	udp_rx_handler_f *handler = con->handler;
+	int len;
+	union pico_address ep;
+	char *pkt = con->packet;
+
+	if (ev == PICO_SOCK_EV_ERR) {
+		printf(">>>>>> PICO_SOCK_EV_ERR (%d)\n", pico_err);
+		return;
+	}
+
+	len = pico_socket_recvfrom(sock, pkt, UDP_PAYLOAD_SIZE, &ep, &con->remote_port);
+
+	handler(con, pkt, len);
+}
+
 struct net_connection *net_udp_new(IPaddr_t dest, uint16_t dport,
 		udp_rx_handler_f *handler, void *ctx)
 {
@@ -324,6 +362,26 @@ struct net_connection *net_udp_new(IPaddr_t dest, uint16_t dport,
 	if (IS_ERR(con))
 		return con;
 
+	if (IS_ENABLED(CONFIG_NET_PICOTCP)) {
+		union pico_address remote_address;
+
+		remote_address.ip4.addr = dest;
+
+		con->sock = pico_socket_open(PICO_PROTO_IPV4,
+						PICO_PROTO_UDP, picotcp_udp_cb);
+
+		if (!con->sock)
+			return ERR_PTR(-ENOBUFS);
+
+		/* FIXME: check return value */
+		pico_socket_connect(con->sock, &remote_address, htons(dport));
+
+		con->sock->priv = con;
+		con->priv = ctx;
+
+		return con;
+	}
+
 	con->proto = IPPROTO_UDP;
 	con->udp->uh_dport = htons(dport);
 	con->udp->uh_sport = htons(net_udp_new_localport());
@@ -348,6 +406,10 @@ struct net_connection *net_icmp_new(IPaddr_t dest, rx_handler_f *handler,
 
 void net_unregister(struct net_connection *con)
 {
+	if (IS_ENABLED(CONFIG_NET_PICOTCP)) {
+		pico_socket_close(con->sock);
+	}
+
 	list_del(&con->list);
 	free(con->packet);
 	free(con);
@@ -365,6 +427,13 @@ static int net_ip_send(struct net_connection *con, int len)
 
 int net_udp_send(struct net_connection *con, char *payload, int len)
 {
+	if (IS_ENABLED(CONFIG_NET_PICOTCP)) {
+		/* FIXME: pico_socket_send() ret code is ignored */
+		pico_socket_send(con->sock, payload, len);
+
+		return 0;
+	}
+
 	con->udp->uh_ulen = htons(len + 8);
 	con->udp->uh_sum = 0;
 
@@ -544,12 +613,22 @@ bad:
 	return 0;
 }
 
+#include <pico_stack.h>
+
 int net_receive(struct eth_device *edev, unsigned char *pkt, int len)
 {
 	struct ethernet *et = (struct ethernet *)pkt;
 	int et_protlen = ntohs(et->et_protlen);
 	int ret;
 
+	if (IS_ENABLED(CONFIG_NET_PICOTCP)) {
+		pico_stack_recv(edev->picodev, pkt, len);
+
+		led_trigger_network(LED_TRIGGER_NET_RX);
+
+		return 0;
+	}
+
 	led_trigger_network(LED_TRIGGER_NET_RX);
 
 	if (len < ETHER_HDR_SIZE) {
diff --git a/net/picotcp.c b/net/picotcp.c
new file mode 100644
index 0000000..ee16a68
--- /dev/null
+++ b/net/picotcp.c
@@ -0,0 +1,20 @@
+#include <init.h>
+#include <poller.h>
+#include <pico_stack.h>
+
+static struct poller_struct picotcp_poller;
+
+static void picotcp_poller_cb(struct poller_struct *poller)
+{
+	pico_stack_tick();
+}
+
+static int picotcp_net_init(void)
+{
+	pico_stack_init();
+
+	picotcp_poller.func = picotcp_poller_cb;
+
+	return poller_register(&picotcp_poller);
+}
+postcore_initcall(picotcp_net_init);
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 12/16] net: picotcp: add test_picotcp command
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (10 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 11/16] net: add initial picotcp support Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 13/16] net: picotcp: add ifconfig command Antony Pavlov
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

See original test_ipv4() from picotcp.git/test/unit/unit_ipv4.c.

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 net/Makefile            |  2 ++
 net/picotcp/Kconfig     |  7 ++++
 net/picotcp_test_ipv4.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+)

diff --git a/net/Makefile b/net/Makefile
index 7a4597d..bfe74fb 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -10,3 +10,5 @@ obj-$(CONFIG_NET_IFUP)	+= ifup.o
 
 obj-$(CONFIG_NET_PICOTCP) += picotcp/
 obj-$(CONFIG_NET_PICOTCP) += picotcp.o
+
+obj-$(CONFIG_CMD_PICOTCP_TEST_IPV4) += picotcp_test_ipv4.o
diff --git a/net/picotcp/Kconfig b/net/picotcp/Kconfig
index 3882984..17b8293 100644
--- a/net/picotcp/Kconfig
+++ b/net/picotcp/Kconfig
@@ -31,4 +31,11 @@ config NET_PICO_BIGENDIAN
 	bool
 	prompt "bigendian picotcp"
 
+comment "Commands"
+
+config CMD_PICOTCP_TEST_IPV4
+	bool
+	depends on NET_PICO_SUPPORT_IPV4
+	prompt "test_picotcp command"
+
 endif # NET_PICOTCP
diff --git a/net/picotcp_test_ipv4.c b/net/picotcp_test_ipv4.c
new file mode 100644
index 0000000..314d21c
--- /dev/null
+++ b/net/picotcp_test_ipv4.c
@@ -0,0 +1,96 @@
+#include <common.h>
+#include <command.h>
+#include <complete.h>
+
+#include <pico_stack.h>
+#include <pico_ipv4.h>
+#include <pico_dev_null.h>
+
+#define fail_if(a, msg) \
+	if (a) { \
+		printf("%s\n", msg); \
+		return; \
+	}
+
+#define fail_unless(a, msg) fail_if(!(a), msg)
+
+static void do_test_ipv4(void)
+{
+	#define IP_TST_SIZ 256
+	int i;
+
+	struct pico_device *dev[IP_TST_SIZ];
+	char devname[8];
+	struct pico_ip4 a[IP_TST_SIZ], d[IP_TST_SIZ], *source[IP_TST_SIZ], nm16, nm32, gw[IP_TST_SIZ], r[IP_TST_SIZ], ret;
+	struct pico_ipv4_link *l[IP_TST_SIZ];
+
+	char ipstr[] = "192.168.1.1";
+	struct pico_ip4 ipaddr;
+
+	struct pico_frame *f_NULL = NULL;
+	struct pico_ip4 *dst_NULL = NULL;
+
+	nm16.addr = long_be(0xFFFF0000);
+	nm32.addr = long_be(0xFFFFFFFF);
+
+	/*link_add*/
+	for (i = 0; i < IP_TST_SIZ; i++) {
+		snprintf(devname, 8, "nul%d", i);
+		dev[i] = pico_null_create(devname);
+		a[i].addr = long_be(0x0a000001 + (i << 16));
+		d[i].addr = long_be(0x0a000002 + (i << 16));
+		fail_if(pico_ipv4_link_add(dev[i], a[i], nm16) != 0, "Error adding link");
+	}
+	/*link_find + link_get + route_add*/
+	for (i = 0; i < IP_TST_SIZ; i++) {
+		gw[i].addr = long_be(0x0a0000f0 + (i << 16));
+		r[i].addr = long_be(0x0c00001 + (i << 16));
+		fail_unless(pico_ipv4_link_find(&a[i]) == dev[i], "Error finding link");
+		l[i] = pico_ipv4_link_get(&a[i]);
+		fail_if(l[i] == NULL, "Error getting link");
+		fail_if(pico_ipv4_route_add(r[i], nm32, gw[i], 1, l[i]) != 0, "Error adding route");
+		fail_if(pico_ipv4_route_add(d[i], nm32, gw[i], 1, l[i]) != 0, "Error adding route");
+	}
+	/*get_gateway + source_find*/
+	for (i = 0; i < IP_TST_SIZ; i++) {
+		ret = pico_ipv4_route_get_gateway(&r[i]);
+		fail_if(ret.addr != gw[i].addr, "Error get gateway: returned wrong route");
+		source[i] = pico_ipv4_source_find(&d[i]);
+		fail_if(source[i]->addr != a[i].addr, "Error find source: returned wrong route");
+	}
+	/*route_del + link_del*/
+	for (i = 0; i < IP_TST_SIZ; i++) {
+		fail_if(pico_ipv4_route_del(r[i], nm32, 1) != 0, "Error deleting route");
+		fail_if(pico_ipv4_link_del(dev[i], a[i]) != 0, "Error deleting link");
+	}
+	/*string_to_ipv4 + ipv4_to_string*/
+	pico_string_to_ipv4(ipstr, &(ipaddr.addr));
+	fail_if(ipaddr.addr != long_be(0xc0a80101), "Error string to ipv4");
+	memset(ipstr, 0, 12);
+	pico_ipv4_to_string(ipstr, ipaddr.addr);
+	fail_if(strncmp(ipstr, "192.168.1.1", 11) != 0, "Error ipv4 to string");
+
+	/*valid_netmask*/
+	fail_if(pico_ipv4_valid_netmask(long_be(nm32.addr)) != 32, "Error checking netmask");
+
+	/*is_unicast*/
+	fail_if((pico_ipv4_is_unicast(long_be(0xc0a80101))) != 1, "Error checking unicast");
+	fail_if((pico_ipv4_is_unicast(long_be(0xe0000001))) != 0, "Error checking unicast");
+
+	/*rebound*/
+	fail_if(pico_ipv4_rebound(f_NULL) != -1, "Error rebound frame");
+
+	/*frame_push*/
+	fail_if(pico_ipv4_frame_push(f_NULL, dst_NULL, PICO_PROTO_TCP) != -1, "Error push frame");
+}
+
+static int do_test_picotcp(int argc, char *argv[])
+{
+	do_test_ipv4();
+
+	return 0;
+}
+
+BAREBOX_CMD_START(test_picotcp)
+	.cmd		= do_test_picotcp,
+BAREBOX_CMD_END
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 13/16] net: picotcp: add ifconfig command
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (11 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 12/16] net: picotcp: add test_picotcp command Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 14/16] net: picotcp: add ping command Antony Pavlov
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 net/Makefile           |   1 +
 net/picotcp/Kconfig    |   5 +++
 net/picotcp_ifconfig.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 122 insertions(+)

diff --git a/net/Makefile b/net/Makefile
index bfe74fb..d5b133b 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_NET_PICOTCP) += picotcp/
 obj-$(CONFIG_NET_PICOTCP) += picotcp.o
 
 obj-$(CONFIG_CMD_PICOTCP_TEST_IPV4) += picotcp_test_ipv4.o
+obj-$(CONFIG_CMD_PICOTCP_IFCONFIG) += picotcp_ifconfig.o
diff --git a/net/picotcp/Kconfig b/net/picotcp/Kconfig
index 17b8293..9a2d628 100644
--- a/net/picotcp/Kconfig
+++ b/net/picotcp/Kconfig
@@ -38,4 +38,9 @@ config CMD_PICOTCP_TEST_IPV4
 	depends on NET_PICO_SUPPORT_IPV4
 	prompt "test_picotcp command"
 
+config CMD_PICOTCP_IFCONFIG
+	bool
+	depends on NET_PICO_SUPPORT_IPV4
+	prompt "ifconfig command"
+
 endif # NET_PICOTCP
diff --git a/net/picotcp_ifconfig.c b/net/picotcp_ifconfig.c
new file mode 100644
index 0000000..1d4e89b
--- /dev/null
+++ b/net/picotcp_ifconfig.c
@@ -0,0 +1,116 @@
+#include <common.h>
+#include <command.h>
+#include <complete.h>
+
+#include <pico_stack.h>
+#include <pico_ipv4.h>
+#include <pico_dev_null.h>
+#include <pico_icmp4.h>
+#include <pico_tree.h>
+
+extern struct pico_tree Device_tree;
+extern struct pico_tree Tree_dev_link;
+
+static void printf_iface(struct pico_device *dev)
+{
+	struct pico_ipv4_link *link;
+	struct pico_tree_node *index;
+
+	printf("%-10s", dev->name);
+
+	if (dev->eth) {
+		struct pico_ethdev *eth = dev->eth;
+
+		printf("Link encap:Ethernet  HWaddr ");
+		printf("%02x:%02x:%02x:%02x:%02x:%02x",
+			eth->mac.addr[0], eth->mac.addr[1],
+			eth->mac.addr[2], eth->mac.addr[3],
+			eth->mac.addr[4], eth->mac.addr[5]);
+	}
+	printf("\n");
+
+	pico_tree_foreach(index, &Tree_dev_link) {
+		link = index->keyValue;
+		if (dev == link->dev) {
+			char ipstr[16];
+			pico_ipv4_to_string(ipstr, link->address.addr);
+			printf("          inet addr:%s", ipstr);
+			pico_ipv4_to_string(ipstr, link->netmask.addr);
+			printf(" Mask:%s\n", ipstr);
+		}
+	}
+	printf("\n");
+}
+
+static int do_ifconfig(int argc, char *argv[])
+{
+	struct pico_device *picodev;
+	struct pico_ip4 ipaddr, nm;
+	int ret;
+
+	if (argc == 1) {
+		struct pico_tree_node *index;
+
+		pico_tree_foreach(index, &Device_tree) {
+			printf_iface(index->keyValue);
+		}
+
+		return 0;
+	}
+
+	picodev = pico_get_device(argv[1]);
+	if (!picodev) {
+		struct pico_device *dev;
+		struct pico_tree_node *index;
+
+		perror("wrong device name");
+
+		printf("available interfaces:\n");
+
+		pico_tree_foreach(index, &Device_tree) {
+			dev = index->keyValue;
+			printf("%s\n", dev->name);
+		}
+
+		return 1;
+	}
+
+	if (argc == 2) {
+		struct pico_tree_node *index;
+
+		pico_tree_foreach(index, &Device_tree) {
+			struct pico_device *dev = index->keyValue;
+
+			if (!strcmp(dev->name, argv[1])) {
+				printf_iface(dev);
+			}
+		}
+
+		return 0;
+	}
+
+	if (argc < 4) {
+		perror("ifconfig");
+		return 1;
+	}
+
+	ret = pico_string_to_ipv4(argv[2], &(ipaddr.addr));
+	if (ret) {
+		perror("wrong ipaddr");
+		return 1;
+	}
+
+	ret = pico_string_to_ipv4(argv[3], &(nm.addr));
+	if (ret) {
+		perror("wrong netmask");
+		return 1;
+	}
+
+	pico_ipv4_link_add(picodev, ipaddr, nm);
+
+	return 0;
+}
+
+BAREBOX_CMD_START(ifconfig)
+	.cmd		= do_ifconfig,
+BAREBOX_CMD_END
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 14/16] net: picotcp: add ping command
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (12 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 13/16] net: picotcp: add ifconfig command Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 15/16] net: picotcp: add route command Antony Pavlov
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 net/Makefile        |  1 +
 net/picotcp/Kconfig |  5 ++++
 net/picotcp_ping.c  | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+)

diff --git a/net/Makefile b/net/Makefile
index d5b133b..04e347f 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_NET_PICOTCP) += picotcp.o
 
 obj-$(CONFIG_CMD_PICOTCP_TEST_IPV4) += picotcp_test_ipv4.o
 obj-$(CONFIG_CMD_PICOTCP_IFCONFIG) += picotcp_ifconfig.o
+obj-$(CONFIG_CMD_PICOTCP_PING) += picotcp_ping.o
diff --git a/net/picotcp/Kconfig b/net/picotcp/Kconfig
index 9a2d628..cb60001 100644
--- a/net/picotcp/Kconfig
+++ b/net/picotcp/Kconfig
@@ -43,4 +43,9 @@ config CMD_PICOTCP_IFCONFIG
 	depends on NET_PICO_SUPPORT_IPV4
 	prompt "ifconfig command"
 
+config CMD_PICOTCP_PING
+	bool
+	depends on NET_PICO_SUPPORT_ICMP4
+	prompt "ping command"
+
 endif # NET_PICOTCP
diff --git a/net/picotcp_ping.c b/net/picotcp_ping.c
new file mode 100644
index 0000000..ed69fb5
--- /dev/null
+++ b/net/picotcp_ping.c
@@ -0,0 +1,85 @@
+#include <command.h>
+#include <common.h>
+#include <complete.h>
+#include <driver.h>
+#include <poller.h>
+
+#include <pico_stack.h>
+#include <pico_ipv4.h>
+#include <pico_dev_null.h>
+#include <pico_dhcp_client.h>
+#include <pico_icmp4.h>
+
+#define NUM_PING 3
+
+static int ping_done;
+static int ping_code;
+
+/* callback function for receiving ping reply */
+void cb_ping(struct pico_icmp4_stats *s)
+{
+	char host[30];
+	int time_sec = 0;
+	int time_msec = 0;
+
+	/* convert ip address from icmp4_stats structure to string */
+	pico_ipv4_to_string(host, s->dst.addr);
+
+	/* get time information from icmp4_stats structure */
+	time_sec = s->time / 1000;
+	time_msec = s->time % 1000;
+
+	if (s->err == PICO_PING_ERR_REPLIED) {
+		/* print info if no error reported in icmp4_stats structure */
+		printf("%lu bytes from %s: icmp_req=%lu ttl=%lu time=%llu ms\n", \
+			s->size, host, s->seq, s->ttl, s->time);
+		if (s->seq == NUM_PING) {
+			ping_done = 1;
+		}
+	} else {
+		/* else, print error info */
+		printf("PING %lu to %s: Error %d\n", s->seq, host, s->err);
+		ping_done = 1;
+	}
+
+	ping_code = s->err;
+}
+
+static int do_picoping(int argc, char *argv[])
+{
+	int id;
+
+	if (argc < 1) {
+		perror("picoping");
+		return 1;
+	}
+
+	id = pico_icmp4_ping(argv[1], NUM_PING, 1000, 5000, 48, cb_ping);
+
+	if (id == -1) {
+		return -EIO;
+	}
+
+	ping_done = 0;
+	ping_code = PICO_PING_ERR_PENDING;
+
+	while (!ping_done) {
+		if (ctrlc()) {
+			break;
+		}
+		get_time_ns();
+		poller_call();
+	}
+
+	pico_icmp4_ping_abort(id);
+
+	if (ping_code != PICO_PING_ERR_REPLIED) {
+		return -EIO;
+	}
+
+	return 0;
+}
+
+BAREBOX_CMD_START(picoping)
+	.cmd		= do_picoping,
+BAREBOX_CMD_END
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 15/16] net: picotcp: add route command
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (13 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 14/16] net: picotcp: add ping command Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-19 20:07 ` [RFC v2 16/16] sandbox_defconfig: switch to picotcp Antony Pavlov
  2015-07-20  7:10 ` [RFC v2 00/16] barebox picotcp integration (2015.07.19) Sascha Hauer
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 net/Makefile        |  1 +
 net/picotcp/Kconfig |  5 +++++
 net/picotcp_route.c | 36 ++++++++++++++++++++++++++++++++++++
 3 files changed, 42 insertions(+)

diff --git a/net/Makefile b/net/Makefile
index 04e347f..6261454 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_NET_PICOTCP) += picotcp.o
 obj-$(CONFIG_CMD_PICOTCP_TEST_IPV4) += picotcp_test_ipv4.o
 obj-$(CONFIG_CMD_PICOTCP_IFCONFIG) += picotcp_ifconfig.o
 obj-$(CONFIG_CMD_PICOTCP_PING) += picotcp_ping.o
+obj-$(CONFIG_CMD_PICOTCP_ROUTE) += picotcp_route.o
diff --git a/net/picotcp/Kconfig b/net/picotcp/Kconfig
index cb60001..2cd04d2 100644
--- a/net/picotcp/Kconfig
+++ b/net/picotcp/Kconfig
@@ -48,4 +48,9 @@ config CMD_PICOTCP_PING
 	depends on NET_PICO_SUPPORT_ICMP4
 	prompt "ping command"
 
+config CMD_PICOTCP_ROUTE
+	bool
+	depends on NET_PICO_SUPPORT_IPV4
+	prompt "route command"
+
 endif # NET_PICOTCP
diff --git a/net/picotcp_route.c b/net/picotcp_route.c
new file mode 100644
index 0000000..d24e9ba
--- /dev/null
+++ b/net/picotcp_route.c
@@ -0,0 +1,36 @@
+#include <common.h>
+#include <command.h>
+#include <complete.h>
+
+#include <pico_stack.h>
+#include <pico_ipv4.h>
+#include <pico_icmp4.h>
+
+static int do_route(int argc, char *argv[])
+{
+	struct pico_ipv4_route *r;
+	struct pico_tree_node *index;
+
+	printf("picotcp IPv4 routing table\n");
+	printf("Destination     Gateway         Genmask         Metric Iface\n");
+
+	pico_tree_foreach(index, &Routes) {
+		char ipstr[32];
+
+		r = index->keyValue;
+
+		pico_ipv4_to_string(ipstr, r->dest.addr);
+		printf("%-16s", ipstr);
+		pico_ipv4_to_string(ipstr, r->gateway.addr);
+		printf("%-16s", ipstr);
+		pico_ipv4_to_string(ipstr, r->netmask.addr);
+		printf("%-16s", ipstr);
+		printf("%-7d%s\n", r->metric, r->link->dev->name);
+	}
+
+	return 0;
+}
+
+BAREBOX_CMD_START(route)
+	.cmd		= do_route,
+BAREBOX_CMD_END
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC v2 16/16] sandbox_defconfig: switch to picotcp
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (14 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 15/16] net: picotcp: add route command Antony Pavlov
@ 2015-07-19 20:07 ` Antony Pavlov
  2015-07-20  7:10 ` [RFC v2 00/16] barebox picotcp integration (2015.07.19) Sascha Hauer
  16 siblings, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-19 20:07 UTC (permalink / raw)
  To: barebox

Picotcp sandbox barebox howto
=============================

Compile sandbox barebox:

  $ cd barebox.git
  $ unset ARCH
  $ unset CROSS_COMPILE
  $ make sandbox_defconfig
  ...
  $ make

Run barebox:

  $ su
  # ./barebox

Testing ping
------------

While sandbox barebox is running setup a IP-address
for your host 'barebox' network interface, e.g.:

  # ifconfig barebox 192.168.1.1

Next, in sandbox barebox console setup network interface
and try to ping host:

  barebox:/ ifconfig eth 192.168.1.2 255.255.255.0
  Assigned ipv4 192.168.1.2 to device eth
  barebox:/ picoping 192.168.1.1
  48 bytes from 192.168.1.1: icmp_req=1 ttl=64 time=1 ms
  ...
  48 bytes from 192.168.1.1: icmp_req=10 ttl=64 time=0 ms

Testing domain name resolving
-----------------------------

Install simple maradns name server on the host.

Edit /etc/maradns/mararc config file, add these lines:

  csv2 = {}
  csv2["example.com."] = "db.example.com"

  bind_address = "192.168.1.1"

Edit /etc/maradns/db.example.com, add these lines:

  example.com. 192.168.1.1 ~
  www.example.com. 192.168.1.1 ~
  barebox.example.com. 192.168.1.2 ~

Run sandbox barebox and setup the www.example.com IP-address
for your host 'barebox' network interface, e.g.:

  # ifconfig barebox 192.168.1.1

Restart maradns:

  $ /etc/init.d/maradns restart

Check name resolution:

  barebox@barebox sandbox:/ ifconfig eth 192.168.1.2 255.255.255.0
  Assigned ipv4 192.168.1.2 to device eth
  barebox@barebox sandbox:/ net.nameserver=192.168.1.1
  barebox@barebox sandbox:/ host barebox.example.com
  barebox.example.com is at 192.168.1.2
  barebox@barebox sandbox:/ host www.example.com
  www.example.com is at 192.168.1.1

The same checks for barebox legacy network stack:

  barebox@barebox sandbox:/ eth0.ipaddr=192.168.1.2
  barebox@barebox sandbox:/ eth0.serverip=192.168.1.1
  barebox@barebox sandbox:/ net.domainname=example.com
  barebox@barebox sandbox:/ net.nameserver=192.168.1.1
  barebox@barebox sandbox:/ host barebox.example.com
  warning: No MAC address set. Using random address 9a:a1:86:31:05:1e
  barebox.example.com is at 192.168.1.2
  barebox@barebox sandbox:/ host www.example.com
  www.example.com is at 192.168.1.1

Testing dhcp (ad memorandum)
----------------------------

Configure your host dhcp server, e.g. add this
to your /etc/dhcp/dhcpd.conf:

  subnet 192.168.1.0 netmask 255.255.255.0 {
    range dynamic-bootp 192.168.1.26 192.168.1.29;
    option routers 192.168.1.1;
    option broadcast-address 192.168.1.255;
    default-lease-time 600;
    max-lease-time 7200;
  }

While sandbox barebox is running setup a IP-address
for your host 'barebox' network interface and restart
your host dhcp server, e.g.:

  # ifconfig barebox 192.168.1.1
  # /etc/init.d/isc-dhcp-server restart

Next, in your sandbox barebox console run 'dhclient':

  barebox:/ dhclient eth
  Assigned ipv4 0.0.0.0 to device eth
  Assigned ipv4 192.168.1.26 to device eth
  DHCP client: renewal time (T1) 300
  DHCP client: rebinding time (T2) 525
  DHCP client: lease time 496
  DHCP client: IP assigned by the server: 192.168.1.26

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 arch/sandbox/configs/sandbox_defconfig | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/arch/sandbox/configs/sandbox_defconfig b/arch/sandbox/configs/sandbox_defconfig
index d82579b..320a22b 100644
--- a/arch/sandbox/configs/sandbox_defconfig
+++ b/arch/sandbox/configs/sandbox_defconfig
@@ -36,10 +36,7 @@ CONFIG_CMD_LET=y
 CONFIG_CMD_MSLEEP=y
 CONFIG_CMD_READF=y
 CONFIG_CMD_SLEEP=y
-CONFIG_CMD_DHCP=y
 CONFIG_CMD_HOST=y
-CONFIG_CMD_PING=y
-CONFIG_CMD_TFTP=y
 CONFIG_CMD_ECHO_E=y
 CONFIG_CMD_EDIT=y
 CONFIG_CMD_MENU=y
@@ -61,8 +58,13 @@ CONFIG_CMD_OFTREE=y
 CONFIG_CMD_TIME=y
 CONFIG_CMD_SPD_DECODE=y
 CONFIG_NET=y
+CONFIG_NET_PICOTCP=y
 CONFIG_NET_NFS=y
 CONFIG_NET_NETCONSOLE=y
+CONFIG_CMD_PICOTCP_TEST_IPV4=y
+CONFIG_CMD_PICOTCP_IFCONFIG=y
+CONFIG_CMD_PICOTCP_PING=y
+CONFIG_CMD_PICOTCP_ROUTE=y
 CONFIG_OFDEVICE=y
 CONFIG_OF_BAREBOX_DRIVERS=y
 CONFIG_DRIVER_NET_TAP=y
-- 
2.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC v2 00/16] barebox picotcp integration (2015.07.19)
  2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
                   ` (15 preceding siblings ...)
  2015-07-19 20:07 ` [RFC v2 16/16] sandbox_defconfig: switch to picotcp Antony Pavlov
@ 2015-07-20  7:10 ` Sascha Hauer
  2015-07-20  9:50   ` Antony Pavlov
  2015-07-20 10:06   ` Antony Pavlov
  16 siblings, 2 replies; 24+ messages in thread
From: Sascha Hauer @ 2015-07-20  7:10 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

Hi Antony,

On Sun, Jul 19, 2015 at 11:07:07PM +0300, Antony Pavlov wrote:
> I have just published latest picotcp-enabled barebox.
> Please see my 20150719.picotcp branch in my github barebox repo
> (https://github.com/frantony/barebox/tree/20150719.picotcp).
> 
> This version is based on the latest barebox-next and picotcp v1.5.0
> (there is also picotcp v1.5.1, but is has no interested
> for barebox changes since v1.5.0).
> 
> 
> Changes since 2015.07.15 (see http://lists.infradead.org/pipermail/barebox/2015-June/024174.html):
> 
>     * net: UDP API changed to satisfy the picotcp integration needs;
>     * nfs, tftp and dns subsystems have no picotcp-related stuff anymore.
>     * netconsole works on top of picotcp with no additional changes.
> 
> 
> Here are some notes:
> 
>   1. just now tftp/nfs file transfer on top of picotcp is slower than
>      the same transfer on top of legacy network stack;
> 
>   2. there is no $<current network interface> anymore,
>      so dhcp, tftp and ifup commands don't work on top of picotcp.
>      The ifconfig command is used for network interfaces setup.
> 
>      N.B. There is an old patch for dhcp support on top of picotcp
>         https://github.com/frantony/barebox/commit/94021b6d7bb933cd50b7ea9e2c55725b5c404205
> 
>   3. The picoping command is used insted of traditional ping command.

First of all I applied patches 1-4 to next.

I can't get this version to work. I have done:

# eth0.ethaddr=00:04:9f:01:b5:37
# eth0.ipaddr=192.168.23.170
# eth0.netmask=255.255.0.0
# mount -t tftp 192.168.23.4 /mnt/
# cp mnt/b b
T T T T could not open mnt/b: Interrupted system call
# picoping 192.168.23.4
 ---- Ping timeout!!!
PING 1 to 192.168.23.4: Error 1
picoping: I/O error

Anything I have missed?

I noticed that the MAC address is no longer set and the stack no longer
checks for a link. I believe picotcp should call eth_send rather than
invoking eth->send directly.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC v2 00/16] barebox picotcp integration (2015.07.19)
  2015-07-20  7:10 ` [RFC v2 00/16] barebox picotcp integration (2015.07.19) Sascha Hauer
@ 2015-07-20  9:50   ` Antony Pavlov
  2015-07-20 10:06   ` Antony Pavlov
  1 sibling, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-20  9:50 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On Mon, 20 Jul 2015 09:10:13 +0200
Sascha Hauer <s.hauer@pengutronix.de> wrote:

> Hi Antony,
> 
> On Sun, Jul 19, 2015 at 11:07:07PM +0300, Antony Pavlov wrote:
> > I have just published latest picotcp-enabled barebox.
> > Please see my 20150719.picotcp branch in my github barebox repo
> > (https://github.com/frantony/barebox/tree/20150719.picotcp).
> > 
> > This version is based on the latest barebox-next and picotcp v1.5.0
> > (there is also picotcp v1.5.1, but is has no interested
> > for barebox changes since v1.5.0).
> > 
> > 
> > Changes since 2015.07.15 (see http://lists.infradead.org/pipermail/barebox/2015-June/024174.html):
> > 
> >     * net: UDP API changed to satisfy the picotcp integration needs;
> >     * nfs, tftp and dns subsystems have no picotcp-related stuff anymore.
> >     * netconsole works on top of picotcp with no additional changes.
> > 
> > 
> > Here are some notes:
> > 
> >   1. just now tftp/nfs file transfer on top of picotcp is slower than
> >      the same transfer on top of legacy network stack;
> > 
> >   2. there is no $<current network interface> anymore,
> >      so dhcp, tftp and ifup commands don't work on top of picotcp.
> >      The ifconfig command is used for network interfaces setup.
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This is the reason of your 'Ping timeout!!!'

> 
> I can't get this version to work. I have done:
> 
> # eth0.ethaddr=00:04:9f:01:b5:37
> # eth0.ipaddr=192.168.23.170
> # eth0.netmask=255.255.0.0
> # mount -t tftp 192.168.23.4 /mnt/
> # cp mnt/b b
> T T T T could not open mnt/b: Interrupted system call
> # picoping 192.168.23.4
>  ---- Ping timeout!!!
> PING 1 to 192.168.23.4: Error 1
> picoping: I/O error
> 
> Anything I have missed?

Please use ifconfig for interface setup. E.g.

ifconfig eth 192.168.23.170 255.255.0.0

I think it is possible to implement network interface setup via 
eth0.ipaddr and eth0.netmask manipulation (and even sacrifice ifconfig command).


Here is my picotcp test script

#!/bin/sh

SERVER=192.168.100.1
ifconfig eth 192.168.100.2 255.255.255.0

picoping $SERVER

net.nameserver=$SERVER
host barebox.example.com
host www.example.com

mount -t nfs $SERVER:/tftpboot /mnt
ls /mnt
md5sum /mnt/bash
umount /mnt
ls /mnt

mount -t tftp $SERVER /mnt
md5sum /mnt/test
umount /mnt

> I noticed that the MAC address is no longer set and the stack no longer
> checks for a link. I believe picotcp should call eth_send rather than
> invoking eth->send directly.

Hmmm, It looks like I have completely missed any MAC-address manipulation stuff.

I see no means to use eth_send() from picotcp code at the moment.

Just now picotcp "parasitize" on legacy stack: for one phisical network interface
there are the picotcp network interface and the legacy network interface at the same time,
but only picotcp actualy operates (but some legacy network interface functions are not
realized).

The main problem is that barebox has the 'only one network interface is active' conception,
but picotcp can handle several active network interfaces at the same time.
In this patchseries the 'only one network interface is active' conception is not used, so
some commands (dhcp, ifup) do not work.

Picotcp selects necessary network interface for eth->send() invoking after routing.
But if I just call eth_send() from picotcp a collision is possible.
E.g. if you have two network interfaces and picotcp want to use the 2nd for packet sending
but barebox thinks that the 1st interface is active then eth_send() leads to sending via the 1st one.

I think it is possible to impart current_active_interface
property to picotcp-barebox glue code for smooth integration.

I'll try to take into account your notes in the next picotcp integration patchseries;

-- 
Best regards,
  Antony Pavlov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC v2 00/16] barebox picotcp integration (2015.07.19)
  2015-07-20  7:10 ` [RFC v2 00/16] barebox picotcp integration (2015.07.19) Sascha Hauer
  2015-07-20  9:50   ` Antony Pavlov
@ 2015-07-20 10:06   ` Antony Pavlov
  2015-07-20 10:45     ` Sascha Hauer
  1 sibling, 1 reply; 24+ messages in thread
From: Antony Pavlov @ 2015-07-20 10:06 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On Mon, 20 Jul 2015 09:10:13 +0200
Sascha Hauer <s.hauer@pengutronix.de> wrote:

> Hi Antony,
> 
> On Sun, Jul 19, 2015 at 11:07:07PM +0300, Antony Pavlov wrote:
> > I have just published latest picotcp-enabled barebox.
> > Please see my 20150719.picotcp branch in my github barebox repo
> > (https://github.com/frantony/barebox/tree/20150719.picotcp).
> > 
> > This version is based on the latest barebox-next and picotcp v1.5.0
> > (there is also picotcp v1.5.1, but is has no interested
> > for barebox changes since v1.5.0).
> > 
> > 
> > Changes since 2015.07.15 (see http://lists.infradead.org/pipermail/barebox/2015-June/024174.html):
> > 
> >     * net: UDP API changed to satisfy the picotcp integration needs;
> >     * nfs, tftp and dns subsystems have no picotcp-related stuff anymore.
> >     * netconsole works on top of picotcp with no additional changes.
> > 
> > 
> > Here are some notes:
> > 
> >   1. just now tftp/nfs file transfer on top of picotcp is slower than
> >      the same transfer on top of legacy network stack;
> > 
> >   2. there is no $<current network interface> anymore,
> >      so dhcp, tftp and ifup commands don't work on top of picotcp.
> >      The ifconfig command is used for network interfaces setup.
> > 
> >      N.B. There is an old patch for dhcp support on top of picotcp
> >         https://github.com/frantony/barebox/commit/94021b6d7bb933cd50b7ea9e2c55725b5c404205
> > 
> >   3. The picoping command is used insted of traditional ping command.
> 
> First of all I applied patches 1-4 to next.

Sascha!

Please comment patches 5-7!

Probably these patches will be changed in the next picotcp integration patchseries version,
but your comment on them could be very beneficial.

-- 
Best regards,
  Antony Pavlov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC v2 00/16] barebox picotcp integration (2015.07.19)
  2015-07-20 10:06   ` Antony Pavlov
@ 2015-07-20 10:45     ` Sascha Hauer
  2015-07-20 12:16       ` Antony Pavlov
  2015-07-24  4:58       ` Antony Pavlov
  0 siblings, 2 replies; 24+ messages in thread
From: Sascha Hauer @ 2015-07-20 10:45 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

On Mon, Jul 20, 2015 at 01:06:49PM +0300, Antony Pavlov wrote:
> On Mon, 20 Jul 2015 09:10:13 +0200
> Sascha Hauer <s.hauer@pengutronix.de> wrote:
> 
> > Hi Antony,
> > 
> > On Sun, Jul 19, 2015 at 11:07:07PM +0300, Antony Pavlov wrote:
> > > I have just published latest picotcp-enabled barebox.
> > > Please see my 20150719.picotcp branch in my github barebox repo
> > > (https://github.com/frantony/barebox/tree/20150719.picotcp).
> > > 
> > > This version is based on the latest barebox-next and picotcp v1.5.0
> > > (there is also picotcp v1.5.1, but is has no interested
> > > for barebox changes since v1.5.0).
> > > 
> > > 
> > > Changes since 2015.07.15 (see http://lists.infradead.org/pipermail/barebox/2015-June/024174.html):
> > > 
> > >     * net: UDP API changed to satisfy the picotcp integration needs;
> > >     * nfs, tftp and dns subsystems have no picotcp-related stuff anymore.
> > >     * netconsole works on top of picotcp with no additional changes.
> > > 
> > > 
> > > Here are some notes:
> > > 
> > >   1. just now tftp/nfs file transfer on top of picotcp is slower than
> > >      the same transfer on top of legacy network stack;
> > > 
> > >   2. there is no $<current network interface> anymore,
> > >      so dhcp, tftp and ifup commands don't work on top of picotcp.
> > >      The ifconfig command is used for network interfaces setup.
> > > 
> > >      N.B. There is an old patch for dhcp support on top of picotcp
> > >         https://github.com/frantony/barebox/commit/94021b6d7bb933cd50b7ea9e2c55725b5c404205
> > > 
> > >   3. The picoping command is used insted of traditional ping command.
> > 
> > First of all I applied patches 1-4 to next.
> 
> Sascha!
> 
> Please comment patches 5-7!
> 
> Probably these patches will be changed in the next picotcp integration patchseries version,
> but your comment on them could be very beneficial.

From looking at them they are ok. I haven't found the place where you
allocate packets now, but please make sure they are aligned for dma
accesses, i.e. use net_alloc_packet(). Otherwise this happens:

eth0: Transmit data not aligned: c0416acc!

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC v2 00/16] barebox picotcp integration (2015.07.19)
  2015-07-20 10:45     ` Sascha Hauer
@ 2015-07-20 12:16       ` Antony Pavlov
  2015-07-24  4:58       ` Antony Pavlov
  1 sibling, 0 replies; 24+ messages in thread
From: Antony Pavlov @ 2015-07-20 12:16 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On Mon, 20 Jul 2015 12:45:24 +0200
Sascha Hauer <s.hauer@pengutronix.de> wrote:

> On Mon, Jul 20, 2015 at 01:06:49PM +0300, Antony Pavlov wrote:
> > On Mon, 20 Jul 2015 09:10:13 +0200
> > Sascha Hauer <s.hauer@pengutronix.de> wrote:
> > 
> > > Hi Antony,
> > > 
> > > On Sun, Jul 19, 2015 at 11:07:07PM +0300, Antony Pavlov wrote:
> > > > I have just published latest picotcp-enabled barebox.
> > > > Please see my 20150719.picotcp branch in my github barebox repo
> > > > (https://github.com/frantony/barebox/tree/20150719.picotcp).
> > > > 
> > > > This version is based on the latest barebox-next and picotcp v1.5.0
> > > > (there is also picotcp v1.5.1, but is has no interested
> > > > for barebox changes since v1.5.0).
> > > > 
> > > > 
> > > > Changes since 2015.07.15 (see http://lists.infradead.org/pipermail/barebox/2015-June/024174.html):
> > > > 
> > > >     * net: UDP API changed to satisfy the picotcp integration needs;
> > > >     * nfs, tftp and dns subsystems have no picotcp-related stuff anymore.
> > > >     * netconsole works on top of picotcp with no additional changes.
> > > > 
> > > > 
> > > > Here are some notes:
> > > > 
> > > >   1. just now tftp/nfs file transfer on top of picotcp is slower than
> > > >      the same transfer on top of legacy network stack;
> > > > 
> > > >   2. there is no $<current network interface> anymore,
> > > >      so dhcp, tftp and ifup commands don't work on top of picotcp.
> > > >      The ifconfig command is used for network interfaces setup.
> > > > 
> > > >      N.B. There is an old patch for dhcp support on top of picotcp
> > > >         https://github.com/frantony/barebox/commit/94021b6d7bb933cd50b7ea9e2c55725b5c404205
> > > > 
> > > >   3. The picoping command is used insted of traditional ping command.
> > > 
> > > First of all I applied patches 1-4 to next.
> > 
> > Sascha!
> > 
> > Please comment patches 5-7!
> > 
> > Probably these patches will be changed in the next picotcp integration patchseries version,
> > but your comment on them could be very beneficial.
> 
> From looking at them they are ok. I haven't found the place where you
> allocate packets now, but please make sure they are aligned for dma
> accesses, i.e. use net_alloc_packet(). Otherwise this happens:
> 
> eth0: Transmit data not aligned: c0416acc!

I see only one possibility: fix pico_zalloc() macro definition in net/picotcp/include/arch/pico_barebox.h.

Could you please check it on your hardware?

-- 
Best regards,
  Antony Pavlov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC v2 00/16] barebox picotcp integration (2015.07.19)
  2015-07-20 10:45     ` Sascha Hauer
  2015-07-20 12:16       ` Antony Pavlov
@ 2015-07-24  4:58       ` Antony Pavlov
  2015-07-24  7:19         ` Sascha Hauer
  1 sibling, 1 reply; 24+ messages in thread
From: Antony Pavlov @ 2015-07-24  4:58 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On Mon, 20 Jul 2015 12:45:24 +0200
Sascha Hauer <s.hauer@pengutronix.de> wrote:

> On Mon, Jul 20, 2015 at 01:06:49PM +0300, Antony Pavlov wrote:
> > On Mon, 20 Jul 2015 09:10:13 +0200
> > Sascha Hauer <s.hauer@pengutronix.de> wrote:
> > 
> > > Hi Antony,
> > > 
> > > On Sun, Jul 19, 2015 at 11:07:07PM +0300, Antony Pavlov wrote:
> > > > I have just published latest picotcp-enabled barebox.
> > > > Please see my 20150719.picotcp branch in my github barebox repo
> > > > (https://github.com/frantony/barebox/tree/20150719.picotcp).
> > > > 
> > > > This version is based on the latest barebox-next and picotcp v1.5.0
> > > > (there is also picotcp v1.5.1, but is has no interested
> > > > for barebox changes since v1.5.0).
> > > > 
> > > > 
> > > > Changes since 2015.07.15 (see http://lists.infradead.org/pipermail/barebox/2015-June/024174.html):
> > > > 
> > > >     * net: UDP API changed to satisfy the picotcp integration needs;
> > > >     * nfs, tftp and dns subsystems have no picotcp-related stuff anymore.
> > > >     * netconsole works on top of picotcp with no additional changes.
> > > > 
> > > > 
> > > > Here are some notes:
> > > > 
> > > >   1. just now tftp/nfs file transfer on top of picotcp is slower than
> > > >      the same transfer on top of legacy network stack;
> > > > 
> > > >   2. there is no $<current network interface> anymore,
> > > >      so dhcp, tftp and ifup commands don't work on top of picotcp.
> > > >      The ifconfig command is used for network interfaces setup.
> > > > 
> > > >      N.B. There is an old patch for dhcp support on top of picotcp
> > > >         https://github.com/frantony/barebox/commit/94021b6d7bb933cd50b7ea9e2c55725b5c404205
> > > > 
> > > >   3. The picoping command is used insted of traditional ping command.
> > > 
> > > First of all I applied patches 1-4 to next.
> > 
> > Sascha!
> > 
> > Please comment patches 5-7!
> > 
> > Probably these patches will be changed in the next picotcp integration patchseries version,
> > but your comment on them could be very beneficial.
> 
> From looking at them they are ok. I haven't found the place where you
> allocate packets now, but please make sure they are aligned for dma
> accesses, i.e. use net_alloc_packet(). Otherwise this happens:
> 
> eth0: Transmit data not aligned: c0416acc!
> 

Could you try this patch, please?

--- a/net/picotcp/include/arch/pico_barebox.h
+++ b/net/picotcp/include/arch/pico_barebox.h
@@ -45,7 +45,16 @@ static inline void pico_free(void *x)
 }
 #else
 
-#define pico_zalloc(x) calloc(x, 1)
+#include <xfuncs.h>
+
+static inline void *xzmemalign(size_t alignment, size_t bytes)
+{
+	void *ptr = xmemalign(alignment, bytes);
+	memset(ptr, 0, bytes);
+	return ptr;
+}
+
+#define pico_zalloc(x) xzmemalign(32, x)
 #define pico_free(x) free(x)
 #endif
 
-- 
Best regards,
  Antony Pavlov

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC v2 00/16] barebox picotcp integration (2015.07.19)
  2015-07-24  4:58       ` Antony Pavlov
@ 2015-07-24  7:19         ` Sascha Hauer
  0 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2015-07-24  7:19 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

On Fri, Jul 24, 2015 at 07:58:56AM +0300, Antony Pavlov wrote:
> On Mon, 20 Jul 2015 12:45:24 +0200
> Sascha Hauer <s.hauer@pengutronix.de> wrote:
> 
> > On Mon, Jul 20, 2015 at 01:06:49PM +0300, Antony Pavlov wrote:
> > > On Mon, 20 Jul 2015 09:10:13 +0200
> > > Sascha Hauer <s.hauer@pengutronix.de> wrote:
> > > 
> > > > Hi Antony,
> > > > 
> > > > On Sun, Jul 19, 2015 at 11:07:07PM +0300, Antony Pavlov wrote:
> > > > > I have just published latest picotcp-enabled barebox.
> > > > > Please see my 20150719.picotcp branch in my github barebox repo
> > > > > (https://github.com/frantony/barebox/tree/20150719.picotcp).
> > > > > 
> > > > > This version is based on the latest barebox-next and picotcp v1.5.0
> > > > > (there is also picotcp v1.5.1, but is has no interested
> > > > > for barebox changes since v1.5.0).
> > > > > 
> > > > > 
> > > > > Changes since 2015.07.15 (see http://lists.infradead.org/pipermail/barebox/2015-June/024174.html):
> > > > > 
> > > > >     * net: UDP API changed to satisfy the picotcp integration needs;
> > > > >     * nfs, tftp and dns subsystems have no picotcp-related stuff anymore.
> > > > >     * netconsole works on top of picotcp with no additional changes.
> > > > > 
> > > > > 
> > > > > Here are some notes:
> > > > > 
> > > > >   1. just now tftp/nfs file transfer on top of picotcp is slower than
> > > > >      the same transfer on top of legacy network stack;
> > > > > 
> > > > >   2. there is no $<current network interface> anymore,
> > > > >      so dhcp, tftp and ifup commands don't work on top of picotcp.
> > > > >      The ifconfig command is used for network interfaces setup.
> > > > > 
> > > > >      N.B. There is an old patch for dhcp support on top of picotcp
> > > > >         https://github.com/frantony/barebox/commit/94021b6d7bb933cd50b7ea9e2c55725b5c404205
> > > > > 
> > > > >   3. The picoping command is used insted of traditional ping command.
> > > > 
> > > > First of all I applied patches 1-4 to next.
> > > 
> > > Sascha!
> > > 
> > > Please comment patches 5-7!
> > > 
> > > Probably these patches will be changed in the next picotcp integration patchseries version,
> > > but your comment on them could be very beneficial.
> > 
> > From looking at them they are ok. I haven't found the place where you
> > allocate packets now, but please make sure they are aligned for dma
> > accesses, i.e. use net_alloc_packet(). Otherwise this happens:
> > 
> > eth0: Transmit data not aligned: c0416acc!
> > 
> 
> Could you try this patch, please?

With this the packets are now sufficiently aligned. When I replace
edev->send with eth_send in pico_adapter_send I get a step further.
Packets are still sent with the wrong mac address. It uses
00:00:00:0a:0b:0c which is probably some dummy value you introduced
somehwere, but the ethernet device is never configured with that value.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2015-07-24  7:19 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-19 20:07 [RFC v2 00/16] barebox picotcp integration (2015.07.19) Antony Pavlov
2015-07-19 20:07 ` [RFC v2 01/16] net_udp_bind(): use uint16_t type for source port Antony Pavlov
2015-07-19 20:07 ` [RFC v2 02/16] fs/tftp.c: drop unused server_port variable Antony Pavlov
2015-07-19 20:07 ` [RFC v2 03/16] fs/nfs.c: use uint16_t for port numbers Antony Pavlov
2015-07-19 20:07 ` [RFC v2 04/16] fs/nfs.c: use SUNRPC_PORT remote port by default Antony Pavlov
2015-07-19 20:07 ` [RFC v2 05/16] net: change UDP handler function API Antony Pavlov
2015-07-19 20:07 ` [RFC v2 06/16] net: change net_udp_send() API Antony Pavlov
2015-07-19 20:07 ` [RFC v2 07/16] net: introduce setudppeerport() Antony Pavlov
2015-07-19 20:07 ` [RFC v2 08/16] net: import picotcp from github Antony Pavlov
2015-07-19 20:07 ` [RFC v2 09/16] picotcp: add barebox target support Antony Pavlov
2015-07-19 20:07 ` [RFC v2 10/16] picotcp: switch to Kbuild Antony Pavlov
2015-07-19 20:07 ` [RFC v2 11/16] net: add initial picotcp support Antony Pavlov
2015-07-19 20:07 ` [RFC v2 12/16] net: picotcp: add test_picotcp command Antony Pavlov
2015-07-19 20:07 ` [RFC v2 13/16] net: picotcp: add ifconfig command Antony Pavlov
2015-07-19 20:07 ` [RFC v2 14/16] net: picotcp: add ping command Antony Pavlov
2015-07-19 20:07 ` [RFC v2 15/16] net: picotcp: add route command Antony Pavlov
2015-07-19 20:07 ` [RFC v2 16/16] sandbox_defconfig: switch to picotcp Antony Pavlov
2015-07-20  7:10 ` [RFC v2 00/16] barebox picotcp integration (2015.07.19) Sascha Hauer
2015-07-20  9:50   ` Antony Pavlov
2015-07-20 10:06   ` Antony Pavlov
2015-07-20 10:45     ` Sascha Hauer
2015-07-20 12:16       ` Antony Pavlov
2015-07-24  4:58       ` Antony Pavlov
2015-07-24  7:19         ` Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox