Add NETLINK_ROUTE socket creation and event propagation

Change-Id: I8cc8788661640600bceadeba8169e239bba98dec
diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp
index 800c86c..0632293 100644
--- a/NetlinkHandler.cpp
+++ b/NetlinkHandler.cpp
@@ -28,8 +28,9 @@
 #include "NetlinkManager.h"
 #include "ResponseCode.h"
 
-NetlinkHandler::NetlinkHandler(NetlinkManager *nm, int listenerSocket) :
-                NetlinkListener(listenerSocket) {
+NetlinkHandler::NetlinkHandler(NetlinkManager *nm, int listenerSocket,
+                               int format) :
+                        NetlinkListener(listenerSocket, format) {
     mNm = nm;
 }
 
@@ -50,18 +51,22 @@
         LOGW("No subsystem found in netlink event");
         return;
     }
+
     if (!strcmp(subsys, "net")) {
         int action = evt->getAction();
+        const char *iface = evt->findParam("INTERFACE");
+
         if (action == evt->NlActionAdd) {
-            const char *iface = evt->findParam("INTERFACE");
             notifyInterfaceAdded(iface);
         } else if (action == evt->NlActionRemove) {
-            const char *iface = evt->findParam("INTERFACE");
             notifyInterfaceRemoved(iface);
         } else if (action == evt->NlActionChange) {
             evt->dump();
-            const char *iface = evt->findParam("INTERFACE");
             notifyInterfaceChanged("nana", true);
+        } else if (action == evt->NlActionLinkUp) {
+            notifyInterfaceLinkChanged(iface, true);
+        } else if (action == evt->NlActionLinkDown) {
+            notifyInterfaceLinkChanged(iface, false);
         }
     }
 }
@@ -84,7 +89,17 @@
 
 void NetlinkHandler::notifyInterfaceChanged(const char *name, bool isUp) {
     char msg[255];
-    snprintf(msg, sizeof(msg), "Iface is %s %s", (isUp ? "up" : "down"), name);
+    snprintf(msg, sizeof(msg), "Iface changed %s %s", name,
+             (isUp ? "up" : "down"));
+
+    mNm->getBroadcaster()->sendBroadcast(ResponseCode::InterfaceChange,
+            msg, false);
+}
+
+void NetlinkHandler::notifyInterfaceLinkChanged(const char *name, bool isUp) {
+    char msg[255];
+    snprintf(msg, sizeof(msg), "Iface linkstatus %s %s", name,
+             (isUp ? "up" : "down"));
 
     mNm->getBroadcaster()->sendBroadcast(ResponseCode::InterfaceChange,
             msg, false);
diff --git a/NetlinkHandler.h b/NetlinkHandler.h
index 8b2498f..492d6b1 100644
--- a/NetlinkHandler.h
+++ b/NetlinkHandler.h
@@ -24,7 +24,7 @@
     NetlinkManager *mNm;
 
 public:
-    NetlinkHandler(NetlinkManager *nm, int listenerSocket);
+    NetlinkHandler(NetlinkManager *nm, int listenerSocket, int format);
     virtual ~NetlinkHandler();
 
     int start(void);
@@ -36,5 +36,6 @@
     void notifyInterfaceAdded(const char *name);
     void notifyInterfaceRemoved(const char *name);
     void notifyInterfaceChanged(const char *name, bool isUp);
+    void notifyInterfaceLinkChanged(const char *name, bool isUp);
 };
 #endif
diff --git a/NetlinkManager.cpp b/NetlinkManager.cpp
index 634fd4d..fabf011 100644
--- a/NetlinkManager.cpp
+++ b/NetlinkManager.cpp
@@ -24,6 +24,7 @@
 #include <sys/un.h>
 
 #include <linux/netlink.h>
+#include <linux/rtnetlink.h>
 
 #define LOG_TAG "Netd"
 
@@ -47,49 +48,81 @@
 NetlinkManager::~NetlinkManager() {
 }
 
-int NetlinkManager::start() {
+NetlinkHandler *NetlinkManager::setupSocket(int *sock, int socketType,
+    int groups, int format) {
+
     struct sockaddr_nl nladdr;
     int sz = 64 * 1024;
 
     memset(&nladdr, 0, sizeof(nladdr));
     nladdr.nl_family = AF_NETLINK;
     nladdr.nl_pid = getpid();
-    nladdr.nl_groups = 0xffffffff;
+    nladdr.nl_groups = groups;
 
-    if ((mSock = socket(PF_NETLINK,
-                        SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) {
-        LOGE("Unable to create uevent socket: %s", strerror(errno));
-        return -1;
+    if ((*sock = socket(PF_NETLINK, SOCK_DGRAM, socketType)) < 0) {
+        LOGE("Unable to create netlink socket: %s", strerror(errno));
+        return NULL;
     }
 
-    if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
-        LOGE("Unable to set uevent socket options: %s", strerror(errno));
-        return -1;
+    if (setsockopt(*sock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) {
+        LOGE("Unable to set netlink socket options: %s", strerror(errno));
+        close(*sock);
+        return NULL;
     }
 
-    if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
-        LOGE("Unable to bind uevent socket: %s", strerror(errno));
-        return -1;
+    if (bind(*sock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
+        LOGE("Unable to bind netlink socket: %s", strerror(errno));
+        close(*sock);
+        return NULL;
     }
 
-    mHandler = new NetlinkHandler(this, mSock);
-    if (mHandler->start()) {
+    NetlinkHandler *handler = new NetlinkHandler(this, *sock, format);
+    if (handler->start()) {
         LOGE("Unable to start NetlinkHandler: %s", strerror(errno));
+        close(*sock);
+        return NULL;
+    }
+
+    return handler;
+}
+
+int NetlinkManager::start() {
+    if ((mUeventHandler = setupSocket(&mUeventSock, NETLINK_KOBJECT_UEVENT,
+         0xffffffff, NetlinkListener::NETLINK_FORMAT_ASCII)) == NULL) {
+        return -1;
+    }
+
+    if ((mRouteHandler = setupSocket(&mRouteSock, NETLINK_ROUTE, RTMGRP_LINK,
+         NetlinkListener::NETLINK_FORMAT_BINARY)) == NULL) {
         return -1;
     }
     return 0;
 }
 
 int NetlinkManager::stop() {
-    if (mHandler->stop()) {
-        LOGE("Unable to stop NetlinkHandler: %s", strerror(errno));
-        return -1;
+    int status = 0;
+
+    if (mUeventHandler->stop()) {
+        LOGE("Unable to stop uevent NetlinkHandler: %s", strerror(errno));
+        status = -1;
     }
-    delete mHandler;
-    mHandler = NULL;
 
-    close(mSock);
-    mSock = -1;
+    delete mUeventHandler;
+    mUeventHandler = NULL;
 
-    return 0;
+    close(mUeventSock);
+    mUeventSock = -1;
+
+    if (mRouteHandler->stop()) {
+        LOGE("Unable to stop route NetlinkHandler: %s", strerror(errno));
+        status = -1;
+    }
+
+    delete mRouteHandler;
+    mRouteHandler = NULL;
+
+    close(mRouteSock);
+    mRouteSock = -1;
+
+    return status;
 }
diff --git a/NetlinkManager.h b/NetlinkManager.h
index 9c7ba11..ff646f4 100644
--- a/NetlinkManager.h
+++ b/NetlinkManager.h
@@ -28,8 +28,10 @@
 
 private:
     SocketListener       *mBroadcaster;
-    NetlinkHandler       *mHandler;
-    int                  mSock;
+    NetlinkHandler       *mUeventHandler;
+    NetlinkHandler       *mRouteHandler;
+    int                  mUeventSock;
+    int                  mRouteSock;
 
 public:
     virtual ~NetlinkManager();
@@ -44,5 +46,7 @@
 
 private:
     NetlinkManager();
+    NetlinkHandler* setupSocket(int *sock, int socketType, int groups,
+        int format);
 };
 #endif