changeset 957:db3e0a2fda2f

2003-04-12 Andrew Lunn <andrew.lunn@ascom.ch> * src/network_support.c (init_loopback_interface): Close the socket when things go wrong otherwise we leak sockets. * src/tftp_server.c (tftpd_server): Added support for IPv6 as well as IPv4. Extended the multithreading support so that it works correctly when there are multiple servers on multiple ports. * doc/tcpip.sgml: Documentation for the changes made to the tftp server. 2003-04-10 Andrew Lunn <andrew.lunn@ascom.ch> * src/network_support.c (init_all_network_interfaces): Wait upto 4 seconds for a router solicit message to be received. Once we have received the message we know we have a valid IPv6 address. * src/tftp_client.c: Added support for IPv6. This requires two new functions, tftp_client_{get|put} which are protocol version independent. * tests/tftp_client_test.c (tftp_test): Added tests which use IPv6 addresses. 2003-04-07 Andrew Lunn <andrew.lunn@ascom.ch> * src/getaddrinfo.c (getaddrinfo): Correctly deal with node when its not NULL. Its OK for the address to not parse for an address family when AF_UNSPEC is passed in hints. Also get the socktype correct when wildcarding for services that use UDP. * tests/addr_test.c: Added more test cases which test IP addresses in number format as node. 2003-04-05 Andrew Lunn <andrew.lunn@ascom.ch> * cdl/net.cdl: Added addr_tests to the HW tests. * tests/addr_test.c (net_test): void function not int. * tests/ping_test.c (net_test): Added IPv6 ping test. This pings the router which answers our router solicit message. * src/ipv6_routing_thread.c (cyg_rs): Print out the router advertisement message. Cleaned up the debug messages so they can be disabled. * src/ipv6_routing_thread.c (cyg_net_get_ipv6_advrouter): New function to return the address of the router. * include/network.h: Added prototype for above and ipv6_start_routing_thread which did not have a prototype. * src/ipv6_routing_thread.c (cyg_rs): Only wait 2 seconds before sending the first solicit request rather than 10. * src/dhcp_prot.c (do_dhcp_down_net): clear the if_laddrreq before using it. If the request fails finish the IPv4 code rather than returning,. 2003-04-02 Andrew Lunn <andrew.lunn@ascom.ch> * tests/ping_lo_test.c: Added IPv6 ping test. * src/getproto.c: Added the protocol ipv6-icmp.
author asl
date Wed, 23 Apr 2003 08:52:08 +0000
parents d9b26cfc0657
children e6231465742f
files packages/net/common/current/ChangeLog packages/net/common/current/cdl/net.cdl packages/net/common/current/doc/tcpip.sgml packages/net/common/current/include/network.h packages/net/common/current/include/tftp_support.h packages/net/common/current/src/dhcp_prot.c packages/net/common/current/src/getaddrinfo.c packages/net/common/current/src/getproto.c packages/net/common/current/src/ifaddrs.c packages/net/common/current/src/ipv6_routing_thread.c packages/net/common/current/src/network_support.c packages/net/common/current/src/tftp_client.c packages/net/common/current/src/tftp_server.c packages/net/common/current/tests/addr_test.c packages/net/common/current/tests/ping_lo_test.c packages/net/common/current/tests/ping_test.c packages/net/common/current/tests/tftp_client_test.c packages/net/common/current/tests/tftp_server_test.c
diffstat 18 files changed, 1603 insertions(+), 476 deletions(-) [+]
line wrap: on
line diff
--- a/packages/net/common/current/ChangeLog
+++ b/packages/net/common/current/ChangeLog
@@ -1,3 +1,14 @@
+2003-04-12  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/network_support.c (init_loopback_interface): Close the
+	socket when things go wrong otherwise we leak sockets.
+
+	* src/tftp_server.c (tftpd_server): Added support for IPv6 as well
+	as IPv4. Extended the multithreading support so that it works
+	correctly when there are multiple servers on multiple ports.  
+	* doc/tcpip.sgml: Documentation for the changes made to the tftp
+	server.
+
 2003-04-11  Jonathan Larmour  <jifl@eCosCentric.com>
 
 	* tests/linux_echo.c: Renamed to....
@@ -19,10 +30,57 @@ 2003-04-11  Michael Checky  <Michael_Che
 	* tests/nc_test_slave.c: changed 'bool' to 'int' because the compiler
 	didn't like 'bool'.
 
+2003-04-10  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/network_support.c (init_all_network_interfaces): Wait upto 4
+	seconds for a router solicit message to be received. Once we have
+	received the message we know we have a valid IPv6 address.
+
+	* src/tftp_client.c: Added support for IPv6. This requires two new
+	functions, tftp_client_{get|put} which are protocol version
+        independent.
+	* tests/tftp_client_test.c (tftp_test): Added tests which use IPv6
+	addresses.
+	
+2003-04-07  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/getaddrinfo.c (getaddrinfo): Correctly deal with node when
+	its not NULL. Its OK for the address to not parse for an address
+	family when AF_UNSPEC is passed in hints. Also get the socktype
+	correct when wildcarding for services that use UDP.
+	* tests/addr_test.c: Added more test cases which test IP addresses
+	in number format as node.
+
+2003-04-05  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* cdl/net.cdl: Added addr_tests to the HW tests.
+	* tests/addr_test.c (net_test): void function not int.
+	* tests/ping_test.c (net_test): Added IPv6 ping test. This pings
+	the router which answers our router solicit message.
+	* src/ipv6_routing_thread.c (cyg_rs): Print out the router
+	advertisement message. Cleaned up the debug messages so they can
+	be disabled.
+	* src/ipv6_routing_thread.c (cyg_net_get_ipv6_advrouter): New
+	function to return the address of the router.
+	* include/network.h: Added prototype for above and
+	ipv6_start_routing_thread which did not have a prototype.
+	* src/ipv6_routing_thread.c (cyg_rs): Only wait 2 seconds before 
+	sending the first solicit request rather than 10. 
+	* src/dhcp_prot.c (do_dhcp_down_net): clear the if_laddrreq
+	before using it. If the request fails finish the IPv4 code rather 
+	than returning,.
+	
 2003-04-02  Andrew Lunn  <andrew.lunn@ascom.ch>
 
-	* src/dhcp_prot.c (do_dhcp_down_net): SIOCGLIFADDR and SIOCDLIFADDR
-	take if_laddrreq not ifreq. This caused stack corruption.
+	* tests/ping_lo_test.c: Added IPv6 ping test.
+	* src/getproto.c: Added the protocol ipv6-icmp.
+
+2003-04-02  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/dhcp_prot.c (do_dhcp_down_net): SIOCGLIFADDR and
+	SIOCDLIFADDR take if_laddrreq not ifreq. This caused stack
+	corruption. Also initialise the if_laddrreq to zero and only do
+	the second IOCTL call if the first once succeeds.
 
 2003-03-21  Nick Garnett  <nickg@balti.calivar.com>
 
--- a/packages/net/common/current/cdl/net.cdl
+++ b/packages/net/common/current/cdl/net.cdl
@@ -154,6 +154,31 @@ cdl_package CYGPKG_NET {
             threads can have precedence over TFTP server processing."
         }
 
+	cdl_component CYGSEM_NET_TFTPD_MULTITHREADED {
+	    display "Multiple TFTPD server threads on the same port."
+	    flavor  bool
+	    default_value 1
+	    description "
+		This option controls the tftp server ability to be
+        	multi-threaded. When enabled, multiple server can be
+	        started on the same port number. This allows multiple
+	        concurrent transfers to be active. When this option is
+	        not enabled, while one transfer is active, other
+	        requests will be delayed or even ignored."
+		
+            cdl_option CYGNUM_NET_TFTPD_MULTITHREADED_PORTS {
+		display "Number of different ports with servers"
+	        flavor data
+	        default_value 1
+	        description "
+		   Each set of servers running on the same port number
+	           require a semaphore to synchronise there operation. This option
+		   controls the number of semaphores and so the number
+                   of port numbers multithreaded servers which can be
+		   running on."
+            }
+        }
+
         cdl_option CYGPKG_NET_TFTP_FILE_ACCESS {
             display       "File I/O functions for TFTP server"
             flavor        bool
@@ -370,7 +395,8 @@ cdl_package CYGPKG_NET {
                     tests/tcp_lo_test \
                     tests/udp_lo_test \
                     tests/multi_lo_select \
-                    tests/tcp_lo_select"
+                    tests/tcp_lo_select \
+                    tests/addr_test.c " 
             :
                     "tests/ping_lo_test \
                     tests/tcp_lo_test \
--- a/packages/net/common/current/doc/tcpip.sgml
+++ b/packages/net/common/current/doc/tcpip.sgml
@@ -112,6 +112,12 @@ CYGHWR_NET_DRIVER_ETH0_IPV6_PREFIX for &
 This is a CDL booldata type, allowing this address to be suppressed if
 not desired.
 </PARA>
+
+<PARA>Alternatively, the system can configure its IPv6 address using
+router solicitation. When the CDL option
+CYGOPT_NET_IPV6_ROUTING_THREAD is enabled,
+<function>init_all_network_interface</function> will start a thread which sends out router solicit messages, process router advertisements and thus configure an IPv6 address to the interface.</PARA>
+
 <PARA>
 Refer to the test cases,
 <FILENAME>&hellip;/packages/net/common/<REPLACEABLE>VERSION</REPLACEABLE>/tests/ftp_test.c</FILENAME>
@@ -228,6 +234,11 @@ the receive timeout.  If there is such a
 2nd set of pings succeeds, confirming that we can talk to a machine
 not previously mentioned by configuration or by bootp. It then does
 the same thing on the other interface, eth1.</PARA>
+
+<PARA>If IPv6 is enabled, the program will also ping to the address it
+last received a router advertisement from. Also a ping will be made to
+that address plus 32, in a similar way the the IPv4 case.</PARA>
+
 <PROGRAMLISTING><EMPHASIS>dhcp_test</EMPHASIS>    - ping test, but also manipulates DHCP leases</PROGRAMLISTING>
 <PARA>This test is very similar to the ping test, but in addition,
 provided the network package is not configured to do this automatically,
@@ -362,6 +373,11 @@ be a copy of
 -rw-rw-rw-  1 root       1076 May  1 15:52 tftp_put
 
 </PROGRAMLISTING>
+
+<PARA>If the configuration contains IPv6 support, the test program
+will also use IPv6. It will attempt to put/get the files listed above
+from the address it last received a routers solicit from.</PARA>
+
 <PROGRAMLISTING><EMPHASIS>tftp_server_test</EMPHASIS> - runs a tftp server for a short while</PROGRAMLISTING>
 <PARA>This test is truly interactive, in that you can use a standard
 tftp application to get and put files from the server, during the
@@ -402,8 +418,81 @@ it &mdash; or it comes pre-set from the 
 <TITLE>TFTP</TITLE>
 <PARA>The TFTP client and server are described in
 <filename>tftp_support.h</filename>;
-the client API is simple and can be easily understood by reading
-<filename>tftp_client_test.c</filename>.</PARA>
+
+<PARA>The TFTP client has and new and an older, depreciated, API. The
+new API works for both IPv4 and IPv6 where as the depreciated API is
+IPv4 only.
+</PARA>
+<PARA>
+The new API is as follows:
+</PARA>
+<PROGRAMLISTING>int tftp_client_get(char *filename,
+		    char *server,
+		    int port,
+		    char *buf,
+		    int len,
+		    int mode,
+		    int *err);
+
+int tftp_client_put(char *filename,
+		    char *server,
+		    int port,
+		    char *buf,
+		    int len,
+		    int mode,
+		    int *err);
+</PROGRAMLISTING>
+<PARA>Currently <varname>server</varname> can only be a numeric IPv4 or
+IPv6 address. The resolver is currently not used, but it is planned to
+add this feature (patches welcome). If <varname>port</varname> is zero
+the client connects to the default TFTP port on the server. Otherwise
+the specified port is used.
+</PARA>
+<PARA> 
+The depreciated API is:
+<PROGRAMLISTING>int tftp_client_get(char *filename,
+		    struct sockaddr_in *server,
+		    char *buf,
+		    int len,
+		    int mode,
+		    int *err);
+
+int tftp_client_put(char *filename,
+		    struct sockaddr_in *server,
+		    char *buf,
+		    int len,
+		    int mode,
+		    int *err);
+</PROGRAMLISTING>
+<PARA>
+The <varname>server</varname> should contain the address of the
+server to contact. If the <varname>sin_port</varname> member of the
+structure is zero the default TFTP port is used. Otherwise the
+specified port is used.
+</PARA>
+<PARA>
+Both API's report errors in the same way. The functions return a value
+of -1 and <varname>*err</varname> will be set to one of the
+following values:
+</PARA>
+<PROGRAMLISTING>
+#define	TFTP_ENOTFOUND   1   /* file not found */
+#define	TFTP_EACCESS     2   /* access violation */
+#define	TFTP_ENOSPACE    3   /* disk full or allocation exceeded */
+#define	TFTP_EBADOP      4   /* illegal TFTP operation */
+#define	TFTP_EBADID      5   /* unknown transfer ID */
+#define	TFTP_EEXISTS     6   /* file already exists */
+#define	TFTP_ENOUSER     7   /* no such user */
+#define TFTP_TIMEOUT     8   /* operation timed out */
+#define TFTP_NETERR      9   /* some sort of network error */
+#define TFTP_INVALID    10   /* invalid parameter */
+#define TFTP_PROTOCOL   11   /* protocol violation */
+#define TFTP_TOOLARGE   12   /* file is larger than buffer */
+</PROGRAMLISTING>
+<PARA>If there are no errors the return value is the number of bytes
+transfered.
+</PARA>
+
 <PARA>The server is more complex.  It requires a filesystem implementation
 to be supplied by the user, and attached to the tftp server by means
 of a vector of function pointers:</PARA>
@@ -414,9 +503,52 @@ of a vector of function pointers:</PARA>
              int (&ast;read)(int, void &ast;, int);
 };</PROGRAMLISTING>
 <PARA>These functions have the obvious semantics.  The structure
-describing the filesystem is an argument to the <function>tftpd_start(int,
-struct tftpd_fileops &ast;);</function> call.
- The first argument is the port to use for the server.</PARA>
+describing the filesystem is an argument to the <function>tftpd_start</function>:
+<PROGRAMLISTING>
+int tftp_start(int port,
+               struct tftpd_fileops *ops);
+</PROGRAMLISTING>
+<PARA>The first argument is the port to use for the server. If this
+port number is zero, the default TFTP port number will be used. The
+return value from <function>tftpd_start</function> is a handle which
+can be passed to <function>tftpd_stop</function>. This will kill the
+tftpd thread. Note that this is not a clean shutdown. The thread will
+simply be killed. <function>tftpd_stop</function> will attempt to
+close the sockets the thread was listening on and free some of its
+allocated memory. But if the thread was actively transferreing data at
+the time <function>tftpd_stop</function> is called, it is quite likely
+some memory and a socket will be leaked. Use this function with
+caution (or implement a clean shutdown and please contribute the code
+back :-).
+</PARA>
+
+<PARA>There are two CDL configuration options that control how many
+servers on how many different ports tftp can be
+started. CYGSEM_NET_TFTPD_MULTITHREADED, when enabled, allows multiple
+tftpd threads to operate on the same port number. With only one
+thread, while the thread is active transferring data, new requests for
+transfers will not be served until the active transfer is
+complete. When multiple threads are started on the same port, multiple
+transfers can take place simultaneous, up to the number of threads
+started. However a semaphore is required to synchronise the
+threads. This semaphore is required per port. The CDL option
+CYGNUM_NET_TFTPD_MULTITHREADED_PORTS controls how many different port
+numbers multithreaded servers can service.
+</PARA>
+<PARA>If CYGSEM_NET_TFTPD_MULTITHREADED is not enabled, only one
+thread may be run per port number. But this removes the need for a
+semaphore and so CYGNUM_NET_TFTPD_MULTITHREADED_PORTS is not required
+and unlimited number of ports can be used. </PARA>
+
+<PARA>It should be noted that the TFTPD does not perform any form of
+file locking. When multiple servers are active, it is assumed the
+underlying filesystem will refuse to open the same file multiple
+times, operate correctly with simultaneous read/writes to the same
+file, or if you are unlucky, corrupt itself beyond all repair.</PARA>
+ 
+<PARA>When IPv6 is enabled the tftpd thread will listen for requests
+from both IPv4 and IPv6 addresses.</PARA>
+
 <PARA>As discussed in the description of the tftp_server_test
 above, an example filesystem is provided in
 <filename>net/common/<REPLACEABLE>VERSION</REPLACEABLE>/src/tftp_dummy_file.c</filename>
--- a/packages/net/common/current/include/network.h
+++ b/packages/net/common/current/include/network.h
@@ -19,7 +19,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, andrew.lunn@ascom.ch
 // Date:         2000-01-10
 // Purpose:      
 // Description:  
@@ -82,4 +82,11 @@ extern const char  *eth1_name;
 #define CYG_NET_GET_MEM_STATS_CLUST 2 // Clust pool
 int cyg_net_get_mem_stats( int which, cyg_mempool_info *p );
 
+#ifdef CYGPKG_NET_INET6
+#ifdef CYGOPT_NET_IPV6_ROUTING_THREAD 
+__externC void ipv6_start_routing_thread(void);
+__externC int cyg_net_get_ipv6_advrouter(struct sockaddr_in6 * addr);
+#endif
+#endif
+
 #endif // _NETWORK_H_
--- a/packages/net/common/current/include/tftp_support.h
+++ b/packages/net/common/current/include/tftp_support.h
@@ -19,7 +19,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, andrew.lunn@ascom.ch
 // Date:         2000-04-06
 // Purpose:      
 // Description:  
@@ -81,6 +81,11 @@ struct tftpd_fileops {
  * Client support
  */
 
+/* IPv4 and IPv6 */
+__externC int tftp_client_get(char *, char *, int, char *, int, int, int *);
+__externC int tftp_client_put(char *, char *, int, char *, int, int, int *);
+
+/* IPv4 only */
 __externC int tftp_get(char *, struct sockaddr_in *, char *, int, int, int *);
 __externC int tftp_put(char *, struct sockaddr_in *, char *, int, int, int *);
 
--- a/packages/net/common/current/src/dhcp_prot.c
+++ b/packages/net/common/current/src/dhcp_prot.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Andrew Lunn
 //
 // eCos 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
@@ -41,7 +42,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):   hmt
-// Contributors: gthomas
+// Contributors: gthomas, andrew.lunn@ascom.ch
 // Date:        2000-07-01
 // Purpose:     DHCP support
 // Description: 
@@ -1311,17 +1312,16 @@ do_dhcp_down_net(const char *intf, struc
         return false;
       }
       // Now delete the ipv6 addr
+      memset(&iflr,0,sizeof(iflr));
       strcpy(iflr.iflr_name, intf);
-      if (ioctl(s6, SIOCGLIFADDR, &iflr)) {
-	perror("SIOCGIFADDR_IN6 1");
-	return false;
-      }
+      if (!ioctl(s6, SIOCGLIFADDR, &iflr)) {
       
-      strcpy(iflr.iflr_name, intf);
-      if (ioctl(s6, SIOCDLIFADDR, &iflr)) { /* delete IF addr */
-        perror("SIOCDIFADDR_IN61");
+	strcpy(iflr.iflr_name, intf);
+	if (ioctl(s6, SIOCDLIFADDR, &ifr)) { /* delete IF addr */
+	  perror("SIOCDIFADDR_IN61");
+	}
+	close(s6);
       }
-      close(s6);
     }
 #endif /* IP6 */
 
--- a/packages/net/common/current/src/getaddrinfo.c
+++ b/packages/net/common/current/src/getaddrinfo.c
@@ -9,6 +9,7 @@
 //
 // Copyright (C) 2000, 2001, 2002 Red Hat, Inc.
 // Copyright (C) 2003 Gary Thomas
+// Copyright (C) 2003 andrew.lunn@ascom.ch
 // All Rights Reserved.
 //
 // Permission is granted to use, copy, modify and redistribute this
@@ -19,7 +20,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, andrew.lunn@ascom.ch
 // Date:         2002-03-05
 // Purpose:      
 // Description:  
@@ -68,7 +69,11 @@ static int
             if (hints->ai_flags & AI_PASSIVE) {
                 sa->sin_addr.s_addr = htonl(INADDR_ANY);
             } else {
+#ifdef CYGPKG_NET_OPENBSD_STACK
+                sa->sin_addr.s_addr = INADDR_LOOPBACK;
+#else
                 sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+#endif
             }
         } else {
             _hent = gethostbyname(node);
@@ -123,11 +128,15 @@ getaddrinfo(const char *nodename, const 
     struct addrinfo dflt_hints;
     struct protoent *proto = (struct protoent *)NULL;
     struct addrinfo *ai;
+#ifdef CYGPKG_NET_INET6
+    struct addrinfo *nai;
+#endif
     char *protoname;
+    char *endptr;
     int port = 0;
-    int family;
     int err;
-
+    int used = 0;
+    
     if (hints == (struct addrinfo *)NULL) {
         dflt_hints.ai_flags = 0;  // No special flags
         dflt_hints.ai_family = PF_UNSPEC;
@@ -142,12 +151,10 @@ getaddrinfo(const char *nodename, const 
     switch (hints->ai_family) {
     case PF_UNSPEC:
     case PF_INET:
-        family = AF_INET;
-        break;
+      break;
 #ifdef CYGPKG_NET_INET6
     case PF_INET6:
-        family = AF_INET6;
-        break;
+      break;
 #endif
     default:
         return EAI_FAMILY;
@@ -161,7 +168,6 @@ getaddrinfo(const char *nodename, const 
     if (hints->ai_protocol != 0) {
         proto = getprotobynumber(hints->ai_protocol);
     }
-    ai->ai_family = family;
     if (servname != (char *)NULL) {
         switch (hints->ai_socktype) {
         case 0:
@@ -178,7 +184,8 @@ getaddrinfo(const char *nodename, const 
             return EAI_SOCKTYPE;
         }
         // See if this is just a port #
-        if ((port = strtol(servname, 0, 0)) >= 0) {
+        if (((port = strtol(servname, &endptr, 0)) >= 0) &&
+	    (endptr > servname)) {
             ai->ai_socktype = hints->ai_socktype;
             if (hints->ai_socktype == 0) {
                 // Need to have complete binding type/port
@@ -199,7 +206,8 @@ getaddrinfo(const char *nodename, const 
                 freeaddrinfo(ai);
                 return EAI_SERVICE;
             }
-            port = ntohs(serv->s_port);      
+            port = ntohs(serv->s_port);  
+            ai->ai_socktype = SOCK_DGRAM;    
         }
         proto = getprotobyname(protoname);
         if (hints->ai_protocol && (hints->ai_protocol != proto->p_proto)) {
@@ -211,30 +219,51 @@ getaddrinfo(const char *nodename, const 
     // Iterate through address types and create addresses
     // Note: this does not handle the case where a given service can be
     // handled via multiple protocols, e.g. http/tcp & http/udp
-    err = _getaddr(ai, nodename, hints, family, port);
-    if (err != EAI_NONE) {
+    if ((hints->ai_family == AF_INET) || (hints->ai_family == PF_UNSPEC)) {
+      err = _getaddr(ai, nodename, hints, AF_INET, port);
+      if ((err != EAI_NONE) && (hints->ai_family == AF_INET)) {
         freeaddrinfo(ai);
         return err;
+      }
+      if (err == EAI_NONE) {
+	ai->ai_family = AF_INET;
+	used = 1;
+      }
     }
 #ifdef CYGPKG_NET_INET6
-    if (hints->ai_family == PF_UNSPEC) {
-        // Add IPv6 address as well
-        struct addrinfo *nai = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
+    if ((hints->ai_family == AF_INET6) || (hints->ai_family == PF_UNSPEC)) {
+      if (1 == used) {
+	nai = (struct addrinfo *)calloc(1,sizeof(struct addrinfo));
         if (nai == (struct addrinfo *)NULL) {
-            freeaddrinfo(ai);
-            return EAI_MEMORY;
+	  freeaddrinfo(ai);
+	  return EAI_MEMORY;
         }
         ai->ai_next = nai;
-        nai->ai_family = PF_INET6;
         nai->ai_socktype = ai->ai_socktype;
         nai->ai_protocol = ai->ai_protocol;
-        err = _getaddr(nai, nodename, hints, AF_INET6, port);
-        if (err != EAI_NONE) {
-            freeaddrinfo(*res);
-            return err;
-        }
+      } else {
+	nai = ai;
+      }
+      err = _getaddr(nai, nodename, hints, AF_INET6, port);
+      if ((err != EAI_NONE) && (hints->ai_family == AF_INET6)) {
+	freeaddrinfo(ai);
+	return err;
+      }
+      // Free the second entry which has not been used
+      if ((err != EAI_NONE) && (1 == used)) {
+	ai->ai_next = NULL;
+	free(nai);
+      }
+      if (err == EAI_NONE) {
+	nai->ai_family = AF_INET6;
+	used = 1;
+      }
     }
 #endif
+    // Do we have at least one address?
+    if (0 == used) {
+      return EAI_NONAME;
+    }
     // Note: null nodename is the same as 'localhost'
     if (nodename == (char *)NULL) {
         nodename = (const char *)"localhost";
--- a/packages/net/common/current/src/getproto.c
+++ b/packages/net/common/current/src/getproto.c
@@ -19,7 +19,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, andrew.lunn@ascom.ch
 // Date:         2000-01-10
 // Purpose:      
 // Description:  
@@ -51,7 +51,8 @@ static struct protoent protocols[] = {
     { "xtp",       36}, // Xpress Tranfer Protocol
     { "ddp",       37}, // Datagram Delivery Protocol
     { "idpr-cmtp", 39}, // IDPR Control Message Transport
-    { "rspf",      73}, //Radio Shortest Path First.
+    { "ipv6-icmp", 58}, // ICMP for IPv6
+    { "rspf",      73}, // Radio Shortest Path First.
     { "vmtp",      81}, // Versatile Message Transport
     { "ospf",      89}, // Open Shortest Path First IGP
     { "ipip",      94}, // Yet Another IP encapsulation
--- a/packages/net/common/current/src/ifaddrs.c
+++ b/packages/net/common/current/src/ifaddrs.c
@@ -52,6 +52,8 @@
  *	BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
  */
 
+#include <cyg/infra/diag.h>
+
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
--- a/packages/net/common/current/src/ipv6_routing_thread.c
+++ b/packages/net/common/current/src/ipv6_routing_thread.c
@@ -19,7 +19,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas, lhamilton
+// Contributors: gthomas, lhamilton, andrew.lunn@ascom.ch
 // Date:         2002-04-16
 // Purpose:      
 // Description:  
@@ -58,7 +58,7 @@
 
 void _show_all_interfaces(void);
 
-#define DBG_PRINT                          1
+//#define DBG_PRINT                          1
 #define ALLROUTER                  "ff02::2"
 
 #define STACK_SIZE    CYGNUM_HAL_STACK_SIZE_TYPICAL+2048
@@ -87,6 +87,19 @@ static struct timeval last_ra_time;
 static struct timeval idle_expire;
 static struct icmp6stat *istat;
 extern struct icmp6stat cyg_icmp6stat;
+static struct sockaddr_in6 router;
+static int router_valid = 0;
+
+// Return the address of the last router to send us a router advertisement 
+// Copy the address into addr and return true. If we have not received an
+// advertisement yet, return false
+int cyg_net_get_ipv6_advrouter(struct sockaddr_in6 * addr) {
+  
+  if (addr) {
+    memcpy(addr,&router,sizeof(*addr));
+  }
+  return router_valid;
+}
 
 static void
 cyg_rs_exit(void)
@@ -154,17 +167,87 @@ receive_ra_packet(void)
 {
   int len;
   char msg[1024];
+  struct nd_router_advert *advert;
+  cyg_uint8 *opts;
+  int optlen;
+  int addrlen = sizeof(router);
+  char buf[64];
 
   dprnt("%s", __FUNCTION__);
 
-  len = read(s, msg, sizeof(msg));
+  len = recvfrom(s, msg, sizeof(msg),0,(struct sockaddr *)&router,&addrlen);
   if (len < 0) {
     dprnt("  Can't read RA data: %s", strerror(errno));
     return;
   }
+  router_valid = 1;
+
+  inet_ntop(AF_INET6,(void *)&router.sin6_addr,buf,64);  
+  dprnt("Router Advertisement from %s",buf);
   dprnt("packet data (buf len=%d) :", len);
+#ifdef DBG_PRINT  
   diag_dump_buf(msg, len);
+#endif
 
+  advert = (struct nd_router_advert *)msg;
+
+  dprnt("AdvCurHopLimit: %d", (int) advert->nd_ra_curhoplimit);
+  dprnt("AdvManagedFlag: %s",
+	(advert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) ? "yes" : "no");
+  dprnt("AdvOtherConfigFlag: %s",
+	(advert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) ? "yes":"no");
+  dprnt("AdvHomeAgentFlag: %s",
+	 (advert->nd_ra_flags_reserved & ND_RA_FLAG_HOME_AGENT) ? 
+	 "yes" : "no");
+  dprnt("AdvReachableTime: %lu", 
+	 (unsigned long)ntohl(advert->nd_ra_reachable));
+  dprnt("AdvRetransTimer: %lu", 
+	(unsigned long)ntohl(advert->nd_ra_retransmit));
+  
+  // Now process the optinal fields 
+  len -= sizeof(*advert);
+  opts = (cyg_uint8 *)(msg + sizeof(struct nd_router_advert));
+
+  while (len > 0) {
+     optlen = (opts[1] << 3);
+     switch (*opts) {
+     case ND_OPT_MTU: {
+       struct nd_opt_mtu *mtu = (struct nd_opt_mtu *) opts;
+
+       dprnt("AdvLinkMTU: %lu", 
+	     (unsigned long)ntohl(mtu->nd_opt_mtu_mtu));
+       break;
+     }
+     case ND_OPT_PREFIX_INFORMATION: {
+       struct nd_opt_prefix_info *pinfo = (struct nd_opt_prefix_info *) opts;
+
+       inet_ntop(AF_INET6,(void *)&pinfo->nd_opt_pi_prefix,buf,64);
+       dprnt("Prefix:  %s/%d",buf,pinfo->nd_opt_pi_prefix_len);
+       break;
+     }
+     case ND_OPT_SOURCE_LINKADDR: {
+       char *cp = buf;
+       int i;
+       
+       for (i = 2 ; i < optlen ; i++) {
+	 cp += diag_sprintf(cp,"%02x ", (unsigned int) opts[i]);
+       }
+      
+       dprnt("AdvSourceLinkAddress: %s",buf);
+       break;
+     }
+     case ND_OPT_ADVINTERVAL:
+     case ND_OPT_HOMEAGENT_INFO:
+       dprnt("Mobile IPv6 entension options (not decoded)");
+       break;
+     default:
+       dprnt("Unknown option %d\n", (int)*opts);
+       break;
+     }
+     len -= optlen;
+     opts += optlen;
+  }
+       
   racount++;
   get_realtime(&last_ra_time);
   dprnt("racount=%d, timestamp=%d sec",
@@ -251,7 +334,9 @@ cyg_rs(cyg_addrword_t param)
   u_int hlim = 255;
   fd_set fdset;
 
+#ifdef DBG_PRINT
   _show_all_interfaces();
+#endif
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = AF_INET6;
@@ -289,7 +374,7 @@ cyg_rs(cyg_addrword_t param)
   idle_expire.tv_usec = 0;
   select_timeout.tv_usec = 0;
   last_ra_time.tv_usec = 0;
-  last_ra_time.tv_sec = 10;
+  last_ra_time.tv_sec = 2;
   select(0, 0, 0, 0, &last_ra_time);
 
   racount = 0;
--- a/packages/net/common/current/src/network_support.c
+++ b/packages/net/common/current/src/network_support.c
@@ -128,6 +128,7 @@ cyg_bool_t init_loopback_interface(int l
     }
     if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) {
         perror("setsockopt");
+	close(s);
         return false;
     }
 
@@ -149,6 +150,7 @@ cyg_bool_t init_loopback_interface(int l
 
     if (ioctl(s, SIOCSIFADDR, &ifr)) {
         perror("SIOCIFADDR");
+        close(s);
         return false;
     }
     
@@ -166,6 +168,7 @@ cyg_bool_t init_loopback_interface(int l
     ifr.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
     if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
         perror("SIOCSIFFLAGS");
+        close(s);
         return false;
     }
 
@@ -191,6 +194,7 @@ cyg_bool_t init_loopback_interface(int l
         diag_printf(", gateway: %s\n", inet_ntoa(((struct sockaddr_in *)&route.rt_gateway)->sin_addr));
         if (errno != EEXIST) {
             perror("SIOCADDRT 3");
+            close(s);
             return false;
         }
     }
@@ -283,6 +287,9 @@ init_all_network_interfaces(void)
 #ifdef CYGPKG_IO_PCMCIA
     cyg_netdevtab_entry_t *t;
 #endif // CYGPKG_IO_PCMCIA
+#ifdef CYGOPT_NET_IPV6_ROUTING_THREAD
+    int rs_wait = 40;
+#endif
 
     cyg_scheduler_lock();
     while ( in_init_all_network_interfaces ) {
@@ -455,6 +462,14 @@ init_all_network_interfaces(void)
 
 #ifdef CYGOPT_NET_IPV6_ROUTING_THREAD
     ipv6_start_routing_thread();
+
+    // Wait for router solicit process to happen.
+    while (rs_wait-- && !cyg_net_get_ipv6_advrouter(NULL)) {
+      cyg_thread_delay(10);
+    }
+    if (rs_wait == 0 ) {
+      diag_printf("No router solicit received\n");
+    } 
 #endif
 
 #ifdef CYGDAT_NS_DNS_DEFAULT_SERVER
--- a/packages/net/common/current/src/tftp_client.c
+++ b/packages/net/common/current/src/tftp_client.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Andrew.Lunn@ascom.ch
 //
 // eCos 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
@@ -41,7 +42,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, andrew.lunn@ascom.ch
 // Date:         2000-04-06
 // Purpose:      
 // Description:  
@@ -63,25 +64,31 @@
 // Read a file from a host into a local buffer.  Returns the
 // number of bytes actually read, or (-1) if an error occurs.
 // On error, *err will hold the reason.
-//
-int
-tftp_get(char *filename,
-         struct sockaddr_in *server,
-         char *buf,
-         int len,
-         int mode,
-         int *err)
-{
-    int res = 0;
-    int s, actual_len, data_len, recv_len, from_len;
+// This version uses the server name. This can be a name for DNS lookup
+// or a dotty or colony number format for IPv4 or IPv6.
+int tftp_client_get(char *filename,
+		    char *server,
+		    int port,
+		    char *buf,
+		    int len,
+		    int mode,
+		    int *err) {
+		    
+    int result = 0;
+    int s=-1;
+    int actual_len, data_len, recv_len, from_len;
     static int get_port = 7700;
-    struct sockaddr_in local_addr, server_addr, from_addr;
+    struct addrinfo * addrinfo;
+    struct addrinfo * res;
+    struct addrinfo hints;
+    int error;
+
+    struct sockaddr local_addr, from_addr;
     char data[SEGSIZE+sizeof(struct tftphdr)];
     struct tftphdr *hdr = (struct tftphdr *)data;
     char *cp, *fp;
     struct timeval timeout;
     unsigned short last_good_block = 0;
-    struct servent *server_info;
     fd_set fds;
     int total_timeouts = 0;
 
@@ -103,130 +110,188 @@ tftp_get(char *filename,
     }
     while (*fp) *cp++ = *fp++;
     *cp++ = '\0';
-    server_info = getservbyname("tftp", "udp");
-    if (server_info == (struct servent *)0) {
-        *err = TFTP_NETERR;
-        return -1;
-    }
 
-    s = socket(AF_INET, SOCK_DGRAM, 0);
-    if (s < 0) {
-        // Couldn't open a communications channel
-        *err = TFTP_NETERR;
-        return -1;
+    memset(&hints,0,sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    error = getaddrinfo(server, "tftp", &hints, &res);
+    if (error) {
+      *err = TFTP_NETERR;
+      return -1;
     }
-    memset((char *)&local_addr, 0, sizeof(local_addr));
-    local_addr.sin_family = AF_INET;
-    local_addr.sin_len = sizeof(local_addr);
-    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    local_addr.sin_port = htons(get_port++);
-    if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
-        // Problem setting up my end
-        *err = TFTP_NETERR;
-        close(s);
-        return -1;
-    }
-    memset((char *)&server_addr, 0, sizeof(server_addr));
-    server_addr.sin_family = AF_INET;
-    server_addr.sin_len = sizeof(server_addr);
-    server_addr.sin_addr = server->sin_addr;
-    if (server->sin_port == 0) {
-        server_addr.sin_port = server_info->s_port; // Network order already
-    } else {
-        server_addr.sin_port = server->sin_port;
-    }
+    
+    addrinfo = res;
+    while (addrinfo) {
+      s = socket(addrinfo->ai_family, addrinfo->ai_socktype, 
+		 addrinfo->ai_protocol);
+      if (s >= 0) {
+	memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen);
+	switch(addrinfo->ai_addr->sa_family) {
+	case AF_INET: {
+	  struct sockaddr_in * saddr = 
+	    (struct sockaddr_in *) addrinfo->ai_addr;
+	  struct sockaddr_in * laddr = 
+	    (struct sockaddr_in *) &local_addr;
+	  if (port) {
+	    saddr->sin_port = htons(port);
+	  }
+	  laddr->sin_port = htons(get_port++);
+	  laddr->sin_addr.s_addr = INADDR_ANY;
+	  break;
+	}
+#ifdef CYGPKG_NET_INET6
+	case AF_INET6: {
+	  struct sockaddr_in6 * saddr = 
+	    (struct sockaddr_in6 *) addrinfo->ai_addr;
+	  struct sockaddr_in6 * laddr = 
+	    (struct sockaddr_in6 *) &local_addr;
+	  if (port) {
+	    saddr->sin6_port = htons(port);
+	  }
+	  laddr->sin6_port = htons(get_port++);
+	  laddr->sin6_addr = in6addr_any;
+	  break;
+	}
+#endif
+	default:
+	  *err = TFTP_NETERR;
+	  goto out;
+	}
 
-    // Send request
-    if (sendto(s, data, (int)(cp - data), 0, 
-               (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
-        // Problem sending request
-        *err = TFTP_NETERR;
-        close(s);
-        return -1;
-    }
+	if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) {
+	  *err = TFTP_NETERR;
+	  goto out;
+	}
+	
+	// Send request
+	if (sendto(s, data, (int)(cp-data), 0, 
+		   addrinfo->ai_addr, 
+		   addrinfo->ai_addrlen) < 0) {
+	  // Problem sending request
+	  *err = TFTP_NETERR;
+	  goto nextaddr;
+	}
 
-    // Read data
-    fp = buf;
-    while (true) {
-        timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
-        timeout.tv_usec = 0;
-        FD_ZERO(&fds);
-        FD_SET(s, &fds);
-        if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
-            if ((++total_timeouts > TFTP_TIMEOUT_MAX) || (last_good_block == 0)) {
-                // Timeout - no data received
-                *err = TFTP_TIMEOUT;
-                close(s);
-                return -1;
-            }
-            // Try resending last ACK
-            hdr->th_opcode = htons(ACK);
-            hdr->th_block = htons(last_good_block);
-            if (sendto(s, data, 4 /* FIXME */, 0, 
-                       (struct sockaddr *)&from_addr, from_len) < 0) {
-                // Problem sending request
-                *err = TFTP_NETERR;
-                close(s);
-                return -1;
-            }
-        } else {
-            recv_len = sizeof(data);
-            from_len = sizeof(from_addr);
-            if ((data_len = recvfrom(s, &data, recv_len, 0, 
-                                     (struct sockaddr *)&from_addr, &from_len)) < 0) {
-                // What happened?
-                *err = TFTP_NETERR;
-                close(s);
-                return -1;
-            }
-            if (ntohs(hdr->th_opcode) == DATA) {
-                actual_len = 0;
-                if (ntohs(hdr->th_block) == (last_good_block+1)) {
-                    // Consume this data
-                    cp = hdr->th_data;
-                    data_len -= 4;  /* Sizeof TFTP header */
-                    actual_len = data_len;
-                    res += actual_len;
-                    while (data_len-- > 0) {
-                        if (len-- > 0) {
-                            *fp++ = *cp++;
-                        } else {
-                            // Buffer overflow
-                            *err = TFTP_TOOLARGE;
-                            close(s);
-                            return -1;
-                        }
-                    }
-                    last_good_block++;
-                }
-                // Send out the ACK
-                hdr->th_opcode = htons(ACK);
-                hdr->th_block = htons(last_good_block);
-                if (sendto(s, data, 4 /* FIXME */, 0, 
-                           (struct sockaddr *)&from_addr, from_len) < 0) {
-                    // Problem sending request
-                    *err = TFTP_NETERR;
-                    close(s);
-                    return -1;
-                }
-                if ((actual_len >= 0) && (actual_len < SEGSIZE)) {
-                    // End of data
-                    close(s);
-                    return res;
-                }
-            } else 
-            if (ntohs(hdr->th_opcode) == ERROR) {
-                *err = ntohs(hdr->th_code);
-                close(s);
-                return -1;
-            } else {
-                // What kind of packet is this?
+	// Read data
+	fp = buf;
+	while (true) {
+	  timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
+	  timeout.tv_usec = 0;
+	  FD_ZERO(&fds);
+	  FD_SET(s, &fds);
+	  if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
+	    if ((++total_timeouts > TFTP_TIMEOUT_MAX) 
+		|| (last_good_block == 0)) {
+	      // Timeout - no data received
+	      *err = TFTP_TIMEOUT;
+	      goto out;
+	    }
+	    // Try resending last ACK
+	    hdr->th_opcode = htons(ACK);
+	    hdr->th_block = htons(last_good_block);
+	    if (sendto(s, data, 4 /* FIXME */, 0, 
+		       &from_addr, from_len) < 0) {
+	      // Problem sending request
+	      *err = TFTP_NETERR;
+	      goto out;
+	    }
+	  } else {
+	    recv_len = sizeof(data);
+	    from_len = sizeof(from_addr);
+	    if ((data_len = recvfrom(s, &data, recv_len, 0, 
+				     &from_addr, &from_len)) < 0) {
+	      // What happened?
+	      *err = TFTP_NETERR;
+	      goto out;
+	    }
+	    if (ntohs(hdr->th_opcode) == DATA) {
+	      actual_len = 0;
+	      if (ntohs(hdr->th_block) == (last_good_block+1)) {
+		// Consume this data
+		cp = hdr->th_data;
+		data_len -= 4;  /* Sizeof TFTP header */
+		actual_len = data_len;
+		result += actual_len;
+		while (data_len-- > 0) {
+		  if (len-- > 0) {
+		    *fp++ = *cp++;
+		  } else {
+		    // Buffer overflow
+		    *err = TFTP_TOOLARGE;
+		    goto out;
+		  }
+		}
+		last_good_block++;
+	      }
+	      // Send out the ACK
+	      hdr->th_opcode = htons(ACK);
+	      hdr->th_block = htons(last_good_block);
+	      if (sendto(s, data, 4 /* FIXME */, 0, 
+			 &from_addr, from_len) < 0) {
+		// Problem sending request
+		*err = TFTP_NETERR;
+		goto out;
+	      }
+	      if ((actual_len >= 0) && (actual_len < SEGSIZE)) {
+		// End of data
+		close(s);
+		freeaddrinfo(res);
+		return result;
+	      }
+	    } else 
+	      if (ntohs(hdr->th_opcode) == ERROR) {
+		*err = ntohs(hdr->th_code);
+		goto out;
+	      } else {
+		// What kind of packet is this?
                 *err = TFTP_PROTOCOL;
-                close(s);
-                return -1;
-            }
-        }
+		goto out;
+	      }
+	  }
+	}
+      }
+      // If we got here, it means there was a problem connecting to the 
+      // server. Try the next address returned by getaddrinfo
+    nextaddr:
+      if (-1 != s) {
+	close(s);
+      }
+      addrinfo=addrinfo->ai_next;
+    }
+    // We ran into problems. Cleanup
+ out:
+    if (-1 != s) {
+      close (s);
     }
+    freeaddrinfo(res);
+    return -1;
+}
+//
+// Read a file from a host into a local buffer.  Returns the
+// number of bytes actually read, or (-1) if an error occurs.
+// On error, *err will hold the reason.
+//
+// Depreciated. Use tftp_client_get instead.
+int
+tftp_get(char *filename,
+         struct sockaddr_in *server,
+         char *buf,
+         int len,
+         int mode,
+         int *err)
+{
+  char server_name[20];
+  char *ret;
+  int port;
+
+  ret = inet_ntop(AF_INET, (void *)&server->sin_addr, 
+		  server_name, sizeof(server_name));
+  if (NULL == ret) {
+      *err = TFTP_NETERR;
+      return -1;
+  }
+  port = server->sin_port;
+
+  return tftp_client_get(filename, server_name, port, buf, len, mode, err);
 }
 
 //
@@ -240,186 +305,247 @@ tftp_put(char *filename,
          int mode,
          int *err)
 {
-    int res = 0;
+  char server_name[20];
+  char *ret;
+  int port;
+
+  ret = inet_ntop(AF_INET, (void *)&server->sin_addr, 
+		  server_name, sizeof(server_name));
+  if (NULL == ret) {
+      *err = TFTP_NETERR;
+      return -1;
+  }
+  port = server->sin_port;
+
+  return tftp_client_put(filename, server_name, port, buf, len, mode, err);
+}
+
+//
+// Put a file to a host from a local buffer.  Returns the
+// number of bytes actually writen, or (-1) if an error occurs.
+// On error, *err will hold the reason.
+// This version uses the server name. This can be a name for DNS lookup
+// or a dotty or colony number format for IPv4 or IPv6.
+int tftp_client_put(char *filename,
+		    char *server,
+		    int port,
+		    char *buf,
+		    int len,
+		    int mode,
+		    int *err) {
+
+    int result = 0;
     int s, actual_len, data_len, recv_len, from_len;
     static int put_port = 7800;
-    struct sockaddr_in local_addr, server_addr, from_addr;
+    struct sockaddr local_addr, from_addr;
     char data[SEGSIZE+sizeof(struct tftphdr)];
     struct tftphdr *hdr = (struct tftphdr *)data;
     char *cp, *fp, *sfp;
     struct timeval timeout;
     unsigned short last_good_block = 0;
-    struct servent *server_info;
     fd_set fds;
     int total_timeouts = 0;
+    struct addrinfo hints;
+    struct addrinfo * addrinfo;
+    struct addrinfo * res;
+    int error;
 
     *err = 0;  // Just in case
 
-    server_info = getservbyname("tftp", "udp");
-    if (server_info == (struct servent *)0) {
-        *err = TFTP_NETERR;
-        return -1;
-    }
-
-    s = socket(AF_INET, SOCK_DGRAM, 0);
-    if (s < 0) {
-        // Couldn't open a communications channel
-        *err = TFTP_NETERR;
-        return -1;
-    }
-    memset((char *)&local_addr, 0, sizeof(local_addr));
-    local_addr.sin_family = AF_INET;
-    local_addr.sin_len = sizeof(local_addr);
-    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    local_addr.sin_port = htons(put_port++);
-    if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
-        // Problem setting up my end
-        *err = TFTP_NETERR;
-        close(s);
-        return -1;
+    memset(&hints,0,sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    error = getaddrinfo(server, "tftp", &hints, &res);
+    if (error) {
+      *err = TFTP_NETERR;
+      return -1;
     }
-    memset((char *)&server_addr, 0, sizeof(server_addr));
-    server_addr.sin_family = AF_INET;
-    server_addr.sin_len = sizeof(server_addr);
-    server_addr.sin_addr = server->sin_addr;
-    if (server->sin_port == 0) {
-        server_addr.sin_port = server_info->s_port; // Network order already
-    } else {
-        server_addr.sin_port = server->sin_port;
-    }
+    
+    addrinfo = res;
+    while (addrinfo) {
+      s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
+		 addrinfo->ai_protocol);
+      if (s >= 0) {
+	memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen);
+	switch(addrinfo->ai_addr->sa_family) {
+	case AF_INET: {
+	  struct sockaddr_in * saddr = 
+	    (struct sockaddr_in *) addrinfo->ai_addr;
+	  struct sockaddr_in * laddr = 
+	    (struct sockaddr_in *) &local_addr;
+	  if (port) {
+	    saddr->sin_port = htons(port);
+	  }
+	  laddr->sin_port = htons(put_port++);
+	  laddr->sin_addr.s_addr = INADDR_ANY;
+	  break;
+	}
+#ifdef CYGPKG_NET_INET6
+	case AF_INET6: {
+	  struct sockaddr_in6 * saddr = 
+	    (struct sockaddr_in6 *) addrinfo->ai_addr;
+	  struct sockaddr_in6 * laddr = 
+	    (struct sockaddr_in6 *) &local_addr;
+	  if (port) {
+	    saddr->sin6_port = htons(port);
+	  }
+	  laddr->sin6_port = htons(put_port++);
+	  laddr->sin6_addr = in6addr_any;
+	  break;
+	}
+#endif
+	default:
+	  *err = TFTP_NETERR;
+	  goto out;
+	}
+	if (bind(s, 
+		 (struct sockaddr *)&local_addr, 
+		 addrinfo->ai_addrlen) < 0) {
+	  // Problem setting up my end
+	  *err = TFTP_NETERR;
+	  goto out;
+	}
 
-    while (1) {
-        // Create initial request
-        hdr->th_opcode = htons(WRQ);  // Create/write file
-        cp = (char *)&hdr->th_stuff;
-        fp = filename;
-        while (*fp) *cp++ = *fp++;
-        *cp++ = '\0';
-        if (mode == TFTP_NETASCII) {
+	while (1) {
+	  // Create initial request
+	  hdr->th_opcode = htons(WRQ);  // Create/write file
+	  cp = (char *)&hdr->th_stuff;
+	  fp = filename;
+	  while (*fp) *cp++ = *fp++;
+	  *cp++ = '\0';
+	  if (mode == TFTP_NETASCII) {
             fp = "NETASCII";
-        } else if (mode == TFTP_OCTET) {
+	  } else if (mode == TFTP_OCTET) {
             fp = "OCTET";
-        } else {
+	  } else {
             *err = TFTP_INVALID;
-            return -1;
-        }
-        while (*fp) *cp++ = *fp++;
-        *cp++ = '\0';
-        // Send request
-        if (sendto(s, data, (int)(cp-data), 0, 
-                   (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
+	    goto out;
+	  }
+	  while (*fp) *cp++ = *fp++;
+	  *cp++ = '\0';
+	  // Send request
+	  if (sendto(s, data, (int)(cp-data), 0, 
+		     addrinfo->ai_addr,
+		     addrinfo->ai_addrlen) < 0) {
             // Problem sending request
             *err = TFTP_NETERR;
-            close(s);
-            return -1;
-        }
-        // Wait for ACK
-        timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
-        timeout.tv_usec = 0;
-        FD_ZERO(&fds);
-        FD_SET(s, &fds);
-        if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
+	    goto nextaddr;
+	  }
+	  // Wait for ACK
+	  timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
+	  timeout.tv_usec = 0;
+	  FD_ZERO(&fds);
+	  FD_SET(s, &fds);
+	  if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
             if (++total_timeouts > TFTP_TIMEOUT_MAX) {
-                // Timeout - no ACK received
-                *err = TFTP_TIMEOUT;
-                close(s);
-                return -1;
+	      // Timeout - no ACK received
+	      *err = TFTP_TIMEOUT;
+	      goto nextaddr;
             }
-        } else {
+	  } else {
             recv_len = sizeof(data);
             from_len = sizeof(from_addr);
             if ((data_len = recvfrom(s, &data, recv_len, 0, 
-                                     (struct sockaddr *)&from_addr, &from_len)) < 0) {
-                // What happened?
-                *err = TFTP_NETERR;
-                close(s);
-                return -1;
+                                     &from_addr, &from_len)) < 0) {
+	      // What happened?
+	      *err = TFTP_NETERR;
+	      goto out;
             }
             if (ntohs(hdr->th_opcode) == ACK) {
-                // Write request accepted - start sending data
-                break;
+	      // Write request accepted - start sending data
+	      break;
             } else 
-            if (ntohs(hdr->th_opcode) == ERROR) {
+	      if (ntohs(hdr->th_opcode) == ERROR) {
                 *err = ntohs(hdr->th_code);
-                close(s);
-                return -1;
-            } else {
+                goto out;
+	      } else {
                 // What kind of packet is this?
-                *err = TFTP_PROTOCOL;
-                close(s);
-                return -1;
-            }
-        }
-    }
-
-    // Send data
-    sfp = buf;
-    last_good_block = 1;
-    while (res < len) {
-        // Build packet of data to send
-        data_len = min(SEGSIZE, len-res);
-        hdr->th_opcode = htons(DATA);
-        hdr->th_block = htons(last_good_block);
-        cp = hdr->th_data;
-        fp = sfp;
-        actual_len = data_len + 4;
-        // FIXME - what about "netascii" data?
-        while (data_len-- > 0) *cp++ = *fp++;
-        // Send data packet
-        if (sendto(s, data, actual_len, 0, 
-                   (struct sockaddr *)&from_addr, from_len) < 0) {
+		goto out;
+	      }
+	  }
+	}
+	
+	// Send data
+	sfp = buf;
+	last_good_block = 1;
+	while (result < len) {
+	  // Build packet of data to send
+	  data_len = min(SEGSIZE, len-result);
+	  hdr->th_opcode = htons(DATA);
+	  hdr->th_block = htons(last_good_block);
+	  cp = hdr->th_data;
+	  fp = sfp;
+	  actual_len = data_len + 4;
+	  // FIXME - what about "netascii" data?
+	  while (data_len-- > 0) *cp++ = *fp++;
+	  // Send data packet
+	  if (sendto(s, data, actual_len, 0, 
+		     &from_addr, from_len) < 0) {
             // Problem sending request
             *err = TFTP_NETERR;
-            close(s);
-            return -1;
-        }
-        // Wait for ACK
-        timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
-        timeout.tv_usec = 0;
-        FD_ZERO(&fds);
-        FD_SET(s, &fds);
-        if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
+	    goto out;
+	  }
+	  // Wait for ACK
+	  timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
+	  timeout.tv_usec = 0;
+	  FD_ZERO(&fds);
+	  FD_SET(s, &fds);
+	  if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
             if (++total_timeouts > TFTP_TIMEOUT_MAX) {
-                // Timeout - no data received
-                *err = TFTP_TIMEOUT;
-                close(s);
-                return -1;
+	      // Timeout - no data received
+	      *err = TFTP_TIMEOUT;
+	      goto out;
             }
-        } else {
+	  } else {
             recv_len = sizeof(data);
             from_len = sizeof(from_addr);
             if ((data_len = recvfrom(s, &data, recv_len, 0, 
-                                     (struct sockaddr *)&from_addr, &from_len)) < 0) {
-                // What happened?
-                *err = TFTP_NETERR;
-                close(s);
-                return -1;
+                                     &from_addr, &from_len)) < 0) {
+	      // What happened?
+	      *err = TFTP_NETERR;
+	      goto out;
             }
             if (ntohs(hdr->th_opcode) == ACK) {
-                if (ntohs(hdr->th_block) == last_good_block) {
-                    // Advance pointers, etc
-                    sfp = fp;
-                    res += (actual_len - 4);
-                    last_good_block++;
-                } else {
-                    diag_printf("Send block #%d, got ACK for #%d\n", 
-                                last_good_block, ntohs(hdr->th_block));
-                }
+	      if (ntohs(hdr->th_block) == last_good_block) {
+		// Advance pointers, etc
+		sfp = fp;
+		result += (actual_len - 4);
+		last_good_block++;
+	      } else {
+		diag_printf("Send block #%d, got ACK for #%d\n", 
+			    last_good_block, ntohs(hdr->th_block));
+	      }
             } else 
-            if (ntohs(hdr->th_opcode) == ERROR) {
+	      if (ntohs(hdr->th_opcode) == ERROR) {
                 *err = ntohs(hdr->th_code);
-                close(s);
-                return -1;
-            } else {
+                goto out;
+	      } else {
                 // What kind of packet is this?
                 *err = TFTP_PROTOCOL;
-                close(s);
-                return -1;
-            }
-        }
+		goto out;
+	      }
+	  }
+	}
+	close (s);
+	return result;
+      }
+
+      // If we got here, it means there was a problem connecting to the 
+      // server. Try the next address returned by getaddrinfo
+    nextaddr:
+      if (-1 != s) {
+	close(s);
+      }
+      addrinfo=addrinfo->ai_next;
     }
-    close(s);
-    return res;
+    // We ran into problems. Cleanup
+ out:
+    if (-1 != s) {
+      close (s);
+    }
+    freeaddrinfo(res);
+    return -1;
 }
 
 // EOF tftp_client.c
+
+
--- a/packages/net/common/current/src/tftp_server.c
+++ b/packages/net/common/current/src/tftp_server.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2003 Andrew Lunn
 //
 // eCos 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
@@ -85,8 +86,18 @@ static struct info tftp_server_instrumen
 
 #endif // CYGOPT_NET_TFTP_SERVER_INSTRUMENT
 
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED
+struct tftpd_sem {
+  int port;
+  cyg_sem_t sem;
+};
+
+static struct tftpd_sem tftpd_sems[CYGNUM_NET_TFTPD_MULTITHREADED_PORTS];
+#endif //CYGSEM_NET_TFTPD_MULTITHREADED
+
 #define STACK_SIZE (((CYGNUM_HAL_STACK_SIZE_TYPICAL+(3*(SEGSIZE+sizeof(struct tftphdr)))) + CYGARC_ALIGNMENT-1) & ~(CYGARC_ALIGNMENT-1))
 static char *TFTP_tag = "TFTPD";
+#define CYGNUM_NET_MAX_INET_PROTOS 2
 struct tftp_server {
     char                 *tag;
     char                  stack[STACK_SIZE];
@@ -94,6 +105,8 @@ struct tftp_server {
     cyg_handle_t          thread_handle;
     int                   port;
     struct tftpd_fileops *ops;
+    int s[CYGNUM_NET_MAX_INET_PROTOS], num_s;
+    struct addrinfo      *res;
 };
 
 static char * errmsg[] = {
@@ -107,10 +120,87 @@ static char * errmsg[] = {
   "No such user",                       // 7 TFTP_ENOUSER   
 };
 
+// Little helper function to set the port number in an address 
+static void set_port(struct sockaddr * address, int port) {
+
+  switch (address->sa_family) {
+  case AF_INET:{
+    struct sockaddr_in *addr = (struct sockaddr_in *)address;
+    addr->sin_port = ntohs(port);
+    break;
+  }
+#ifdef CYGPKG_NET_INET6
+  case AF_INET6:
+    {
+      struct sockaddr_in6 *addr = (struct sockaddr_in6 *)address;
+      addr->sin6_port = ntohs(port);
+      break;
+    }
+#endif
+  default:
+    break;
+  }
+}
+
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED
+
+// Allocate a semaphore for a given port number if one is not already
+// allocated.
+static void sem_alloc(int port) {
+  int i;
+
+  CYG_ASSERT(port != 0, "Invalid port number");
+
+  cyg_scheduler_lock(); // Avoid race with other tftpd's
+  for (i=0; i < CYGNUM_NET_TFTPD_MULTITHREADED_PORTS; i++) {
+    if (tftpd_sems[i].port == port) {
+      cyg_scheduler_unlock();
+      return;
+    }
+    if (tftpd_sems[i].port == 0) {
+      tftpd_sems[i].port = port;
+      cyg_semaphore_init(&tftpd_sems[i].sem,1);
+      cyg_scheduler_unlock();
+      return ;
+    }
+  }
+  cyg_scheduler_unlock();
+  diag_printf("TFTPD: Unable to allocate a semaphore for port %d\n",port);
+}
+  
+// Wait on the semaphore for a given port number.
+static void sem_wait(int port) {
+  int i;
+  CYG_ASSERT(port != 0, "Invalid port number");
+  
+  for (i=0; i < CYGNUM_NET_TFTPD_MULTITHREADED_PORTS; i++) {
+    if (tftpd_sems[i].port == port) {
+      cyg_semaphore_wait(&tftpd_sems[i].sem);
+      return;
+    }
+  }
+  diag_printf("TFTPD: No semaphore for port %d\n",port);
+}
+
+// Release the semaphore for a given port number.
+static void sem_post(int port) {
+  int i;
+  CYG_ASSERT(port != 0, "Invalid port number");
+  
+  for (i=0; i < CYGNUM_NET_TFTPD_MULTITHREADED_PORTS; i++) {
+    if (tftpd_sems[i].port == port) {
+      cyg_semaphore_post(&tftpd_sems[i].sem);
+      return;
+    }
+  }
+  diag_printf("TFTPD: No semaphore for port %d\n",port);
+}
+#endif
+
 /* Send an error packet to the client */
 static void 
 tftpd_send_error(int s, struct tftphdr * reply, int err,
-		 struct sockaddr_in *from_addr, int from_len)
+		 struct sockaddr *from_addr, int from_len)
 {
     CYG_ASSERT( 0 <= err, "err underflow" );
     CYG_ASSERT( sizeof(errmsg)/sizeof(errmsg[0]) > err, "err overflow" );
@@ -121,7 +211,7 @@ tftpd_send_error(int s, struct tftphdr *
         err = 0; // Do not copy a random string from hyperspace
     strcpy(reply->th_msg, errmsg[err]);
     sendto(s, reply, 4+strlen(reply->th_msg)+1, 0, 
-	   (struct sockaddr *)from_addr, from_len);
+	   from_addr, from_len);
 }
 
 //
@@ -130,7 +220,7 @@ tftpd_send_error(int s, struct tftphdr *
 static void
 tftpd_write_file(struct tftp_server *server,
                  struct tftphdr *hdr, 
-                 struct sockaddr_in *from_addr, int from_len)
+                 struct sockaddr *from_addr, int from_len)
 {
     char data_out[SEGSIZE+sizeof(struct tftphdr)];
     char data_in[SEGSIZE+sizeof(struct tftphdr)];
@@ -141,28 +231,43 @@ tftpd_write_file(struct tftp_server *ser
     struct timeval timeout;
     fd_set fds;
     int total_timeouts = 0;
-    struct sockaddr_in client_addr, local_addr;
+    struct sockaddr client_addr;
+    struct addrinfo hints;
+    struct addrinfo *res;
     int client_len;
+    int error;
+    
+    memset(&hints,0,sizeof(hints));
+    hints.ai_family = from_addr->sa_family;
+    hints.ai_flags = AI_PASSIVE;
 
-    s = socket(AF_INET, SOCK_DGRAM, 0);
+    error = getaddrinfo(NULL,"tftp",&hints, &res);
+    if (0 != error) {
+      diag_printf("TFTPD: can't get a suitable local address: %s\n",
+		  gai_strerror(error));
+      return;
+    }
+    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
     if (s < 0) {
         diag_printf("TFTPD: can't open socket for 'write_file'\n");
+	freeaddrinfo(res);
         return;
     }
-    memset((char *)&local_addr, 0, sizeof(local_addr));
-    local_addr.sin_family = AF_INET;
-    local_addr.sin_len = sizeof(local_addr);
-    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    local_addr.sin_port = htons(INADDR_ANY);
-    if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
+
+    // We want the stack to pick a free local port number
+    set_port(res->ai_addr,0);
+
+    if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
         // Problem setting up my end
         diag_printf("TFTPD: can't bind to reply port for 'write_file'\n");
         close(s);
+	freeaddrinfo(res);
         return;
     }
     if ((fd = (server->ops->open)(hdr->th_stuff, O_WRONLY)) < 0) {
         tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len);
         close(s);
+	freeaddrinfo(res);
         return;
     }
     ok = true;
@@ -176,7 +281,7 @@ tftpd_write_file(struct tftp_server *ser
 #ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
             tftp_server_instrument.ack.send++;
 #endif
-            sendto(s, reply, 4, 0, (struct sockaddr *)from_addr, from_len);
+            sendto(s, reply, 4, 0, from_addr, from_len);
         repeat_select:
             timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
             timeout.tv_usec = 0;
@@ -200,7 +305,7 @@ tftpd_write_file(struct tftp_server *ser
             data_len = sizeof(data_in);
             client_len = sizeof(client_addr);
             if ((data_len = recvfrom(s, data_in, data_len, 0, 
-                      (struct sockaddr *)&client_addr, &client_len)) < 0) {
+                      &client_addr, &client_len)) < 0) {
                 // What happened?  No data here!
 #ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
                 tftp_server_instrument.ack.resend++;
@@ -248,7 +353,7 @@ tftpd_write_file(struct tftp_server *ser
 #endif
                     reply->th_opcode = htons(ACK);
                     reply->th_block = htons(block++); // postincrement
-                    sendto(s, reply, 4, 0, (struct sockaddr *)from_addr, from_len);
+                    sendto(s, reply, 4, 0, from_addr, from_len);
                     break; // out of the retries loop
                 }
                 // Happy!  Break out of the retries loop.
@@ -271,6 +376,7 @@ tftpd_write_file(struct tftp_server *ser
         }
     }
     close(s);
+    freeaddrinfo(res);
     if (!closed) {
       (server->ops->close)(fd);
     }
@@ -282,7 +388,7 @@ tftpd_write_file(struct tftp_server *ser
 static void
 tftpd_read_file(struct tftp_server *server,
                 struct tftphdr *hdr, 
-                struct sockaddr_in *from_addr, int from_len)
+                struct sockaddr *from_addr, int from_len)
 {
     char data_out[SEGSIZE+sizeof(struct tftphdr)];
     char data_in[SEGSIZE+sizeof(struct tftphdr)];
@@ -293,28 +399,44 @@ tftpd_read_file(struct tftp_server *serv
     struct timeval timeout;
     fd_set fds;
     int total_timeouts = 0;
-    struct sockaddr_in client_addr, local_addr;
+    struct sockaddr client_addr;
+    struct addrinfo hints;
+    struct addrinfo *res;
     int client_len;
+    int error;
+
+    memset(&hints,0,sizeof(hints));
+    hints.ai_family = from_addr->sa_family;
+    hints.ai_flags = AI_PASSIVE;
 
-    s = socket(AF_INET, SOCK_DGRAM, 0);
+    error = getaddrinfo(NULL,"tftp",&hints, &res);
+    if (0 != error) {
+      diag_printf("TFTPD: can't get a suitable local address: %s\n",
+		  gai_strerror(error));
+      return;
+    }
+    s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
     if (s < 0) {
-        diag_printf("TFTPD: can't open socket for 'read_file'\n");
+        diag_printf("TFTPD: can't open socket for 'write_file'\n");
+	freeaddrinfo(res);
         return;
     }
-    memset((char *)&local_addr, 0, sizeof(local_addr));
-    local_addr.sin_family = AF_INET;
-    local_addr.sin_len = sizeof(local_addr);
-    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    local_addr.sin_port = htons(INADDR_ANY);
-    if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
+
+    // We want the stack to pick a free local port number
+    set_port(res->ai_addr,0);
+
+    if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
         // Problem setting up my end
-        diag_printf("TFTPD: can't bind to reply port for 'read_file'\n");
+        diag_printf("TFTPD: can't bind to reply port for 'write_file'\n");
         close(s);
+	freeaddrinfo(res);
         return;
     }
-    if ((fd = (server->ops->open)(hdr->th_stuff, O_RDONLY)) < 0) {
+
+    if ((fd = (server->ops->open)(hdr->th_stuff, O_WRONLY)) < 0) {
         tftpd_send_error(s,reply,TFTP_ENOTFOUND,from_addr, from_len);
         close(s);
+	freeaddrinfo(res);
         return;
     }
     block = 0;
@@ -329,7 +451,7 @@ tftpd_read_file(struct tftp_server *serv
             tftp_server_instrument.data.send++;
 #endif
             if (sendto(s, reply, 4+len, 0,
-                       (struct sockaddr *)from_addr, from_len) < 0) {
+                       from_addr, from_len) < 0) {
                 // Something went wrong with the network!
                 ok = false;
                 break;
@@ -356,7 +478,7 @@ tftpd_read_file(struct tftp_server *serv
             data_len = sizeof(data_in);
             client_len = sizeof(client_addr);
             if ((data_len = recvfrom(s, data_in, data_len, 0, 
-                                     (struct sockaddr *)&client_addr,
+                                     &client_addr,
                                      &client_len)) < 0) {
                 // What happened?  Maybe someone lied to us...
 #ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
@@ -403,149 +525,222 @@ tftpd_read_file(struct tftp_server *serv
         }
     }
     close(s);
+    freeaddrinfo(res);
     (server->ops->close)(fd);
 }
 
 //
 // Actual TFTP server
 //
-#define CYGSEM_TFTP_SERVER_MULTITHREADED
-#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED
-static cyg_sem_t tftp_server_sem;
-#endif
 
 static void
 tftpd_server(cyg_addrword_t p)
 {
     struct tftp_server *server = (struct tftp_server *)p;
-    int s;
+    int max_s = 0;
     int data_len, recv_len, from_len;
-    struct sockaddr_in local_addr, from_addr;
-    struct servent *server_info;
+    struct sockaddr from_addr;
     char data[SEGSIZE+sizeof(struct tftphdr)];
     struct tftphdr *hdr = (struct tftphdr *)data;
-
+    struct addrinfo hints;
+    struct addrinfo *ai;
+    fd_set readfds;
+    char name[64];
+    int error;
+    int i;
+#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
+    struct info o = tftp_server_instrument;
+#endif
+    
 #ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
     // Otherwise routine printfs fail the test - interrupts disabled too long.
     diag_printf("TFTPD [%x]: port %d\n", p, server->port);
 #endif
 
-    // Set up port
+    memset(&hints,0,sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_flags = AI_PASSIVE;
+
+    error = getaddrinfo(NULL,"tftp",&hints, &server->res);
+    if (0 != error) {
+      diag_printf("TFTPD [%p] : can't get a local server address to bind to: %s\n",
+		  p, gai_strerror(error));
+      return;
+    }
+ 
+    // If the port is 0, we need to use the default TFTP port. Extrace
+    // the port number from one of the addresses returned by
+    // getaddrinfo.
     if (server->port == 0) {
-        server_info = getservbyname("tftp", "udp");
-        if (server_info == (struct servent *)0) {
-            diag_printf("TFTPD: can't get TFTP service information\n");
-            return;
-        }
-        // Network order in info; host order in server:
-        server->port = ntohs( server_info->s_port );
+      switch (server->res->ai_family) {
+      case AF_INET: 
+	{
+	  struct sockaddr_in *addr = (struct sockaddr_in *)server->res->ai_addr;
+	  server->port = ntohs(addr->sin_port);
+	  break;
+	}
+#ifdef CYGPKG_NET_INET6
+      case AF_INET6:
+	{
+	  struct sockaddr_in6 *addr = (struct sockaddr_in6 *)server->res->ai_addr;
+	  server->port = ntohs(addr->sin6_port);
+	  break;
+	}
+#endif
+      default:
+	break;
+      }
     }
 
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED   
+    sem_alloc(server->port);
     while (true) {
-#ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
-        struct info o = tftp_server_instrument;
-#endif
-        // Create socket
-        s = socket(AF_INET, SOCK_DGRAM, 0);
-        if (s < 0) {
-            diag_printf("TFTPD [%x]: can't open socket\n", p);
-            return;
-        }
-        memset((char *)&local_addr, 0, sizeof(local_addr));
-        local_addr.sin_family = AF_INET;
-        local_addr.sin_len = sizeof(local_addr);
-        local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-        local_addr.sin_port = htons(server->port);
-        if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
-            // Problem setting up my end
-            close(s);
-#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED
-#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
-            diag_printf("TFTPD [%x]: waiting to bind to service port\n", p);
 #endif
-            // Wait until the socket is free...
-            cyg_semaphore_wait( &tftp_server_sem );
-            continue; // try re-opening and rebinding the socket.
-#else
-            diag_printf("TFTPD [%x]: can't bind to service port\n", p);
-            return;
+      // Iterate over the addresses and create a local port to listen for requests 
+      ai = server->res;
+      memset(server->s,0,sizeof(server->s));
+      server->num_s = 0;
+      while (ai && (server->num_s < CYGNUM_NET_MAX_INET_PROTOS)) {
+	server->s[server->num_s] = socket(ai->ai_family, 
+					  ai->ai_socktype, 
+					  ai->ai_protocol);
+	if (server->s[server->num_s] < 0 ) {
+	  diag_printf("TFTPD [%x]: can't open socket\n", p);
+	  freeaddrinfo(server->res);
+	  server->res = NULL;
+	  return;
+	}
+	
+	set_port(ai->ai_addr, server->port);
+	
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED   
+	sem_wait(server->port);
 #endif
-        }
-
-        recv_len = sizeof(data);
-        from_len = sizeof(from_addr);
-        data_len = recvfrom(s, hdr, recv_len, 0,
-                            (struct sockaddr *)&from_addr, &from_len);
-        close(s); // so that other servers can bind to the TFTP socket
-#ifdef CYGSEM_TFTP_SERVER_MULTITHREADED
-        // The socket is free...
-        cyg_semaphore_post( &tftp_server_sem );
-#endif
-
-        if ( data_len < 0) {
-            diag_printf("TFTPD [%x]: can't read request\n", p);
-        } else {
-#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
-            diag_printf("TFTPD [%x]: received %x from %s:%d\n", p,
-                        ntohs(hdr->th_opcode), inet_ntoa(from_addr.sin_addr),
-                        from_addr.sin_port);
+	if (bind(server->s[server->num_s],ai->ai_addr, ai->ai_addrlen) < 0) {
+	  // Problem setting up my end
+	  diag_printf("TFTPD [%x]: can't bind to server port\n",p);
+	  close(server->s[server->num_s]);
+	  server->s[server->num_s] = 0;
+	  ai = ai->ai_next;
+	  continue;
+	}
+	// We need to know the highest socket number for select.
+	if (server->s[server->num_s] > max_s)
+	  max_s = server->s[server->num_s];
+	server->num_s++;
+	ai = ai->ai_next;
+      }
+      
+#ifndef CYGSEM_NET_TFTPD_MULTITHREADED   
+      while (true) {
 #endif
-            switch (ntohs(hdr->th_opcode)) {
-            case WRQ:
-                tftpd_write_file(server, hdr, &from_addr, from_len);
-                break;
-            case RRQ:
-                tftpd_read_file(server, hdr, &from_addr, from_len);
-                break;
-            case ACK:
-            case DATA:
-            case ERROR:
-                // Ignore
-                break;
-            default:
-                diag_printf("TFTPD [%x]: bogus request %x from %s:%d\n", p,
-                            ntohs(hdr->th_opcode),
-                            inet_ntoa(from_addr.sin_addr),
-                            from_addr.sin_port );
-                tftpd_send_error(s,hdr,TFTP_EBADOP,&from_addr,from_len);
-            }
-        }
+	FD_ZERO(&readfds);
+	for (i=0; i < CYGNUM_NET_MAX_INET_PROTOS; i++) {
+	  if (server->s[i]) {
+	    FD_SET(server->s[i],&readfds);
+	  }
+	}
+	error = select(max_s+1,&readfds,NULL,NULL,NULL);
+	if ( -1 == error) {
+	  diag_printf("TFTPD [%x]: error in select\n",p);
+	}
+	for (i=0; i < CYGNUM_NET_MAX_INET_PROTOS; i++) {
+	  if (server->s[i] && FD_ISSET(server->s[i],&readfds)) {
+	    recv_len = sizeof(data);
+	    from_len = sizeof(from_addr);
+	    data_len = recvfrom(server->s[i], hdr, recv_len, 0,
+				&from_addr, &from_len);
+	    if ( data_len < 0) {
+	      diag_printf("TFTPD [%x]: can't read request\n", p);
+	    } else {
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED   
+	      // Close the socket and post on the semaphore some
+	      // another thread can start listening for requests. This
+	      // is not quite right. select could of returned with more than
+	      // one socket with data to read. Here we only deal with one of them 
+	      for (i=0; i < CYGNUM_NET_MAX_INET_PROTOS; i++) {
+		if (server->s[i]) {
+		  close (server->s[i]);
+		  server->s[i] = 0;
+		}
+	      }
+	      sem_post(server->port);
+#endif
+#ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
+	      getnameinfo(&from_addr,sizeof(from_addr), name, sizeof(name),0,0,0);
+	      diag_printf("TFTPD [%x]: received %x from %s\n", p,
+			  ntohs(hdr->th_opcode), name);
+#endif
+	      switch (ntohs(hdr->th_opcode)) {
+	      case WRQ:
+		tftpd_write_file(server, hdr, &from_addr, from_len);
+		break;
+	      case RRQ:
+		tftpd_read_file(server, hdr, &from_addr, from_len);
+		break;
+	      case ACK:
+	      case DATA:
+	      case ERROR:
+		// Ignore
+		break;
+	      default:
+		getnameinfo(&from_addr,sizeof(from_addr), name, sizeof(name),0,0,0);
+		diag_printf("TFTPD [%x]: bogus request %x from %s\n", p,
+			    ntohs(hdr->th_opcode),
+			    name);
+		tftpd_send_error(server->s[i],hdr,TFTP_EBADOP,&from_addr,from_len);
+	      }
+	      
 #ifdef CYGOPT_NET_TFTP_SERVER_INSTRUMENT
-        tftp_server_instrument.total_transactions++;
-
-        o.data.rx        -= tftp_server_instrument.data.rx       ;
-        o.data.rx_repeat -= tftp_server_instrument.data.rx_repeat;
-        o.data.rx_skip   -= tftp_server_instrument.data.rx_skip  ;
-        o.data.send      -= tftp_server_instrument.data.send     ;
-        o.data.resend    -= tftp_server_instrument.data.resend   ;
-
-        o.ack.rx         -= tftp_server_instrument.ack.rx        ;
-        o.ack.rx_repeat  -= tftp_server_instrument.ack.rx_repeat ;
-        o.ack.rx_skip    -= tftp_server_instrument.ack.rx_skip   ;
-        o.ack.send       -= tftp_server_instrument.ack.send      ;
-        o.ack.resend     -= tftp_server_instrument.ack.resend    ;
-
-        o.err_send       -= tftp_server_instrument.err_send      ;
-
+	      tftp_server_instrument.total_transactions++;
+	      
+	      o.data.rx        -= tftp_server_instrument.data.rx       ;
+	      o.data.rx_repeat -= tftp_server_instrument.data.rx_repeat;
+	      o.data.rx_skip   -= tftp_server_instrument.data.rx_skip  ;
+	      o.data.send      -= tftp_server_instrument.data.send     ;
+	      o.data.resend    -= tftp_server_instrument.data.resend   ;
+	      
+	      o.ack.rx         -= tftp_server_instrument.ack.rx        ;
+	      o.ack.rx_repeat  -= tftp_server_instrument.ack.rx_repeat ;
+	      o.ack.rx_skip    -= tftp_server_instrument.ack.rx_skip   ;
+	      o.ack.send       -= tftp_server_instrument.ack.send      ;
+	      o.ack.resend     -= tftp_server_instrument.ack.resend    ;
+	      
+	      o.err_send       -= tftp_server_instrument.err_send      ;
+	      
 #ifndef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
-        if ( o.data.rx        ) diag_printf( "data rx       %4d\n", -o.data.rx        );
-        if ( o.data.rx_repeat ) diag_printf( "data rx_repeat%4d\n", -o.data.rx_repeat );
-        if ( o.data.rx_skip   ) diag_printf( "data rx_skip  %4d\n", -o.data.rx_skip   );
-        if ( o.data.send      ) diag_printf( "data send     %4d\n", -o.data.send      );
-        if ( o.data.resend    ) diag_printf( "data resend   %4d\n", -o.data.resend    );
-
-        if ( o.ack.rx        ) diag_printf( " ack rx       %4d\n", -o.ack.rx        );
-        if ( o.ack.rx_repeat ) diag_printf( " ack rx_repeat%4d\n", -o.ack.rx_repeat );
-        if ( o.ack.rx_skip   ) diag_printf( " ack rx_skip  %4d\n", -o.ack.rx_skip   );
-        if ( o.ack.send      ) diag_printf( " ack send     %4d\n", -o.ack.send      );
-        if ( o.ack.resend    ) diag_printf( " ack resend   %4d\n", -o.ack.resend    );
-
-        if ( o.err_send      ) diag_printf( "*error sends  %4d\n", -o.err_send      );
+	      if ( o.data.rx        ) diag_printf( "data rx       %4d\n", -o.data.rx        );
+	      if ( o.data.rx_repeat ) diag_printf( "data rx_repeat%4d\n", -o.data.rx_repeat );
+	      if ( o.data.rx_skip   ) diag_printf( "data rx_skip  %4d\n", -o.data.rx_skip   );
+	      if ( o.data.send      ) diag_printf( "data send     %4d\n", -o.data.send      );
+	      if ( o.data.resend    ) diag_printf( "data resend   %4d\n", -o.data.resend    );
+	      
+	      if ( o.ack.rx         ) diag_printf( " ack rx       %4d\n", -o.ack.rx         );
+	      if ( o.ack.rx_repeat )  diag_printf( " ack rx_repeat%4d\n", -o.ack.rx_repeat  );
+	      if ( o.ack.rx_skip   )  diag_printf( " ack rx_skip  %4d\n", -o.ack.rx_skip    );
+	      if ( o.ack.send      )  diag_printf( " ack send     %4d\n", -o.ack.send       );
+	      if ( o.ack.resend    )  diag_printf( " ack resend   %4d\n", -o.ack.resend     );
+	      
+	      if ( o.err_send      )  diag_printf( "*error sends  %4d\n", -o.err_send      );
 #endif // CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS
 #endif // CYGOPT_NET_TFTP_SERVER_INSTRUMENT
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED
+	      break;
+#endif
+	    }
+	  }
+	}
+	// The following looks a little strange, but it keeps emacs's
+	// auto indention happy.
+#ifndef CYGSEM_NET_TFTPD_MULTITHREADED   
+      }
+#endif
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED   
     }
+#endif
 }
 
+
 //
 // This function is used to create a new server [thread] which supports
 // the TFTP protocol on the given port.  A server 'id' will be returned
@@ -599,7 +794,14 @@ tftpd_stop(int p)
         cyg_thread_set_priority(server->thread_handle, 0);
         cyg_thread_delay(1);  // Make sure it gets to die...
         if (cyg_thread_delete(server->thread_handle)) {
-            // Success shutting down the thread
+            // Success shutting down the thread. Close all its sockets.
+	    int i;
+	    for (i = 0 ; i < CYGNUM_NET_MAX_INET_PROTOS; i++) {
+	      if (server->s[i]) {
+		close (server->s[i]);
+	      }
+	    }
+	    freeaddrinfo(server->res);
             free(server);  // Give up memory
             return 1;
         }
--- a/packages/net/common/current/tests/addr_test.c
+++ b/packages/net/common/current/tests/addr_test.c
@@ -19,7 +19,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, andrew.lunn@ascom.ch
 // Date:         2002-03-19
 // Purpose:      
 // Description:  
@@ -56,13 +56,13 @@ walk_addrs(struct addrinfo *ai, char *ti
     diag_printf("INFO: %s\n", title);
     while (ai) {
         _inet_ntop(ai->ai_addr, addr_buf, sizeof(addr_buf));
-        diag_printf("INFO: Family: %d, Socket: %d, Addr: %s, Port: %d\n", 
+        diag_printf("INFO: Family: %2d, Socket: %d, Addr: %s, Port: %d\n", 
                     ai->ai_family, ai->ai_socktype, addr_buf, _inet_port(ai->ai_addr));
         ai = ai->ai_next;
     }
 }
 
-int 
+void 
 net_test(CYG_ADDRWORD data)
 {
     int err;
@@ -77,6 +77,7 @@ net_test(CYG_ADDRWORD data)
         pexit("getaddrinfo");
     }
     walk_addrs(addrs, "all passive");
+
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
@@ -86,6 +87,7 @@ net_test(CYG_ADDRWORD data)
         pexit("getaddrinfo");
     }
     walk_addrs(addrs, "all active");
+
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_INET;
     hints.ai_socktype = SOCK_STREAM;
@@ -95,6 +97,27 @@ net_test(CYG_ADDRWORD data)
         pexit("getaddrinfo");
     }
     walk_addrs(addrs, "IPv4 passive");
+
+    bzero(&hints, sizeof(hints));
+    hints.ai_family = PF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_PASSIVE;
+    if ((err = getaddrinfo("192.168.1.2", "7734", &hints, &addrs)) != EAI_NONE) {
+        diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
+        pexit("getaddrinfo");
+    }
+    walk_addrs(addrs, "IPv4 passive 192.168.1.2");
+
+    bzero(&hints, sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_PASSIVE;
+    if ((err = getaddrinfo("192.168.1.2", "7734", &hints, &addrs)) != EAI_NONE) {
+        diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
+        pexit("getaddrinfo");
+    }
+    walk_addrs(addrs, "all passive 192.168.1.2");
+
 #ifdef CYGPKG_NET_INET6
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_INET6;
@@ -105,7 +128,27 @@ net_test(CYG_ADDRWORD data)
         pexit("getaddrinfo");
     }
     walk_addrs(addrs, "IPv6 passive");
+
+    bzero(&hints, sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    if ((err = getaddrinfo(NULL, "7734", &hints, &addrs)) != EAI_NONE) {
+        diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
+        pexit("getaddrinfo");
+    }
+    walk_addrs(addrs, "all passive");
+
+    bzero(&hints, sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+    if ((err = getaddrinfo("fe80::260:97ff:feb0:866e", "7734", &hints, &addrs)) 
+	!= EAI_NONE) {
+        diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
+        pexit("getaddrinfo");
+    }
+    walk_addrs(addrs, "all passive fe80::260:97ff:feb0:866e");
 #endif
+
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_DGRAM;
@@ -115,7 +158,18 @@ net_test(CYG_ADDRWORD data)
         pexit("getaddrinfo");
     }
     walk_addrs(addrs, "all snmp/udp");
+
+    bzero(&hints, sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
+    hints.ai_socktype = 0;
+    hints.ai_flags = AI_PASSIVE;
+    if ((err = getaddrinfo(NULL, "snmp", &hints, &addrs)) != EAI_NONE) {
+        diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
+        pexit("getaddrinfo");
+    }
+    walk_addrs(addrs, "all snmp/*");
     CYG_TEST_PASS_FINISH("Address [library] test OK");
+
 }
 void
 cyg_start(void)
--- a/packages/net/common/current/tests/ping_lo_test.c
+++ b/packages/net/common/current/tests/ping_lo_test.c
@@ -19,7 +19,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas, sorin@netappi.com
-// Contributors: gthomas, sorin@netappi.com
+// Contributors: gthomas, sorin@netappi.com, andrew.lunn@ascom.ch
 // Date:         2000-01-10
 // Purpose:      
 // Description:  
@@ -32,6 +32,10 @@
 // PING test code
 
 #include <network.h>
+#ifdef CYGPKG_NET_INET6
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#endif
 
 #include <cyg/infra/testcase.h>
 
@@ -144,7 +148,7 @@ ping_host(int s, struct sockaddr_in *hos
         icmp->icmp_code = 0;
         icmp->icmp_cksum = 0;
         icmp->icmp_seq = seq;
-        icmp->icmp_id = 0x1234;
+        icmp->icmp_id = UNIQUEID;
         // Set up ping data
         tp = (cyg_tick_count_t *)&icmp->icmp_data;
         *tp++ = cyg_current_time();
@@ -206,17 +210,166 @@ ping_test_loopback( int lo )
     ping_host(s, &host);
 }
 
+#ifdef CYGPKG_NET_INET6
+static int
+show6_icmp(unsigned char *pkt, int len, 
+          const struct sockaddr_in6 *from, const struct sockaddr_in6 *to)
+{
+    cyg_tick_count_t *tp, tv;
+    struct icmp6_hdr *icmp;
+    char fromnamebuf[128];
+    char tonamebuf[128];
+    int error;
+
+    error = getnameinfo((struct sockaddr *)from,sizeof(*from), 
+			fromnamebuf, sizeof(fromnamebuf), 
+			NULL, 0,
+			NI_NUMERICHOST);
+    if (error) {
+      perror ("getnameinfo(from)");
+      return 0;
+    }
+
+    error = getnameinfo((struct sockaddr *)to,sizeof(*to), 
+			tonamebuf, sizeof(tonamebuf), 
+			NULL, 0,
+			NI_NUMERICHOST);
+    if (error) {
+      perror ("getnameinfo(to)");
+      return 0;
+    }
+
+    tv = cyg_current_time();
+    icmp = (struct icmp6_hdr *)pkt;
+    tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
+   
+    if (icmp->icmp6_type != ICMP6_ECHO_REPLY) {
+        return 0;
+    }
+    if (icmp->icmp6_id != UNIQUEID) {
+        diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", 
+                    fromnamebuf, UNIQUEID, icmp->icmp6_id);
+    }
+    diag_printf("%d bytes from %s: ", len, fromnamebuf);
+    diag_printf("icmp_seq=%d", icmp->icmp6_seq);
+    diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
+    return (!memcmp(&from->sin6_addr, &to->sin6_addr,sizeof(from->sin6_addr)));
+}
+
+static void
+ping6_host(int s, const struct sockaddr_in6 *host)
+{
+    struct icmp6_hdr *icmp = (struct icmp6_hdr *)pkt1;
+    int icmp_len = 64;
+    int seq, ok_recv, bogus_recv;
+    cyg_tick_count_t *tp;
+    long *dp;
+    struct sockaddr_in6 from;
+    int i, len, fromlen;
+    char namebuf[128];
+    int error;
+    int echo_responce;
+
+    ok_recv = 0;
+    bogus_recv = 0;
+    error = getnameinfo((struct sockaddr *)host,sizeof(*host), 
+			namebuf, sizeof(namebuf), 
+			NULL, 0,
+			NI_NUMERICHOST);
+    if (error) {
+      perror ("getnameinfo");
+    } else {
+      diag_printf("PING6 server %s\n", namebuf);
+    }
+    for (seq = 0;  seq < NUM_PINGS;  seq++) {
+        // Build ICMP packet
+        icmp->icmp6_type = ICMP6_ECHO_REQUEST;
+        icmp->icmp6_code = 0;
+        icmp->icmp6_cksum = 0;
+        icmp->icmp6_seq = seq;
+        icmp->icmp6_id = UNIQUEID;
+
+        // Set up ping data
+        tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
+        *tp++ = cyg_current_time();
+        dp = (long *)tp;
+        for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
+            *dp++ = i;
+        }
+        // Add checksum
+        icmp->icmp6_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
+        // Send it off
+        if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
+            perror("sendto");
+            continue;
+        }
+        // Wait for a response. We get our own ECHO_REQUEST and the responce
+	echo_responce = 0;
+	while (!echo_responce) {
+	  fromlen = sizeof(from);
+	  len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
+	  if (len < 0) {
+            perror("recvfrom");
+	    echo_responce=1;
+	  } else {
+            if (show6_icmp(pkt2, len, &from, host)) {
+	      ok_recv++;
+	      echo_responce=1;
+	    }
+	  }
+        }
+    }
+    diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);
+}
+
+static void
+ping6_test_loopback( int lo )
+{
+    struct protoent *p;
+    struct timeval tv;
+    struct sockaddr_in6 host;
+    int s;
+
+    if ((p = getprotobyname("ipv6-icmp")) == (struct protoent *)0) {
+        perror("getprotobyname");
+        return;
+    }
+    s = socket(AF_INET6, SOCK_RAW, p->p_proto);
+    if (s < 0) {
+        perror("socket");
+        return;
+    }
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+    // Set up host address
+    host.sin6_family = AF_INET6;
+    host.sin6_len = sizeof(host);
+    host.sin6_addr = in6addr_loopback;
+    host.sin6_port = 0;
+    ping6_host(s, &host);
+    // Now try a bogus host
+    host.sin6_addr.s6_addr[15] = host.sin6_addr.s6_addr[15] + 32;
+    ping6_host(s, &host);
+}
+#endif
+
 void
 net_test(cyg_addrword_t p)
 {
     int i;
     diag_printf("Start PING test\n");
+
     init_all_network_interfaces();
 #if NLOOP > 0
     for ( i = 0; i < NLOOP; i++ )
         ping_test_loopback( i );
     for ( i = 0; i < NLOOP; i++ )
         ping_test_loopback( i );
+#ifdef CYGPKG_NET_INET6
+    for ( i = 0; i < NLOOP; i++ )
+        ping6_test_loopback( i );
+#endif
     CYG_TEST_PASS_FINISH( "Done pinging loopback" );
 #endif
     CYG_TEST_NA( "No loopback devs" );
--- a/packages/net/common/current/tests/ping_test.c
+++ b/packages/net/common/current/tests/ping_test.c
@@ -19,7 +19,7 @@
 //#####DESCRIPTIONBEGIN####
 //
 // Author(s):    gthomas
-// Contributors: gthomas
+// Contributors: gthomas, andrew.lunn@ascom.ch
 // Date:         2000-01-10
 // Purpose:      
 // Description:  
@@ -32,6 +32,10 @@
 // PING test code
 
 #include <network.h>
+#ifdef CYGPKG_NET_INET6
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#endif
 
 #include <pkgconf/system.h>
 #include <pkgconf/net.h>
@@ -215,6 +219,151 @@ ping_host(int s, struct sockaddr_in *hos
     diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);
 }
 
+#ifdef CYGPKG_NET_INET6
+static int
+show6_icmp(unsigned char *pkt, int len, 
+          const struct sockaddr_in6 *from, const struct sockaddr_in6 *to)
+{
+    cyg_tick_count_t *tp, tv;
+    struct icmp6_hdr *icmp;
+    char fromnamebuf[128];
+    char tonamebuf[128];
+    int error;
+
+    error = getnameinfo((struct sockaddr *)from,sizeof(*from), 
+			fromnamebuf, sizeof(fromnamebuf), 
+			NULL, 0,
+			NI_NUMERICHOST);
+    if (error) {
+      perror ("getnameinfo(from)");
+      return 0;
+    }
+
+    error = getnameinfo((struct sockaddr *)to,sizeof(*to), 
+			tonamebuf, sizeof(tonamebuf), 
+			NULL, 0,
+			NI_NUMERICHOST);
+    if (error) {
+      perror ("getnameinfo(to)");
+      return 0;
+    }
+
+    tv = cyg_current_time();
+    icmp = (struct icmp6_hdr *)pkt;
+    tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
+   
+    if (icmp->icmp6_type != ICMP6_ECHO_REPLY) {
+        return 0;
+    }
+    if (icmp->icmp6_id != UNIQUEID) {
+        diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", 
+                    fromnamebuf, UNIQUEID, icmp->icmp6_id);
+    }
+    diag_printf("%d bytes from %s: ", len, fromnamebuf);
+    diag_printf("icmp_seq=%d", icmp->icmp6_seq);
+    diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
+    return (!memcmp(&from->sin6_addr, &to->sin6_addr,sizeof(from->sin6_addr)));
+}
+
+static void
+ping6_host(int s, const struct sockaddr_in6 *host)
+{
+    struct icmp6_hdr *icmp = (struct icmp6_hdr *)pkt1;
+    int icmp_len = 64;
+    int seq, ok_recv, bogus_recv;
+    cyg_tick_count_t *tp;
+    long *dp;
+    struct sockaddr_in6 from;
+    int i, len, fromlen;
+    char namebuf[128];
+    int error;
+    int echo_responce;
+
+    ok_recv = 0;
+    bogus_recv = 0;
+    error = getnameinfo((struct sockaddr *)host,sizeof(*host), 
+			namebuf, sizeof(namebuf), 
+			NULL, 0,
+			NI_NUMERICHOST);
+    if (error) {
+      perror ("getnameinfo");
+    } else {
+      diag_printf("PING6 server %s\n", namebuf);
+    }
+    for (seq = 0;  seq < NUM_PINGS;  seq++) {
+        // Build ICMP packet
+        icmp->icmp6_type = ICMP6_ECHO_REQUEST;
+        icmp->icmp6_code = 0;
+        icmp->icmp6_cksum = 0;
+        icmp->icmp6_seq = seq;
+        icmp->icmp6_id = UNIQUEID;
+
+        // Set up ping data
+        tp = (cyg_tick_count_t *)&icmp->icmp6_data8[4];
+        *tp++ = cyg_current_time();
+        dp = (long *)tp;
+        for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
+            *dp++ = i;
+        }
+        // Add checksum
+        icmp->icmp6_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
+        // Send it off
+        if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, 
+		   sizeof(*host)) < 0) {
+            perror("sendto");
+            continue;
+        }
+        // Wait for a response. We get our own ECHO_REQUEST and the responce
+	echo_responce = 0;
+	while (!echo_responce) {
+	  fromlen = sizeof(from);
+	  len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, 
+			 &fromlen);
+	  if (len < 0) {
+            perror("recvfrom");
+	    echo_responce=1;
+	  } else {
+            if (show6_icmp(pkt2, len, &from, host)) {
+	      ok_recv++;
+	      echo_responce=1;
+	    }
+	  }
+        }
+    }
+    diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, 
+		ok_recv, bogus_recv);
+}
+
+static void
+ping6_test( struct sockaddr_in6 *host)
+{
+    struct protoent *p;
+    struct timeval tv;
+    struct sockaddr_in6 addr;
+    int s;
+
+    if ((p = getprotobyname("ipv6-icmp")) == (struct protoent *)0) {
+        perror("getprotobyname");
+        return;
+    }
+    s = socket(AF_INET6, SOCK_RAW, p->p_proto);
+    if (s < 0) {
+        perror("socket");
+        return;
+    }
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+
+    ping6_host(s, host);
+
+    // Now try a bogus host
+    memcpy(&addr,host,sizeof(addr));
+    addr.sin6_addr.s6_addr[15] = addr.sin6_addr.s6_addr[15] + 32;
+    ping6_host(s, &addr);
+}
+#endif
+
 static void
 ping_test(struct bootp *bp)
 {
@@ -249,6 +398,10 @@ ping_test(struct bootp *bp)
 void
 net_test(cyg_addrword_t p)
 {
+#ifdef CYGPKG_NET_INET6
+    struct sockaddr_in6 ipv6router;
+#endif
+
     diag_printf("Start PING test\n");
     TNR_INIT();
     init_all_network_interfaces();
@@ -262,6 +415,13 @@ net_test(cyg_addrword_t p)
         ping_test(&eth1_bootp_data);
     }
 #endif
+#ifdef CYGPKG_NET_INET6
+    if (cyg_net_get_ipv6_advrouter(&ipv6router)) {
+      ping6_test(&ipv6router);
+    } else {
+      CYG_TEST_FAIL("No router advertisement recieved");
+    }
+#endif
     TNR_PRINT_ACTIVITY();
     CYG_TEST_PASS_FINISH("Ping test OK");
 }
--- a/packages/net/common/current/tests/tftp_client_test.c
+++ b/packages/net/common/current/tests/tftp_client_test.c
@@ -62,6 +62,10 @@ tftp_test(struct bootp *bp)
 {
     int res, err, len;
     struct sockaddr_in host;
+#ifdef CYGPKG_NET_INET6
+    struct sockaddr_in6 ipv6router;
+    char server[64];
+#endif
 
     memset((char *)&host, 0, sizeof(host));
     host.sin_len = sizeof(host);
@@ -75,10 +79,35 @@ tftp_test(struct bootp *bp)
         diag_dump_buf(buf, min(res,1024));
     }
     len = res;
-    diag_printf("Trying tftp_put %d %16s, length %d\n",
+    diag_printf("Trying tftp_put %s %16s, length %d\n",
                 PUTFILE, inet_ntoa(host.sin_addr), len);
     res = tftp_put( PUTFILE, &host, buf, len, TFTP_OCTET, &err);
     diag_printf("put - res: %d\n", res);
+
+#ifdef CYGPKG_NET_INET6
+    // Wait for router solicit process to happen.
+    if (!cyg_net_get_ipv6_advrouter(&ipv6router)) {
+      diag_printf("No router advertisement recieved\n");
+      cyg_test_exit();
+    }
+
+    getnameinfo((struct sockaddr *)&ipv6router,sizeof(ipv6router),
+		server, sizeof(server), 0 ,0 ,NI_NUMERICHOST);
+
+    diag_printf("Trying tftp_get %s using IPv6 from %16s...\n", GETFILE, server);
+
+    res = tftp_client_get( GETFILE, server, 0, buf, sizeof(buf), 
+			   TFTP_OCTET, &err);
+    diag_printf("IPv6 res = %d, err = %d\n", res, err);
+    if (res > 0) {
+        diag_dump_buf(buf, min(res,1024));
+    }
+    len = res;
+    diag_printf("Trying tftp_put %s using IPv6 to %16s, length %d\n",
+                PUTFILE, server, len);
+    res = tftp_client_put( PUTFILE, server, 0, buf, len, TFTP_OCTET, &err);
+    diag_printf("put - res: %d\n", res);
+#endif
 }
 
 void
@@ -115,3 +144,5 @@ cyg_start(void)
     cyg_thread_resume(thread_handle);  // Start it
     cyg_scheduler_start();
 }
+
+
--- a/packages/net/common/current/tests/tftp_server_test.c
+++ b/packages/net/common/current/tests/tftp_server_test.c
@@ -81,22 +81,63 @@ pexit(char *s)
 static void
 tftp_test(struct bootp *bp)
 {
-    int server_id, res;
+    int res;
+    int server1_id = 0;
+    int server2_id = 0;
+    int server3_id = 0;
+
     extern struct tftpd_fileops dummy_fileops;
-    server_id = tftpd_start(0, &dummy_fileops);
-    if (server_id > 0) {
-        diag_printf("TFTP server created - id: %x\n", server_id);
-        // Only let the server run for 5 minutes
-        cyg_thread_delay(2*100); // let the tftpd start up first
-        TNR_ON();
-        cyg_thread_delay(5*60*100);
-        TNR_OFF();
-        res = tftpd_stop(server_id);
-        diag_printf("TFTP server stopped - res: %d\n", res);
+
+    server1_id = tftpd_start(0, &dummy_fileops);
+    if (server1_id > 0) {
+      diag_printf("TFTP server created - id: %x\n", server1_id);
+    } else {
+      diag_printf("Couldn't create first server!\n");
+    }
+
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED
+    server2_id = tftpd_start(0, &dummy_fileops);
+    if (server2_id > 0) {
+      diag_printf("Second TFTP server created - id: %x\n", server2_id);
+    } else {
+      diag_printf("Couldn't create a second server!\n");
+    }
+#if CYGNUM_NET_TFTPD_MULTITHREADED_PORTS > 1
+    server3_id = tftpd_start(1025, &dummy_fileops);
+    if (server3_id > 0) {
+      diag_printf("Third TFTP server created - id: %x\n", server3_id);
     } else {
-        diag_printf("Couldn't create a server!\n");
+      diag_printf("Couldn't create a third server!\n");
+    }
+#endif //CYGNUM_NET_TFTPD_MULTITHREADED_PORTS > 1
+#else  //CYGSEM_NET_TFTPD_MULTITHREADED
+    server2_id = tftpd_start(1025, &dummy_fileops);
+    if (server2_id > 0) {
+      diag_printf("Second TFTP server created - id: %x\n", server2_id);
+    } else {
+      diag_printf("Couldn't create a second server!\n");
     }
-}
+#endif //!CYGSEM_NET_TFTPD_MULTITHREADED
+    
+    // Only let the server run for 5 minutes
+    cyg_thread_delay(2*100); // let the tftpd start up first
+    TNR_ON();
+    cyg_thread_delay(5*60*100);
+    TNR_OFF();
+    
+    if (server1_id > 0) {
+      res = tftpd_stop(server1_id);
+      diag_printf("TFTP server - id: %x stopped - res: %d\n", server1_id, res);
+    }
+    if (server2_id > 0) {
+      res = tftpd_stop(server2_id);
+      diag_printf("TFTP server - id: %x stopped - res: %d\n", server2_id, res);
+    }
+    if (server3_id > 0) {
+      res = tftpd_stop(server2_id);
+      diag_printf("TFTP server - id: %x stopped - res: %d\n", server2_id, res);
+    }
+} 
 
 void
 net_test(cyg_addrword_t param)