Add getifaddrs support and a test.
authorRonald G. Minnich <rminnich@gmail.com>
Wed, 20 Apr 2016 18:09:26 +0000 (11:09 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 20 Apr 2016 23:29:12 +0000 (16:29 -0700)
Per the man page, we don't have to fill out addr, mask, and
broadaddr, and this is such a dump API that we don't.

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
[closed net and addr on error]
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tests/getifaddrs.c [new file with mode: 0644]
user/iplib/ifaddr.c [new file with mode: 0644]

diff --git a/tests/getifaddrs.c b/tests/getifaddrs.c
new file mode 100644 (file)
index 0000000..c8e2277
--- /dev/null
@@ -0,0 +1,45 @@
+/* This file is part of the UCB release of Plan 9. It is subject to the license
+ * terms in the LICENSE file found in the top-level directory of this
+ * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
+ * part of the UCB release of Plan 9, including this file, may be copied,
+ * modified, propagated, or distributed except according to the terms contained
+ * in the LICENSE file. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <parlib/parlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <iplib/iplib.h>
+#include <iplib/icmp.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <parlib/spinlock.h>
+#include <parlib/timing.h>
+#include <parlib/tsc-compat.h>
+#include <parlib/printf-ext.h>
+#include <benchutil/alarm.h>
+#include <ndblib/ndb.h>
+#include <ifaddrs.h>
+
+int main(int argc, char **argv)
+{
+       int i, naddr, o;
+       uint8_t *cp;
+       struct ifaddrs *ifa;
+
+       naddr = getifaddrs(&ifa);
+
+       for (naddr = 0; ifa; ifa = ifa->ifa_next, naddr++) {
+               printf("%s: ", ifa->ifa_name);
+               cp = ifa->ifa_data;
+               for (o = 0; o < 6; o++) {
+                       printf("%02x", cp[o]);
+                       if (o < 5)
+                               printf(":");
+               }
+               printf("\n");
+       }
+       printf("%d ifaddrs\n", naddr);
+       freeifaddrs(ifa);
+}
diff --git a/user/iplib/ifaddr.c b/user/iplib/ifaddr.c
new file mode 100644 (file)
index 0000000..f011b83
--- /dev/null
@@ -0,0 +1,90 @@
+#define _LARGEFILE64_SOURCE /* needed to use lseek64 */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <parlib/arch/arch.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dirent.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <ifaddrs.h>
+#include <ros/syscall.h>
+#include <ros/fs.h>
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+       DIR *net;
+       struct dirent *d;
+       int addr;
+       /* 6 is known everywhere, defined nowhere. So is 6 * 2 */
+       char etheraddr[12];
+       struct ifaddrs *ifa = NULL;
+       uint8_t *v;
+       int i;
+
+       *ifap = NULL;
+
+       net = opendir("/net");
+       if (net == NULL) {
+               fprintf(stderr, "/net: %r");
+               return -1;
+       }
+
+       for (d = readdir(net); d; d = readdir(net)) {
+               /*
+                * For now we only do ethernet MACs.  It's easy to
+                * change later: just get rid of the following 2
+                * lines.
+                */
+               if (strncmp(d->d_name, "ether", 5))
+                       continue;
+               sprintf(etheraddr, "/net/%s/addr", d->d_name);
+               addr = open(etheraddr, O_RDONLY);
+               if (addr < 0)
+                       continue;
+               if (read(addr, etheraddr, sizeof(etheraddr)) < sizeof(etheraddr)) {
+                       fprintf(stderr, "Read addr from %s: %r", d->d_name);
+                       close(addr);
+                       continue;
+               }
+               /* getifaddrds is a stupid design as it only admits of
+                * one address per interface.  Don't even bother
+                * filling in ifa_{addr,netmask}. They're allowed to
+                * be NULL.  Broadaddr need be set IFF a bit is set
+                * in the flags field. We don't set either one.
+                */
+               if (!ifa) {
+                       ifa = calloc(sizeof(*ifa), 1);
+                       *ifap = ifa;
+               } else {
+                       ifa->ifa_next = calloc(sizeof(*ifa), 1);
+                       ifa = ifa->ifa_next;
+               }
+               ifa->ifa_name = strdup(d->d_name);
+               /*
+                * 6 is known everywhere, not defined anywhere.  oh
+                * yeah, another binary thing. 1976 all over again.
+                */
+               v = malloc(6);
+               for (i = 0; i < 6; i++)
+                       sscanf(&etheraddr[i*2], "%02x", &v[i]);
+               ifa->ifa_data = v;
+               close(addr);
+       }
+       closedir(net);
+       return 0;
+}
+
+void freeifaddrs(struct ifaddrs *ifa)
+{
+       for (; ifa; ifa = ifa->ifa_next)
+               free(ifa);
+}