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

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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

Files at this revision

API Documentation at this revision

Comitter:
tass
Date:
Wed Nov 27 10:20:00 2013 +0000
Parent:
122:5b1e9de8bf7f
Child:
124:a6ecd840c965
Child:
125:96003ae6f1d8
Commit message:
Update from masterbranch + created stack dummy macros.

Changed in this revision

include/arch/pico_mbed.h Show annotated file Show diff for this revision Revisions of this file
include/pico_arp.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_http_client.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_olsr.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_slaacv4.c Show annotated file Show diff for this revision Revisions of this file
modules/pico_slaacv4.h Show annotated file Show diff for this revision Revisions of this file
modules/pico_tcp.c Show annotated file Show diff for this revision Revisions of this file
stack/pico_arp.c Show annotated file Show diff for this revision Revisions of this file
stack/pico_socket.c Show annotated file Show diff for this revision Revisions of this file
--- a/include/arch/pico_mbed.h	Thu Nov 21 09:48:05 2013 +0000
+++ b/include/arch/pico_mbed.h	Wed Nov 27 10:20:00 2013 +0000
@@ -11,7 +11,6 @@
 #ifndef PICO_SUPPORT_MBED
 #define PICO_SUPPORT_MBED
 #include <stdio.h>
-
 //#include "mbed.h"
 //#include "serial_api.h"
 
@@ -36,7 +35,10 @@
 void stack_fill_pattern(void *ptr);
 void stack_count_free_words(void *ptr);
 int stack_get_free_words(void);
-
+#else 
+#define stack_fill_pattern(...) do{}while(0)
+#define stack_count_free_words(...) do{}while(0)
+#define stack_get_free_words() (0)
 #endif
 
 #ifdef MEMORY_MEASURE // in case, comment out the two defines above me.
--- a/include/pico_arp.h	Thu Nov 21 09:48:05 2013 +0000
+++ b/include/pico_arp.h	Wed Nov 27 10:20:00 2013 +0000
@@ -12,15 +12,19 @@
 
 
 struct pico_eth *pico_arp_get(struct pico_frame *f);
-int32_t pico_arp_query(struct pico_device *dev, struct pico_ip4 *dst);
+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));
 #endif
--- a/modules/pico_http_client.c	Thu Nov 21 09:48:05 2013 +0000
+++ b/modules/pico_http_client.c	Wed Nov 27 10:20:00 2013 +0000
@@ -37,17 +37,19 @@
 
 #ifdef dbg
 	#undef dbg
-	#define dbg(...) do{}while(0);
 #endif
 
+#define dbg(...) do{}while(0)
+
+
 #define consumeChar(c) 							(pico_socket_read(client->sck,&c,1u))
 #define isLocation(line) 						(memcmp(line,"Location",8u) == 0)
 #define isContentLength(line) 			(memcmp(line,"Content-Length",14u) == 0u)
 #define isTransferEncoding(line)		(memcmp(line,"Transfer-Encoding",17u) == 0u)
 #define isChunked(line)							(memcmp(line," chunked",8u) == 0u)
 #define isNotHTTPv1(line)						(memcmp(line,"HTTP/1.",7u))
-#define is_hex_digit(x) ( ('0' <= x && x <= '9') || ('a' <= x && x <= 'f') )
-#define hex_digit_to_dec(x) ( ('0' <= x && x <= '9') ? x-'0' : ( ('a' <= x && x <= 'f') ? x-'a' + 10 : -1) )
+#define is_hex_digit(x) ((('0' <= x) && (x <= '9')) || (('a' <= x) && (x <= 'f')))
+#define hex_digit_to_dec(x) ( (('0' <= x) && (x <= '9')) ? (x-'0') : ( (('a' <= x) && (x <= 'f')) ? (x-'a' + 10) : -1) )
 
 struct pico_http_client
 {
@@ -128,7 +130,7 @@
 				if(client->header->responseCode != HTTP_CONTINUE)
 				{
 					client->wakeup(
-							client->header->responseCode == HTTP_OK ?
+							(client->header->responseCode == HTTP_OK) ?
 							EV_HTTP_REQ | EV_HTTP_BODY : // data comes for sure only when 200 is received
 							EV_HTTP_REQ
 							,client->connectionID);
@@ -344,7 +346,7 @@
 		if(size >= client->header->contentLengthOrChunk)
 		{
 			// read the rest of the chunk, if chunk is done, proceed to the next chunk
-			while(lenRead <= size)
+			while((uint16_t)lenRead <= size)
 			{
 				int tmpLenRead = 0;
 
@@ -353,7 +355,7 @@
 
 					// if needed truncate the data
 					tmpLenRead = pico_socket_read(client->sck,data + lenRead,
-					client->header->contentLengthOrChunk < (uint32_t)(size-lenRead) ? (int)client->header->contentLengthOrChunk : (int)(size-lenRead));
+					(client->header->contentLengthOrChunk < (uint32_t)(size-lenRead)) ? (int)client->header->contentLengthOrChunk : (int)(size-lenRead));
 
 					if(tmpLenRead > 0)
 					{
@@ -546,7 +548,7 @@
 	// check the integrity of the response
 	// make sure we have enough characters to include the response code
 	// make sure the server response starts with HTTP/1.
-	if(index < RESPONSE_INDEX+2 || isNotHTTPv1(line))
+	if((index < RESPONSE_INDEX+2u) || isNotHTTPv1(line))
 	{
 		// wrong format of the the response
 		pico_err = PICO_ERR_EINVAL;
--- a/modules/pico_olsr.c	Thu Nov 21 09:48:05 2013 +0000
+++ b/modules/pico_olsr.c	Wed Nov 27 10:20:00 2013 +0000
@@ -651,7 +651,7 @@
 {
   struct olsr_dev_entry *icur = Local_devices;
   while(icur) {
-    pico_arp_query(icur->dev, addr);
+    pico_arp_request(icur->dev, addr, PICO_ARP_QUERY);
     icur = icur->next;
   }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_slaacv4.c	Wed Nov 27 10:20:00 2013 +0000
@@ -0,0 +1,192 @@
+/*********************************************************************
+PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+See LICENSE and COPYING for usage.
+
+Authors: Bogdan Lupu
+*********************************************************************/
+#include "pico_slaacv4.h"
+#include "pico_arp.h"
+#include "pico_constants.h"
+#include "pico_stack.h"
+
+#ifdef PICO_SUPPORT_SLAACV4
+
+#define SLAACV4_ADDRESS  0xa9fe0000
+#define SLAACV4_MASK     0x0000FFFF
+#define SLAACV4_MINRANGE 0x00000100
+#define SLAACV4_MAXRANGE 0x0000FD00
+
+#define SLAACV4_CREATE_IPV4(seed) (((seed % SLAACV4_MAXRANGE ) + SLAACV4_MINRANGE) & SLAACV4_MASK) | SLAACV4_ADDRESS
+
+#define PROBE_WAIT           1 // delay between two tries during claim
+#define PROBE_NB             3 // number of probe packets during claim
+//#define PROBE_MIN  1
+//#define PROBE_MAX  2
+#define ANNOUNCE_WAIT        2 // delay before start announcing
+#define ANNOUNCE_NB          2 // number of announcement packets
+#define ANNOUNCE_INTERVAL    2 // time between announcement packets
+#define MAX_CONFLICTS       10 // max conflicts before rate limiting
+#define RATE_LIMIT_INTERVAL 60 // time between successive attempts
+#define DEFEND_INTERVAL     10 // minimum interval between defensive ARP
+
+enum slaacv4_state{
+	SLAACV4_RESET = 0,
+	SLAACV4_CLAIMING,
+	SLAACV4_CLAIMED,
+	SLAACV4_ANNOUNCING,
+	SLAACV4_ERROR
+};
+
+struct slaacv4_cookie{
+	uint8_t state;
+    uint8_t probe_try_nb;
+    uint8_t conflict_nb;
+    uint8_t announce_nb;
+    struct pico_ip4 ip;
+    struct pico_device *device;
+    struct pico_timer *timer;
+    void (*cb)(struct pico_ip4 *ip, uint8_t code);
+};
+
+static struct slaacv4_cookie slaacv4_local;
+
+static uint32_t pico_slaacv4_getip(struct pico_device *dev, uint8_t rand)
+{
+  uint32_t seed = 0;
+  if (dev->eth != NULL)
+  {
+    seed = pico_hash((const char *)dev->eth->mac.addr);
+  }
+  if (rand)
+  {
+    seed += pico_rand();
+  }
+  return SLAACV4_CREATE_IPV4(seed);
+}
+
+static void pico_slaacv4_init_cookie(struct pico_ip4 *ip, struct pico_device *dev, struct slaacv4_cookie *ck, void (*cb)(struct pico_ip4 *ip,  uint8_t code))
+{
+  ck->state = SLAACV4_RESET;
+  ck->probe_try_nb = 0;
+  ck->conflict_nb = 0;
+  ck->announce_nb = 0;
+  ck->cb = cb;
+  ck->device = dev;
+  ck->ip.addr = ip->addr;
+  ck->timer = NULL;
+}
+
+static void pico_slaacv4_cancel_timers(struct slaacv4_cookie *tmp)
+{
+  pico_timer_cancel(tmp->timer);
+
+  tmp->timer = NULL;
+}
+
+static void pico_slaacv4_send_announce_timer(uint32_t __attribute__((unused)) now, void *arg)
+{
+  struct slaacv4_cookie *tmp = (struct slaacv4_cookie *)arg;
+  struct pico_ip4 netmask = {.addr = 0x0000FFFF};
+
+  if (tmp->announce_nb < ANNOUNCE_NB)
+  {
+	pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_ANNOUNCE);
+	tmp->announce_nb++;
+	tmp->timer = pico_timer_add(ANNOUNCE_INTERVAL*1000,pico_slaacv4_send_announce_timer, arg);
+  }
+  else
+  {
+	tmp->state = SLAACV4_CLAIMED;
+	pico_ipv4_link_add(tmp->device, tmp->ip, netmask);
+	if (tmp->cb != NULL)
+      tmp->cb(&tmp->ip, PICO_SLAACV4_SUCCESS);
+  }
+}
+
+static void pico_slaacv4_send_probe_timer(uint32_t __attribute__((unused)) now, void *arg)
+{
+
+  struct slaacv4_cookie *tmp = (struct slaacv4_cookie *)arg;
+
+  if (tmp->probe_try_nb < PROBE_NB)
+  {
+    pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_PROBE);
+    tmp->probe_try_nb++;
+    tmp->timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, tmp);
+  }
+  else
+  {
+	tmp->state = SLAACV4_ANNOUNCING;
+	tmp->timer = pico_timer_add(ANNOUNCE_WAIT*1000,pico_slaacv4_send_announce_timer, arg);
+  }
+}
+
+
+
+static void pico_slaacv4_receive_ipconflict(void)
+{
+  struct slaacv4_cookie *tmp = &slaacv4_local;
+
+  tmp->conflict_nb++;
+  pico_slaacv4_cancel_timers(tmp);
+
+  if(tmp->state == SLAACV4_CLAIMED)
+  {
+	pico_ipv4_link_del(tmp->device,tmp->ip);
+  }
+
+  if (tmp->conflict_nb < MAX_CONFLICTS)
+  {
+	tmp->state = SLAACV4_CLAIMING;
+	tmp->probe_try_nb = 0;
+	tmp->announce_nb = 0;
+    tmp->ip.addr = long_be(pico_slaacv4_getip(tmp->device, (uint8_t)1));
+    pico_arp_register_ipconflict(&tmp->ip, &tmp->device->eth->mac, pico_slaacv4_receive_ipconflict);
+    pico_arp_request(tmp->device, &tmp->ip, PICO_ARP_PROBE);
+    tmp->probe_try_nb++;
+    tmp->timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, tmp);
+  }
+  else
+  {
+    if (tmp->cb != NULL)
+    {
+      tmp->cb(&tmp->ip, PICO_SLAACV4_ERROR);
+    }
+    tmp->state = SLAACV4_ERROR;
+  }
+
+}
+
+uint8_t pico_slaacv4_claimip(struct pico_device *dev, void (*cb)(struct pico_ip4 *ip,  uint8_t code))
+{
+  struct pico_ip4 ip;
+
+  ip.addr = long_be(pico_slaacv4_getip(dev, 0));
+
+  pico_slaacv4_init_cookie(&ip, dev, &slaacv4_local, cb);
+  pico_arp_register_ipconflict(&ip, &dev->eth->mac, pico_slaacv4_receive_ipconflict);
+  pico_arp_request(dev, &ip, PICO_ARP_PROBE);
+  slaacv4_local.state = SLAACV4_CLAIMING;
+  slaacv4_local.probe_try_nb++;
+  slaacv4_local.timer = pico_timer_add(PROBE_WAIT * 1000, pico_slaacv4_send_probe_timer, &slaacv4_local);
+
+  return 0;
+}
+
+void pico_slaacv4_unregisterip(void)
+{
+  struct slaacv4_cookie *tmp = &slaacv4_local;
+  struct pico_ip4 empty = { .addr = 0x00000000 };
+
+  if (tmp->state == SLAACV4_CLAIMED)
+  {
+	pico_ipv4_link_del(tmp->device,tmp->ip);
+  }
+
+  pico_slaacv4_cancel_timers(tmp);
+  pico_slaacv4_init_cookie(&empty, NULL, tmp, NULL);
+  pico_arp_register_ipconflict(&tmp->ip, NULL, NULL);
+
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_slaacv4.h	Wed Nov 27 10:20:00 2013 +0000
@@ -0,0 +1,18 @@
+/*********************************************************************
+PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+See LICENSE and COPYING for usage.
+
+Authors: Bogdan Lupu
+*********************************************************************/
+#ifndef _INCLUDE_PICO_SUPPORT_SLAACV4
+#define _INCLUDE_PICO_SUPPORT_SLAACV4
+#include "pico_arp.h"
+
+#define PICO_SLAACV4_SUCCESS  0
+#define PICO_SLAACV4_ERROR    1
+
+uint8_t pico_slaacv4_claimip(struct pico_device *dev, void (*cb)(struct pico_ip4 *ip,  uint8_t code));
+void    pico_slaacv4_unregisterip(void);
+
+#endif /* _INCLUDE_PICO_SUPPORT_SLAACV4 */
+
--- a/modules/pico_tcp.c	Thu Nov 21 09:48:05 2013 +0000
+++ b/modules/pico_tcp.c	Wed Nov 27 10:20:00 2013 +0000
@@ -48,6 +48,7 @@
 #define IS_INPUT_QUEUE(q)  (q->pool.compare==input_segment_compare)
 #define TCP_INPUT_OVERHEAD (sizeof(struct tcp_input_segment)+sizeof(struct pico_tree_node))
 
+
 #ifdef PICO_SUPPORT_TCP
 #define tcp_dbg_nagle(...) do{}while(0)
 #define tcp_dbg_options(...) do{}while(0)
@@ -335,12 +336,13 @@
   return ret;
 }
 
-static int release_all_until(struct pico_tcp_queue *q, uint32_t seq)
+static int release_all_until(struct pico_tcp_queue *q, uint32_t seq,uint32_t * timestamp)
 {
   void *f = NULL, *tmp __attribute__((unused));
   struct pico_tree_node * idx, * temp;
   int seq_result;
   int ret = 0;
+  *timestamp = 0;
 
   pico_tree_foreach_safe(idx,&q->pool,temp){
   f = idx->keyValue;
@@ -349,6 +351,8 @@
 		  seq_compare(SEQN((struct pico_frame *)f) + ((struct pico_frame *)f)->payload_len, seq);
     if (seq_result<= 0) {
       tcp_dbg("Releasing %p\n", f);
+      if(seq_result == 0)
+    	  *timestamp = ((struct pico_frame *)f)->timestamp;
       pico_discard_segment(q, f);
       ret++;
     } else
@@ -1280,9 +1284,9 @@
   }
 }
 
-static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f)
+static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f, uint32_t * timestamp)
 {
-  int ret =  release_all_until(&t->tcpq_out, ACKN(f));
+  int ret =  release_all_until(&t->tcpq_out, ACKN(f),timestamp);
   if (ret > 0)
     t->sock.ev_pending |= PICO_SOCK_EV_WR;
   return ret;
@@ -1393,6 +1397,7 @@
 				cpy = pico_frame_copy(f);
 				if (pico_enqueue(&tcp_out, cpy) > 0) {
 					t->backoff++;
+					t->snd_last_out = SEQN(cpy);
 					add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick);
 					tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight);
 					return;
@@ -1520,6 +1525,9 @@
   struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr;
   uint32_t rtt = 0;
   uint16_t acked = 0;
+  uint32_t acked_timestamp = 0;
+  uint8_t restart_tmr = 0;
+
   struct pico_frame *una = NULL;
   if ((hdr->flags & PICO_TCP_ACK) == 0)
     return -1;
@@ -1531,18 +1539,27 @@
   tcp_parse_options(f);
   t->recv_wnd = short_be(hdr->rwnd);
 
-  acked = (uint16_t)tcp_ack_advance_una(t, f);
+  acked = (uint16_t)tcp_ack_advance_una(t, f,&acked_timestamp);
   una = first_segment(&t->tcpq_out);
 
   if ((t->x_mode == PICO_TCP_BLACKOUT) || 
     ((t->x_mode == PICO_TCP_WINDOW_FULL) && ((t->recv_wnd << t->recv_wnd_scale) > t->mss))) {
+	int prev_mode = t->x_mode;
     tcp_dbg("Re-entering look-ahead...\n\n\n");
     t->x_mode = PICO_TCP_LOOKAHEAD;
     t->backoff = 0;
+
+    if((prev_mode == PICO_TCP_BLACKOUT) && (acked>0) && una)
+    {
+		t->snd_nxt = SEQN(una);
+		// restart the retrans timer
+		pico_timer_cancel(t->retrans_tmr);
+		t->timer_running = 0;
+		restart_tmr = 1u;
+    }
   }
 
   /* One should be acked. */
-//  if ((acked == 0) && (t->in_flight > 0))
   if ((acked == 0) && (f->payload_len  == 0) && (t->in_flight > 0))
     t->in_flight--;
   if (!una || acked > 0) {
@@ -1556,9 +1573,9 @@
       rtt = time_diff(pico_tick, f->timestamp);
       if (rtt)
         tcp_rtt(t, rtt);
-    } else if(una && (una->timestamp != 0)) {
+    } else if(acked_timestamp) {
       /* If no timestamps are there, use conservatve estimation on the una */
-        rtt = time_diff(pico_tick, una->timestamp);
+        rtt = time_diff(pico_tick, acked_timestamp);
         if (rtt)
           tcp_rtt(t, rtt);
     }
@@ -1655,6 +1672,11 @@
     }
   }
 
+  if(restart_tmr)
+  {
+  	add_retransmission_timer(t,pico_tick+t->rto);
+  }
+
   t->snd_old_ack = ACKN(f);
   return 0;
 }
@@ -2151,8 +2173,8 @@
   int sent = 0;
 
   una = first_segment(&t->tcpq_out);
+  f = peek_segment(&t->tcpq_out, t->snd_nxt);
 
-  f = peek_segment(&t->tcpq_out, t->snd_nxt);
   while((f) && (t->cwnd >= t->in_flight)) {
     hdr = (struct pico_tcp_hdr *)f->transport_hdr;
     f->timestamp = pico_tick;
--- a/stack/pico_arp.c	Thu Nov 21 09:48:05 2013 +0000
+++ b/stack/pico_arp.c	Wed Nov 27 10:20:00 2013 +0000
@@ -58,6 +58,13 @@
   struct pico_ip4 dst;
 };
 
+struct arp_service_ipconflict{
+	struct pico_eth mac;
+	struct pico_ip4 ip;
+	void (*conflict)(void);
+};
+
+static struct arp_service_ipconflict conflict_ipv4;
 
 #define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr)))
 
@@ -141,9 +148,9 @@
        dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count);
        /* check if dst is local (gateway = 0), or if to use gateway */
        if (gateway.addr != 0)
-         pico_arp_query(f->dev, &gateway);  /* arp to gateway */
+    	 pico_arp_request(f->dev, &gateway, PICO_ARP_QUERY);  /* arp to gateway */
        else
-         pico_arp_query(f->dev, &hdr->dst); /* arp to dst */
+    	 pico_arp_request(f->dev, &hdr->dst, PICO_ARP_QUERY); /* arp to dst */
 
        pico_enqueue(&pending, f);
        if (!pending_timer_on) {
@@ -178,7 +185,7 @@
   IGNORE_PARAMETER(now);
   stale->arp_status = PICO_ARP_STATUS_STALE;
   arp_dbg("ARP: Setting arp_status to STALE\n");
-  pico_arp_query(stale->dev, &stale->ipv4);
+  pico_arp_request(stale->dev, &stale->ipv4, PICO_ARP_QUERY);
 
 }
 
@@ -218,6 +225,11 @@
   if (!hdr)
     goto end;
 
+  if (conflict_ipv4.conflict != NULL)
+  {
+    if ((conflict_ipv4.ip.addr == hdr->src.addr) && (memcmp(hdr->s_mac,conflict_ipv4.mac.addr,6) != 0))
+      conflict_ipv4.conflict();
+  }
 
   /* Populate a new arp entry */
   search.ipv4.addr = hdr->src.addr;
@@ -280,7 +292,7 @@
   return ret;
 }
 
-int32_t pico_arp_query(struct pico_device *dev, struct pico_ip4 *dst)
+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;
@@ -288,9 +300,12 @@
   struct pico_ip4 *src;
   int ret;
 
-  src = pico_ipv4_source_find(dst);
-  if (!src)
-    return -1;
+  if (type == PICO_ARP_QUERY)
+  {
+    src = pico_ipv4_source_find(dst);
+    if (!src)
+      return -1;
+  }
 
   arp_dbg("QUERY: %08x\n", dst->addr);
 
@@ -311,9 +326,22 @@
   ah->psize  = PICO_SIZE_IP4;
   ah->opcode = PICO_ARP_REQUEST;
   memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH);
-  ah->src.addr = src->addr;
-  ah->dst.addr = dst->addr;
-  arp_dbg("Sending arp query.\n");
+
+  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;
+  default:
+	  ah->src.addr = src->addr;
+	  ah->dst.addr = dst->addr;
+  }
+
+  arp_dbg("Sending arp request.\n");
   ret = dev->send(dev, q->start,(int) q->len);
   pico_frame_discard(q);
   return ret;
@@ -334,3 +362,11 @@
   }
   return i;
 }
+
+void pico_arp_register_ipconflict(struct pico_ip4 *ip, struct pico_eth *mac, void(*cb)(void))
+{
+  conflict_ipv4.conflict = cb;
+  conflict_ipv4.ip.addr = ip->addr;
+  if (mac != NULL)
+    memcpy(conflict_ipv4.mac.addr, mac, 6);
+}
--- a/stack/pico_socket.c	Thu Nov 21 09:48:05 2013 +0000
+++ b/stack/pico_socket.c	Wed Nov 27 10:20:00 2013 +0000
@@ -2102,6 +2102,7 @@
 	// if no activity, force the socket into closing state
 	if( TCP_STATE(s) == PICO_SOCKET_STATE_TCP_ESTABLISHED )
 	{
+	  s->wakeup(PICO_SOCK_EV_CLOSE,s);
 	  pico_socket_close(s);
 	  s->timestamp = PICO_TIME_MS();
 	}