This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
getifaddrs
- From: Momchil Velikov <velco at fadata dot bg>
- To: libc-alpha at sources dot redhat dot com
- Date: 25 Nov 2002 01:46:39 +0200
- Subject: getifaddrs
Functions ``__ifreq'' and ``getifaddrs'' were changed to support
``struct sockaddr'' structures of arbitrary size.
The fields ``ifa_netmask'' and ``ifa_broadaddr'' are set to NULL, if
the coresponding ``ioctl'' fails, per BSD manual pages.
On NetBSD these ioctls fail for the large number of down interfaces,
as a result no information can be obtained for up interfaces.
~velco
diff -rudpN libc/tags/initial/inet/test-ifaddrs.c libc/trunk/inet/test-ifaddrs.c
--- libc/tags/initial/inet/test-ifaddrs.c Sun Nov 24 23:51:38 2002
+++ libc/trunk/inet/test-ifaddrs.c Sun Nov 24 23:40:53 2002
@@ -50,6 +50,9 @@ Name Flags Address N
char abuf[64], mbuf[64], dbuf[64];
inline const char *addr_string (struct sockaddr *sa, char *buf)
{
+ if (sa == NULL)
+ return "<none>";
+
switch (sa->sa_family)
{
case AF_INET:
@@ -60,6 +63,10 @@ Name Flags Address N
return inet_ntop (AF_INET6,
&((struct sockaddr_in6 *) sa)->sin6_addr,
buf, sizeof abuf);
+#ifdef AF_LINK
+ case AF_LINK:
+ return "<link>";
+#endif
case AF_UNSPEC:
return "---";
default:
diff -rudpN libc/tags/initial/sysdeps/gnu/ifaddrs.c libc/trunk/sysdeps/gnu/ifaddrs.c
--- libc/tags/initial/sysdeps/gnu/ifaddrs.c Sun Nov 24 23:46:45 2002
+++ libc/trunk/sysdeps/gnu/ifaddrs.c Sun Nov 24 23:36:20 2002
@@ -31,13 +31,14 @@
/* Create a linked list of `struct ifaddrs' structures, one for each
network interface on the host machine. If successful, store the
- list in *IFAP and return 0. On errors, return -1 and set `errno'. */
+ list in *IFAP and return 0. On errors, return -1 and set
+ `errno'. */
int
getifaddrs (struct ifaddrs **ifap)
{
- /* This implementation handles only IPv4 interfaces.
- The various ioctls below will only work on an AF_INET socket.
- Some different mechanism entirely must be used for IPv6. */
+ /* This implementation handles only IPv4 interfaces. The various
+ ioctls below will only work on an AF_INET socket. Some different
+ mechanism entirely must be used for IPv6. */
int fd = __socket (AF_INET, SOCK_DGRAM, 0);
struct ifreq *ifreqs;
int nifs;
@@ -46,14 +47,15 @@ getifaddrs (struct ifaddrs **ifap)
return -1;
__ifreq (&ifreqs, &nifs, fd);
- if (ifreqs == NULL) /* XXX doesn't distinguish error vs none */
+ if (ifreqs == NULL) /* XXX doesn't distinguish error vs none */
{
__close (fd);
return -1;
}
- /* Now we have the list of interfaces and each one's address.
- Put it into the expected format and fill in the remaining details. */
+ /* Now we have the list of interfaces and each one's address. Put
+ it into the expected format and fill in the remaining
+ details. */
if (nifs == 0)
*ifap = NULL;
else
@@ -61,10 +63,12 @@ getifaddrs (struct ifaddrs **ifap)
struct
{
struct ifaddrs ia;
- struct sockaddr addr, netmask, broadaddr;
+ struct sockaddr_storage addr;
+ struct sockaddr_storage netmask;
+ struct sockaddr_storage broadaddr;
char name[IF_NAMESIZE];
} *storage;
- struct ifreq *ifr;
+ struct ifreq *ifr, *next;
int i;
storage = malloc (nifs * sizeof storage[0]);
@@ -79,51 +83,69 @@ getifaddrs (struct ifaddrs **ifap)
ifr = ifreqs;
do
{
- /* Fill in all pointers to the storage we've already allocated. */
- storage[i].ia.ifa_next = &storage[i + 1].ia;
- storage[i].ia.ifa_addr = &storage[i].addr;
- storage[i].ia.ifa_netmask = &storage[i].netmask;
- storage[i].ia.ifa_broadaddr = &storage[i].broadaddr; /* & dstaddr */
+ next = __if_nextreq (ifr);
- /* Now copy the information we already have from SIOCGIFCONF. */
- storage[i].ia.ifa_name = strncpy (storage[i].name, ifr->ifr_name,
- sizeof storage[i].name);
- storage[i].addr = ifr->ifr_addr;
+ /* Fill in all pointers to the storage we've already
+ allocated. */
+ storage[i].ia.ifa_next = &storage [i + 1].ia;
+ storage[i].ia.ifa_addr = (struct sockaddr *) &storage [i].addr;
+ storage[i].ia.ifa_netmask =
+ (struct sockaddr *) &storage [i].netmask;
+ storage[i].ia.ifa_broadaddr =
+ (struct scokaddr *) &storage [i].broadaddr; /* & dstaddr */
+
+ /* Now copy the information we already have from
+ SIOCGIFCONF. */
+ storage [i].ia.ifa_name =
+ strncpy (storage [i].name, ifr->ifr_name,
+ sizeof storage [i].name);
+
+ memcpy (&storage [i].addr, &ifr->ifr_addr,
+ ifr->ifr_addr.sa_len);
/* The SIOCGIFCONF call filled in only the name and address.
- Now we must also ask for the other information we need. */
+ Now we must also ask for the other information we
+ need. */
if (__ioctl (fd, SIOCGIFFLAGS, ifr) < 0)
break;
storage[i].ia.ifa_flags = ifr->ifr_flags;
- ifr->ifr_addr = storage[i].addr;
-
+ memcpy (&ifr->ifr_addr, storage [i].ia.ifa_addr,
+ storage [i].ia.ifa_addr->sa_len);
+
if (__ioctl (fd, SIOCGIFNETMASK, ifr) < 0)
- break;
- storage[i].netmask = ifr->ifr_netmask;
-
+ storage [i].ia.ifa_netmask = NULL;
+ else
+ memcpy (&storage [i].netmask, &ifr->ifr_netmask,
+ ifr->ifr_netmask.sa_len);
+
if (ifr->ifr_flags & IFF_BROADCAST)
{
- ifr->ifr_addr = storage[i].addr;
+ memcpy (&ifr->ifr_addr, storage [i].ia.ifa_addr,
+ storage [i].ia.ifa_addr->sa_len);
+
if (__ioctl (fd, SIOCGIFBRDADDR, ifr) < 0)
- break;
- storage[i].broadaddr = ifr->ifr_broadaddr;
+ storage [i].ia.ifa_broadaddr = NULL;
+ else
+ memcpy (&storage [i].broadaddr, &ifr->ifr_broadaddr,
+ ifr->ifr_broadaddr.sa_len);
}
else if (ifr->ifr_flags & IFF_POINTOPOINT)
{
- ifr->ifr_addr = storage[i].addr;
+ memcpy (&ifr->ifr_addr, storage [i].ia.ifa_addr,
+ storage [i].ia.ifa_addr->sa_len);
+
if (__ioctl (fd, SIOCGIFDSTADDR, ifr) < 0)
- break;
- storage[i].broadaddr = ifr->ifr_dstaddr;
+ storage [i].ia.ifa_broadaddr = NULL;
+ else
+ memcpy (&storage [i].broadaddr, &ifr->ifr_dstaddr,
+ ifr->ifr_dstaddr.sa_len);
}
- else
- /* Just 'cause. */
- memset (&storage[i].broadaddr, 0, sizeof storage[i].broadaddr);
storage[i].ia.ifa_data = NULL; /* Nothing here for now. */
- ifr = __if_nextreq (ifr);
+ ifr = next;
} while (++i < nifs);
if (i < nifs) /* Broke out early on error. */
{
diff -rudpN libc/tags/initial/sysdeps/generic/ifreq.h libc/trunk/sysdeps/generic/ifreq.h
--- libc/tags/initial/sysdeps/generic/ifreq.h Sun Nov 24 23:49:30 2002
+++ libc/trunk/sysdeps/generic/ifreq.h Sun Nov 24 23:39:00 2002
@@ -24,12 +24,22 @@
#include <sys/socket.h>
#include <sys/ioctl.h>
+static inline struct ifreq *
+__if_nextreq (struct ifreq *ifr)
+{
+ return (struct ifreq *)
+ ((char *) ifr + IFNAMSIZ
+ + (__builtin_expect (ifr->ifr_addr.sa_len <= sizeof (struct sockaddr), 1)
+ ? sizeof (struct sockaddr)
+ : ifr->ifr_addr.sa_len));
+}
static inline void
__ifreq (struct ifreq **ifreqs, int *num_ifs, int sockfd)
{
int fd = sockfd;
struct ifconf ifc;
+ struct ifreq *ifr, *fence;
int rq_len;
int nifs;
# define RQ_IFS 4
@@ -63,22 +73,17 @@ __ifreq (struct ifreq **ifreqs, int *num
}
while (rq_len < sizeof (struct ifreq) + ifc.ifc_len);
- nifs = ifc.ifc_len / sizeof (struct ifreq);
+ nifs = 0;
+ fence = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = (struct ifreq *) ifc.ifc_buf; ifr < fence; nifs++)
+ ifr = __if_nextreq (ifr);
if (fd != sockfd)
__close (fd);
*num_ifs = nifs;
- *ifreqs = realloc (ifc.ifc_buf, nifs * sizeof (struct ifreq));
-}
-
-
-static inline struct ifreq *
-__if_nextreq (struct ifreq *ifr)
-{
- return ifr + 1;
+ *ifreqs = realloc (ifc.ifc_buf, ifc.ifc_len);
}
-
static inline void
__if_freereq (struct ifreq *ifreqs, int num_ifs)