summaryrefslogtreecommitdiff
path: root/libc/inet/if_index.c
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2006-01-06 04:57:40 +0000
committerMike Frysinger <vapier@gentoo.org>2006-01-06 04:57:40 +0000
commitc47542925c44be2522adb442f268506dee9f34a7 (patch)
treebec955a1c15c5a41ca6c3a6fc3fc3c59f75e0f24 /libc/inet/if_index.c
parentd2d573391d1cb10aa4f9ac4125741810354dd740 (diff)
as weber notes in Bug 99:
if_nameindex doesnt list all of my interfaces! this is because we are still using the old style ioctl(SIOCGIFINDEX) for gathering interface names/indexes. while this code is pretty small, the kernel does not return all interfaces via this method. so we import the new style netlink code from glibc and make it optional so those people who need the full functionality can get it.
Diffstat (limited to 'libc/inet/if_index.c')
-rw-r--r--libc/inet/if_index.c133
1 files changed, 131 insertions, 2 deletions
diff --git a/libc/inet/if_index.c b/libc/inet/if_index.c
index dfddbc0d4..40e46d538 100644
--- a/libc/inet/if_index.c
+++ b/libc/inet/if_index.c
@@ -36,6 +36,8 @@
#include <sys/ioctl.h>
#include <libc-internal.h>
+#include "netlinkaccess.h"
+
extern int __opensock(void) attribute_hidden;
unsigned int
@@ -78,7 +80,9 @@ if_freenameindex (struct if_nameindex *ifn)
}
free (ifn);
}
+hidden_strong_alias(if_freenameindex,__if_freenameindex)
+#if !__ASSUME_NETLINK_SUPPORT
struct if_nameindex *
if_nameindex (void)
{
@@ -157,6 +161,131 @@ if_nameindex (void)
return idx;
#endif
}
+#else
+struct if_nameindex *
+if_nameindex (void)
+{
+ unsigned int nifs = 0;
+ struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
+ struct if_nameindex *idx = NULL;
+ struct netlink_res *nlp;
+
+ if (__netlink_open (&nh) < 0)
+ return NULL;
+
+
+ /* Tell the kernel that we wish to get a list of all
+ active interfaces. Collect all data for every interface. */
+ if (__netlink_request (&nh, RTM_GETLINK) < 0)
+ goto exit_free;
+
+ /* Count the interfaces. */
+ for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
+ {
+ struct nlmsghdr *nlh;
+ size_t size = nlp->size;
+
+ if (nlp->nlh == NULL)
+ continue;
+
+ /* Walk through all entries we got from the kernel and look, which
+ message type they contain. */
+ for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
+ {
+ /* Check if the message is what we want. */
+ if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
+ continue;
+
+ if (nlh->nlmsg_type == NLMSG_DONE)
+ break; /* ok */
+
+ if (nlh->nlmsg_type == RTM_NEWLINK)
+ ++nifs;
+ }
+ }
+
+ idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
+ if (idx == NULL)
+ {
+ nomem:
+ __set_errno (ENOBUFS);
+ goto exit_free;
+ }
+
+ /* Add the interfaces. */
+ nifs = 0;
+ for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
+ {
+ struct nlmsghdr *nlh;
+ size_t size = nlp->size;
+
+ if (nlp->nlh == NULL)
+ continue;
+
+ /* Walk through all entries we got from the kernel and look, which
+ message type they contain. */
+ for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
+ {
+ /* Check if the message is what we want. */
+ if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
+ continue;
+
+ if (nlh->nlmsg_type == NLMSG_DONE)
+ break; /* ok */
+
+ if (nlh->nlmsg_type == RTM_NEWLINK)
+ {
+ struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
+ struct rtattr *rta = IFLA_RTA (ifim);
+ size_t rtasize = IFLA_PAYLOAD (nlh);
+
+ idx[nifs].if_index = ifim->ifi_index;
+
+ while (RTA_OK (rta, rtasize))
+ {
+ char *rta_data = RTA_DATA (rta);
+ size_t rta_payload = RTA_PAYLOAD (rta);
+
+ if (rta->rta_type == IFLA_IFNAME)
+ {
+ idx[nifs].if_name = __strndup (rta_data, rta_payload);
+ if (idx[nifs].if_name == NULL)
+ {
+ idx[nifs].if_index = 0;
+ __if_freenameindex (idx);
+ idx = NULL;
+ goto nomem;
+ }
+ break;
+ }
+
+ rta = RTA_NEXT (rta, rtasize);
+ }
+
+ ++nifs;
+ }
+ }
+ }
+
+ idx[nifs].if_index = 0;
+ idx[nifs].if_name = NULL;
+
+ exit_free:
+ __netlink_free_handle (&nh);
+ __netlink_close (&nh);
+
+ return idx;
+}
+#endif
+hidden_strong_alias(if_nameindex,__if_nameindex)
+
+#if 0
+struct if_nameindex *
+if_nameindex (void)
+{
+ return (if_nameindex_netlink () != NULL ? : if_nameindex_ioctl ());
+}
+#endif
char *
if_indextoname (unsigned int ifindex, char *ifname)
@@ -194,7 +323,7 @@ if_indextoname (unsigned int ifindex, char *ifname)
struct if_nameindex *p;
char *result = NULL;
- idx = if_nameindex();
+ idx = __if_nameindex();
if (idx != NULL)
{
@@ -205,7 +334,7 @@ if_indextoname (unsigned int ifindex, char *ifname)
break;
}
- if_freenameindex (idx);
+ __if_freenameindex (idx);
if (result == NULL)
__set_errno (ENXIO);