ifnet: add getInterfaceLinkState function
authorFerry Huberts <ferry.huberts@pelagic.nl>
Wed, 10 Feb 2016 13:17:59 +0000 (14:17 +0100)
committerFerry Huberts <ferry.huberts@pelagic.nl>
Wed, 10 Feb 2016 13:32:41 +0000 (14:32 +0100)
This Linux-only function queries a network interface to see if it has a
carrier (cable (dis)connected, medium up/down, etc).

Signed-off-by: Ferry Huberts <ferry.huberts@pelagic.nl>
src/ifnet.h
src/unix/ifnet.c

index 3bc1dd7..fa22f17 100644 (file)
@@ -62,6 +62,18 @@ int chk_if_up(struct olsr_if *, int);
 
 int add_hemu_if(struct olsr_if *);
 
+typedef enum {
+  LINKSTATE_UNKNOWN, LINKSTATE_UP, LINKSTATE_DOWN
+} LinkState;
+
+#if defined(__linux__) && !defined(__ANDROID__)
+  LinkState getInterfaceLinkState(const char * iface);
+#else
+  static INLINE LinkState getInterfaceLinkState(__attribute__((unused)) const char * iface) {
+    return LINKSTATE_UNKNOWN;
+  }
+#endif /* defined(__linux__) && !defined(__ANDROID__) */
+
 #endif /* _OLSR_IFNET */
 
 /*
index c1055ec..e475b9d 100644 (file)
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <unistd.h>
+#if defined(__linux__) && !defined(__ANDROID__)
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
+#endif /* defined(__linux__) && !defined(__ANDROID__) */
 
 /**
  * Fix bug in GLIBC, see https://bugzilla.redhat.com/show_bug.cgi?id=635260
@@ -836,6 +840,44 @@ chk_if_up(struct olsr_if *iface, int debuglvl __attribute__ ((unused)))
   return 1;
 }
 
+#if defined(__linux__) && !defined(__ANDROID__)
+LinkState getInterfaceLinkState(const char * iface) {
+  LinkState r = LINKSTATE_UNKNOWN;
+  int fd;
+  struct ethtool_value edata;
+  struct ifreq ifr;
+
+  if (!iface) {
+    return r;
+  }
+
+  memset(&ifr, 0, sizeof(ifr));
+
+  fd = socket(AF_INET, SOCK_DGRAM, 0);
+  if (fd < 0) {
+    return r;
+  }
+
+  edata.cmd = ETHTOOL_GLINK;
+  strcpy(ifr.ifr_name, iface);
+  ifr.ifr_data = (caddr_t) &edata;
+  errno = 0;
+  if (!ioctl(fd, SIOCETHTOOL, &ifr)) {
+    /* ioctl success */
+    r = edata.data ? LINKSTATE_UP : LINKSTATE_DOWN;
+  } else if (errno == EOPNOTSUPP) {
+    /* no kernel support */
+    r = LINKSTATE_UNKNOWN;
+  } else {
+    /* other error */
+    r = LINKSTATE_UNKNOWN;
+  }
+
+  close(fd);
+  return r;
+}
+#endif /* defined(__linux__) && !defined(__ANDROID__) */
+
 /*
  * Local Variables:
  * c-basic-offset: 2