netd: Add Flush out enumerating/configuring interfaces

Signed-off-by: San Mehat <san@google.com>
diff --git a/Android.mk b/Android.mk
index d62d1d0..06af7d7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -28,7 +28,7 @@
                     $(LOCAL_PATH)/../bluetooth/bluez-clean-headers
 
 LOCAL_CFLAGS := 
-LOCAL_SHARED_LIBRARIES := libsysutils libcutils
+LOCAL_SHARED_LIBRARIES := libsysutils libcutils libnetutils
 
 ifeq ($(BOARD_HdAVE_BLUETOOTH),true)
   LOCAL_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES) libbluedroid
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 448ae1d..5c2b2c0 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -22,6 +22,8 @@
 #include <dirent.h>
 #include <errno.h>
 
+#include <linux/if.h>
+
 #define LOG_TAG "CommandListener"
 #include <cutils/log.h>
 
@@ -30,6 +32,14 @@
 #include "CommandListener.h"
 #include "ResponseCode.h"
 
+extern "C" int ifc_init(void);
+extern "C" int ifc_get_hwaddr(const char *name, void *ptr);
+extern "C" int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags);
+extern "C" int ifc_set_addr(const char *name, in_addr_t addr);
+extern "C" int ifc_set_mask(const char *name, in_addr_t mask);
+extern "C" int ifc_up(const char *name);
+extern "C" int ifc_down(const char *name);
+
 TetherController *CommandListener::sTetherCtrl = NULL;
 NatController *CommandListener::sNatCtrl = NULL;
 PppController *CommandListener::sPppCtrl = NULL;
@@ -37,7 +47,7 @@
 
 CommandListener::CommandListener() :
                  FrameworkListener("netd") {
-    registerCmd(new ListInterfacesCmd());
+    registerCmd(new InterfaceCmd());
     registerCmd(new IpFwdCmd());
     registerCmd(new TetherCmd());
     registerCmd(new NatCmd());
@@ -55,14 +65,142 @@
         sPanCtrl = new PanController();
 }
 
-CommandListener::ListInterfacesCmd::ListInterfacesCmd() :
-                 NetdCommand("list_interfaces") {
+CommandListener::InterfaceCmd::InterfaceCmd() :
+                 NetdCommand("interface") {
 }
 
-int CommandListener::ListInterfacesCmd::runCommand(SocketClient *cli,
+int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
                                                       int argc, char **argv) {
-    // XXX: Send a series of InterfaceListResults
-    cli->sendMsg(ResponseCode::CommandOkay, "Interfaces listed.", false);
+    if (argc < 2) {
+        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+        return 0;
+    }
+
+    if (!strcmp(argv[1], "list")) {
+        DIR *d;
+        struct dirent *de;
+
+        if (!(d = opendir("/sys/class/net"))) {
+            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open sysfs dir", true);
+            return 0;
+        }
+
+        while((de = readdir(d))) {
+            if (de->d_name[0] == '.')
+                continue;
+            cli->sendMsg(ResponseCode::InterfaceListResult, de->d_name, false);
+        }
+        closedir(d);
+        cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
+        return 0;
+    } else {
+        /*
+         * These commands take a minimum of 3 arguments
+         */
+        if (argc < 3) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+            return 0;
+        }
+        if (!strcmp(argv[1], "getcfg")) {
+            struct in_addr addr, mask;
+            unsigned char hwaddr[6];
+            unsigned flags = 0;
+
+            ifc_init();
+            memset(hwaddr, 0, sizeof(hwaddr));
+
+            if (ifc_get_info(argv[2], &addr.s_addr, &mask.s_addr, &flags)) {
+                cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
+                return 0;
+            }
+
+            if (ifc_get_hwaddr(argv[2], (void *) hwaddr)) {
+                LOGW("Failed to retrieve HW addr for %s (%s)", argv[2], strerror(errno));
+            }
+
+            char *addr_s = strdup(inet_ntoa(addr));
+            char *mask_s = strdup(inet_ntoa(mask));
+            const char *updown, *brdcst, *loopbk, *ppp, *running, *multi;
+
+            updown =  (flags & IFF_UP)           ? "up" : "down";
+            brdcst =  (flags & IFF_BROADCAST)    ? " broadcast" : "";
+            loopbk =  (flags & IFF_LOOPBACK)     ? " loopback" : "";
+            ppp =     (flags & IFF_POINTOPOINT)  ? " point-to-point" : "";
+            running = (flags & IFF_RUNNING)      ? " running" : "";
+            multi =   (flags & IFF_MULTICAST)    ? " multicast" : "";
+
+            char *flag_s;
+
+            asprintf(&flag_s, "[%s%s%s%s%s%s]\n", updown, brdcst, loopbk, ppp, running, multi);
+
+            char *msg = NULL;
+            asprintf(&msg, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x %s %s %s",
+                     hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5],
+                     addr_s, mask_s, flag_s);
+
+            cli->sendMsg(ResponseCode::InterfaceGetInfoResult, msg, false);
+
+            free(addr_s);
+            free(mask_s);
+            free(flag_s);
+            free(msg);
+            return 0;
+        } else if (!strcmp(argv[1], "setcfg")) {
+            if (argc < 5) {
+                cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+                return 0;
+            }
+
+            struct in_addr addr, mask;
+            unsigned flags = 0;
+
+            if (!inet_aton(argv[3], &addr)) {
+                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
+                return 0;
+            }
+
+            if (!inet_aton(argv[4], &mask)) {
+                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid netmask", false);
+                return 0;
+            }
+
+            ifc_init();
+            if (ifc_set_addr(argv[2], addr.s_addr)) {
+                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
+                return 0;
+            }
+
+            if (ifc_set_mask(argv[2], mask.s_addr)) {
+                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set netmask", true);
+                return 0;
+            }
+
+            /* Process flags */
+            for (int i = 5; i < argc; i++) {
+                if (!strcmp(argv[i], "up")) {
+                    if (ifc_up(argv[2])) {
+                        LOGE("Error upping interface");
+                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to up interface", true);
+                        return 0;
+                    }
+                } else if (!strcmp(argv[i], "down")) {
+                    if (ifc_down(argv[2])) {
+                        LOGE("Error downing interface");
+                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to down interface", true);
+                        return 0;
+                    }
+                } else {
+                    cli->sendMsg(ResponseCode::CommandParameterError, "Flag unsupported", false);
+                    return 0;
+                }
+            }
+            cli->sendMsg(ResponseCode::CommandOkay, "Interface configuration set", false);
+            return 0;
+        } else {
+            cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
+            return 0;
+        }
+    }
     return 0;
 }
 
diff --git a/CommandListener.h b/CommandListener.h
index c005c59..84476dd 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -37,10 +37,10 @@
 
 private:
 
-    class ListInterfacesCmd : public NetdCommand {
+    class InterfaceCmd : public NetdCommand {
     public:
-        ListInterfacesCmd();
-        virtual ~ListInterfacesCmd() {}
+        InterfaceCmd();
+        virtual ~InterfaceCmd() {}
         int runCommand(SocketClient *c, int argc, char ** argv);
     };
 
diff --git a/ResponseCode.h b/ResponseCode.h
index cf818ae..c8e1b70 100644
--- a/ResponseCode.h
+++ b/ResponseCode.h
@@ -33,6 +33,7 @@
     static const int TetherStatusResult       = 210;
     static const int IpFwdStatusResult        = 211;
     static const int PanStatusResult          = 212;
+    static const int InterfaceGetInfoResult   = 213;
 
     // 400 series - The command was accepted but the requested action
     // did not take place.
diff --git a/main.cpp b/main.cpp
index 98e1c3f..7c31179 100644
--- a/main.cpp
+++ b/main.cpp
@@ -16,10 +16,12 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <signal.h>
 #include <errno.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 
 #include <fcntl.h>
 #include <dirent.h>
@@ -32,6 +34,7 @@
 #include "NetlinkManager.h"
 
 static void coldboot(const char *path);
+static void sigchld_handler(int sig);
 
 int main() {
 
@@ -40,6 +43,8 @@
 
     LOGI("Netd 1.0 starting");
 
+    signal(SIGCHLD, sigchld_handler);
+
     if (!(nm = NetlinkManager::Instance())) {
         LOGE("Unable to create NetlinkManager");
         exit(1);
@@ -115,3 +120,8 @@
         closedir(d);
     }
 }
+
+static void sigchld_handler(int sig) {
+    pid_t pid = wait(NULL);
+    LOGD("Child process %d exited", pid);
+}