changeset 2162:02b2b5ad1fef

* tests/nc_test_slave.c (nc_slave): Fix some of the compiler warnings. * cdl/lwip_net.cdl Changed default value of CYGNUM_LWIP_MEMP_NUM_SYS_TIMEOUT (required for DHCP). Replaced CYGPKG_LWIP_DHCP_OPTIONS with CYGPKG_LWIP_DHCP and add CYGOPT_LWIP_DHCP_MANAGEMENT for automatic DHCP management. * include/lwip/ip_addr.h Add macro ip_addr_netcmp() (copied from lwIP CVS). * include/netif/etharp.h Updated file to version of lwIP CVS. * src/ecos/init.c Add include <pkgconf/net_lwip.h> Add lwip_dhcp_fine_tmr() and lwip_dhcp_coarse_tmr() for DHCP processing. Change tcpip_init_done() to start DHCP timers and ARP timer. Changed lwip_set_addr() to properly setup IP adress if DHCP is used. Added lwip_dhcp_init() for start of DHCP client. Removed start of ARP timer from ecosclue_init(). * src/netif/etharp.c Updated file to version of lwIP CVS.
author asl
date Wed, 15 Mar 2006 08:02:39 +0000
parents afacaa648a92
children 77e15aa63326
files packages/net/lwip_tcpip/current/ChangeLog packages/net/lwip_tcpip/current/cdl/lwip_net.cdl packages/net/lwip_tcpip/current/include/lwip/ip_addr.h packages/net/lwip_tcpip/current/include/lwipopts.h packages/net/lwip_tcpip/current/include/netif/etharp.h packages/net/lwip_tcpip/current/src/api/sockets.c packages/net/lwip_tcpip/current/src/ecos/init.c packages/net/lwip_tcpip/current/src/netif/etharp.c packages/net/lwip_tcpip/current/tests/httpd.c packages/net/lwip_tcpip/current/tests/nc_test_slave.c packages/net/lwip_tcpip/current/tests/socket.c packages/net/lwip_tcpip/current/tests/tcpecho.c packages/net/lwip_tcpip/current/tests/udpecho.c
diffstat 13 files changed, 657 insertions(+), 499 deletions(-) [+]
line wrap: on
line diff
--- a/packages/net/lwip_tcpip/current/ChangeLog
+++ b/packages/net/lwip_tcpip/current/ChangeLog
@@ -1,3 +1,31 @@
+2006-03-15  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* tests/nc_test_slave.c (nc_slave): Fix some of the compiler
+	warnings.
+
+2006-03-13  Uwe Kindler <uwe_kindler@web.de>
+
+	* cdl/lwip_net.cdl Changed default value of 
+	CYGNUM_LWIP_MEMP_NUM_SYS_TIMEOUT (required for DHCP). 
+	Replaced CYGPKG_LWIP_DHCP_OPTIONS with CYGPKG_LWIP_DHCP 
+	and add CYGOPT_LWIP_DHCP_MANAGEMENT for automatic DHCP
+	management.
+	* include/lwip/ip_addr.h Add macro ip_addr_netcmp() 
+	(copied from lwIP CVS).
+	* include/netif/etharp.h Updated file to version of
+	lwIP CVS.
+	* src/ecos/init.c Add include <pkgconf/net_lwip.h>
+	Add lwip_dhcp_fine_tmr() and lwip_dhcp_coarse_tmr()
+	for DHCP processing.
+	Change tcpip_init_done() to start DHCP timers and
+	ARP timer.
+	Changed lwip_set_addr() to properly setup IP adress
+	if DHCP is used.
+	Added lwip_dhcp_init() for start of DHCP client.
+	Removed start of ARP timer from ecosclue_init().
+	* src/netif/etharp.c Updated file to version of
+	lwIP CVS.
+	
 2006-03-02  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* cdl/lwip_net.cdl: Add the interfaces CYGPKG_NET_STACK,
--- a/packages/net/lwip_tcpip/current/cdl/lwip_net.cdl
+++ b/packages/net/lwip_tcpip/current/cdl/lwip_net.cdl
@@ -169,7 +169,7 @@ cdl_package CYGPKG_NET_LWIP {
 		no_define
 		description   	"
 			Tunables for various aspects of memory usage throughout the stack."
-			
+				
 		cdl_option CYGNUM_LWIP_MEM_ALIGNMENT {
 			display		"Memory alignment"
 			flavor		data
@@ -185,7 +185,7 @@ cdl_package CYGPKG_NET_LWIP {
 			default_value 	4000
 			description   	"
 				MEM_SIZE: the size of the heap memory. If the application will send
-				a lot of data that needs to be copied, this should be set high."
+				a lot of data that needs to be copied, this should be set high."		
 		}		 
 		
 		cdl_option CYGNUM_LWIP_MEMP_NUM_PBUF {
@@ -237,7 +237,7 @@ cdl_package CYGPKG_NET_LWIP {
 		cdl_option CYGNUM_LWIP_MEMP_NUM_SYS_TIMEOUT {
 			display		"Simultaneous active timeouts"
 			flavor		data
-			default_value 	3
+			default_value 	CYGPKG_LWIP_DHCP ? 6 : 4
 			description   	"
 				MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
 				timeouts."
@@ -249,7 +249,7 @@ cdl_package CYGPKG_NET_LWIP {
 			no_define
 			description	"
 				The following four are used only with the sequential API and can be
-  			        set to 0 if the application only will use the raw API."
+  			    set to 0 if the application only will use the raw API."
 		
 
 			cdl_option CYGNUM_LWIP_MEMP_NUM_NETBUF {
@@ -315,7 +315,7 @@ cdl_package CYGPKG_NET_LWIP {
 			default_value 	1024
 			description   	"
 			PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool."
-		}		 
+		}		
 		 
 		cdl_option CYGNUM_LWIP_PBUF_LINK_HLEN {
 			display		"Allocation for a link level header"
@@ -332,7 +332,7 @@ cdl_package CYGPKG_NET_LWIP {
 		flavor 		none
 		no_define
 		description   	"
-		Tune the TCP protocol details"
+		           Tune the TCP protocol details"
 			
 		cdl_option CYGFUN_LWIP_TCP {
 			display		"Activate TCP"
@@ -372,7 +372,7 @@ cdl_package CYGPKG_NET_LWIP {
 			default_value 	2048
 			description   	"
 				TCP Maximum segment size."
-		}		 
+		}	
 			 
 		cdl_option CYGNUM_LWIP_TCP_SND_BUF {
 			display		"Sender buffer space"
@@ -486,27 +486,32 @@ cdl_package CYGPKG_NET_LWIP {
 		}
 	}
 
-	cdl_component CYGPKG_LWIP_DHCP_OPTIONS {
-		display		"DHCP"
-		flavor		none
-		no_define
-
+	cdl_component CYGPKG_LWIP_DHCP {
+		display		  "Use DHCP"
+		flavor		  bool
+		default_value 0
+		requires  { CYGNUM_LWIP_MEMP_NUM_SYS_TIMEOUT >= 6 }
+		description "
+		    Provide DHCP for initializing the IP address of network interfaces."
+		compile core/dhcp.c
 
-		cdl_option CYGFUN_LWIP_DHCP {
-			display		"Activate DHCP"
-			flavor		bool
-			default_value 	0
-			description   	"
-				Enable this option if you want DHCP configuration of
-				interfaces."
-			compile core/dhcp.c
-		}
-
-
+        cdl_option CYGOPT_LWIP_DHCP_MANAGEMENT {
+            display    "DHCP management"
+            flavor     bool
+            default_value 1
+            description "
+                If enabled then the lwIP stack automatically calls dhcp_start(), 
+                dhcp_fine_tmr() and dhcp_coarse_tmr(). The DHCP stuff is handled 
+                in the TCP/IP thread. If this causes trouble on high traffic loads 
+                or if the application need to be aware of the DHCP state then it 
+                is better to disable this option. In this case managing the DHCP 
+                state in an application aware thread is recommended."        
+        }
+        
 		cdl_option CYGOPT_LWIP_DHCP_DOES_ARP_CHECK {
 			display		"Check offered address"
 			flavor		bool
-			default_value 	0
+			default_value 	1
 			description   	"
 				Enable this option if you want to do an ARP check on the offered address
 				(recommended)."
@@ -557,7 +562,7 @@ cdl_package CYGPKG_NET_LWIP {
 			flavor 	data
 			default_value {"\"/dev/ser0\""}
 			description "
-			Which serial port to use SLIP on."
+			        Which serial port to use SLIP on."
 		}
 	}
 	
--- a/packages/net/lwip_tcpip/current/include/lwip/ip_addr.h
+++ b/packages/net/lwip_tcpip/current/include/lwip/ip_addr.h
@@ -142,6 +142,20 @@ u8_t ip_addr_isbroadcast(struct ip_addr 
 #define ip4_addr2(ipaddr) ((unsigned int)(ntohl((ipaddr)->addr) >> 16) & 0xff)
 #define ip4_addr3(ipaddr) ((unsigned int)(ntohl((ipaddr)->addr) >> 8) & 0xff)
 #define ip4_addr4(ipaddr) ((unsigned int)(ntohl((ipaddr)->addr)) & 0xff)
+
+/**
+ * Determine if two address are on the same network.
+ *
+ * @arg addr1 IP address 1
+ * @arg addr2 IP address 2
+ * @arg mask network identifier mask
+ * @return !0 if the network identifiers of both address match
+ */
+#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
+                                              (mask)->addr) == \
+                                             ((addr2)->addr & \
+                                              (mask)->addr))
+                                              
 #endif /* __LWIP_IP_ADDR_H__ */
 
 
--- a/packages/net/lwip_tcpip/current/include/lwipopts.h
+++ b/packages/net/lwip_tcpip/current/include/lwipopts.h
@@ -158,7 +158,7 @@ a lot of data that needs to be copied, t
 /* Define LWIP_DHCP to 1 if you want DHCP configuration of
    interfaces.*/
 
-#ifdef CYGFUN_LWIP_DHCP
+#ifdef CYGPKG_LWIP_DHCP
   #define LWIP_DHCP               1
 
 /* 1 if you want to do an ARP check on the offered address
@@ -202,7 +202,7 @@ a lot of data that needs to be copied, t
 #else
 #define LWIP_HAVE_LOOPIF	    0
 #endif
-/* ---------- PPP options --------- */  
+/* ---------- PPP options --------- */ 
 #ifdef CYGPKG_LWIP_PPP 
 #define PPP_SUPPORT             1
 #else
--- a/packages/net/lwip_tcpip/current/include/netif/etharp.h
+++ b/packages/net/lwip_tcpip/current/include/netif/etharp.h
@@ -35,8 +35,8 @@
 #ifndef __NETIF_ETHARP_H__
 #define __NETIF_ETHARP_H__
 
-#ifndef PAD_ETH_SIZE
-#define PAD_ETH_SIZE 0
+#ifndef ETH_PAD_SIZE
+#define ETH_PAD_SIZE 0
 #endif
 
 #include "lwip/pbuf.h"
@@ -52,18 +52,30 @@ struct eth_addr {
   PACK_STRUCT_FIELD(u8_t addr[6]);
 } PACK_STRUCT_STRUCT;
 PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
 
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
 PACK_STRUCT_BEGIN
 struct eth_hdr {
-#if PAD_ETH_SIZE
-  PACK_STRUCT_FIELD(u8_t padding[PAD_ETH_SIZE]);
+#if ETH_PAD_SIZE
+  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
 #endif
   PACK_STRUCT_FIELD(struct eth_addr dest);
   PACK_STRUCT_FIELD(struct eth_addr src);
   PACK_STRUCT_FIELD(u16_t type);
 } PACK_STRUCT_STRUCT;
 PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
 
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
 PACK_STRUCT_BEGIN
 /** the ARP message */
 struct etharp_hdr {
@@ -78,30 +90,37 @@ struct etharp_hdr {
   PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);
 } PACK_STRUCT_STRUCT;
 PACK_STRUCT_END
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/epstruct.h"
+#endif
 
+#ifdef PACK_STRUCT_USE_INCLUDES
+#  include "arch/bpstruct.h"
+#endif
 PACK_STRUCT_BEGIN
 struct ethip_hdr {
   PACK_STRUCT_FIELD(struct eth_hdr eth);
   PACK_STRUCT_FIELD(struct ip_hdr ip);
-};
+} PACK_STRUCT_STRUCT;
+PACK_STRUCT_END
 #ifdef PACK_STRUCT_USE_INCLUDES
 #  include "arch/epstruct.h"
 #endif
 
-#define ARP_TMR_INTERVAL 10000
+/** 5 seconds period */
+#define ARP_TMR_INTERVAL 5000
 
 #define ETHTYPE_ARP 0x0806
 #define ETHTYPE_IP  0x0800
 
 void etharp_init(void);
 void etharp_tmr(void);
-struct pbuf *etharp_ip_input(struct netif *netif, struct pbuf *p);
-struct pbuf *etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,
+void etharp_ip_input(struct netif *netif, struct pbuf *p);
+void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,
          struct pbuf *p);
-struct pbuf *etharp_output(struct netif *netif, struct ip_addr *ipaddr,
+err_t etharp_output(struct netif *netif, struct ip_addr *ipaddr,
          struct pbuf *q);
 err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);
-
-
+err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);
 
 #endif /* __NETIF_ARP_H__ */
--- a/packages/net/lwip_tcpip/current/src/api/sockets.c
+++ b/packages/net/lwip_tcpip/current/src/api/sockets.c
@@ -499,7 +499,7 @@ lwip_send(int s, void *data, int size, u
     /* deallocated the buffer */
     netbuf_delete(buf);
   }
-    break;
+  break;
 #endif
 #if LWIP_TCP
   case NETCONN_TCP:
--- a/packages/net/lwip_tcpip/current/src/ecos/init.c
+++ b/packages/net/lwip_tcpip/current/src/ecos/init.c
@@ -34,6 +34,7 @@
  * init.c - misc lwip ecos glue functions 
  */
 #include <pkgconf/system.h>
+#include <pkgconf/net_lwip.h>
 #include "lwip/opt.h"
 #include "lwip/sys.h"
 #include "lwip/memp.h"
@@ -75,12 +76,6 @@ void inline IP_ADDR(struct ip_addr *ipad
 }
 
 
-void tcpip_init_done(void * arg)
-{
-	sys_sem_t *sem = arg;
-	sys_sem_signal(*sem);
-}
-
 struct netif mynetif, loopif;
 void lwip_set_addr(struct netif *netif);
 #if PPP_SUPPORT
@@ -116,6 +111,48 @@ ppp_trace(int level, const char *format,
 struct netif ecos_loopif;
 #endif
 
+
+static void
+arp_timer(void *arg)
+{
+  etharp_tmr();
+  sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler) arp_timer, NULL);
+}
+
+#if LWIP_DHCP
+static void lwip_dhcp_fine_tmr(void *arg)
+{
+    dhcp_fine_tmr();
+    sys_timeout(500, (sys_timeout_handler) lwip_dhcp_fine_tmr, NULL);
+}
+
+static void lwip_dhcp_coarse_tmr(void *arg)
+{
+    dhcp_coarse_tmr();
+    sys_timeout(60000, (sys_timeout_handler) lwip_dhcp_coarse_tmr, NULL);
+}
+#endif
+
+
+//
+// This function is called when tcpip thread finished initialisation.
+// We start several timers here - these timers are all handled in the
+// tcpip thread. That means that also the DHCP stuff is handled in the
+// TCPIP thread. If this causes any trouble than it may be necessaray to
+// use an own DHCP thread insted.
+//
+void tcpip_init_done(void * arg)
+{
+    sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler) arp_timer, NULL);
+#ifdef CYGOPT_LWIP_DHCP_MANAGEMENT
+	sys_timeout(500, (sys_timeout_handler) lwip_dhcp_fine_tmr, NULL);
+	sys_timeout(60000, (sys_timeout_handler) lwip_dhcp_coarse_tmr, NULL);
+#endif
+	sys_sem_t *sem = arg;
+	sys_sem_signal(*sem);
+}
+
+
 /*
  * Called by the eCos application at startup
  * wraps various init calls
@@ -169,22 +206,43 @@ lwip_init(void)
 	return 0;
 }
 
+
+err_t lwip_dummy_netif_init(struct netif *netif)
+{
+    return ERR_OK; 
+}
+
+
 void
 lwip_set_addr(struct netif *netif)
 {
 	struct ip_addr ipaddr, netmask, gw;
+  
+#if LWIP_DHCP
+    IP4_ADDR(&gw, 0,0,0,0);
+    IP4_ADDR(&ipaddr, 0,0,0,0);
+    IP4_ADDR(&netmask, 0,0,0,0);
 
+    netif_add(netif, &ipaddr, &netmask, &gw, netif->state, lwip_dummy_netif_init, tcpip_input);
+    netif_set_default(netif);
+#else
 	IP_ADDR(&gw, CYGDAT_LWIP_SERV_ADDR);
 	IP_ADDR(&ipaddr, CYGDAT_LWIP_MY_ADDR);
 	IP_ADDR(&netmask, CYGDAT_LWIP_NETMASK);
-	netif_set_addr(netif, &ipaddr, &netmask, &gw);
-	netif->next = netif_list;
-	netif_list = netif;
-	
-	netif->input = tcpip_input;
-	//netif->input = ip_input;
+
+	netif_add(netif, &ipaddr, &netmask, &gw, netif->state, lwip_dummy_netif_init, tcpip_input);
+    netif_set_default(netif); 
+#endif 
 }
 
+void lwip_dhcp_init(struct netif *netif)
+{
+#ifdef CYGOPT_LWIP_DHCP_MANAGEMENT
+    dhcp_start(netif);
+#endif
+}
+
+
 #ifdef CYGPKG_LWIP_ETH
 //io eth stuff
 
@@ -224,6 +282,7 @@ input_thread(void *arg)
 
 }
 
+
 // Initialize all network devices
 static void
 init_hw_drivers(void)
@@ -240,22 +299,15 @@ init_hw_drivers(void)
   }
 }
 
-static void
-arp_timer(void *arg)
-{
-  etharp_tmr();
-  sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler) arp_timer, NULL);
-}
-
+extern struct netif *netif_default;
 
 static void
 ecosglue_init(void)
 {
-  cyg_semaphore_init(&delivery, 0);
-  init_hw_drivers();
-  sys_thread_new(input_thread, (void*)0, CYGNUM_LWIP_ETH_THREAD_PRIORITY);
-  etharp_init();
-  sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler) arp_timer, NULL);
+    etharp_init();
+    cyg_semaphore_init(&delivery, 0);
+    init_hw_drivers();
+    sys_thread_new(input_thread, (void*)0, CYGNUM_LWIP_ETH_THREAD_PRIORITY);
 }
 
 #endif //CYGPKG_LWIP_ETH
--- a/packages/net/lwip_tcpip/current/src/netif/etharp.c
+++ b/packages/net/lwip_tcpip/current/src/netif/etharp.c
@@ -6,8 +6,10 @@
  * to a physical address when sending a packet, and the second part answers
  * requests from other machines for our physical address.
  *
- * This implementation complies with RFC 826 (Ethernet ARP) and supports
- * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6.
+ * This implementation complies with RFC 826 (Ethernet ARP). It supports
+ * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6
+ * if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon
+ * address change.
  */
 
 /*
@@ -37,52 +39,11 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  * OF SUCH DAMAGE.
- *
+ * 
  * This file is part of the lwIP TCP/IP stack.
  *
- * Author: Adam Dunkels <adam@sics.se>
- *
  */
 
-/**
- * TODO:
- * - pbufs should be sent from the queue once an ARP entry state
- *   goes from PENDING to STABLE.
- * - Non-PENDING entries MUST NOT have queued packets.
- */
-
-/*
- * TODO:
- *
-RFC 3220 4.6          IP Mobility Support for IPv4          January 2002
-
-      -  A Gratuitous ARP [45] is an ARP packet sent by a node in order
-         to spontaneously cause other nodes to update an entry in their
-         ARP cache.  A gratuitous ARP MAY use either an ARP Request or
-         an ARP Reply packet.  In either case, the ARP Sender Protocol
-         Address and ARP Target Protocol Address are both set to the IP
-         address of the cache entry to be updated, and the ARP Sender
-         Hardware Address is set to the link-layer address to which this
-         cache entry should be updated.  When using an ARP Reply packet,
-         the Target Hardware Address is also set to the link-layer
-         address to which this cache entry should be updated (this field
-         is not used in an ARP Request packet).
-
-         In either case, for a gratuitous ARP, the ARP packet MUST be
-         transmitted as a local broadcast packet on the local link.  As
-         specified in [36], any node receiving any ARP packet (Request
-         or Reply) MUST update its local ARP cache with the Sender
-         Protocol and Hardware Addresses in the ARP packet, if the
-         receiving node has an entry for that IP address already in its
-         ARP cache.  This requirement in the ARP protocol applies even
-         for ARP Request packets, and for ARP Reply packets that do not
-         match any ARP Request transmitted by the receiving node [36].
-*
-  My suggestion would be to send a ARP request for our newly obtained
-  address upon configuration of an Ethernet interface.
-
-*/
-
 #include "lwip/opt.h"
 #include "lwip/inet.h"
 #include "netif/etharp.h"
@@ -94,13 +55,17 @@ RFC 3220 4.6          IP Mobility Suppor
 #  include "lwip/dhcp.h"
 #endif
 
-/* allows new queueing code to be disabled (0) for regression testing */
-#define ARP_NEW_QUEUE 1
-
-/** the time an ARP entry stays valid after its last update, (120 * 10) seconds = 20 minutes. */
-#define ARP_MAXAGE 120
-/** the time an ARP entry stays pending after first request, (1 * 10) seconds = 10 seconds. */
-#define ARP_MAXPENDING 1
+/** the time an ARP entry stays valid after its last update,
+ * (240 * 5) seconds = 20 minutes.
+ */
+#define ARP_MAXAGE 240
+/** the time an ARP entry stays pending after first request,
+ * (2 * 5) seconds = 10 seconds.
+ * 
+ * @internal Keep this number at least 2, otherwise it might
+ * run out instantly if the timeout occurs directly after a request.
+ */
+#define ARP_MAXPENDING 2
 
 #define HWTYPE_ETHERNET 1
 
@@ -118,37 +83,40 @@ enum etharp_state {
   ETHARP_STATE_EMPTY,
   ETHARP_STATE_PENDING,
   ETHARP_STATE_STABLE,
-  /** @internal convenience transitional state used in etharp_tmr() */
+  /** @internal transitional state used in etharp_tmr() for convenience*/
   ETHARP_STATE_EXPIRED
 };
 
 struct etharp_entry {
+#if ARP_QUEUEING
+  /** 
+   * Pointer to queue of pending outgoing packets on this ARP entry.
+   */
+   struct pbuf *p;
+#endif
   struct ip_addr ipaddr;
   struct eth_addr ethaddr;
   enum etharp_state state;
-#if ARP_QUEUEING
-  /** 
-   * Pointer to queue of pending outgoing packets on this ARP entry.
-   * Must be at most a single packet for now. */
-  struct pbuf *p;
-#endif
   u8_t ctime;
 };
 
 static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
 static struct etharp_entry arp_table[ARP_TABLE_SIZE];
 
-static s8_t find_arp_entry(void);
-/** ask update_arp_entry() to add instead of merely update an ARP entry */
-#define ARP_INSERT_FLAG 1
-static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
+/**
+ * Try hard to create a new entry - we want the IP address to appear in
+ * the cache (even if this means removing an active entry or so). */
+#define ETHARP_TRY_HARD 1
+
+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);
+static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
 /**
  * Initializes ARP module.
  */
 void
 etharp_init(void)
 {
-  s8_t i;
+  u8_t i;
   /* clear ARP entries */
   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
     arp_table[i].state = ETHARP_STATE_EMPTY;
@@ -162,30 +130,35 @@ etharp_init(void)
 /**
  * Clears expired entries in the ARP table.
  *
- * This function should be called every ETHARP_TMR_INTERVAL microseconds (10 seconds),
+ * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),
  * in order to expire entries in the ARP table.
  */
 void
 etharp_tmr(void)
 {
-  s8_t i;
+  u8_t i;
 
   LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
   /* remove expired entries from the ARP table */
   for (i = 0; i < ARP_TABLE_SIZE; ++i) {
     arp_table[i].ctime++;
-    /* a resolved/stable entry? */
+    /* stable entry? */
     if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
          /* entry has become old? */
         (arp_table[i].ctime >= ARP_MAXAGE)) {
-      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i));
+      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %"U16_F".\n", (u16_t)i));
       arp_table[i].state = ETHARP_STATE_EXPIRED;
-    /* an unresolved/pending entry? */
-    } else if ((arp_table[i].state == ETHARP_STATE_PENDING) &&
-         /* entry unresolved/pending for too long? */
-        (arp_table[i].ctime >= ARP_MAXPENDING)) {
-      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i));
-      arp_table[i].state = ETHARP_STATE_EXPIRED;
+    /* pending entry? */
+    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
+      /* entry unresolved/pending for too long? */
+      if (arp_table[i].ctime >= ARP_MAXPENDING) {
+        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %"U16_F".\n", (u16_t)i));
+        arp_table[i].state = ETHARP_STATE_EXPIRED;
+#if ARP_QUEUEING
+      } else if (arp_table[i].p != NULL) {
+        /* resend an ARP query here */
+#endif
+      }
     }
     /* clean up entries that have just been expired */
     if (arp_table[i].state == ETHARP_STATE_EXPIRED) {
@@ -193,7 +166,7 @@ etharp_tmr(void)
       /* and empty packet queue */
       if (arp_table[i].p != NULL) {
         /* remove all queued packets */
-        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %u, packet queue %p.\n", i, (void *)(arp_table[i].p)));
+        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].p)));
         pbuf_free(arp_table[i].p);
         arp_table[i].p = NULL;
       }
@@ -205,59 +178,161 @@ etharp_tmr(void)
 }
 
 /**
- * Return an empty ARP entry (possibly recycling the oldest stable entry).
+ * Search the ARP table for a matching or new entry.
+ * 
+ * If an IP address is given, return a pending or stable ARP entry that matches
+ * the address. If no match is found, create a new entry with this address set,
+ * but in state ETHARP_EMPTY. The caller must check and possibly change the
+ * state of the returned entry.
+ * 
+ * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
+ * 
+ * In all cases, attempt to create new entries from an empty entry. If no
+ * empty entries are available and ETHARP_TRY_HARD flag is set, recycle
+ * old entries. Heuristic choose the least important entry for recycling.
  *
- * @return The ARP entry index that is available, ERR_MEM if no usable
- * entry is found.
+ * @param ipaddr IP address to find in ARP cache, or to add if not found.
+ * @param flags
+ * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of
+ * active (stable or pending) entries.
+ *  
+ * @return The ARP entry index that matched or is created, ERR_MEM if no
+ * entry is found or could be recycled.
  */
-static s8_t
-find_arp_entry(void)
+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
 {
-  s8_t i, j;
-  u8_t maxtime = 0;
+  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
+  s8_t empty = ARP_TABLE_SIZE;
+  u8_t i = 0, age_pending = 0, age_stable = 0;
+#if ARP_QUEUEING
+  /* oldest entry with packets on queue */
+  s8_t old_queue = ARP_TABLE_SIZE;
+  /* its age */
+  u8_t age_queue = 0;
+#endif
+
+  /**
+   * a) do a search through the cache, remember candidates
+   * b) select candidate entry
+   * c) create new entry
+   */
 
-  j = ARP_TABLE_SIZE;
-  /* search ARP table for an unused or old entry */
+  /* a) in a single search sweep, do all of this
+   * 1) remember the first empty entry (if any)
+   * 2) remember the oldest stable entry (if any)
+   * 3) remember the oldest pending entry without queued packets (if any)
+   * 4) remember the oldest pending entry with queued packets (if any)
+   * 5) search for a matching IP entry, either pending or stable
+   *    until 5 matches, or all entries are searched for.
+   */
+
   for (i = 0; i < ARP_TABLE_SIZE; ++i) {
-  	/* empty entry? */
-    if (arp_table[i].state == ETHARP_STATE_EMPTY) {
-      LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning empty entry %u\n", i));
-      return i;
-  	/* stable entry? */
-    } else if (arp_table[i].state == ETHARP_STATE_STABLE) {
-      /* remember entry with oldest stable entry in j */
-      if (arp_table[i].ctime >= maxtime) maxtime = arp_table[j = i].ctime;
+    /* no empty entry found yet and now we do find one? */
+    if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {
+      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
+      /* remember first empty entry */
+      empty = i;
+    }
+    /* pending entry? */
+    else if (arp_table[i].state == ETHARP_STATE_PENDING) {
+      /* if given, does IP address match IP address in ARP entry? */
+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i));
+        /* found exact IP address match, simply bail out */
+        return i;
+#if ARP_QUEUEING
+      /* pending with queued packets? */
+      } else if (arp_table[i].p != NULL) {
+        if (arp_table[i].ctime >= age_queue) {
+          old_queue = i;
+          age_queue = arp_table[i].ctime;
+        }
+#endif
+      /* pending without queued packets? */
+      } else {
+        if (arp_table[i].ctime >= age_pending) {
+          old_pending = i;
+          age_pending = arp_table[i].ctime;
+        }
+      }        
+    }
+    /* stable entry? */
+    else if (arp_table[i].state == ETHARP_STATE_STABLE) {
+      /* if given, does IP address match IP address in ARP entry? */
+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i));
+        /* found exact IP address match, simply bail out */
+        return i;
+      /* remember entry with oldest stable entry in oldest, its age in maxtime */
+      } else if (arp_table[i].ctime >= age_stable) {
+        old_stable = i;
+        age_stable = arp_table[i].ctime;
+      }
     }
   }
-  /* no empty entry found? */
-  if (i == ARP_TABLE_SIZE) {
-  	LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j));
-    /* fall-back to oldest stable */
-  	i = j;
+  /* { we have no match } => try to create a new entry */
+   
+  /* no empty entry found and not allowed to recycle? */
+  if ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))
+  {
+  	return (s8_t)ERR_MEM;
+  }
+  
+  /* b) choose the least destructive entry to recycle:
+   * 1) empty entry
+   * 2) oldest stable entry
+   * 3) oldest pending entry without queued packets
+   * 4) oldest pending entry without queued packets
+   * 
+   * { ETHARP_TRY_HARD is set at this point }
+   */ 
+
+  /* 1) empty entry available? */
+  if (empty < ARP_TABLE_SIZE) {
+    i = empty;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
   }
-  /* no available entry found? */
-  if (i == ARP_TABLE_SIZE) {
-    LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: no replacable entry could be found\n"));
-    /* return failure */
-    return ERR_MEM;
+  /* 2) found recyclable stable entry? */
+  else if (old_stable < ARP_TABLE_SIZE) {
+    /* recycle oldest stable*/
+    i = old_stable;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
+#if ARP_QUEUEING
+    /* no queued packets should exist on stable entries */
+    LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL);
+#endif
+  /* 3) found recyclable pending entry without queued packets? */
+  } else if (old_pending < ARP_TABLE_SIZE) {
+    /* recycle oldest pending */
+    i = old_pending;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
+#if ARP_QUEUEING
+  /* 4) found recyclable pending entry with queued packets? */
+  } else if (old_queue < ARP_TABLE_SIZE) {
+    /* recycle oldest pending */
+    i = old_queue;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].p)));
+    pbuf_free(arp_table[i].p);
+    arp_table[i].p = NULL;
+#endif
+    /* no empty or recyclable entries found */
+  } else {
+    return (s8_t)ERR_MEM;
   }
 
-  /* clean up the recycled stable entry */
-  if (arp_table[i].state == ETHARP_STATE_STABLE) {
-#if ARP_QUEUEING
-    /* and empty the packet queue */
-    if (arp_table[i].p != NULL) {
-      /* remove all queued packets */
-      LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: freeing entry %u, packet queue %p.\n", i, (void *)(arp_table[i].p)));
-      pbuf_free(arp_table[i].p);
-      arp_table[i].p = NULL;
-    }
-#endif
-    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_arp_entry: recycling oldest stable entry %u\n", i));
-    arp_table[i].state = ETHARP_STATE_EMPTY;
+  /* { empty or recyclable entry found } */
+  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
+
+  /* recycle entry (no-op for an already empty entry) */
+  arp_table[i].state = ETHARP_STATE_EMPTY;
+
+  /* IP address given? */
+  if (ipaddr != NULL) {
+    /* set IP address */
+    ip_addr_set(&arp_table[i].ipaddr, ipaddr);
   }
-  LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u\n", i));
-  return i;
+  arp_table[i].ctime = 0;
+  return (err_t)i;
 }
 
 /**
@@ -269,118 +344,72 @@ find_arp_entry(void)
  * @param ipaddr IP address of the inserted ARP entry.
  * @param ethaddr Ethernet address of the inserted ARP entry.
  * @param flags Defines behaviour:
- * - ARP_INSERT_FLAG Allows ARP to insert this as a new item. If not specified,
+ * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
  * only existing ARP entries will be updated.
  *
- * @return pbuf If non-NULL, a packet that was queued on a pending entry.
- * You should sent it and must call pbuf_free() afterwards.
+ * @return
+ * - ERR_OK Succesfully updated ARP cache.
+ * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
  *
  * @see pbuf_free()
  */
-static struct pbuf *
+static err_t
 update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
 {
   s8_t i, k;
   LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n"));
   LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0);
-  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %u.%u.%u.%u - %02x:%02x:%02x:%02x:%02x:%02x\n",
+  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
                                         ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), 
                                         ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
                                         ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
-  /* do not update for 0.0.0.0 addresses */
-  if (ipaddr->addr == 0) {
-    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add 0.0.0.0 to ARP cache\n"));
-    return NULL;
+  /* non-unicast address? */
+  if (ip_addr_isany(ipaddr) ||
+      ip_addr_isbroadcast(ipaddr, netif) ||
+      ip_addr_ismulticast(ipaddr)) {
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
+    return ERR_ARG;
   }
-  /* Walk through the ARP mapping table and try to find an entry to
-  update. If none is found, the IP -> MAC address mapping is
-  inserted in the ARP table. */
-  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
-    /* Check if the source IP address of the incoming packet matches
-    the IP address in this ARP table entry. */
-    if (arp_table[i].state != ETHARP_STATE_EMPTY &&
-    	ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
-      /* pending entry? */
-      if (arp_table[i].state == ETHARP_STATE_PENDING) {
-        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: pending entry %u goes stable\n", i));
-        /* A pending entry was found, mark it stable */
-        arp_table[i].state = ETHARP_STATE_STABLE;
-        /* fall-through to next if */
-      }
-      /* stable entry? (possibly just marked to become stable) */
-      if (arp_table[i].state == ETHARP_STATE_STABLE) {
-#if ARP_QUEUEING
-        struct pbuf *p;
-        struct eth_hdr *ethhdr;
-#endif
-        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i));
-        /* An old entry found, update this and return. */
-        for (k = 0; k < netif->hwaddr_len; ++k) {
-          arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
-        }
-        /* reset time stamp */
-        arp_table[i].ctime = 0;
+  /* find or create ARP entry */
+  i = find_entry(ipaddr, flags);
+  /* bail out if no entry could be found */
+  if (i < 0) return (err_t)i;
+  
+  /* mark it stable */
+  arp_table[i].state = ETHARP_STATE_STABLE;
+
+  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
+  /* update address */
+  for (k = 0; k < netif->hwaddr_len; ++k) {
+    arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
+  }
+  /* reset time stamp */
+  arp_table[i].ctime = 0;
 /* this is where we will send out queued packets! */
 #if ARP_QUEUEING
-        while (arp_table[i].p != NULL) {
-          /* get the first packet on the queue (if any) */
-          p = arp_table[i].p;
-          /* remember (and reference) remainder of queue */
-          arp_table[i].p = pbuf_dequeue(p);
-          /* fill-in Ethernet header */
-          ethhdr = p->payload;
-          for (k = 0; k < netif->hwaddr_len; ++k) {
-            ethhdr->dest.addr[k] = ethaddr->addr[k];
-            ethhdr->src.addr[k] = netif->hwaddr[k];
-          }
-          ethhdr->type = htons(ETHTYPE_IP);
-          LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
-          /* send the queued IP packet */
-          netif->linkoutput(netif, p);
-          /* free the queued IP packet */
-          pbuf_free(p);
-        }
+  while (arp_table[i].p != NULL) {
+    /* get the first packet on the queue */
+    struct pbuf *p = arp_table[i].p;
+    /* Ethernet header */
+    struct eth_hdr *ethhdr = p->payload;
+    /* remember (and reference) remainder of queue */
+    /* note: this will also terminate the p pbuf chain */
+    arp_table[i].p = pbuf_dequeue(p);
+    /* fill-in Ethernet header */
+    for (k = 0; k < netif->hwaddr_len; ++k) {
+      ethhdr->dest.addr[k] = ethaddr->addr[k];
+      ethhdr->src.addr[k] = netif->hwaddr[k];
+    }
+    ethhdr->type = htons(ETHTYPE_IP);
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
+    /* send the queued IP packet */
+    netif->linkoutput(netif, p);
+    /* free the queued IP packet */
+    pbuf_free(p);
+  }
 #endif
-        /* IP addresses should only occur once in the ARP entry, we are done */
-        return NULL;
-      }
-    } /* if STABLE */
-  } /* for all ARP entries */
-
-  /* no matching ARP entry was found */
-  LWIP_ASSERT("update_arp_entry: i == ARP_TABLE_SIZE", i == ARP_TABLE_SIZE);
-
-  LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: IP address not yet in table\n"));
-  /* allowed to insert a new entry? */
-  if (flags & ARP_INSERT_FLAG)
-  {
-    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n"));
-    /* find an empty or old entry. */
-    i = find_arp_entry();
-    if (i == ERR_MEM) {
-      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n"));
-      return NULL;
-    }
-    /* set IP address */
-    ip_addr_set(&arp_table[i].ipaddr, ipaddr);
-    /* set Ethernet hardware address */
-    for (k = 0; k < netif->hwaddr_len; ++k) {
-      arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
-    }
-    /* reset time-stamp */
-    arp_table[i].ctime = 0;
-    /* mark as stable */
-    arp_table[i].state = ETHARP_STATE_STABLE;
-    /* no queued packet */
-#if ARP_QUEUEING
-    arp_table[i].p = NULL;
-#endif
-  }
-  else
-  {
-    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no matching stable entry to update\n"));
-  }
-  return NULL;
+  return ERR_OK;
 }
 
 /**
@@ -398,24 +427,25 @@ update_arp_entry(struct netif *netif, st
  *
  * @see pbuf_free()
  */
-struct pbuf *
+void
 etharp_ip_input(struct netif *netif, struct pbuf *p)
 {
   struct ethip_hdr *hdr;
-
+  LWIP_ASSERT("netif != NULL", netif != NULL);
   /* Only insert an entry if the source IP address of the
      incoming IP packet comes from a host on the local network. */
   hdr = p->payload;
-  /* source is on local network? */
-  if (!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
+  /* source is not on the local network? */
+  if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
     /* do nothing */
-    return NULL;
+    return;
   }
 
   LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
-  /* update ARP table, ask to insert entry */
-  update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), ARP_INSERT_FLAG);
-  return NULL;
+  /* update ARP table */
+  /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk
+   * back soon (for example, if the destination IP address is ours. */
+  update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);
 }
 
 
@@ -434,7 +464,7 @@ etharp_ip_input(struct netif *netif, str
  *
  * @see pbuf_free()
  */
-struct pbuf *
+void
 etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
 {
   struct etharp_hdr *hdr;
@@ -443,11 +473,13 @@ etharp_arp_input(struct netif *netif, st
   u8_t i;
   u8_t for_us;
 
+  LWIP_ASSERT("netif != NULL", netif != NULL);
+  
   /* drop short ARP packets */
   if (p->tot_len < sizeof(struct etharp_hdr)) {
-    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr)));
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, sizeof(struct etharp_hdr)));
     pbuf_free(p);
-    return NULL;
+    return;
   }
 
   hdr = p->payload;
@@ -468,7 +500,7 @@ etharp_arp_input(struct netif *netif, st
   if (for_us) {
     /* add IP address in ARP cache; assume requester wants to talk to us.
      * can result in directly sending the queued packets for this host. */
-    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ARP_INSERT_FLAG);
+    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
   /* ARP message not directed to us? */
   } else {
     /* update the source IP address in the cache, if present */
@@ -521,77 +553,70 @@ etharp_arp_input(struct netif *netif, st
     }
     break;
   case ARP_REPLY:
-    /* ARP reply. We insert or update the ARP table later. */
+    /* ARP reply. We already updated the ARP cache earlier. */
     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
 #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
-    /* DHCP wants to know about ARP replies to our wanna-have-address */
-    if (for_us) dhcp_arp_reply(netif, &sipaddr);
+    /* DHCP wants to know about ARP replies from any host with an
+     * IP address also offered to us by the DHCP server. We do not
+     * want to take a duplicate IP address on a single network.
+     * @todo How should we handle redundant (fail-over) interfaces?
+     * */
+    dhcp_arp_reply(netif, &sipaddr);
 #endif
     break;
   default:
-    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %d\n", htons(hdr->opcode)));
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));
     break;
   }
   /* free ARP packet */
   pbuf_free(p);
-  p = NULL;
-  /* nothing to send, we did it! */
-  return NULL;
 }
 
 /**
  * Resolve and fill-in Ethernet address header for outgoing packet.
  *
- * If ARP has the Ethernet address in cache, the given packet is
- * returned, ready to be sent.
+ * For IP multicast and broadcast, corresponding Ethernet addresses
+ * are selected and the packet is transmitted on the link.
  *
- * If ARP does not have the Ethernet address in cache the packet is
- * queued (if enabled and space available) and a ARP request is sent.
- * This ARP request is returned as a pbuf, which should be sent by
- * the caller.
- *
- * A returned non-NULL packet should be sent by the caller.
- *
- * If ARP failed to allocate resources, NULL is returned.
+ * For unicast addresses, the packet is submitted to etharp_query(). In
+ * case the IP address is outside the local network, the IP address of
+ * the gateway is used.
  *
  * @param netif The lwIP network interface which the IP packet will be sent on.
  * @param ipaddr The IP address of the packet destination.
  * @param pbuf The pbuf(s) containing the IP packet to be sent.
  *
- * @return If non-NULL, a packet ready to be sent by caller.
- *
+ * @return
+ * - ERR_RTE No route to destination (no gateway to external networks),
+ * or the return type of either etharp_query() or netif->linkoutput().
  */
-struct pbuf *
+err_t
 etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
 {
   struct eth_addr *dest, *srcaddr, mcastaddr;
   struct eth_hdr *ethhdr;
-  s8_t i;
+  u8_t i;
 
-  /* make room for Ethernet header */
+  /* make room for Ethernet header - should not fail */
   if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
-    /* The pbuf_header() call shouldn't fail, and we'll just bail
-    out if it does.. */
+    /* bail out */
     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));
     LINK_STATS_INC(link.lenerr);
-    return NULL;
+    return ERR_BUF;
   }
 
   /* assume unresolved Ethernet address */
   dest = NULL;
-  /* Construct Ethernet header. Start with looking up deciding which
-     MAC address to use as a destination address. Broadcasts and
-     multicasts are special, all other addresses are looked up in the
-     ARP table. */
+  /* Determine on destination hardware address. Broadcasts and multicasts
+   * are special, other IP addresses are looked up in the ARP table. */
 
-  /* destination IP address is an IP broadcast address? */
-  if (ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, netif)) {
+  /* broadcast destination IP address? */
+  if (ip_addr_isbroadcast(ipaddr, netif)) {
     /* broadcast on Ethernet also */
     dest = (struct eth_addr *)&ethbroadcast;
-  }
-  /* destination IP address is an IP multicast address? */
-  else if (ip_addr_ismulticast(ipaddr)) {
-    /* Hash IP multicast address to MAC address. */
+  /* multicast destination IP address? */
+  } else if (ip_addr_ismulticast(ipaddr)) {
+    /* Hash IP multicast address to MAC address.*/
     mcastaddr.addr[0] = 0x01;
     mcastaddr.addr[1] = 0x00;
     mcastaddr.addr[2] = 0x5e;
@@ -600,192 +625,207 @@ etharp_output(struct netif *netif, struc
     mcastaddr.addr[5] = ip4_addr4(ipaddr);
     /* destination Ethernet address is multicast */
     dest = &mcastaddr;
-  }
-  /* destination IP address is an IP unicast address */
-  else {
-    /* destination IP network address not on local network?
-     * IP layer wants us to forward to the default gateway */
-    if (!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
+  /* unicast destination IP address? */
+  } else {
+    /* outside local network? */
+    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
       /* interface has default gateway? */
-      if (netif->gw.addr != 0)
-      {
-        /* route to default gateway IP address */
+      if (netif->gw.addr != 0) {
+        /* send to hardware address of default gateway IP address */
         ipaddr = &(netif->gw);
-      }
-      /* no gateway available? */
-      else
-      {
-        /* IP destination address outside local network, but no gateway available */
-        /* { packet is discarded } */
-        return NULL;
-      }
-    }
-
-    /* Ethernet address for IP destination address is in ARP cache? */
-    for (i = 0; i < ARP_TABLE_SIZE; ++i) {
-      /* match found? */
-      if (arp_table[i].state == ETHARP_STATE_STABLE &&
-        ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
-        dest = &arp_table[i].ethaddr;
-        break;
+      /* no default gateway available */
+      } else {
+        /* no route to destination error (default gateway missing) */
+        return ERR_RTE;
       }
     }
-    /* could not find the destination Ethernet address in ARP cache? */
-    if (dest == NULL) {
-      /* ARP query for the IP address, submit this IP packet for queueing */
-      /* TODO: How do we handle netif->ipaddr == ipaddr? */
-      etharp_query(netif, ipaddr, q);
-      /* { packet was queued (ERR_OK), or discarded } */
-      /* return nothing */
-      return NULL;
-    }
-    /* destination Ethernet address resolved from ARP cache */
-    else
-    {
-      /* fallthrough */
-    }
+    /* queue on destination Ethernet address belonging to ipaddr */
+    return etharp_query(netif, ipaddr, q);
   }
 
-  /* destination Ethernet address known */
-  if (dest != NULL) {
-    /* obtain source Ethernet address of the given interface */
-    srcaddr = (struct eth_addr *)netif->hwaddr;
-
-    /* A valid IP->MAC address mapping was found, fill in the
-     * Ethernet header for the outgoing packet */
-    ethhdr = q->payload;
-
-    for(i = 0; i < netif->hwaddr_len; i++) {
-      ethhdr->dest.addr[i] = dest->addr[i];
-      ethhdr->src.addr[i] = srcaddr->addr[i];
-    }
-
-    ethhdr->type = htons(ETHTYPE_IP);
-    /* return the outgoing packet */
-    return q;
+  /* continuation for multicast/broadcast destinations */
+  /* obtain source Ethernet address of the given interface */
+  srcaddr = (struct eth_addr *)netif->hwaddr;
+  ethhdr = q->payload;
+  for (i = 0; i < netif->hwaddr_len; i++) {
+    ethhdr->dest.addr[i] = dest->addr[i];
+    ethhdr->src.addr[i] = srcaddr->addr[i];
   }
-  /* never reached; here for safety */
-  return NULL;
+  ethhdr->type = htons(ETHTYPE_IP);
+  /* send packet directly on the link */
+  return netif->linkoutput(netif, q);
 }
 
 /**
- * Send an ARP request for the given IP address.
+ * Send an ARP request for the given IP address and/or queue a packet.
+ *
+ * If the IP address was not yet in the cache, a pending ARP cache entry
+ * is added and an ARP request is sent for the given address. The packet
+ * is queued on this entry.
  *
- * Sends an ARP request for the given IP address, unless
- * a request for this address is already pending. Optionally
- * queues an outgoing packet on the resulting ARP entry.
+ * If the IP address was already pending in the cache, a new ARP request
+ * is sent for the given address. The packet is queued on this entry.
  *
- * @param netif The lwIP network interface where ipaddr
+ * If the IP address was already stable in the cache, and a packet is
+ * given, it is directly sent and no ARP request is sent out. 
+ * 
+ * If the IP address was already stable in the cache, and no packet is
+ * given, an ARP request is sent out.
+ * 
+ * @param netif The lwIP network interface on which ipaddr
  * must be queried for.
  * @param ipaddr The IP address to be resolved.
- * @param q If non-NULL, a pbuf that must be queued on the
- * ARP entry for the ipaddr IP address.
- *
- * @return NULL.
+ * @param q If non-NULL, a pbuf that must be delivered to the IP address.
+ * q is not freed by this function.
  *
- * @note Might be used in the future by manual IP configuration
- * as well.
+ * @return
+ * - ERR_BUF Could not make room for Ethernet header.
+ * - ERR_MEM Hardware address unknown, and no more ARP entries available
+ *   to query for address or queue the packet.
+ * - ERR_MEM Could not queue packet due to memory shortage.
+ * - ERR_RTE No route to destination (no gateway to external networks).
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
  *
- * TODO: use the ctime field to see how long ago an ARP request was sent,
- * possibly retry.
  */
 err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
 {
-  struct eth_addr *srcaddr;
-  struct etharp_hdr *hdr;
-  err_t result = ERR_OK;
-  s8_t i;
-  u8_t perform_arp_request = 1;
-  /* prevent 'unused argument' warning if ARP_QUEUEING == 0 */
-  (void)q;
-  srcaddr = (struct eth_addr *)netif->hwaddr;
-  /* bail out if this IP address is pending */
-  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
-    if (arp_table[i].state != ETHARP_STATE_EMPTY &&
-    	ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
-      if (arp_table[i].state == ETHARP_STATE_PENDING) {
-        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending as entry %u\n", i));
-        /* break out of for-loop, user may wish to queue a packet on a pending entry */
-        /* TODO: we will issue a new ARP request, which should not occur too often */
-        /* we might want to run a faster timer on ARP to limit this */
-        break;
-      }
-      else if (arp_table[i].state == ETHARP_STATE_STABLE) {
-        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already stable as entry %u\n", i));
-        /* User wishes to queue a packet on a stable entry (or does she want to send
-         * out the packet immediately, we will not know), so we force an ARP request.
-         * Upon response we will send out the queued packet in etharp_update().
-         * 
-         * Alternatively, we could accept the stable entry, and just send out the packet
-         * immediately. I chose to implement the former approach.
-         */
-        perform_arp_request = (q?1:0);
-        break;
-      }
-    }
+  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
+  err_t result = ERR_MEM;
+  s8_t i; /* ARP entry index */
+  u8_t k; /* Ethernet address octet index */
+
+  /* non-unicast address? */
+  if (ip_addr_isbroadcast(ipaddr, netif) ||
+      ip_addr_ismulticast(ipaddr) ||
+      ip_addr_isany(ipaddr)) {
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
+    return ERR_ARG;
   }
-  /* queried address not yet in ARP table? */
-  if (i == ARP_TABLE_SIZE) {
-    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n"));
-    /* find an available (unused or old) entry */
-    i = find_arp_entry();
-    /* bail out if no ARP entries are available */
-    if (i == ERR_MEM) {
-      LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available. Should seldom occur.\n"));
-      return ERR_MEM;
-    }
-    /* i is available, create ARP entry */
+
+  /* find entry in ARP cache, ask to create entry if queueing packet */
+  i = find_entry(ipaddr, ETHARP_TRY_HARD);
+
+  /* could not find or create entry? */
+  if (i < 0)
+  {
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
+    if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n"));
+    return (err_t)i;
+  }
+
+  /* mark a fresh entry as pending (we just sent a request) */
+  if (arp_table[i].state == ETHARP_STATE_EMPTY) {
     arp_table[i].state = ETHARP_STATE_PENDING;
-    ip_addr_set(&arp_table[i].ipaddr, ipaddr);
+  }
+
+  /* { i is either a STABLE or (new or existing) PENDING entry } */
+  LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
+  ((arp_table[i].state == ETHARP_STATE_PENDING) ||
+   (arp_table[i].state == ETHARP_STATE_STABLE)));
+
+  /* do we have a pending entry? or an implicit query request? */
+  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
+    /* try to resolve it; send out ARP request */
+    result = etharp_request(netif, ipaddr);
   }
-  /* { i is now valid } */
-#if ARP_QUEUEING /* queue packet (even on a stable entry, see above) */
-  /* copy any PBUF_REF referenced payloads into PBUF_RAM */
-  q = pbuf_take(q);
-  pbuf_queue(arp_table[i].p, q);
+  
+  /* packet given? */
+  if (q != NULL) {
+    /* stable entry? */
+    if (arp_table[i].state == ETHARP_STATE_STABLE) {
+      /* we have a valid IP->Ethernet address mapping,
+       * fill in the Ethernet header for the outgoing packet */
+      struct eth_hdr *ethhdr = q->payload;
+      for(k = 0; k < netif->hwaddr_len; k++) {
+        ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];
+        ethhdr->src.addr[k]  = srcaddr->addr[k];
+      }
+      ethhdr->type = htons(ETHTYPE_IP);
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q));
+      /* send the packet */
+      result = netif->linkoutput(netif, q);
+    /* pending entry? (either just created or already pending */
+    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
+#if ARP_QUEUEING /* queue the given q packet */
+      struct pbuf *p;
+      /* copy any PBUF_REF referenced payloads into PBUF_RAM */
+      /* (the caller of lwIP assumes the referenced payload can be
+       * freed after it returns from the lwIP call that brought us here) */
+      p = pbuf_take(q);
+      /* packet could be taken over? */
+      if (p != NULL) {
+        /* queue packet ... */
+        if (arp_table[i].p == NULL) {
+        	/* ... in the empty queue */
+        	pbuf_ref(p);
+        	arp_table[i].p = p;
+#if 0 /* multi-packet-queueing disabled, see bug #11400 */
+        } else {
+        	/* ... at tail of non-empty queue */
+          pbuf_queue(arp_table[i].p, p);
 #endif
-  /* ARP request? */
-  if (perform_arp_request)
-  {
-    struct pbuf *p;
-    /* allocate a pbuf for the outgoing ARP request packet */
-    p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
-    /* could allocate pbuf? */
-    if (p != NULL) {
-      u8_t j;
-      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending ARP request.\n"));
-      hdr = p->payload;
-      hdr->opcode = htons(ARP_REQUEST);
-      for (j = 0; j < netif->hwaddr_len; ++j)
-      {
-        hdr->shwaddr.addr[j] = srcaddr->addr[j];
-        /* the hardware address is what we ask for, in
-         * a request it is a don't-care, we use 0's */
-        hdr->dhwaddr.addr[j] = 0x00;
+        }
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
+        result = ERR_OK;
+      } else {
+        LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
+        /* { result == ERR_MEM } through initialization */
       }
-      hdr->dipaddr = *(struct ip_addr2 *)ipaddr;
-      hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
-
-      hdr->hwtype = htons(HWTYPE_ETHERNET);
-      ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
-
-      hdr->proto = htons(ETHTYPE_IP);
-      ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
-      for (j = 0; j < netif->hwaddr_len; ++j)
-      {
-        hdr->ethhdr.dest.addr[j] = 0xff;
-        hdr->ethhdr.src.addr[j] = srcaddr->addr[j];
-      }
-      hdr->ethhdr.type = htons(ETHTYPE_ARP);
-      /* send ARP query */
-      result = netif->linkoutput(netif, p);
-      /* free ARP query packet */
-      pbuf_free(p);
-      p = NULL;
-    } else {
-      result = ERR_MEM;
-      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_query: could not allocate pbuf for ARP request.\n"));
+#else /* ARP_QUEUEING == 0 */
+      /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
+      /* { result == ERR_MEM } through initialization */
+      LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
+#endif
     }
   }
   return result;
 }
+
+err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr)
+{
+  struct pbuf *p;
+  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
+  err_t result = ERR_OK;
+  u8_t k; /* ARP entry index */
+
+  /* allocate a pbuf for the outgoing ARP request packet */
+  p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
+  /* could allocate a pbuf for an ARP request? */
+  if (p != NULL) {
+    struct etharp_hdr *hdr = p->payload;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n"));
+    hdr->opcode = htons(ARP_REQUEST);
+    for (k = 0; k < netif->hwaddr_len; k++)
+    {
+      hdr->shwaddr.addr[k] = srcaddr->addr[k];
+      /* the hardware address is what we ask for, in
+       * a request it is a don't-care value, we use zeroes */
+      hdr->dhwaddr.addr[k] = 0x00;
+    }
+    hdr->dipaddr = *(struct ip_addr2 *)ipaddr;
+    hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
+
+    hdr->hwtype = htons(HWTYPE_ETHERNET);
+    ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
+
+    hdr->proto = htons(ETHTYPE_IP);
+    ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
+    for (k = 0; k < netif->hwaddr_len; ++k)
+    {
+      /* broadcast to all network interfaces on the local network */
+      hdr->ethhdr.dest.addr[k] = 0xff;
+      hdr->ethhdr.src.addr[k] = srcaddr->addr[k];
+    }
+    hdr->ethhdr.type = htons(ETHTYPE_ARP);
+    /* send ARP query */
+    result = netif->linkoutput(netif, p);
+    /* free ARP query packet */
+    pbuf_free(p);
+    p = NULL;
+  /* could not allocate pbuf for ARP request */
+  } else {
+    result = ERR_MEM;
+    LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n"));
+  }
+  return result;
+}
--- a/packages/net/lwip_tcpip/current/tests/httpd.c
+++ b/packages/net/lwip_tcpip/current/tests/httpd.c
@@ -39,7 +39,7 @@
 #include "lwip/tcp.h"
 
 struct http_state {
-  char *file;
+  const char *file;
   u32_t left;
   u8_t retries;
 };
@@ -171,7 +171,7 @@ http_recv(void *arg, struct tcp_pcb *pcb
 	  }
 	}
 
-	hs->file = &sdata;
+	hs->file = sdata;
 	hs->left = sizeof(sdata);
 
 	pbuf_free(p);
@@ -250,7 +250,7 @@ tmain(cyg_addrword_t p)
   sys_thread_new(httpd_init, (void*)"httpd",7);  
 }
 
-#define STACK_SIZE 0x4000
+#define STACK_SIZE 0x1000
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/lwip_tcpip/current/tests/nc_test_slave.c
+++ b/packages/net/lwip_tcpip/current/tests/nc_test_slave.c
@@ -185,13 +185,13 @@ do_udp_test(int s1, struct nc_request *r
                 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
                     (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
                     if (ntohl(tdp->seq) != seq) {
-                        test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
+                        test_printf("Packets out of sequence - recvd: %ld, expected: %d\n",
                                     ntohl(tdp->seq), seq);
                         seq = ntohl(tdp->seq);
                         seq_errors++;
                     }
                 } else {
-                    test_printf("Bad data packet - key: %lx/%lx, seq: %d\n",
+                    test_printf("Bad data packet - key: %lx/%lx, seq: %ld\n",
                                 ntohl(tdp->key1), ntohl(tdp->key2),
                                 ntohl(tdp->seq));
                 }
@@ -358,13 +358,13 @@ do_tcp_test(int s1, struct nc_request *r
                 if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
                     (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
                     if (ntohl(tdp->seq) != seq) {
-                        test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
+                        test_printf("Packets out of sequence - recvd: %ld, expected: %d\n",
                                     ntohl(tdp->seq), seq);
                         seq = ntohl(tdp->seq);
                         seq_errors++;
                     }
                 } else {
-                    test_printf("Bad data packet - key: %lx/%lx, seq: %d\n",
+                    test_printf("Bad data packet - key: %lx/%lx, seq: %ld\n",
                                 ntohl(tdp->key1), ntohl(tdp->key2),
                                 ntohl(tdp->seq));
                 }
@@ -452,22 +452,22 @@ nc_slave(test_param_t param)
             done = true;
             break;
         case NC_REQUEST_UDP_SEND:
-            test_printf("UDP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            test_printf("UDP send - %ld buffers, %ld bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
             break;
         case NC_REQUEST_UDP_RECV:
-            test_printf("UDP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            test_printf("UDP recv - %ld buffers, %ld bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
             break;
         case NC_REQUEST_UDP_ECHO:
-            test_printf("UDP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            test_printf("UDP echo - %ld buffers, %ld bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
             break;
         case NC_REQUEST_TCP_SEND:
-            test_printf("TCP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            test_printf("TCP send - %ld buffers, %ld bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
             break;
         case NC_REQUEST_TCP_RECV:
-            test_printf("TCP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            test_printf("TCP recv - %ld buffers, %ld bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
             break;
         case NC_REQUEST_TCP_ECHO:
-            test_printf("TCP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            test_printf("TCP echo - %ld buffers, %ld bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
             break;
         case NC_REQUEST_SET_LOAD:
             start_load(ntohl(req.nbufs));
@@ -487,7 +487,7 @@ nc_slave(test_param_t param)
             reply.misc.idle_results.count[1] = htonl((long)idle_thread_count);
             break;
         default:
-            test_printf("Unrecognized request: %d\n", ntohl(req.type));
+            test_printf("Unrecognized request: %ld\n", ntohl(req.type));
             reply.response = htonl(NC_REPLY_NAK);
             reply.reason = htonl(NC_REPLY_NAK_UNKNOWN_REQUEST);
             break;
--- a/packages/net/lwip_tcpip/current/tests/socket.c
+++ b/packages/net/lwip_tcpip/current/tests/socket.c
@@ -68,7 +68,7 @@ tmain(cyg_addrword_t p)
   sys_thread_new(socket_thread, (void*)"socket",7);
 }
 
-#define STACK_SIZE 0x4000
+#define STACK_SIZE 0x1000
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/lwip_tcpip/current/tests/tcpecho.c
+++ b/packages/net/lwip_tcpip/current/tests/tcpecho.c
@@ -82,7 +82,7 @@ tmain(cyg_addrword_t p)
   sys_thread_new(tcpecho_thread, (void*)"tcpecho",7);  
 }
 
-#define STACK_SIZE 0x4000
+#define STACK_SIZE 0x1000
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/lwip_tcpip/current/tests/udpecho.c
+++ b/packages/net/lwip_tcpip/current/tests/udpecho.c
@@ -65,7 +65,7 @@ void tmain(cyg_addrword_t p)
   sys_thread_new(udpecho_thread, (void*)"udpecho",7);
 }
 
-#define STACK_SIZE 0x4000
+#define STACK_SIZE 0x1000
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;