Mercurial > ecos
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 {
