Revert "Revert "Add NETLINK_ROUTE processing to the netlink client code, so that Ethernet""

This reverts commit 1d504eeb50d980c222572629383bb76315f32ca0.

Conflicts:

	libsysutils/src/NetlinkEvent.cpp

Bring back the changes from Stan Chesnutt regarding adding NETLINK_ROUTE
processing.  The original commit message description was:

    Add NETLINK_ROUTE processing to the netlink client code, so that Ethernet
    physical-layer up/down events can be tracked.  Upper layers will use these
    events to enable/disable Ethernet connectivity.

The original change was reverted due to an incompatiblity with Motorola's
ril.so binary.  I'll submit a patch to workaround that incompatiblity
separately.

Change-Id: I4e97ac98833b10543e654c63ecae3b9b8c7db44f
Signed-off-by: Mike J. Chen <mjchen@google.com>
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index c8d3b1f..65cfb4e 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -19,12 +19,20 @@
 #define LOG_TAG "NetlinkEvent"
 #include <cutils/log.h>
 
+#include <sysutils/NetlinkListener.h>
 #include <sysutils/NetlinkEvent.h>
 
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/rtnetlink.h>
+#include <linux/if.h>
+
 const int NetlinkEvent::NlActionUnknown = 0;
 const int NetlinkEvent::NlActionAdd = 1;
 const int NetlinkEvent::NlActionRemove = 2;
 const int NetlinkEvent::NlActionChange = 3;
+const int NetlinkEvent::NlActionLinkUp = 4;
+const int NetlinkEvent::NlActionLinkDown = 5;
 
 NetlinkEvent::NetlinkEvent() {
     mAction = NlActionUnknown;
@@ -56,6 +64,51 @@
     }
 }
 
+/*
+ * Parse an binary message from a NETLINK_ROUTE netlink socket.
+ */
+bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
+    size_t sz = size;
+    struct nlmsghdr *nh = (struct nlmsghdr *) buffer;
+
+    while (NLMSG_OK(nh, sz) && (nh->nlmsg_type != NLMSG_DONE)) {
+        if (nh->nlmsg_type == RTM_NEWLINK) {
+            int len = nh->nlmsg_len - sizeof(*nh);
+            struct ifinfomsg *ifi;
+
+            if (sizeof(*ifi) <= (size_t) len) {
+                ifi = (ifinfomsg *)NLMSG_DATA(nh);
+
+                if ((ifi->ifi_flags & IFF_LOOPBACK) == 0) {
+                    struct rtattr *rta = (struct rtattr *)
+                      ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
+                    len = NLMSG_PAYLOAD(nh, sizeof(*ifi));
+
+                    while(RTA_OK(rta, len)) {
+                        switch(rta->rta_type) {
+                        case IFLA_IFNAME:
+                            char buffer[16 + IFNAMSIZ];
+                            snprintf(buffer, sizeof(buffer), "INTERFACE=%s",
+                                     (char *) RTA_DATA(rta));
+                            mParams[0] = strdup(buffer);
+                            mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?
+                              NlActionLinkUp : NlActionLinkDown;
+                            mSubsystem = strdup("net");
+                            break;
+                        }
+
+                        rta = RTA_NEXT(rta, len);
+                    }
+                }
+            }
+        }
+
+        nh = NLMSG_NEXT(nh, size);
+    }
+
+    return true;
+}
+
 /* If the string between 'str' and 'end' begins with 'prefixlen' characters
  * from the 'prefix' array, then return 'str + prefixlen', otherwise return
  * NULL.
@@ -76,9 +129,13 @@
 #define HAS_CONST_PREFIX(str,end,prefix)  has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
 
 
-bool NetlinkEvent::decode(char *buffer, int size) {
-    const char *s = buffer;
-    const char *end;
+/*
+ * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT
+ * netlink socket.
+ */
+bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {
+    char *s = buffer;
+    char *end;
     int param_idx = 0;
     int i;
     int first = 1;
@@ -123,6 +180,14 @@
     return true;
 }
 
+bool NetlinkEvent::decode(char *buffer, int size, int format) {
+  if (format == NetlinkListener::NETLINK_FORMAT_BINARY) {
+    return parseBinaryNetlinkMessage(buffer, size);
+  } else {
+    return parseAsciiNetlinkMessage(buffer, size);
+  }
+}
+
 const char *NetlinkEvent::findParam(const char *paramName) {
     size_t len = strlen(paramName);
     for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {