changeset 1007:16d247bb9c70

* src/ifaddrs.c (getifaddrs): Fill in flags, netmask and broadcast addresses, for both IPv4 and IPv6 and enabled. * src/ipv6_routing_thread.c (ipv6_start_routing_thread): Only start the thread once. * src/getaddrinfo.c (getaddrinfo): Correctly return TCP when it is! * tests/addr_test.c (net_test): Added a test which uses protocol TCP * src/tftp_client.c (tftp_get): If we timeout on the first block, try other addresses for the server if we have any. * src/network_support.c (init_all_network_interfaces): After router solicitation has given us an address, wait a couple of seconds for duplicate address detection to do its work. While DAD is active, we cannot use the new address. * src/tftp_client.c (tftp_client_put): Fixed compiler warning. * src/getaddrinfo.c (getnameinfo): Fixed some endian issues with port numbers and a typo. Added an interface to the DNS client for reverse lookups. * tests/addr_test.c (net_test): Added tests for getnameinfo. Fixed some memory leaks. * src/getaddrinfo.c (getaddrinfo): Virtually a re-write to interface to the DNS client. * include/net/netdb.h: const correctness.
author asl
date Mon, 12 May 2003 10:13:37 +0000
parents 766a12db7c5b
children 4ca8a5f30c03
files packages/net/common/current/ChangeLog packages/net/common/current/include/net/netdb.h packages/net/common/current/src/getaddrinfo.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/ga_server_test.c
diffstat 10 files changed, 541 insertions(+), 181 deletions(-) [+]
line wrap: on
line diff
--- a/packages/net/common/current/ChangeLog
+++ b/packages/net/common/current/ChangeLog
@@ -1,8 +1,47 @@
+2003-05-09  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/ifaddrs.c (getifaddrs): Fill in flags, netmask and broadcast
+	addresses, for both IPv4 and IPv6 and enabled.
+	* src/ipv6_routing_thread.c (ipv6_start_routing_thread): Only
+	start the thread once. 
+
+2003-04-26  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/getaddrinfo.c (getaddrinfo): Correctly return TCP when it is!
+	* tests/addr_test.c (net_test): Added a test which uses protocol TCP
+	* src/tftp_client.c (tftp_get): If we timeout on the first block,
+	try other addresses for the server if we have any.
+	* src/network_support.c (init_all_network_interfaces): After
+	router solicitation has given us an address, wait a couple of
+	seconds for duplicate address detection to do its work. While DAD
+	is active, we cannot use the new address.
+
 2003-04-24  Jonathan Larmour  <jifl@eCosCentric.com>
 
 	* doc/tcpip.sgml: Fix some docbook errors only reported by certain
 	Jade versions.
 
+2003-04-24  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/tftp_client.c (tftp_client_put): Fixed compiler warning. 
+
+2003-04-21  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/getaddrinfo.c (getnameinfo): Fixed some endian issues with
+	port numbers and a typo. Added an interface to the DNS client for 
+	reverse lookups.
+	* tests/addr_test.c (net_test): Added tests for getnameinfo. Fixed
+	some memory leaks.
+
+2003-04-20  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/getaddrinfo.c (getaddrinfo): Virtually a re-write to
+	interface to the DNS client.
+
+2003-04-14  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* include/net/netdb.h: const correctness. 
+
 2003-04-12  Andrew Lunn  <andrew.lunn@ascom.ch>
 
 	* src/network_support.c (init_loopback_interface): Close the
--- a/packages/net/common/current/include/net/netdb.h
+++ b/packages/net/common/current/include/net/netdb.h
@@ -133,8 +133,8 @@ int getnameinfo (const struct sockaddr *
 // Miscellaneous address manipulation functions
 #include <netinet/in.h>
 char     *inet_ntoa(struct in_addr);
-char     *inet_ntop(int af, char *src, char *dst, size_t len);
-int      inet_pton(int af, char *src, char *dst);
+char     *inet_ntop(int af, const char *src, char *dst, size_t len);
+int      inet_pton(int af, const char *src, char *dst);
 char     *_inet_ntop(struct sockaddr *sa, char *dst, size_t len);
 u_int16_t _inet_port(struct sockaddr *sa);
 
--- a/packages/net/common/current/src/getaddrinfo.c
+++ b/packages/net/common/current/src/getaddrinfo.c
@@ -38,87 +38,232 @@
 #include <errno.h>
 #include <cyg/infra/cyg_ass.h>
 
+#include <pkgconf/system.h>
+#ifdef CYGPKG_NS_DNS
+#include <pkgconf/ns_dns.h>
+#include <cyg/ns/dns/dns.h>
+#endif
+
 extern int  sprintf(char *, const char *, ...);
 extern long strtol(const char *, char **, int);
 extern void *malloc(size_t);
 extern void *calloc(int, size_t);
 extern void free(void *);
 
-// This routine is the real meat of the host->address translation
+// Allocate a new addrinfo structure and if passed an existing
+// addrinfo copy all the port, protocol info into the new structure
+// and then link the new onto the old.
+
+struct addrinfo * alloc_addrinfo(struct addrinfo * ai) {
+    
+    struct addrinfo * nai;
+    struct sockaddr * sa;
+
+    nai = (struct addrinfo *)malloc(sizeof(struct addrinfo));
+    if (!nai) {
+        return NULL;
+    }
+    sa = (struct sockaddr *) malloc(sizeof(struct sockaddr));
+    if (!sa) {
+        free (nai);
+        return NULL;
+    }
+    memset(sa,0,sizeof(*sa));
+
+    if (ai) {
+        memcpy(nai,ai,sizeof(struct addrinfo));
+        ai->ai_next = nai;
+    } else {
+        memset(nai,0,sizeof(*nai));
+    }
+    nai->ai_addr = sa;
+    nai->ai_addrlen = sizeof(*sa);
+
+    return nai;
+}
+
+// getaddrinfo has not been passed a hostname. So it should use the
+// loopback or the any address.
 static int
-_getaddr(struct addrinfo *ai, const char *node, 
-         const struct addrinfo *hints, int family, int port)
-{
-    struct hostent *_hent;
+no_node_addr(struct addrinfo *ai, const struct addrinfo *hints, int port) {
 
-    switch (family) {
-    case AF_INET:
-    {
-        struct sockaddr_in *sa;
-        sa = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
-        memset(sa, 0, sizeof(*sa));
-        ai->ai_addr = (struct sockaddr *)sa;
-        ai->ai_addrlen = sizeof(*sa);
-        if (ai->ai_addr == (struct sockaddr *)NULL) {
-            return EAI_MEMORY;
+    switch (hints->ai_family) {
+    case AF_INET: {
+        struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+        if (hints->ai_flags & AI_PASSIVE) {
+            sa->sin_addr.s_addr = htonl(INADDR_ANY);
+        } else {
+            sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
         }
+        sa->sin_len = sizeof(*sa);
+        sa->sin_port = htons(port);
         sa->sin_family = AF_INET;
+        ai->ai_family = AF_INET;
+        break;
+    }
+#ifdef CYGPKG_NET_INET6
+    case AF_INET6: {
+        struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
+        if (hints->ai_flags & AI_PASSIVE) {
+            memcpy(&sa->sin6_addr, &in6addr_any, sizeof(sa->sin6_addr));
+        } else {
+            memcpy(&sa->sin6_addr, &in6addr_loopback, sizeof(sa->sin6_addr));
+        }
+        sa->sin6_len = sizeof(*sa);
+        sa->sin6_port = htons(port);
+        sa->sin6_family = AF_INET6;
+        ai->ai_family = AF_INET6;
+        break;
+    }
+#endif
+    case PF_UNSPEC: {
+        struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+        if (hints->ai_flags & AI_PASSIVE) {
+            sa->sin_addr.s_addr = htonl(INADDR_ANY);
+        } else {
+            sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+        }
         sa->sin_len = sizeof(*sa);
         sa->sin_port = htons(port);
-        if (node == (char *)NULL) {
+        sa->sin_family = AF_INET;
+        ai->ai_family = AF_INET;
+#ifdef CYGPKG_NET_INET6 
+        {
+            struct sockaddr_in6 *sa6;
+            ai=alloc_addrinfo(ai);
+            if (ai == NULL) {
+                return EAI_MEMORY;
+            }
+            sa6 = (struct sockaddr_in6 *) ai->ai_addr;
             if (hints->ai_flags & AI_PASSIVE) {
-                sa->sin_addr.s_addr = htonl(INADDR_ANY);
+                memcpy(&sa6->sin6_addr, &in6addr_any, sizeof(sa6->sin6_addr));
             } else {
-#ifdef CYGPKG_NET_OPENBSD_STACK
-                sa->sin_addr.s_addr = INADDR_LOOPBACK;
-#else
-                sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-#endif
+                memcpy(&sa6->sin6_addr, &in6addr_loopback, sizeof(sa6->sin6_addr));
             }
-        } else {
-            _hent = gethostbyname(node);
-            if (_hent) {
-                memcpy(&sa->sin_addr.s_addr, _hent->h_addr, sizeof(struct in_addr));
-            } else {
-                // For now, only numeric "presentation" addresses supported
-                if (!inet_pton(AF_INET, (char *)node, (char *)&sa->sin_addr.s_addr)) {
-                    return EAI_FAIL;  // Couldn't resolve name
-                }
+            sa6->sin6_len = sizeof(*sa);
+            sa6->sin6_port = htons(port);
+            sa6->sin6_family = AF_INET6;
+            ai->ai_family = AF_INET6;
+        }
+#endif
+        break;
+    }
+    }
+   return EAI_NONE;
+}
+
+
+// We have been asked to convert only numeric addresses so as to not
+// need a DNS server query.
+static int
+numeric_node_addr(struct addrinfo *ai, const char *node, 
+               const struct addrinfo *hints, int port) {
+    
+    switch (hints->ai_family) {
+    case AF_INET: {
+        struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+        if (!inet_pton(AF_INET, node, (void *)&sa->sin_addr.s_addr)) {
+            return EAI_FAIL;
+        }
+        sa->sin_port = htons(port);
+        sa->sin_family = AF_INET;
+        sa->sin_len = sizeof(*sa);
+        ai->ai_family = AF_INET;
+        break;
+    }
+#ifdef CYGPKG_NET_INET6
+    case AF_INET6: {
+        struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
+        if (!inet_pton(AF_INET6, node, (void *)&sa->sin6_addr.s6_addr)) {
+            return EAI_FAIL;
+        }
+        sa->sin6_port = htons(port);
+        sa->sin6_family = AF_INET6;
+        sa->sin6_len = sizeof(*sa);
+        ai->ai_family = AF_INET6;
+        break;
+    }
+#endif
+    case PF_UNSPEC: {
+        struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+        sa->sin_len = sizeof(*sa);
+        sa->sin_port = htons(port);
+        sa->sin_family = AF_INET;
+        ai->ai_family = AF_INET;
+        if (inet_pton(AF_INET, node, (void *)&sa->sin_addr.s_addr)) {
+          return EAI_NONE;
+        }
+#ifdef CYGPKG_NET_INET6
+        {
+            struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
+            sa->sin6_len = sizeof(*sa);
+            sa->sin6_port = htons(port);
+            sa->sin6_family = AF_INET6;
+            ai->ai_family = AF_INET6;
+            if (inet_pton(AF_INET6, node, (void *)&sa->sin6_addr.s6_addr)) {
+                return EAI_NONE;
             }
         }
+#endif
+        return EAI_FAIL;
+        break;
+    }
+    }
+    return EAI_NONE;
+}
+
+// We have a host name. Use the DNS client to perform a lookup. If the
+// DNS client is not part of the configuration try using the numeric
+// convertion.
+static int
+with_node_addr(struct addrinfo *ai, const char *node, 
+               const struct addrinfo *hints, int port) {
+    
+#ifdef CYGPKG_NS_DNS
+    struct sockaddr addrs[CYGNUM_NS_DNS_GETADDRINFO_ADDRESSES];
+    int nresults;
+    int i;
+    char ** canon = NULL;
+    
+    if (hints->ai_flags & AI_CANONNAME) {
+        canon = &ai->ai_canonname;
+    }
+    nresults = cyg_dns_getaddrinfo(node, 
+                                   addrs, CYGNUM_NS_DNS_GETADDRINFO_ADDRESSES, 
+                                   hints->ai_family, canon);
+    if (nresults < 0) {
+        return -nresults;
+    }
+    
+    for (i=0; i < nresults; i++) {
+        if (i != 0) {
+            ai = alloc_addrinfo(ai);
+            if (ai == NULL) {
+                return EAI_MEMORY;
+            }
+        }
+        memcpy(ai->ai_addr, &addrs[i], sizeof(addrs[i]));        
+        ai->ai_family = addrs[i].sa_family;
+        ai->ai_addrlen = addrs[i].sa_len;
+        switch (ai->ai_family) {
+        case AF_INET: {
+            struct sockaddr_in *sa = (struct sockaddr_in *) ai->ai_addr;
+            sa->sin_port = htons(port);
+            break;
+        }
+#ifdef CYGPKG_NET_INET6
+        case AF_INET6: {
+            struct sockaddr_in6 *sa = (struct sockaddr_in6 *) ai->ai_addr;
+            sa->sin6_port = htons(port);
+            break;
+        }
+#endif
+        }
     }
-    break;
-#ifdef CYGPKG_NET_INET6
-    case AF_INET6:
-    {
-        struct sockaddr_in6 *sa;
-        sa = (struct sockaddr_in6 *)malloc(sizeof(struct sockaddr_in6));
-        memset(sa, 0, sizeof(*sa));
-        ai->ai_addr = (struct sockaddr *)sa;
-        ai->ai_addrlen = sizeof(*sa);
-        if (ai->ai_addr == (struct sockaddr *)NULL) {
-            return EAI_MEMORY;
-        }
-        sa->sin6_family = AF_INET6;
-        sa->sin6_len = sizeof(*sa);
-        sa->sin6_port = htons(port);
-        if (node == (char *)NULL) {
-            if (hints->ai_flags & AI_PASSIVE) {
-                sa->sin6_addr = in6addr_any;
-            } else {
-                sa->sin6_addr = in6addr_loopback;
-            }
-        } else {
-            // For now, only numeric "presentation" addresses supported
-            if (!inet_pton(AF_INET6, (char *)node, (char *)&sa->sin6_addr)) {
-                return EAI_FAIL;  // Couldn't resolve name
-            }
-        }
-    }
-    break;
+    return EAI_NONE;
+#else
+    return (numeric_node_addr(ai, node, hints, hints->ai_family, port));
 #endif
-    }
-    return EAI_NONE;
 }
 
 int   
@@ -128,15 +273,12 @@ 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 err;
-    int used = 0;
-    
+    int used;
+
     if (hints == (struct addrinfo *)NULL) {
         dflt_hints.ai_flags = 0;  // No special flags
         dflt_hints.ai_family = PF_UNSPEC;
@@ -151,16 +293,16 @@ getaddrinfo(const char *nodename, const 
     switch (hints->ai_family) {
     case PF_UNSPEC:
     case PF_INET:
-      break;
+        break;
 #ifdef CYGPKG_NET_INET6
     case PF_INET6:
-      break;
+        break;
 #endif
     default:
         return EAI_FAMILY;
     }
     // Allocate the first/primary result
-    *res = ai = (struct addrinfo *)calloc(1, sizeof(struct addrinfo));
+    *res = ai = alloc_addrinfo(NULL);
     if (ai == (struct addrinfo *)NULL) {
         return EAI_MEMORY;
     }
@@ -168,6 +310,9 @@ getaddrinfo(const char *nodename, const 
     if (hints->ai_protocol != 0) {
         proto = getprotobynumber(hints->ai_protocol);
     }
+    
+    // Note: this does not handle the case where a given service can be
+    // handled via multiple protocols, e.g. http/tcp & http/udp
     if (servname != (char *)NULL) {
         switch (hints->ai_socktype) {
         case 0:
@@ -185,7 +330,7 @@ getaddrinfo(const char *nodename, const 
         }
         // See if this is just a port #
         if (((port = strtol(servname, &endptr, 0)) >= 0) &&
-	    (endptr > servname)) {
+            (endptr > servname)) {
             ai->ai_socktype = hints->ai_socktype;
             if (hints->ai_socktype == 0) {
                 // Need to have complete binding type/port
@@ -194,11 +339,12 @@ getaddrinfo(const char *nodename, const 
             }
         } else {
             struct servent *serv = (struct servent *)NULL;
-
+            
             serv = getservbyname(servname, protoname);
             if (serv == (struct servent *)NULL) {
                 if (hints->ai_socktype == 0) {
                     protoname = "udp";
+                    ai->ai_socktype = SOCK_DGRAM;    
                     serv = getservbyname(servname, protoname);
                 }
             }
@@ -207,7 +353,6 @@ getaddrinfo(const char *nodename, const 
                 return EAI_SERVICE;
             }
             port = ntohs(serv->s_port);  
-            ai->ai_socktype = SOCK_DGRAM;    
         }
         proto = getprotobyname(protoname);
         if (hints->ai_protocol && (hints->ai_protocol != proto->p_proto)) {
@@ -216,81 +361,59 @@ getaddrinfo(const char *nodename, const 
         }
         ai->ai_protocol = proto->p_proto;
     }
-    // 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
-    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)) {
+    
+    if (nodename) {
+        if (hints->ai_flags & AI_NUMERICHOST) {
+            err = numeric_node_addr(ai, nodename, hints, port);
+        } else {
+            err = with_node_addr(ai, nodename, hints, port );
+        }
+    } else {
+        err = no_node_addr(ai, hints, port);
+    }
+    
+    if (err != EAI_NONE) {
         freeaddrinfo(ai);
         return err;
-      }
-      if (err == EAI_NONE) {
-	ai->ai_family = AF_INET;
-	used = 1;
-      }
+    }
+    if (err == EAI_NONE) {
+        ai->ai_family = AF_INET;
+        used = 1;
     }
-#ifdef CYGPKG_NET_INET6
-    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;
-        }
-        ai->ai_next = nai;
-        nai->ai_socktype = ai->ai_socktype;
-        nai->ai_protocol = ai->ai_protocol;
-      } 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";
-    }
-    if (hints->ai_flags & AI_CANONNAME) {
-        // Hack - until host name handling is more complete
-        ai = *res;  // Canonical name is only in primary record
-        ai->ai_canonname = malloc(strlen(nodename)+1);
+    
+    if ((hints->ai_flags & AI_CANONNAME) && !nodename) {
+        ai->ai_canonname = malloc(strlen("localhost")+1);
         if (ai->ai_canonname) {
-            strcpy(ai->ai_canonname, nodename);
+            strcpy(ai->ai_canonname, "localhost");
+        } else {
+            freeaddrinfo(ai);
+            return EAI_MEMORY;
         }
     }
-    if (hints->ai_flags & AI_PASSIVE) {
-        // Incomplete addressing - used for bind/listen
-    } else {
-        // Complete addressing - used for connect/send/...
+    
+    /* The DNS code may have filled in the official address. If not
+       and we have been asked for it, return an error */
+    if ((hints->ai_flags & AI_CANONNAME) & !ai->ai_canonname) {
+        freeaddrinfo(ai);
+        return EAI_FAIL;
     }
     return EAI_NONE;  // No errors
 }
 
+// The canonname will probably point to the same memory in each
+// addrinfo in the linked list. Don't free it multiple times.
 void  
 freeaddrinfo(struct addrinfo *ai)
 {
     struct addrinfo *next = ai;
+    char * last_canonname = NULL;
 
     while ((ai = next) != (struct addrinfo *)NULL) {
-        if (ai->ai_canonname) free(ai->ai_canonname);
+        if ((ai->ai_canonname) && 
+            (ai->ai_canonname != last_canonname)) { 
+            free(ai->ai_canonname);
+            last_canonname = ai->ai_canonname;
+        }
         if (ai->ai_addr) free(ai->ai_addr);
         next = ai->ai_next;
         free(ai);
@@ -342,6 +465,8 @@ getnameinfo (const struct sockaddr *sa, 
     int port;
     char *s;
     struct servent *se;
+    int error;
+    int numeric = (flags & NI_NUMERICHOST);
 
     if ((flags & ~NI_MASK) != 0) {
         return EAI_BADFLAGS;
@@ -352,11 +477,31 @@ getnameinfo (const struct sockaddr *sa, 
     case PF_INET6:
 #endif
         if (host != (char *)NULL) {
-            s = _inet_ntop((struct sockaddr *)sa, host, hostlen);
-            if (!s) {
-                return EAI_FAIL;
+            if ( !numeric) {
+                error = EAI_NONAME;
+#ifdef CYGPKG_NS_DNS
+                error = -cyg_dns_getnameinfo(sa, host,hostlen);
+#endif
+                if ((error == EAI_NONAME) && (flags & NI_NAMEREQD)) {
+                    return EAI_NONAME;
+                }
+                // If lookup failed, try it as numeric address
+                numeric = !(error == EAI_NONE);
+            }
+            if (numeric) {
+                s = _inet_ntop((struct sockaddr *)sa, host, hostlen);
+                if (!s) {
+                    return EAI_FAIL;
+                }
+            }
+            if (!numeric && flags & NI_NOFQDN) {
+                s = index(host, '.');
+                if (s) {
+                    *s = '\0';
+                }
             }
         }
+    
         if (serv != (char *)NULL) {
             port = _inet_port((struct sockaddr *)sa);
             if (!port) {
@@ -365,16 +510,16 @@ getnameinfo (const struct sockaddr *sa, 
             se = (struct servent *)NULL;
             if ((flags & NI_NUMERICSERV) == 0) {
                 if ((flags & NI_DGRAM) == 0) {
-                    se = getservbyport(port, "tcp");
+                    se = getservbyport(htons(port), "tcp");
                 }
                 if (se == (struct servent *)NULL) {
-                    se = getservbyport(port, "ucp");
+                    se = getservbyport(htons(port), "udp");
                 }
             }
             if (se != (struct servent *)NULL) {
-                sprintf(serv, "%s/%s", se->s_name, se->s_proto);
+                diag_snprintf(serv,servlen, "%s/%s", se->s_name, se->s_proto);
             } else {
-                sprintf(serv, "%d", port);
+                diag_snprintf(serv,servlen, "%d", port);
             }
         }
         break;
--- a/packages/net/common/current/src/ifaddrs.c
+++ b/packages/net/common/current/src/ifaddrs.c
@@ -66,10 +66,15 @@
 #include <sys/socket.h>
 #include <net/if.h>
 #include <net/if_dl.h>
+#ifndef CYGPKG_NET_OPENBSD_STACK
+#include <net/if_var.h>
+#endif
 #include <errno.h>
 #include <netinet/in.h>
 #include <net/netdb.h>
 #include <ifaddrs.h>
+#include <netinet/in_var.h>
+
 
 #if !defined(AF_LINK)
 #define	SA_LEN(sa)	sizeof(struct sockaddr)
@@ -101,8 +106,13 @@ getifaddrs(struct ifaddrs **pif)
     int ncnt = 0;  // Length of interface names
     char buf[1024];
     int i, sock;
+#ifdef CYGPKG_NET_INET6
+    int sock6;
+    struct in6_ifreq ifrq6;
+#endif
     struct ifconf ifc;
     struct ifreq *ifr, *lifr;
+    struct ifreq ifrq;
     char *data, *names;
     struct ifaddrs *ifa, *ift;
 
@@ -112,9 +122,11 @@ getifaddrs(struct ifaddrs **pif)
     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
         return (-1);
     i =  ioctl(sock, SIOCGIFCONF, (char *)&ifc);
-    close(sock);
-    if (i < 0)
+
+    if (i < 0) {
+        close(sock); 
         return (-1);
+    }
 
     ifr = ifc.ifc_req;
     lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
@@ -124,7 +136,7 @@ getifaddrs(struct ifaddrs **pif)
 
         sa = &ifr->ifr_addr;
         ++icnt;
-        dcnt += SA_RLEN(sa);
+        dcnt += SA_RLEN(sa) * 3;  /* addr, mask, brdcst */
         ncnt += sizeof(ifr->ifr_name) + 1;
 		
         if (SA_LEN(sa) < sizeof(*sa))
@@ -137,11 +149,13 @@ getifaddrs(struct ifaddrs **pif)
         // Nothing found
         *pif = NULL;
         free(buf);
+        close(sock);
         return (0);
     }
     data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
     if (data == NULL) {
         free(buf);
+        close(sock);
         return(-1);
     }
 
@@ -155,8 +169,15 @@ getifaddrs(struct ifaddrs **pif)
     ifr = ifc.ifc_req;
     lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len];
 
+#ifdef CYGPKG_NET_INET6
+    if ((sock6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
+      close(sock);
+      return (-1);
+    }
+#endif
+
     while (ifr < lifr) {
-        struct sockaddr *sa;
+       struct sockaddr * sa;
 
         ift->ifa_name = names;
         names[sizeof(ifr->ifr_name)] = 0;
@@ -167,7 +188,46 @@ getifaddrs(struct ifaddrs **pif)
         sa = &ifr->ifr_addr;
         memcpy(data, sa, SA_LEN(sa));
         data += SA_RLEN(sa);
-		
+
+        if ((sa->sa_family == AF_INET) || (sa->sa_family == AF_INET6)) {
+          struct sockaddr *sa_netmask;
+          struct sockaddr *sa_broadcast;
+
+          memset(&ifrq,0,sizeof(ifrq));
+          strcpy(ifrq.ifr_name,ifr->ifr_name);
+          ioctl( sock, SIOCGIFFLAGS, &ifrq );
+
+          ift->ifa_flags = ifrq.ifr_flags;
+
+          memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
+          if (sa->sa_family == AF_INET) {
+            ioctl(sock, SIOCGIFNETMASK, &ifrq); 
+            sa_netmask = &ifrq.ifr_addr;
+          }
+#ifdef CYGPKG_NET_INET6
+          if (sa->sa_family == AF_INET6) {
+            memset(&ifrq6,0,sizeof(ifrq));
+            strcpy(ifrq6.ifr_name,ifr->ifr_name);
+            memcpy(&ifrq6.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
+          
+            ioctl(sock6, SIOCGIFNETMASK_IN6, &ifrq6);
+            sa_netmask = (struct sockaddr *)&ifrq6.ifr_addr;
+          }
+#endif
+          ift->ifa_netmask = (struct sockaddr *)data;
+          memcpy(data, sa_netmask, SA_LEN(sa_netmask));
+          data += SA_RLEN(sa_netmask);
+
+          memcpy(&ifrq.ifr_addr, ift->ifa_addr,sizeof(struct sockaddr));
+          if (sa->sa_family == AF_INET) {
+            if (ioctl(sock, SIOCGIFBRDADDR, &ifrq) == 0) {
+              sa_broadcast = &ifrq.ifr_addr;
+              ift->ifa_broadaddr = (struct sockaddr *)data;
+              memcpy(data, sa_broadcast, SA_LEN(sa_broadcast));
+              data += SA_RLEN(sa_broadcast);
+            }
+          }
+        }
         if (SA_LEN(sa) < sizeof(*sa))
             ifr = (struct ifreq *)(((char *)sa) + sizeof(*sa));
         else
@@ -182,6 +242,10 @@ getifaddrs(struct ifaddrs **pif)
         *pif = NULL;
         free(ifa);
     }
+#ifdef CYGPKG_NET_INET6
+    close(sock6);
+#endif
+    close(sock);
     return (0);
 }
 
@@ -205,7 +269,8 @@ void
     ifp = iflist;
     while (ifp != (struct ifaddrs *)NULL) {
         if (ifp->ifa_addr->sa_family != AF_LINK) {
-            getnameinfo (ifp->ifa_addr, ifp->ifa_addr->sa_len, addr, sizeof(addr), 0, 0, 0);
+            getnameinfo (ifp->ifa_addr, ifp->ifa_addr->sa_len, addr, 
+                         sizeof(addr), 0, 0, NI_NUMERICHOST);
             diag_printf("%p - %s - %s\n", ifp, ifp->ifa_name, addr);
         }
         ifp = ifp->ifa_next;
--- a/packages/net/common/current/src/ipv6_routing_thread.c
+++ b/packages/net/common/current/src/ipv6_routing_thread.c
@@ -340,6 +340,7 @@ cyg_rs(cyg_addrword_t param)
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = AF_INET6;
+  hints.ai_flags = AI_NUMERICHOST;
   err = getaddrinfo(ALLROUTER, NULL, &hints, &res);
   if (err) {
     dprnt("%s - failed to get ALL ROUTER: %s",
@@ -412,6 +413,12 @@ cyg_rs(cyg_addrword_t param)
 void
 ipv6_start_routing_thread(void)
 {
+  static int started = 0;
+  
+  started++;
+
+  if (started == 1) {
+  
     cyg_thread_create(
         CYGINT_NET_IPV6_ROUTING_THREAD_PRIORITY, // Priority
         cyg_rs,                                  // entry
@@ -424,5 +431,7 @@ ipv6_start_routing_thread(void)
         );
     cyg_thread_resume(rs_thread_handle);         // Start it
     diag_printf("IPv6 routing thread started\n");
+  }
 }
 
+
--- a/packages/net/common/current/src/network_support.c
+++ b/packages/net/common/current/src/network_support.c
@@ -469,7 +469,10 @@ init_all_network_interfaces(void)
     }
     if (rs_wait == 0 ) {
       diag_printf("No router solicit received\n");
-    } 
+    } else {
+      // Give Duplicate Address Detection time to work
+      cyg_thread_delay(200);
+    }
 #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
@@ -158,9 +158,9 @@ int tftp_client_get(char *filename,
 	}
 
 	if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) {
-	  *err = TFTP_NETERR;
-	  goto out;
-	}
+          *err = TFTP_NETERR;
+          goto out;
+        }
 	
 	// Send request
 	if (sendto(s, data, (int)(cp-data), 0, 
@@ -179,21 +179,38 @@ int tftp_client_get(char *filename,
 	  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
+            total_timeouts++;
+            if ((last_good_block == 0) && (total_timeouts > TFTP_RETRIES_MAX)) {
+	      // Timeout - no data received. Probably no server.
 	      *err = TFTP_TIMEOUT;
-	      goto out;
+	      goto nextaddr;
+            }
+	    if (total_timeouts > TFTP_TIMEOUT_MAX) {
+              // Timeout - have received data. Network problem?
+              *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;
-	    }
+            
+            if (last_good_block == 0 ) {
+              // 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;
+              }
+            } else {
+              // 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);
@@ -335,7 +352,7 @@ int tftp_client_put(char *filename,
 		    int *err) {
 
     int result = 0;
-    int s, actual_len, data_len, recv_len, from_len;
+    int s = -1, actual_len, data_len, recv_len, from_len;
     static int put_port = 7800;
     struct sockaddr local_addr, from_addr;
     char data[SEGSIZE+sizeof(struct tftphdr)];
@@ -436,7 +453,7 @@ int tftp_client_put(char *filename,
 	  FD_ZERO(&fds);
 	  FD_SET(s, &fds);
 	  if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
-            if (++total_timeouts > TFTP_TIMEOUT_MAX) {
+            if (++total_timeouts > TFTP_RETRIES_MAX) {
 	      // Timeout - no ACK received
 	      *err = TFTP_TIMEOUT;
 	      goto nextaddr;
@@ -547,5 +564,3 @@ int tftp_client_put(char *filename,
 }
 
 // EOF tftp_client.c
-
-
--- a/packages/net/common/current/src/tftp_server.c
+++ b/packages/net/common/current/src/tftp_server.c
@@ -600,6 +600,9 @@ tftpd_server(cyg_addrword_t p)
       ai = server->res;
       memset(server->s,0,sizeof(server->s));
       server->num_s = 0;
+#ifdef CYGSEM_NET_TFTPD_MULTITHREADED   
+      sem_wait(server->port);
+#endif
       while (ai && (server->num_s < CYGNUM_NET_MAX_INET_PROTOS)) {
 	server->s[server->num_s] = socket(ai->ai_family, 
 					  ai->ai_socktype, 
@@ -613,9 +616,6 @@ tftpd_server(cyg_addrword_t p)
 	
 	set_port(ai->ai_addr, server->port);
 	
-#ifdef CYGSEM_NET_TFTPD_MULTITHREADED   
-	sem_wait(server->port);
-#endif
 	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);
--- a/packages/net/common/current/tests/addr_test.c
+++ b/packages/net/common/current/tests/addr_test.c
@@ -67,107 +67,190 @@ net_test(CYG_ADDRWORD data)
 {
     int err;
     struct addrinfo *addrs, hints;
+    size_t hostlen = 128;
+    size_t servlen = 64;
+    char host[hostlen];
+    char serv[servlen];
 
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = AI_PASSIVE;
+    hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
     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");
 
+    err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen, 
+                      NULL, 0, serv,servlen, 0);
+    if (err != EAI_NONE) {
+        diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+        pexit("getnameinfo");
+    }
+    diag_printf("INFO: service: %s\n",serv);
+    freeaddrinfo(addrs);
+
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = 0;
+    hints.ai_flags = AI_NUMERICHOST;
     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 active");
+    freeaddrinfo(addrs);
 
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_INET;
     hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = AI_PASSIVE;
+    hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
     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, "IPv4 passive");
+    freeaddrinfo(addrs);
 
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_INET;
     hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = AI_PASSIVE;
+    hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
     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");
 
+    err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen, 
+                      host, hostlen, serv, servlen, NI_NUMERICHOST);
+    if (err != EAI_NONE) {
+        diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+        pexit("getnameinfo");
+    }
+    diag_printf("INFO: host: %s service: %s\n",host, serv);
+    freeaddrinfo(addrs);
+
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = AI_PASSIVE;
+    hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
     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");
+    freeaddrinfo(addrs);
 
 #ifdef CYGPKG_NET_INET6
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_INET6;
     hints.ai_socktype = SOCK_STREAM;
-    hints.ai_flags = AI_PASSIVE;
+    hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
     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, "IPv6 passive");
 
+    err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen, 
+                      NULL, 0, serv,servlen, 0);
+    if (err != EAI_NONE) {
+        diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+        pexit("getnameinfo");
+    }
+    diag_printf("INFO: service: %s\n",serv);
+    freeaddrinfo(addrs);
+    
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_NUMERICHOST;
     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");
-
+    freeaddrinfo(addrs);
+    
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_NUMERICHOST;
     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");
+
+    err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen, 
+                      host, hostlen, serv, servlen, NI_NUMERICHOST);
+    if (err != EAI_NONE) {
+        diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+        pexit("getnameinfo");
+    }
+    diag_printf("INFO: host: %s service: %s\n",host, serv);
+    freeaddrinfo(addrs);
 #endif
 
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_UNSPEC;
+    hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
+    if ((err = getaddrinfo(NULL, "ftp", &hints, &addrs)) != EAI_NONE) {
+        diag_printf("<ERROR> can't getaddrinfo(): %s\n", gai_strerror(err));
+        pexit("getaddrinfo");
+    }
+    walk_addrs(addrs, "all snmp/udp");
+
+    err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen, 
+                      NULL, 0, serv,servlen, 0);
+    if (err != EAI_NONE) {
+        diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+        pexit("getnameinfo");
+    }
+    diag_printf("INFO: service: %s\n",serv);
+    freeaddrinfo(addrs);
+
+    bzero(&hints, sizeof(hints));
+    hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = SOCK_DGRAM;
-    hints.ai_flags = AI_PASSIVE;
+    hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST;
     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/udp");
 
+    err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen, 
+                      NULL, 0, serv,servlen, 0);
+    if (err != EAI_NONE) {
+        diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+        pexit("getnameinfo");
+    }
+    diag_printf("INFO: service: %s\n",serv);
+    freeaddrinfo(addrs);
+    
     bzero(&hints, sizeof(hints));
     hints.ai_family = PF_UNSPEC;
     hints.ai_socktype = 0;
-    hints.ai_flags = AI_PASSIVE;
+    hints.ai_flags = AI_NUMERICHOST;
     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/*");
+
+    err = getnameinfo(addrs->ai_addr, addrs->ai_addrlen, 
+                      NULL, 0, serv,servlen, NI_NUMERICSERV);
+    if (err != EAI_NONE) {
+        diag_printf("<ERROR> can't getnameinfo(): %s\n", gai_strerror(err));
+        pexit("getnameinfo");
+    }
+    diag_printf("INFO: service: %s\n",serv);
+    freeaddrinfo(addrs);
+
     CYG_TEST_PASS_FINISH("Address [library] test OK");
 
 }
--- a/packages/net/common/current/tests/ga_server_test.c
+++ b/packages/net/common/current/tests/ga_server_test.c
@@ -121,7 +121,8 @@ server_test(struct bootp *bp)
                     getpeername(client, &client_addr, &client_len);
                     if (getnameinfo (&client_addr, client_len, 
                                      host_addr_buf, sizeof(host_addr_buf),
-                                     host_port_buf, sizeof(host_port_buf), 0) == EAI_NONE) {
+                                     host_port_buf, sizeof(host_port_buf), 
+                                     NI_NUMERIC) == EAI_NONE) {
                         diag_printf("connection from %s(%s)\n", host_addr_buf, host_port_buf);
                         diag_sprintf(buf, "Hello %s(%s)\n", host_addr_buf, host_port_buf);
                     } else {