changeset 1005:1f968b35cd30

* doc/dns.sgml: Updated to reflect changes for IPv6. * include/dns_impl.inl (setdomainname): Append a . to the end of the domainname if it does not have one. * cdl/dns.cdl: CYGOPT_NS_DNS_FIRST_FAMILTY to control order of results. * src/dns.c: Order the results from cyg_dns_getaddrinfo. * test/dns1.c: Re-written to perform better testing and for getaddrinfo and getnameinfo. * test/dns2.c: Removed. It does not add anything useful. * src/dns.c (cyg_dns_getnameinfo): New. Interface between getnameinfo and the DNS client. * src/dns.c (cyg_dns_getaddrinfo): New. Interface between getaddrinfo and the DNS client. This supports both IPv4 and IPv6 * test/dns1.c: Added tests for getnameinfo using both IPv4 and IPv6 addresses.
author asl
date Mon, 12 May 2003 10:06:05 +0000
parents c1abcb7d0cf8
children 766a12db7c5b
files packages/net/ns/dns/current/ChangeLog packages/net/ns/dns/current/cdl/dns.cdl packages/net/ns/dns/current/doc/dns.sgml packages/net/ns/dns/current/include/dns.h packages/net/ns/dns/current/include/dns_impl.inl packages/net/ns/dns/current/include/dns_priv.h packages/net/ns/dns/current/src/dns.c packages/net/ns/dns/current/tests/dns1.c
diffstat 8 files changed, 1432 insertions(+), 161 deletions(-) [+]
line wrap: on
line diff
--- a/packages/net/ns/dns/current/ChangeLog
+++ b/packages/net/ns/dns/current/ChangeLog
@@ -1,3 +1,30 @@
+2003-04-25  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* doc/dns.sgml: Updated to reflect changes for IPv6.
+
+2003-04-24  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* include/dns_impl.inl (setdomainname): Append a . to the end of 
+	the domainname if it does not have one.
+	* cdl/dns.cdl: CYGOPT_NS_DNS_FIRST_FAMILTY to control order of
+	results.
+	* src/dns.c: Order the results from cyg_dns_getaddrinfo.
+	* test/dns1.c: Re-written to perform better testing and for
+	getaddrinfo and getnameinfo.
+	* test/dns2.c: Removed. It does not add anything useful.
+
+2003-04-21  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/dns.c (cyg_dns_getnameinfo): New. Interface between
+	getnameinfo and the DNS client.
+
+2003-04-19  Andrew Lunn  <andrew.lunn@ascom.ch>
+
+	* src/dns.c (cyg_dns_getaddrinfo): New. Interface between
+	getaddrinfo and the DNS client. This supports both IPv4 and IPv6
+	* test/dns1.c: Added tests for getnameinfo using both IPv4 and
+	IPv6 addresses.
+	
 2003-03-03  Jonathan Larmour  <jifl@eCosCentric.com>
 
 	* tests/dns1.c: Use BOOTP info where possible in preference to
--- a/packages/net/ns/dns/current/cdl/dns.cdl
+++ b/packages/net/ns/dns/current/cdl/dns.cdl
@@ -108,6 +108,31 @@ cdl_package CYGPKG_NS_DNS {
             default_value { "default.domain.com" }
         }
     }
+
+    cdl_option CYGNUM_NS_DNS_GETADDRINFO_ADDRESSES {
+        display "Max number of results for getaddrinfo"
+        flavor data
+        default_value 5
+        description "
+            This option controls the number of addresses the DNS client
+            can return to getaddrinfo and hence the size of the buffer
+            passed to the DNS client."
+    }       
+
+    cdl_option CYGOPT_NS_DNS_FIRST_FAMILY {
+        display       "AF_INET or AF_INET6 first in the getaddrinfo list"
+        active_if     CYGPKG_NET_INET6
+        flavor        data
+        default_value {"AF_INET6"}
+        legal_values  {"AF_INET4" "AF_INET6"}
+        description   "
+           This option controls the order DNS results will appear in the 
+           information returned by getaddrinfo. This will in turn control 
+           the order in which network clients try talking to servers,
+           ie does it try IPv6 or IPv4 addresses first when it has both 
+           types of addresses."
+    }
+
     cdl_component CYGPKG_NS_DNS_OPTIONS {
         display "DNS support build options"
         flavor  none
@@ -142,7 +167,7 @@ cdl_package CYGPKG_NS_DNS {
         flavor  data
         active_if CYGPKG_NS_DNS_BUILD
         no_define
-        calculated { "tests/dns1 tests/dns2" }
+        calculated { "tests/dns1" }
 
         description   "
             This option specifies the set of tests for the DNS package."
--- a/packages/net/ns/dns/current/doc/dns.sgml
+++ b/packages/net/ns/dns/current/doc/dns.sgml
@@ -11,6 +11,7 @@
 <!--                                                                 -->
 <!-- =============================================================== -->
 <!-- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.  -->
+<!-- Copyright (c) 2003 Andrew Lunn                                  -->
 <!-- This material may be distributed only subject to the terms      -->
 <!-- and conditions set forth in the Open Publication License, v1.0  -->
 <!-- or later (the latest version is presently available at          -->
@@ -43,19 +44,18 @@ can both use the DNS package to perform 
 <SECT1 id="net-ns-dns-api1">
 <TITLE>DNS API</TITLE>
 <PARA>The DNS client uses the normal BSD API for performing lookups:
-<function>gethostbyname()</function> and
-<FUNCTION>gethostbyaddr()</FUNCTION>.
+<function>gethostbyname(),</function>
+<FUNCTION>gethostbyaddr()</FUNCTION>,
+<FUNCTION>getaddrinfo()</function>,
+<FUNCTION>getnameinfo()</function>. 
 </PARA>
 <PARA>There are a few restrictions:</PARA>
 <ITEMIZEDLIST>
 <LISTITEM>
-<PARA>Only IPv4 is supported, ie IPv6 addresses cannot be looked
-up.</PARA>
-</LISTITEM>
-<LISTITEM>
 <PARA>If the DNS server returns multiple authoritive records
-for a host name, the hostent will only contain a record for the
-first entry.</PARA>
+for a host name to <function>gethostbyname</function>, the hostent will only contain a record for the
+first entry. If multiple records are desired, use 
+<function>getaddrinfo</function>, which will return multiple results.</PARA>
 </LISTITEM>
 <LISTITEM>
 <PARA>The code has been made thread safe. ie multiple threads
@@ -67,7 +67,15 @@ is not safe is one thread using both
  and 
 <FUNCTION>gethostbyaddr()</FUNCTION>.
 A call to one will destroy the results from the previous call
-to the other function.</PARA>
+to the other function. <FUNCTION>getaddrinfo()</FUNCTION> is thread
+safe and so is the preferred interface.</PARA>
+</LISTITEM>
+<LISTITEM>
+<PARA>The client only uses IPv4 to access the DNS server.</PARA>
+</LISTITEM>
+<LISTITEM><PARA>The DNS client will only return IPv4 addresses to
+RedBoot. At the moment this is not really a limitation,
+since RedBoot only supports IPv4 and not IPv6.</PARA>
 </LISTITEM>
 </ITEMIZEDLIST>
 <PARA>To initialise the DNS client the following function must be
@@ -77,12 +85,14 @@ int cyg_dns_res_init(struct in_addr *dns
 <PARA>where dns_server is the address of the DNS server
 the client should query. On Error this function returns -1, otherwise
 0 for success. If lookups are attemped before this function has
-been called, they will fail and return NULL.</PARA>
+been called, they will fail and return NULL, unless numeric host addresses
+are passed. In this cause, the address will be converted and returned
+without the need for a lookup.</PARA>
 
 <PARA>A default, hard coded, server may be specified in the CDL option
 <literal>CYGDAT_NS_DNS_DEFAULT_SERVER</literal>. The use of this is
 controlled by <literal>CYGPKG_NS_DNS_DEFAULT</literal>. If this is
-enabled, <literal>init_all_network_interfaces</literal> will
+enabled, <literal>init_all_network_interfaces()</literal> will
 initialize the resolver with the hard coded address. The DHCP client
 or user code my override this address by calling
 <literal>cyg_dns_res_init</literal> again. </PARA>
@@ -110,9 +120,95 @@ The boolean <literal>CYGPKG_NS_DNS_DOMAI
 and the domain name is taken from
 <literal>CYGPKG_NS_DNS_DOMAINNAME_NAME</literal>.</PARA>
 
-<PARA>Once set, the DNS client will first perform a lookup with the domain
-name appended. If this fails it will then perform a second lookup
-without the appended domain name. </PARA>
-</SECT1>
-</CHAPTER>
+<PARA>Once set, the DNS client will use some simple heuristics when
+      deciding how to use the domainname. If the name given to the
+      client ends with a "." it is assumed to be a FQDN and the domain
+      name will not be used. If the name contains a "." somewhere
+      within it, first a lookup will be performed without the
+      domainname. If that fails the domainname will be appended and
+      looked up. If the name does not contain a ".", the domainname is
+      appended and used for the first query. If that fails, the
+      unadorned name is lookup.
+</PARA>
+      <PARA>The <FUNCTION>getaddrinfo</FUNCTION> will return both IPv4 and
+        IPv6 addresses for a given host name, when IPv6 is enabled in
+        the eCos configuration.  The CDL option
+        <LITERAL>CYGOPT_NS_DNS_FIRST_FAMILY</LITERAL> controls the order
+        IPv6 and IPv4 addresses are returned in the linked list of
+        <LITERAL>addrinfo</LITERAL> structures. If the value
+        <LITERAL>AF_INET</LITERAL> is used, the IPv4 addresses will be
+        first. If the value <LITERAL>AF_INET6</LITERAL>, which is the
+        default, is used, IPv6 address will be first. This ordering will
+        control how clients attempt to connect to servers, ie using IPv6
+        or IPv4 first. 
+      </PARA>
+    </SECT1>
+    <SECT1 id="net-ns-dns-testing">
+      <TITLE>DNS Client Testing</TITLE> 
+      
+      <PARA>The DNS client has a test program, dns1.c, which tests many of
+        the features of the DNS client and the functions
+        <FUNCTION>gethostbyname(),</FUNCTION>
+        <FUNCTION>gethostbyaddr()</FUNCTION>,
+        <FUNCTION>getaddrinfo()</FUNCTION>,
+        <FUNCTION>getnameinfo()</FUNCTION>.
+      </PARA>
+      <PARA>In order for this test to work, a DNS server must be configured
+        with a number of names and addresses. The following is an example
+        forward address resolution database for bind v9, which explains the
+        requirements.</para>
+      
+      <PROGRAMLISTING>
+        $TTL            680400
+        @               IN      SOA     lunn.org.       andrew.lunn.lunn.org (
+        2003041801      ; serial
+        10800           ; refresh
+        1800            ; retry
+        3600000         ; expire
+        259200)         ; mimimum
+        IN      NS      londo.lunn.org.
+        
+        hostnamev4      IN      A       192.168.88.1
+        cnamev4         IN      CNAME   hostnamev4
+        hostnamev6      IN      AAAA    fec0::88:4:3:2:1
+        cnamev6         IN      CNAME   hostnamev6
+        hostnamev46     IN      A       192.168.88.2
+        hostnamev46     IN      AAAA    fec0::88:4:3:2:2
+        cnamev46        IN      CNAME   hostnamev46
+      </PROGRAMLISTING>
+      <PARA>The actual names and addresses do not matter, since they are
+        configurable in the test. What is important is the relationship
+        between the names and the addresses and there family. ie
+        hostnamev4 should map to one IPv4 address. hostnamev46 should
+        map to both an IPv4 and an IPv6 address. cnamev4 should be a
+        CNAME record for hostname4. Reverse lookup information is also
+        needed by the test.
+      </PARA>
+      <PARA>The information placed into the DNS server is also need in the
+        test case. A structure is defined to hold this
+        information:</PARA>
+      <PROGRAMLISTING>
+        struct test_info_s {
+            char * dns_server;
+            char * domain_name;
+            char * hostname_v4;
+            char * cname_v4;
+            char * ip_addr_v4;
+            char * hostname_v6;
+            char * cname_v6;
+            char * ip_addr_v6;
+            char * hostname_v46;
+            char * cname_v46;
+            char * ip_addr_v46_v4;
+            char * ip_addr_v46_v6;
+        };
+        </PROGRAMLISTING>
+      <PARA>The test program may hold a number of such structures for
+        different DNS server. The test will use each structure in turn
+        to perform the tests.  If IPv6 is not enabled in the eCos
+        configuration, the entries which use IPv6 may be assigned to
+        NULL.
+        </PARA>
+    </SECT1>
+  </CHAPTER>
 </PART>
--- a/packages/net/ns/dns/current/include/dns.h
+++ b/packages/net/ns/dns/current/include/dns.h
@@ -83,6 +83,15 @@ externC const char* hstrerror(int err);
 #define NO_RECOVERY    3
 #define NO_DATA        4
 
+// Interface between the DNS client and getaddrinfo
+externC int 
+cyg_dns_getaddrinfo(const char * hostname, 
+                    struct sockaddr addrs[], int num,
+                    int family, char **canon);
+// Interface between the DNS client and getnameinfo
+externC int
+cyg_dns_getnameinfo(const struct sockaddr * sa, char * host, size_t hostlen);
+
 //-----------------------------------------------------------------------------
 #endif // CYGONCE_NS_DNS_DNS_H
 // End of dns.h
--- a/packages/net/ns/dns/current/include/dns_impl.inl
+++ b/packages/net/ns/dns/current/include/dns_impl.inl
@@ -191,7 +191,7 @@ real_name(char *msg, unsigned char *qnam
 /* Build a query message which can be sent to the server. If something
    goes wrong return -1, otherwise the length of the query message */
 static int 
-build_query(char * msg, const char * hostname, short rr_type)
+build_query(const char * msg, const char * hostname, short rr_type)
 {
     struct dns_header *dns_hdr;
     char *ptr;
@@ -251,6 +251,33 @@ dot_hostname(const char *hostname)
     return hent;
 }
 
+#ifdef CYGPKG_NET_INET6
+/* Check if the hostname is actually colon format of IPv6. If so convert it 
+   and return host entity structure. If not, return NULL. */
+static struct hostent *
+colon_hostname(const char *hostname) 
+{   
+  struct sockaddr_in6 addr;
+  struct hostent *hent = NULL;
+
+  if (inet_pton(AF_INET6, hostname, (void *)&addr)) {
+    hent = alloc_hent();
+    if (hent) {
+      memcpy(hent->h_addr_list[0], &addr, sizeof(addr));
+      hent->h_addrtype = AF_INET6;
+      hent->h_length = sizeof(addr);
+      hent->h_name = alloc_string(strlen(hostname)+1);
+      if (!hent->h_name) {
+        free_hent(hent);
+        return NULL;
+      }
+      strcpy(hent->h_name, hostname);
+    }
+  }
+  return hent;
+}
+#endif
+
 /* Decode the answer from the server. Returns NULL if failed, or 
    a hostent structure containing different data depending on the
    query type:
@@ -418,14 +445,37 @@ gethostbyaddr(const char *addr, int len,
     return hent;
 }
 
+/* Build message, send, receive and decode */
+static struct hostent *
+do_query(const char * hostname) 
+{
+    unsigned char msg[MAXDNSMSGSIZE];
+    int len;
+        
+    memset(msg, 0, sizeof(msg));
+    len = build_query(msg, hostname, DNS_TYPE_A);
+    if (len < 0) {
+        return NULL;
+    }
+  
+    /* Send the query and wait for an answer */
+    len = send_recv(msg, len, sizeof(msg));
+    if (len < 0) {
+        return NULL;
+    }
+  
+    /* Decode the answer */
+    return parse_answer(msg, DNS_TYPE_A);
+}
+
+
 /* Given a hostname find out the IP address */
 struct hostent *
 gethostbyname(const char * hostname)
 {
-    unsigned char msg[MAXDNSMSGSIZE];
     char name[256];
+    char * dot;
     struct hostent *hent;
-    int len;
 
     CYG_REPORT_FUNCNAMETYPE( "gethostbyname", "returning %08x" );
     CYG_REPORT_FUNCARG1( "hostname=%08x", hostname );
@@ -448,42 +498,25 @@ gethostbyname(const char * hostname)
     free_stored_hent();
   
     if (!valid_hostname(hostname)) {
-        /* It could be a dot address */
-        hent = dot_hostname(hostname);
-        store_hent(hent);
-        CYG_REPORT_RETVAL( hent );
-        return hent;
+         /* It could be a dot address */
+         if ((hent = dot_hostname(hostname)) != NULL) {
+              store_hent(hent);
+              CYG_REPORT_RETVAL( hent );
+              return hent;
+         }
+#ifdef CYGPKG_NET_INET6
+         /* It could be a colon seperated IPv6 address */
+         if ((hent = colon_hostname(hostname)) != NULL) {
+              store_hent(hent);
+              CYG_REPORT_RETVAL( hent );
+              return hent;
+         }
+#endif
+         CYG_REPORT_RETVAL( hent );
+         return hent;
     }
-
     cyg_drv_mutex_lock(&dns_mutex);
 
-    /* First try the name as passed in */
-    memset(msg, 0, sizeof(msg));
-    len = build_query(msg, hostname, DNS_TYPE_A);
-    if (len < 0) {
-        cyg_drv_mutex_unlock(&dns_mutex);
-        CYG_REPORT_RETVAL( NULL );
-        return NULL;
-    }
-  
-    /* Send the query and wait for an answer */
-    len = send_recv(msg, len, sizeof(msg));
-    if (len < 0) {
-        cyg_drv_mutex_unlock(&dns_mutex);
-        CYG_REPORT_RETVAL( NULL );
-        return NULL;
-    }
-  
-    /* Decode the answer */
-    hent = parse_answer(msg, DNS_TYPE_A);
-    if (hent) {
-        cyg_drv_mutex_unlock(&dns_mutex); 
-        store_hent(hent);
-        CYG_REPORT_RETVAL( hent );
-        return hent;
-    }
-
-    /* If no match, try appending the domainname if we have one */
     if (domainname) {
         if ((strlen(hostname) + strlen(domainname)) > 254) {
             h_errno = NO_RECOVERY;
@@ -494,27 +527,36 @@ gethostbyname(const char * hostname)
         strcpy(name, hostname);
         strcat(name, ".");
         strcat(name, domainname);
-    
-        memset(msg, 0, sizeof(msg));
-        len = build_query(msg, name, DNS_TYPE_A);
-        if (len < 0) {
-            cyg_drv_mutex_unlock(&dns_mutex);
-            CYG_REPORT_RETVAL( NULL );
-            return NULL;
-        }
-    
-        /* Send the query and wait for an answer */
-        len = send_recv(msg, len, sizeof(msg));
-        if (len < 0) {
-            cyg_drv_mutex_unlock(&dns_mutex);
-            CYG_REPORT_RETVAL( NULL );
-            return NULL;
-        }
-    
-        /* Decode the answer */
-        hent = parse_answer(msg, DNS_TYPE_A);
     }
 
+        /* If the hostname ends with . it a FQDN. Don't bother adding the
+    domainname. If it does not contain a . , try appending with the
+    domainname first. If it does have a . , try without a domain name
+    first. */
+
+    dot = rindex(hostname,'.');
+    if (dot) {
+        if (*(dot+1) == '\0') {
+            /* FQDN */
+            hent = do_query(hostname);
+        } else {
+          /* Dot somewhere */
+          hent = do_query(hostname);
+          if (domainname && (hent == NULL)) { 
+            hent = do_query(name);
+          }
+        }
+    } else {
+    /* No Dot. Try adding domainname first */
+        hent = NULL;
+        if (domainname) {
+            hent = do_query(name);
+        }
+        if (hent == NULL) {
+            hent = do_query(hostname);
+        }
+    }
+    
     cyg_drv_mutex_unlock(&dns_mutex); 
     store_hent(hent);
     CYG_REPORT_RETVAL( hent );
@@ -526,6 +568,7 @@ int
 setdomainname(const char *name, size_t len)
 {
     char * ptr;
+    int length;
 
     CYG_REPORT_FUNCNAMETYPE( "setdomainname", "returning %d" );
     CYG_REPORT_FUNCARG2( "name=%08x, len=%d", name, len );
@@ -537,13 +580,28 @@ setdomainname(const char *name, size_t l
     }
     if (len != 0) {
         CYG_CHECK_DATA_PTR( name, "name is not a valid pointer!" );
-        ptr = alloc_string(len+1);
+        length = strlen(name);
+        if (length > len) {
+            h_errno = NO_RECOVERY;
+            CYG_REPORT_RETVAL( -1 );
+            return -1;
+        }
+        if (name[length-1] != '.') {
+                length++;
+        }       
+        ptr = alloc_string(length+1);
         if (!ptr) {         
+            h_errno = NO_RECOVERY;
             CYG_REPORT_RETVAL( -1 );
             return -1;
         } 
         memcpy(ptr, name, len);
-        ptr[len]=0;
+        if (name[length-1] != '.') {
+            ptr[length-1] = '.';
+            ptr[length] = '\0';
+        } else {
+            ptr[len]=0;
+        }
     } else {
         ptr = NULL;
     }
--- a/packages/net/ns/dns/current/include/dns_priv.h
+++ b/packages/net/ns/dns/current/include/dns_priv.h
@@ -112,6 +112,7 @@ struct resource_record {
 #define DNS_TYPE_NS    2   /* Authoritative name server */
 #define DNS_TYPE_CNAME 5   /* Canonical name for an alias */
 #define DNS_TYPE_PTR   12  /* Domain name pointer */
+#define DNS_TYPE_AAAA  28  /* IPv6 host address */
 
 /* DNS CLASSs */
 #define DNS_CLASS_IN   1   /* Internet */
--- a/packages/net/ns/dns/current/src/dns.c
+++ b/packages/net/ns/dns/current/src/dns.c
@@ -315,3 +315,389 @@ cyg_dns_res_init(struct in_addr *dns_ser
     CYG_REPORT_RETVAL( 0 );
     return 0;
 }
+
+/* add_answer checks to see if we already have this answer and if not,
+   adds it to the answers. */
+static int 
+add_answer(char *rdata, short rr_type, int family, 
+           struct sockaddr addrs[], int num, int used) {
+    int i;
+    int found = 0;
+    
+    for (i = 0; i < used ; i++) {
+        if ((addrs[i].sa_family == family) &&
+            !memcmp(addrs[i].sa_data, rdata, addrs[i].sa_len)) {
+            found = 1;
+            break;
+        }
+    }
+    if (!found) {
+        memset(&addrs[used],0,sizeof(addrs[used]));
+        addrs[used].sa_family = family;
+        
+        switch(family) {
+        case AF_INET: {
+            struct sockaddr_in * addr = (struct sockaddr_in *) &addrs[used];
+            addr->sin_len = sizeof(*addr);
+            memcpy(&addr->sin_addr, rdata, sizeof(struct in_addr));
+            used++;
+            break;
+        }
+#ifdef CYGPKG_NET_INET6
+        case AF_INET6: {
+            struct sockaddr_in6 * addr = (struct sockaddr_in6 *) &addrs[used];
+            addr->sin6_len = sizeof(*addr);
+            memcpy(&addr->sin6_addr, rdata, sizeof(struct in6_addr));
+            used++;
+            break;
+        }
+#endif
+        default:
+            used = -EAI_FAMILY;
+        }
+    }
+    return used;
+}
+      
+/* This decodes the answer and puts the results into the addrs
+   array. This function can deal with IPv6 AAAA records as well as A
+   records. Thus its more complex than the parse_answer function in
+   the inline code. This complexity is only needed by getaddrinfo, so
+   i decided to leave parse_anser alone. */
+
+static int
+decode(char *msg, short rr_type, int family, 
+       struct sockaddr addrs[], int num, int used, char **canon) {
+  
+    struct dns_header *dns_hdr;
+    struct resource_record rr, *rr_p = NULL;
+    char *qname = NULL;
+    char *ptr;
+    
+    dns_hdr = (struct dns_header *)msg;
+    
+    if (DNS_REPLY_NAME_ERROR == dns_hdr->rcode) {
+        h_errno = HOST_NOT_FOUND;
+        return -EAI_NONAME;
+    }
+    
+    if ((dns_hdr->qr != 1) ||
+        (dns_hdr->opcode != DNS_QUERY)) {
+      return -EAI_FAIL;
+    }
+    
+    if (dns_hdr->rcode != DNS_REPLY_NOERR) {
+      return -EAI_NONAME;
+    }
+
+    dns_hdr->ancount = ntohs(dns_hdr->ancount);
+    dns_hdr->qdcount = ntohs(dns_hdr->qdcount);
+    ptr = (char *)&dns_hdr[1];
+    
+    /* Skip over the query section */
+    if (dns_hdr->qdcount > 0) {
+        while (dns_hdr->qdcount) {
+            ptr += qname_len(ptr);
+            ptr += 4;                   /* skip type & class */
+            dns_hdr->qdcount--;
+        }
+    }  
+    
+    /* Read the answers resource records to find an answer of the
+       correct type. */
+    while (dns_hdr->ancount && (used >= 0) && (used < num)) {
+        qname = ptr;
+        ptr += qname_len(ptr);
+        rr_p = (struct resource_record *)ptr;
+        memcpy(&rr, ptr, sizeof(rr));
+        if ((rr.rr_type == htons(rr_type)) && 
+            (rr.class == htons(DNS_CLASS_IN))) {
+            used = add_answer(rr_p->rdata, rr_type, family, addrs, num, used);
+            if (canon && !*canon) {
+                *canon = real_name(msg,qname);
+            }
+        }
+        ptr += sizeof(struct resource_record) - 
+            sizeof(rr.rdata) + ntohs(rr.rdlength);
+        dns_hdr->ancount--;
+    }
+    if (used == 0) {
+        return -EAI_NONAME;
+    }
+    return used;
+}
+
+/* Do a lookup for a particular type of resource record. */
+static int 
+do_lookup (const char * hostname, 
+           struct sockaddr addrs[], int num, int used, 
+           short rr_type, int family, char **canon) {
+
+    unsigned char msg[MAXDNSMSGSIZE];
+    int error;
+    int len;
+
+    /* First try the name as passed in */
+    memset(msg, 0, sizeof(msg));
+    len = build_query(msg, hostname, rr_type);
+    if (len < 0) {
+        return -EAI_FAIL;
+    }
+    
+    /* Send the query and wait for an answer */
+    len = send_recv(msg, len, sizeof(msg));
+    if (len < 0) {
+        return -EAI_FAIL;
+    }
+    
+    /* Decode the answer */
+    error = decode(msg, rr_type, family, addrs, num, used, canon);
+    return error;
+}
+
+static int do_lookups(const char * hostname, 
+                      struct sockaddr addrs[], int num, 
+                      int family, char ** canon) {
+    int error;
+#ifdef CYGPKG_NET_INET6
+    int error6;
+#endif
+
+    switch (family) {
+    case AF_INET:
+        error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, AF_INET, canon);
+        break;
+#ifdef CYGPKG_NET_INET6
+    case AF_INET6:
+        error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_AAAA, AF_INET6, canon);
+        break;
+#endif
+    case PF_UNSPEC:
+#ifndef CYGPKG_NET_INET6
+        error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, AF_INET, canon);
+#else 
+#ifdef CYGOPT_NS_DNS_FIRST_FAMILTY_AF_INET
+        error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, AF_INET, canon);
+        if (error > 0 ) {
+            error6 = do_lookup(hostname, addrs, num, error, DNS_TYPE_AAAA, 
+                               AF_INET6, canon);
+        } else {
+            error6 = do_lookup(hostname, addrs, num, 0, DNS_TYPE_AAAA, 
+                               AF_INET6, canon);
+        }
+        if (error6 > 0) {
+            error = error6;
+        }
+#else // CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET
+        error6 = do_lookup(hostname, addrs, num, 0, DNS_TYPE_AAAA, 
+                           AF_INET6, canon);
+        if (error6> 0 ) {
+            error = do_lookup(hostname, addrs, num, error6, DNS_TYPE_A, 
+                               AF_INET, canon);
+        } else {
+            error = do_lookup(hostname, addrs, num, 0, DNS_TYPE_A, 
+                               AF_INET, canon);
+        }
+#endif // CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET
+#endif // CYGPKG_NET_INET6
+        break;
+    default:
+        error = -EAI_FAMILY;
+    }
+    return error;
+}
+
+/* This implements the interface between getaddrinfo and the dns
+   client. hostent is not used here since that only works with IPv4
+   addresses, where as this function needs to be protocol
+   independent. */
+int 
+cyg_dns_getaddrinfo(const char * hostname, 
+                    struct sockaddr addrs[], int num,
+                    int family,
+                    char ** canon)
+{
+    int error;
+    char name[256];
+    char * dot;
+
+    CYG_REPORT_FUNCNAMETYPE( "cyg_dns_getaddrinfo", "returning %08x" );
+    CYG_REPORT_FUNCARG3( "hostname=%08x, addrs=%08x, num=%2d", 
+                         hostname, addrs, num );
+    
+    if ( !hostname || !addrs || !num ) {
+        CYG_REPORT_RETVAL( NULL );
+        return -EAI_FAIL;
+    }
+    
+    CYG_CHECK_DATA_PTR( hostname, "hostname is not a valid pointer!" );
+    CYG_CHECK_DATA_PTR( addrs, "addrs is not a valid pointer!");
+    CYG_ASSERT( num > 0, "Invalid number of sockaddr stuctures");
+    
+    if (!valid_hostname(hostname)) {
+        /* it could be a dot address */
+        struct sockaddr_in * sa4 = (struct sockaddr_in *)&addrs[0];
+        memset(&addrs[0],0,sizeof(struct sockaddr));
+        if (inet_pton(AF_INET, hostname, (char *)&sa4->sin_addr.s_addr)) {
+            sa4->sin_family = AF_INET;
+            sa4->sin_len = sizeof(*sa4);
+            CYG_REPORT_RETVAL (1);
+            return 1;
+        }
+#ifdef CYGPKG_NET_INET6
+        {
+            /* it could be a colon address */
+            struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *)&addrs[0];
+            memset(&addrs[0],0,sizeof(struct sockaddr));
+            if (inet_pton(AF_INET6, hostname, (char *)&sa6->sin6_addr.s6_addr)) {
+                sa6->sin6_family = AF_INET6;
+                sa6->sin6_len = sizeof(*sa6);
+                CYG_REPORT_RETVAL (1);
+                return 1;
+            }
+        }
+#endif
+        CYG_REPORT_RETVAL (-EAI_NONAME);
+        return -EAI_NONAME;
+    }
+    
+    /* Has the socket to the DNS server been opened? */
+    if (s < 0) {
+        CYG_REPORT_RETVAL( -EIA_FAIL );
+        return -EAI_FAIL;
+    }
+    
+    if (domainname) {
+        if ((strlen(hostname) + strlen(domainname)) > 254) {
+            cyg_drv_mutex_unlock(&dns_mutex);
+            CYG_REPORT_RETVAL( -EAI_FAIL );
+            return -EAI_FAIL;
+        }
+        strcpy(name, hostname);
+        strcat(name, ".");
+        strcat(name, domainname);
+    }
+    cyg_drv_mutex_lock(&dns_mutex);
+
+    /* If the hostname ends with . it a FQDN. Don't bother adding the
+    domainname. If it does not contain a . , try appending with the
+    domainname first. If it does have a . , try without a domain name
+    first. */
+
+    dot = rindex(hostname,'.');
+    if (dot) {
+        if (*(dot+1) == '\0') {
+            /* FQDN */
+            error = do_lookups(hostname, addrs, num, family, canon);
+        } else {
+          /* Dot somewhere */
+          error = do_lookups(hostname, addrs, num, family, canon);
+          if (domainname && (error == -EAI_NONAME)) { 
+            error = do_lookups(name, addrs, num, family, canon);
+          }
+        }
+    } else {
+    /* No Dot. Try adding domainname first */
+        error = -EAI_NONAME;
+        if (domainname) {
+            error = do_lookups(name, addrs, num, family, canon);
+        }
+        if (error == -EAI_NONAME) {
+            error = do_lookups(hostname, addrs, num, family, canon);
+        }
+    }
+    cyg_drv_mutex_unlock(&dns_mutex);
+    CYG_REPORT_RETVAL( error );
+    return error;
+}
+
+/* This implements the interface between getnameinfo and the dns
+   client. */
+externC int
+cyg_dns_getnameinfo(const struct sockaddr * sa, char * host, size_t hostlen) 
+{
+    char hostname[80];
+    unsigned char msg[MAXDNSMSGSIZE];
+    struct hostent * hent;
+    int len;
+
+    CYG_REPORT_FUNCNAMETYPE( "cyg_dns_getnameinfo", "returning %08x" );
+    CYG_REPORT_FUNCARG3( "sa=%08x, host=%08x, hostlen=%3d", 
+                         sa, host, hostlen );
+    
+    CYG_CHECK_DATA_PTR( sa, "sa is not a valid pointer");
+    CYG_CHECK_DATA_PTR( host, "host is not a valid data pointer");
+    CYG_ASSERT(hostlen >0, "Invalid host length");
+    
+    /* Has the socket to the DNS server been opened? */
+    if (s < 0) {
+        CYG_REPORT_RETVAL( -EIA_FAIL );
+        return -EAI_FAIL;
+    }
+    
+    cyg_drv_mutex_lock(&dns_mutex);
+    
+    switch (sa->sa_family) {
+    case AF_INET: {
+        struct sockaddr_in * sa4 = (struct sockaddr_in *)sa;
+        unsigned char * addr = (char *)&sa4->sin_addr.s_addr;
+        sprintf(hostname, "%d.%d.%d.%d.IN-ADDR.ARPA.",
+                addr[3],addr[2],addr[1],addr[0]);
+        break;
+    }
+#ifdef CYGPKG_NET_INET6
+    case AF_INET6: {
+        struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *)sa;
+        int i;
+        
+        for (i=15; i >= 0; i--) {
+            sprintf(&hostname[(15*2*2) - (i*2*2)], "%x.%x.",
+                    sa6->sin6_addr.s6_addr[i] & 0x0f,
+                    (sa6->sin6_addr.s6_addr[i] & 0xf0) >> 4);
+        }
+        sprintf(&hostname[16*2*2],"IP6.INT");
+        break;
+    }
+#endif
+    default:
+        cyg_drv_mutex_lock(&dns_mutex);
+        CYG_REPORT_RETVAL( -EAI_FAMILY);
+        return -EAI_FAMILY;
+    }
+
+    memset(msg, 0, sizeof(msg));
+  
+    /* Build a PTR type request using the hostname */
+    len = build_query(msg, hostname, DNS_TYPE_PTR);
+    if (len < 0) {
+        cyg_drv_mutex_unlock(&dns_mutex);
+        CYG_REPORT_RETVAL( -EAI_FAIL );
+        return -EAI_FAIL;
+    }
+
+    /* Send the request and wait for an answer */
+    len = send_recv(msg, len, sizeof(msg));
+    if (len < 0) {
+        cyg_drv_mutex_unlock(&dns_mutex);
+        CYG_REPORT_RETVAL( -EAI_FAIL );
+        return -EAI_FAIL;
+    }
+ 
+    /* Parse the answer for the host name */
+    hent = parse_answer(msg, DNS_TYPE_PTR);
+    
+    /* If no name is known return an error */
+    if (!hent) {
+        cyg_drv_mutex_unlock(&dns_mutex);
+        CYG_REPORT_RETVAL( -EAI_NONAME );
+        return -EAI_NONAME;
+    }
+    
+    /* Otherwise copy it into our results buffer and tidy up */
+    strncpy(host, hent->h_name,hostlen);
+    free_hent(hent);
+    
+    cyg_drv_mutex_unlock(&dns_mutex);
+    CYG_REPORT_RETVAL( -EAI_NONE );
+    return -EAI_NONE;
+}
--- a/packages/net/ns/dns/current/tests/dns1.c
+++ b/packages/net/ns/dns/current/tests/dns1.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
@@ -44,7 +45,7 @@
 // Contributors: andrew.lunn, jskov
 // Date:         2001-09-18
 // Purpose:      
-// Description:  Test DNS functions. Note that the _XXX defines below
+// Description:  Test DNS functions. Note that the structure below that
 //               control what addresses the test uses. These must be
 //               changed to match the particular testing network in which
 //               the test is to be run.
@@ -52,6 +53,7 @@
 //####DESCRIPTIONEND####
 //
 //==========================================================================
+#include <pkgconf/ns_dns.h>
 
 #include <network.h>
 #include <netdb.h>
@@ -65,23 +67,760 @@ static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
 
-#define __string(_x) #_x
-#define __xstring(_x) __string(_x)
+#define NELEM(x) (sizeof(x) / sizeof(x[0]))
+
+struct test_info_s {
+    char * dns_server;
+    char * domain_name;
+    char * hostname_v4;
+    char * cname_v4;
+    char * ip_addr_v4;
+    char * hostname_v6;
+    char * cname_v6;
+    char * ip_addr_v6;
+    char * hostname_v46;
+    char * cname_v46;
+    char * ip_addr_v46_v4;
+    char * ip_addr_v46_v6;
+};
 
-// Change the following if you aren't using BOOTP! It's almost certainly not right for you.
-#define _DNS_IP            __xstring(172.16.1.254) // test farm host addr
-#define _LOOKUP_FQDN       __xstring(b.root-servers.net.) // should stay the same?
-#define _LOOKUP_DOMAINNAME __xstring(root-servers.net.)
-#define _LOOKUP_HOSTNAME   __xstring(b)
-#define _LOOKUP_IP         __xstring(128.9.0.107) // must be same as _LOOKUP_FQDN
-#define _LOOKUP_IP_BAD     __xstring(10.0.0.0)
+struct test_info_s test_info[] = {
+    {
+        "192.168.10.1",
+        "lunn.org.",
+        "hostnamev4",
+        "cnamev4",
+        "192.168.88.1",
+        "hostnamev6",
+        "cnamev6",
+        "fec0::88:4:3:2:1",
+        "hostnamev46",
+        "cnamev46",
+        "192.168.88.2",
+        "fec0::88:4:3:2:2"
+    }
+};
 
-void
-dns_test(cyg_addrword_t p)
-{
+char * familytoa(int family) {
+    
+    switch (family) {
+    case AF_INET:
+        return "AF_INET";
+#ifdef CYGPKG_NET_INET6
+    case AF_INET6:
+        return "AF_INET6";
+#endif
+    default:
+        return "Unknown";
+    }
+}
+
+void dns_test(struct test_info_s *info) {
     struct in_addr addr;
     struct hostent *hent;
     char dn[256];
+    char name[256];
+    char cname[256];
+    char buffer[256];
+    char buff[64];
+    size_t hostlen = 128;
+    char host[hostlen];
+    struct addrinfo * res;
+    struct addrinfo hints;
+    struct sockaddr_in sa4;
+#ifdef CYGPKG_NET_INET6
+    struct sockaddr_in6 sa6;
+    struct addrinfo *ai4, *ai6;
+#endif
+    int error;
+    
+    if (inet_pton(AF_INET, info->dns_server, (void *)&addr) < 0) {
+      CYG_TEST_FAIL_FINISH("Error with DNS server address");
+    }
+    cyg_dns_res_init(&addr);
+
+    setdomainname(NULL,0);
+    
+    inet_aton(info->ip_addr_v4, &addr);
+    strcpy(name,info->hostname_v4);
+    strcat(name,".");
+    strcat(name,info->domain_name);
+    strcpy(cname,info->cname_v4);
+    strcat(cname,".");
+    strcat(cname,info->domain_name);
+    
+    // Lookup the IPv4 FQDN hostname 
+    hent = gethostbyname(name);
+    if (hent != NULL) {
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s>", 
+                     name,
+                     hent->h_name, 
+                     inet_ntoa(*(struct in_addr *)hent->h_addr));
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr, 
+                                        (void*)(hent->h_addr), 
+                                        sizeof(struct in_addr))),
+                           "IPv4 FQDN hostname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)), 
+                           "IPv4 FQDN hostname name");
+    } else {
+        diag_sprintf(buffer,"IPv4 FQDN hostname: error %s", 
+                     hstrerror(h_errno));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Lookup the IPv4 FQDN cname
+    hent = gethostbyname(cname);
+    if (hent != NULL) {
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s>", 
+                     cname,
+                     hent->h_name, 
+                     inet_ntoa(*(struct in_addr *)hent->h_addr));
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr, 
+                                        (void*)(hent->h_addr), 
+                                        sizeof(struct in_addr))),
+                           "IPv4 FQDN cname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)), 
+                           "IPv4 FQDN hostname name");
+    } else {
+        diag_sprintf(buffer,"IPv4 FQDN cname: error %s", hstrerror(h_errno));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Lookup the IP address as a string.  This does not require a DNS
+    // lookup. Just turn the value into binary
+    hent = gethostbyname(info->ip_addr_v4);
+    if (hent != NULL) {
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s>", 
+                     info->ip_addr_v4,
+                     hent->h_name, 
+                     inet_ntoa(*(struct in_addr *)hent->h_addr));
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr, 
+                                        (void*)(hent->h_addr), 
+                                        sizeof(struct in_addr))),
+                           "IPv4 IP address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(info->ip_addr_v4, hent->h_name)), 
+                           "IPv4 IP address name");
+        
+    } else {
+        diag_sprintf(buffer,"IPv4 IP address: error %s", hstrerror(h_errno));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Reverse lookup the IPv4 address, expect the FQDN hostname
+    hent = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
+    if (hent != NULL) {
+        inet_ntop(AF_INET,(void *)&addr, buff, sizeof(buff));
+        diag_sprintf(buffer,"Reverse lookup %s: Result <%s is %s>", 
+                     buff,
+                     hent->h_name, 
+                     inet_ntoa(*(struct in_addr *)hent->h_addr));
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr, 
+                                        (void*)(hent->h_addr), 
+                                        sizeof(struct in_addr))),
+                           "Reverse lookup IPv4 IP address");
+        
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)), 
+                           "Reverse lookup IPv4 IP address name");
+    } else {
+        diag_sprintf(buffer,"Reverse lookup IPv4 IP address: error %s", 
+                     hstrerror(h_errno));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Setup a domainname. We now don't have to use fully qualified
+    // domain names
+    setdomainname(info->domain_name, strlen(info->domain_name));
+    getdomainname(dn, sizeof(dn));
+    CYG_TEST_PASS_FAIL(0 == strcmp(info->domain_name, dn), 
+                       "{get|set}domainname");
+    
+    // Make sure FQDN still work
+    strcpy(name,info->hostname_v4);
+    strcat(name,".");
+    strcat(name,info->domain_name);
+    
+    hent = gethostbyname(name);
+    if (hent != NULL) {
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s>", 
+                     name,
+                     hent->h_name, 
+                     inet_ntoa(*(struct in_addr *)hent->h_addr));
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr, 
+                                        (void*)(hent->h_addr), 
+                                        sizeof(struct in_addr))),
+                           "IPv4 FQDN hostname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)), 
+                           "IPv4 FQDN hostname name");
+    } else {
+        diag_sprintf(buffer,"IPv4 FQDN hostname: error %s", 
+                     hstrerror(h_errno));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Now just the hostname
+    hent = gethostbyname(info->hostname_v4);
+    if (hent != NULL) {
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s>", 
+                     info->hostname_v4,
+                     hent->h_name, 
+                     inet_ntoa(*(struct in_addr *)hent->h_addr));
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void*)&addr, 
+                                        (void*)(hent->h_addr), 
+                                        sizeof(struct in_addr))),
+                           "IPv4 hostname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, hent->h_name)), 
+                           "IPv4 hostname name");
+    } else {
+        diag_sprintf(buffer,"IPv4 hostname: error %s", hstrerror(h_errno));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Run the same tests as above, but this time use getaddrinfo and
+    // getnameinfo.
+    setdomainname(NULL,0);
+    
+    memset(&hints,0,sizeof(hints));
+    hints.ai_flags = AI_CANONNAME;
+    memset(&sa4,0,sizeof(sa4));
+    memcpy(&sa4.sin_addr, &addr, sizeof(addr));
+    sa4.sin_family=AF_INET;
+    sa4.sin_len = sizeof(sa4);
+    
+    // Lookup the IPv4 FQDN hostname 
+    error = getaddrinfo(name, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     name,
+                     res->ai_canonname, 
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa4))) &&
+                           (res->ai_family == AF_INET),
+                           "IPv4 FQDN hostname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)), 
+                           "IPv4 FQDN hostname name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv4 FQDN hostname one result");
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv4 FQDN hostname: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Lookup the IPv4 FQDN cname 
+    error = getaddrinfo(cname, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     cname,
+                     res->ai_canonname, 
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa4))) &&
+                           (res->ai_family == AF_INET),
+                           "IPv4 FQDN cname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)), 
+                           "IPv4 FQDN cname name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv4 FQDN cname one result");
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv4 FQDN cname: error %s", gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Lookup the IP address as a string.  This does not require a DNS
+    // lookup. Just turn the value into binary
+    hints.ai_flags = AI_NUMERICHOST;
+    error = getaddrinfo(info->ip_addr_v4, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s %s>", 
+                     info->ip_addr_v4,
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa4))) &&
+                           (res->ai_family == AF_INET),
+                           "IPv4 IP address");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_canonname), 
+                           "IPv4 IP address name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv4 IP address one result");        
+        // Don't free results - use for next test.
+    } else {
+        diag_sprintf(buffer,"IPv4 IP address: error %s", gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+
+    // Reverse lookup the IPv4 address, expect the FQDN hostname
+    error = getnameinfo(res->ai_addr,res->ai_addrlen,
+                       host, hostlen, NULL, 0, 0);
+    if (error == EAI_NONE) {
+        diag_sprintf(buffer, "IPv4 Reverse lookup FDQN %s: Result %s",
+                    info->ip_addr_v4,
+                    host);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, host)), 
+                           "IPv4 Reverse lookup FQDN");
+    } else {
+        diag_sprintf(buffer,"IPv4 Reverse lookup FQDN: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+    // Reverse lookup the IPv4 address, expect just the hostname part
+    error = getnameinfo(res->ai_addr,res->ai_addrlen,
+                       host, hostlen, NULL, 0, NI_NOFQDN);
+    if (error == EAI_NONE) {
+        diag_sprintf(buffer, "IPv4 Reverse lookup hostname part %s: Result %s",
+                    info->ip_addr_v4,
+                    host);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == strcmp(info->hostname_v4, host)), 
+                           "IPv4 Reverse lookup hostname part");
+    } else {
+        diag_sprintf(buffer,"IPv4 Reverse lookup hostname part: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+    freeaddrinfo(res);
+
+    // Setup a domainname. We now don't have to use fully qualified
+    // domain names
+    setdomainname(info->domain_name, strlen(info->domain_name));
+    getdomainname(dn, sizeof(dn));
+    CYG_TEST_PASS_FAIL(0 == strcmp(info->domain_name, dn), 
+                       "{get|set}domainname");
+    
+    // Lookup the IPv4 FQDN hostname to make sure it still works
+    hints.ai_flags = AI_CANONNAME;
+    error = getaddrinfo(name, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     name,
+                     res->ai_canonname, 
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa4))) &&
+                           (res->ai_family == AF_INET),
+                           "IPv4 FQDN hostname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)), 
+                           "IPv4 FQDN hostname name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv4 FQDN hostname one result");
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv4 FQDN hostname: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Now the host name without the domain name 
+    error = getaddrinfo(info->hostname_v4, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     info->hostname_v4,
+                     res->ai_canonname, 
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa4))) &&
+                           (res->ai_family == AF_INET),
+                           "IPv4 hostname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)), 
+                           "IPv4 hostname name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv4 hostname one result");        
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv4 hostname: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+#ifdef CYGPKG_NET_INET6
+    // Check we have the needed information for the IPv6 tests
+    if (!info->hostname_v6 || !info->cname_v6 || !info->ip_addr_v6) {
+        return;
+    }
+
+    setdomainname(NULL,0);
+    
+    strcpy(name,info->hostname_v6);
+    strcat(name,".");
+    strcat(name,info->domain_name);
+    strcpy(cname,info->cname_v6);
+    strcat(cname,".");
+    strcat(cname,info->domain_name);
+    
+    memset(&sa6,0,sizeof(sa6));
+    sa6.sin6_family = AF_INET6;
+    sa6.sin6_len = sizeof(sa6);
+    inet_pton(AF_INET6, info->ip_addr_v6, (void *)&sa6.sin6_addr);
+
+    // Lookup the IPv6 FQDN hostname 
+    error = getaddrinfo(name, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     name,
+                     res->ai_canonname, 
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa6))) &&
+                           (res->ai_family == AF_INET6),
+                           "IPv6 FQDN hostname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)), 
+                           "IPv6 FQDN hostname name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv6 FQDN hostname one result");
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv6 FQDN hostname: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+
+    // Lookup the IPv6 FQDN cname 
+    error = getaddrinfo(cname, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     cname,
+                     res->ai_canonname, 
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa6))) &&
+                           (res->ai_family == AF_INET6),
+                           "IPv6 FQDN cname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)), 
+                           "IPv6 FQDN cname name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv6 FQDN cname one result");
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv6 FQDN cname: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+
+    // Lookup the IP address as a string.  This does not require a DNS
+    // lookup. Just turn the value into binary
+    hints.ai_flags = AI_NUMERICHOST;
+    error = getaddrinfo(info->ip_addr_v6, NULL, &hints, &res);
+
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s %s>", 
+                     info->ip_addr_v6,
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa6))) &&
+                           (res->ai_family == AF_INET6),
+                           "IPv6 IP address");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_canonname), 
+                           "IPv6 IP address name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv6 IP address one result");
+        // Don't free the result, use it in the next tests
+    } else {
+        diag_sprintf(buffer,"IPv6 IP address: error %s", gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+
+    // Reverse lookup the IPv6 address, expect the FQDN hostname
+    error = getnameinfo(res->ai_addr,res->ai_addrlen,
+                       host, hostlen, NULL, 0, 0);
+    if (error == EAI_NONE) {
+        diag_sprintf(buffer, "IPv6 Reverse lookup FDQN %s: Result %s",
+                    info->ip_addr_v6,
+                    host);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, host)), 
+                           "IPv6 Reverse lookup FQDN");
+    } else {
+        diag_sprintf(buffer,"IPv6 Reverse lookup FQDN: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+    // Reverse lookup the IPv6 address, expect just the hostname part
+    error = getnameinfo(res->ai_addr,res->ai_addrlen,
+                       host, hostlen, NULL, 0, NI_NOFQDN);
+    if (error == EAI_NONE) {
+        diag_sprintf(buffer, "IPv6 Reverse lookup hostname part %s: Result %s",
+                    info->ip_addr_v6,
+                    host);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == strcmp(info->hostname_v6, host)), 
+                           "IPv6 Reverse lookup hostname part");
+    } else {
+        diag_sprintf(buffer,"IPv6 Reverse lookup hostname part: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+    freeaddrinfo(res);
+
+    // Setup a domainname. We now don't have to use fully qualified
+    // domain names
+    setdomainname(info->domain_name, strlen(info->domain_name));
+    getdomainname(dn, sizeof(dn));
+    CYG_TEST_PASS_FAIL(0 == strcmp(info->domain_name, dn), 
+                       "{get|set}domainname");
+
+    // Lookup the IPv6 FQDN hostname to make sure it still works
+    hints.ai_flags = AI_CANONNAME;
+    error = getaddrinfo(name, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     name,
+                     res->ai_canonname, 
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa6))) &&
+                           (res->ai_family == AF_INET6),
+                           "IPv6 FQDN hostname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)), 
+                           "IPv6 FQDN hostname name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv6 FQDN hostname one result");
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv6 FQDN hostname: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+
+    // Now the host name without the domain name
+    error = getaddrinfo(info->hostname_v6, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+        getnameinfo(res->ai_addr, res->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     info->hostname_v6,
+                     res->ai_canonname, 
+                     familytoa(res->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6, 
+                                        (void*)res->ai_addr,
+                                        sizeof(sa6))) &&
+                           (res->ai_family == AF_INET6),
+                           "IPv6 hostname address");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, res->ai_canonname)), 
+                           "IPv6 hostname name");
+        CYG_TEST_PASS_FAIL((NULL == res->ai_next),
+                           "IPv6 hostname one result");
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv6 hostname: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+
+    // Check if we have the information to do tests which result in two
+    // answers, an AF_INET and an AF_INET6
+    if (!info->hostname_v46 || !info->cname_v46 || 
+        !info->ip_addr_v46_v4 || !info->ip_addr_v46_v6 ) {
+        return;
+    }
+    setdomainname(NULL,0);
+    
+    strcpy(name,info->hostname_v46);
+    strcat(name,".");
+    strcat(name,info->domain_name);
+    strcpy(cname,info->cname_v46);
+    strcat(cname,".");
+    strcat(cname,info->domain_name);
+
+    inet_aton(info->ip_addr_v46_v4, &addr);
+    memset(&sa4,0,sizeof(sa4));
+    memcpy(&sa4.sin_addr, &addr, sizeof(addr));
+    sa4.sin_family=AF_INET;
+    sa4.sin_len = sizeof(sa4);
+    
+    memset(&sa6,0,sizeof(sa6));
+    sa6.sin6_family = AF_INET6;
+    sa6.sin6_len = sizeof(sa6);
+    inet_pton(AF_INET6, info->ip_addr_v46_v6, (void *)&sa6.sin6_addr);
+    
+    // Lookup the IPv4 and IPv6 FQDN hostname 
+    error = getaddrinfo(name, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+#ifdef CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET6
+        ai6 = res;
+        ai4 = res->ai_next;
+        CYG_TEST_PASS_FAIL((NULL != ai6->ai_next),
+                           "IPv6 FQDN hostname not one result");
+        CYG_TEST_PASS_FAIL((NULL == ai4->ai_next),
+                           "IPv4 & IPv6 FQDN hostname two results");
+#else
+        ai4 = res;
+        ai6 = res->ai_next;
+        CYG_TEST_PASS_FAIL((NULL != ai4->ai_next),
+                           "IPv6 FQDN hostname not one result");
+        CYG_TEST_PASS_FAIL((NULL == ai6->ai_next),
+                           "IPv4 & IPv6 FQDN hostname two results");
+#endif
+        getnameinfo(ai4->ai_addr, ai4->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     name,
+                     ai4->ai_canonname, 
+                     familytoa(ai4->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4, 
+                                        (void*)ai4->ai_addr,
+                                        sizeof(sa4))) &&
+                           (ai4->ai_family == AF_INET),
+                           "IPv4 & IPv6 FQDN hostname address IPv4");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, ai4->ai_canonname)), 
+                           "IPv4 & IPv6 FQDN hostname name");
+        getnameinfo(ai6->ai_addr, ai6->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s %s>", 
+                     name,
+                     familytoa(ai6->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6, 
+                                        (void*)ai6->ai_addr,
+                                        sizeof(sa6))) &&
+                           (ai6->ai_family == AF_INET6),
+                           "IPv4 & IPv6 FQDN hostname address IPv6");
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv4 & IPv6 FQDN hostname: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+    
+    // Lookup the IPv4 and IPv6 FQDN cname 
+    error = getaddrinfo(cname, NULL, &hints, &res);
+    
+    if (error == EAI_NONE) {
+#ifdef CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET6
+        ai6 = res;
+        ai4 = res->ai_next;
+        CYG_TEST_PASS_FAIL((NULL != ai6->ai_next),
+                           "IPv6 FQDN hostname not one result");
+        CYG_TEST_PASS_FAIL((NULL == ai4->ai_next),
+                           "IPv4 & IPv6 FQDN hostname two results");
+#else
+        ai4 = res;
+        ai6 = res->ai_next;
+        CYG_TEST_PASS_FAIL((NULL != ai4->ai_next),
+                           "IPv6 FQDN hostname not one result");
+        CYG_TEST_PASS_FAIL((NULL == ai6->ai_next),
+                           "IPv4 & IPv6 FQDN hostname two results");
+#endif
+        getnameinfo(ai4->ai_addr, ai4->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s is %s %s>", 
+                     cname,
+                     ai4->ai_canonname, 
+                     familytoa(ai4->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4, 
+                                        (void*)ai4->ai_addr,
+                                        sizeof(sa4))) &&
+                           (ai4->ai_family == AF_INET),
+                           "IPv4 & IPv6 FQDN cname address IPv4");
+        CYG_TEST_PASS_FAIL((0 == strcmp(name, ai4->ai_canonname)), 
+                           "IPv4 & IPv6 FQDN cname name");
+        getnameinfo(ai6->ai_addr, ai6->ai_addrlen, 
+                    buff, sizeof(buff),
+                    NULL,0,NI_NUMERICHOST);
+        diag_sprintf(buffer,"Lookup %s: Result <%s %s>", 
+                     cname,
+                     familytoa(ai6->ai_family),
+                     buff);
+        CYG_TEST_INFO(buffer);
+        CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6, 
+                                        (void*)ai6->ai_addr,
+                                        sizeof(sa6))) &&
+                           (ai6->ai_family == AF_INET6),
+                           "IPv4 & IPv6 FQDN cname address IPv6");
+        freeaddrinfo(res);
+    } else {
+        diag_sprintf(buffer,"IPv4 & IPv6 FQDN cname: error %s", 
+                     gai_strerror(error));
+        CYG_TEST_FAIL(buffer);
+    }
+#endif
+}
+
+void
+dns_test_thread(cyg_addrword_t p)
+{
     int i;
 
     CYG_TEST_INIT();
@@ -89,81 +828,11 @@ dns_test(cyg_addrword_t p)
     init_all_network_interfaces();
 
     CYG_TEST_INFO("Starting dns1 test");
-
-    setdomainname(NULL,0);
     
-    for (i=0; i<2; i++) {
-        /* Expect _LOOKUP_IP as the answer. This is a CNAME lookup */
-        inet_aton(_LOOKUP_IP, &addr);
-        hent = gethostbyname(_LOOKUP_FQDN);
-        if (hent != NULL) {
-            diag_printf("PASS:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
-            if (0 != memcmp((void*)&addr, (void*)(hent->h_addr), sizeof(struct in_addr))) {
-                diag_printf("FAIL:<expected " _LOOKUP_FQDN " to be " _LOOKUP_IP ">\n");
-            }
-            break;
-        } else {
-            diag_printf("FAIL:<Asked for " _LOOKUP_FQDN ". No answer: %s>\n", hstrerror(h_errno));
-            CYG_TEST_INFO("Retrying with explicit DNS server");
-            CYG_TEST_INFO("Connecting to DNS at " _DNS_IP);
-            inet_aton(_DNS_IP, &addr);
-            CYG_TEST_CHECK(cyg_dns_res_init(&addr) == 0, "Failed to initialize resolver");
-        }
-    }
-
-    /* Reverse lookup the _LOOKUP_IP addres, expect _LOOKUP_FQDN
-       as the answer. */
-    hent = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
-    if (hent != NULL) {
-        diag_printf("PASS:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
-        if (0 != strcmp(_LOOKUP_FQDN, hent->h_name)) {
-          diag_printf("FAIL:<expected " _LOOKUP_IP " to be " _LOOKUP_FQDN ">\n");
-        }
-    } else {
-        diag_printf("FAIL:<Asked for " _LOOKUP_IP ". No answer: %s>\n", hstrerror(h_errno));
+    for (i = 0; i < NELEM(test_info); i++) {
+      dns_test(&test_info[i]);
     }
- 
-    /* This does not require a DNS lookup. Just turn the value into
-       binary */
-    hent = gethostbyname(_LOOKUP_IP);
-    if (hent != NULL) {
-        diag_printf("PASS:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
-    } else {
-        diag_printf("FAIL:<Asked for " _LOOKUP_IP ". No answer: %s>\n", hstrerror(h_errno));
-    }
- 
-    /* Reverse lookup an address this is not in the server. Expect a
-       NULL back */
-    inet_aton(_LOOKUP_IP_BAD, &addr);
-    hent = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
-    if (hent != NULL) {
-        diag_printf("FAIL:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
-    } else {
-        diag_printf("PASS:<Asked for bad IP " _LOOKUP_IP_BAD ". No answer: %s>\n", hstrerror(h_errno));
-    }
-
-    /* Setup a domainname. We now don't have to use fully qualified
-       domain names */
-    setdomainname(_LOOKUP_DOMAINNAME, sizeof(_LOOKUP_DOMAINNAME));
-    getdomainname(dn, sizeof(dn));
-    diag_printf("INFO:<Domainname is now %s>\n", dn);
-
-    /* Make sure FQDN still work */
-    hent = gethostbyname(_LOOKUP_FQDN);
-    if (hent != NULL) {
-        diag_printf("PASS:<%s is %s>\n", hent->h_name, inet_ntoa(*(struct in_addr *)hent->h_addr));
-    } else {
-        diag_printf("FAIL:<Asked for " _LOOKUP_FQDN ". No answer: %s>\n", hstrerror(h_errno));
-    }
-
-    /* Now just the hostname */
-    hent = gethostbyname(_LOOKUP_HOSTNAME);
-    if (hent != NULL) {
-        diag_printf("PASS:<%s is %s>\n", _LOOKUP_HOSTNAME, inet_ntoa(*(struct in_addr *)hent->h_addr));
-    } else {
-        diag_printf("FAIL:<Asked for " _LOOKUP_HOSTNAME ". No answer: %s>\n", hstrerror(h_errno));
-    }
-
+    
     CYG_TEST_FINISH("dns1 test completed");
 }
 
@@ -172,7 +841,7 @@ cyg_start(void)
 {
     // Create a main thread, so we can run the scheduler and have time 'pass'
     cyg_thread_create(10,                // Priority - just a number
-                      dns_test,          // entry
+                      dns_test_thread,   // entry
                       0,                 // entry parameter
                       "DNS test",        // Name
                       &stack[0],         // Stack