am 484bdcab: am 63790dce: am 42b4c508: (-s ours) am 11ff695d: (-s ours) Reconcile with jb-mr1-release - do not merge

* commit '484bdcab1e7e64c2ad6ee36b9d216dbc94e82608':
diff --git a/Android.mk b/Android.mk
index e4b6ad6..3a3651d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -21,9 +21,7 @@
                   SecondaryTableController.cpp         \
                   SoftapController.cpp                 \
                   TetherController.cpp                 \
-                  ThrottleController.cpp               \
                   oem_iptables_hook.cpp                \
-                  logwrapper.c                         \
                   main.cpp                             \
 
 
@@ -40,7 +38,8 @@
 LOCAL_CFLAGS := -Werror=format
 
 LOCAL_SHARED_LIBRARIES := libstlport libsysutils libcutils libnetutils \
-                          libcrypto libhardware_legacy libmdnssd libdl
+                          libcrypto libhardware_legacy libmdnssd libdl \
+                          liblogwrap
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/BandwidthController.cpp b/BandwidthController.cpp
index e5d3054..d51ea25 100644
--- a/BandwidthController.cpp
+++ b/BandwidthController.cpp
@@ -40,16 +40,13 @@
 #define LOG_TAG "BandwidthController"
 #include <cutils/log.h>
 #include <cutils/properties.h>
-
-extern "C" int logwrap(int argc, const char **argv);
-extern "C" int system_nosh(const char *command);
+#include <logwrap/logwrap.h>
 
 #include "NetdConstants.h"
 #include "BandwidthController.h"
 
 /* Alphabetical */
-#define ALERT_IPT_TEMPLATE "%s %s %s -m quota2 ! --quota %lld --name %s"
-const int  BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
+#define ALERT_IPT_TEMPLATE "%s %s -m quota2 ! --quota %lld --name %s"
 const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
 const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
 const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
@@ -61,8 +58,6 @@
 const int  BandwidthController::MAX_IFACENAME_LEN = 64;
 const int  BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
 
-bool BandwidthController::useLogwrapCall = false;
-
 /**
  * Some comments about the rules:
  *  * Ordering
@@ -128,23 +123,17 @@
 };
 
 const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
-    "-A bw_INPUT -i lo --jump RETURN",
     "-A bw_INPUT -m owner --socket-exists", /* This is a tracking rule. */
 
-    "-A bw_OUTPUT -o lo --jump RETURN",
     "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
 
     "-A costly_shared --jump penalty_box",
 
-    "-t raw -A bw_raw_PREROUTING ! -i lo+ -m owner --socket-exists", /* This is a tracking rule. */
-    "-t mangle -A bw_mangle_POSTROUTING ! -o lo+ -m owner --socket-exists", /* This is a tracking rule. */
+    "-t raw -A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
+    "-t mangle -A bw_mangle_POSTROUTING -m owner --socket-exists", /* This is a tracking rule. */
 };
 
 BandwidthController::BandwidthController(void) {
-    char value[PROPERTY_VALUE_MAX];
-
-    property_get("persist.bandwidth.uselogwrap", value, "0");
-    useLogwrapCall = !strcmp(value, "1");
 }
 
 int BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling,
@@ -172,6 +161,7 @@
     char *next = buffer;
     char *tmp;
     int res;
+    int status = 0;
 
     std::string fullCmd = cmd;
 
@@ -190,28 +180,27 @@
     fullCmd.insert(0, " ");
     fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
 
-    if (!useLogwrapCall) {
-        res = system_nosh(fullCmd.c_str());
-    } else {
-        if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
-            ALOGE("iptables command too long");
+    if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
+        ALOGE("iptables command too long");
+        return -1;
+    }
+
+    argc = 0;
+    while ((tmp = strsep(&next, " "))) {
+        argv[argc++] = tmp;
+        if (argc >= MAX_CMD_ARGS) {
+            ALOGE("iptables argument overflow");
             return -1;
         }
-
-        argc = 0;
-        while ((tmp = strsep(&next, " "))) {
-            argv[argc++] = tmp;
-            if (argc >= MAX_CMD_ARGS) {
-                ALOGE("iptables argument overflow");
-                return -1;
-            }
-        }
-
-        argv[argc] = NULL;
-        res = logwrap(argc, argv);
     }
+
+    argv[argc] = NULL;
+    res = android_fork_execvp(argc, (char **)argv, &status, false,
+            failureHandling == IptFailShow);
+    res = res || !WIFEXITED(status) || WEXITSTATUS(status);
     if (res && failureHandling == IptFailShow) {
-        ALOGE("runIptablesCmd(): failed %s res=%d", fullCmd.c_str(), res);
+      ALOGE("runIptablesCmd(): res=%d status=%d failed %s", res, status,
+            fullCmd.c_str());
     }
     return res;
 }
@@ -290,6 +279,9 @@
     case IptOpInsert:
         opFlag = "-I";
         break;
+    case IptOpAppend:
+        opFlag = "-A";
+        break;
     case IptOpReplace:
         opFlag = "-R";
         break;
@@ -392,6 +384,9 @@
     case IptOpInsert:
         opFlag = "-I";
         break;
+    case IptOpAppend:
+        opFlag = "-A";
+        break;
     case IptOpReplace:
         opFlag = "-R";
         break;
@@ -635,8 +630,14 @@
     }
 
     if (it == quotaIfaces.end()) {
+        /* Preparing the iface adds a penalty_box check */
         res |= prepCostlyIface(ifn, QuotaUnique);
-        quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
+	/*
+	 * The rejecting quota limit should go after the penalty box checks
+	 * or else a naughty app could just eat up the quota.
+	 * So we append here.
+	 */
+        quotaCmd = makeIptablesQuotaCmd(IptOpAppend, costName, maxBytes);
         res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
         if (res) {
             ALOGE("Failed set quota rule");
@@ -740,13 +741,15 @@
 int BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
     int res = 0;
     const char *opFlag;
-    const char *ifaceLimiting;
     char *alertQuotaCmd;
 
     switch (op) {
     case IptOpInsert:
         opFlag = "-I";
         break;
+    case IptOpAppend:
+        opFlag = "-A";
+        break;
     case IptOpReplace:
         opFlag = "-R";
         break;
@@ -756,13 +759,11 @@
         break;
     }
 
-    ifaceLimiting = "! -i lo+";
-    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_INPUT",
+    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT",
         bytes, alertName);
     res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
     free(alertQuotaCmd);
-    ifaceLimiting = "! -o lo+";
-    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_OUTPUT",
+    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT",
         bytes, alertName);
     res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
     free(alertQuotaCmd);
@@ -772,13 +773,15 @@
 int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const char *alertName, int64_t bytes) {
     int res = 0;
     const char *opFlag;
-    const char *ifaceLimiting;
     char *alertQuotaCmd;
 
     switch (op) {
     case IptOpInsert:
         opFlag = "-I";
         break;
+    case IptOpAppend:
+        opFlag = "-A";
+        break;
     case IptOpReplace:
         opFlag = "-R";
         break;
@@ -788,8 +791,7 @@
         break;
     }
 
-    ifaceLimiting = "! -i lo+";
-    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, ifaceLimiting, opFlag, "bw_FORWARD",
+    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD",
         bytes, alertName);
     res = runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
     free(alertQuotaCmd);
@@ -933,7 +935,7 @@
 
 int BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
     char *alertQuotaCmd;
-    char *chainNameAndPos;
+    char *chainName;
     int res = 0;
     char *alertName;
 
@@ -945,11 +947,11 @@
     if (*alertBytes) {
         res = updateQuota(alertName, *alertBytes);
     } else {
-        asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
-        asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-I", chainNameAndPos, bytes, alertName);
+        asprintf(&chainName, "costly_%s", costName);
+        asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-A", chainName, bytes, alertName);
         res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
         free(alertQuotaCmd);
-        free(chainNameAndPos);
+        free(chainName);
     }
     *alertBytes = bytes;
     free(alertName);
@@ -969,7 +971,7 @@
     }
 
     asprintf(&chainName, "costly_%s", costName);
-    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "", "-D", chainName, *alertBytes, alertName);
+    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName);
     res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
     free(alertQuotaCmd);
     free(chainName);
diff --git a/BandwidthController.h b/BandwidthController.h
index 17017d2..b4a2c20 100644
--- a/BandwidthController.h
+++ b/BandwidthController.h
@@ -97,7 +97,7 @@
     };
 
     enum IptIpVer { IptIpV4, IptIpV6 };
-    enum IptOp { IptOpInsert, IptOpReplace, IptOpDelete };
+    enum IptOp { IptOpInsert, IptOpReplace, IptOpDelete, IptOpAppend };
     enum IptRejectOp { IptRejectAdd, IptRejectNoAdd };
     enum NaughtyAppOp { NaughtyAppOpAdd, NaughtyAppOpRemove };
     enum QuotaType { QuotaUnique, QuotaShared };
@@ -169,17 +169,11 @@
     static const char *IPT_BASIC_ACCOUNTING_COMMANDS[];
 
     /* Alphabetical */
-    static const int  ALERT_RULE_POS_IN_COSTLY_CHAIN;
     static const char ALERT_GLOBAL_NAME[];
     static const int  MAX_CMD_ARGS;
     static const int  MAX_CMD_LEN;
     static const int  MAX_IFACENAME_LEN;
     static const int  MAX_IPT_OUTPUT_LINE_LEN;
-
-    /*
-     * When false, it will directly use system() instead of logwrap()
-     */
-    static bool useLogwrapCall;
 };
 
 #endif
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 6f81524..31ae129 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -24,7 +24,6 @@
 #include <dirent.h>
 #include <errno.h>
 #include <string.h>
-#include <fcntl.h>
 #include <linux/if.h>
 
 #define LOG_TAG "CommandListener"
@@ -35,7 +34,6 @@
 
 #include "CommandListener.h"
 #include "ResponseCode.h"
-#include "ThrottleController.h"
 #include "BandwidthController.h"
 #include "IdletimerController.h"
 #include "SecondaryTableController.h"
@@ -207,22 +205,6 @@
                  NetdCommand("interface") {
 }
 
-int CommandListener::writeFile(const char *path, const char *value, int size) {
-    int fd = open(path, O_WRONLY);
-    if (fd < 0) {
-        ALOGE("Failed to open %s: %s", path, strerror(errno));
-        return -1;
-    }
-
-    if (write(fd, value, size) != size) {
-        ALOGE("Failed to write %s: %s", path, strerror(errno));
-        close(fd);
-        return -1;
-    }
-    close(fd);
-    return 0;
-}
-
 int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
                                                       int argc, char **argv) {
     if (argc < 2) {
@@ -247,79 +229,6 @@
         closedir(d);
         cli->sendMsg(ResponseCode::CommandOkay, "Interface list completed", false);
         return 0;
-    } else if (!strcmp(argv[1], "readrxcounter")) {
-        if (argc != 3) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError,
-                    "Usage: interface readrxcounter <interface>", false);
-            return 0;
-        }
-        unsigned long rx = 0, tx = 0;
-        if (readInterfaceCounters(argv[2], &rx, &tx)) {
-            cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true);
-            return 0;
-        }
-
-        char *msg;
-        asprintf(&msg, "%lu", rx);
-        cli->sendMsg(ResponseCode::InterfaceRxCounterResult, msg, false);
-        free(msg);
-
-        return 0;
-    } else if (!strcmp(argv[1], "readtxcounter")) {
-        if (argc != 3) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError,
-                    "Usage: interface readtxcounter <interface>", false);
-            return 0;
-        }
-        unsigned long rx = 0, tx = 0;
-        if (readInterfaceCounters(argv[2], &rx, &tx)) {
-            cli->sendMsg(ResponseCode::OperationFailed, "Failed to read counters", true);
-            return 0;
-        }
-
-        char *msg = NULL;
-        asprintf(&msg, "%lu", tx);
-        cli->sendMsg(ResponseCode::InterfaceTxCounterResult, msg, false);
-        free(msg);
-        return 0;
-    } else if (!strcmp(argv[1], "getthrottle")) {
-        if (argc != 4 || (argc == 4 && (strcmp(argv[3], "rx") && (strcmp(argv[3], "tx"))))) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError,
-                    "Usage: interface getthrottle <interface> <rx|tx>", false);
-            return 0;
-        }
-        int val = 0;
-        int rc = 0;
-        int voldRc = ResponseCode::InterfaceRxThrottleResult;
-
-        if (!strcmp(argv[3], "rx")) {
-            rc = ThrottleController::getInterfaceRxThrottle(argv[2], &val);
-        } else {
-            rc = ThrottleController::getInterfaceTxThrottle(argv[2], &val);
-            voldRc = ResponseCode::InterfaceTxThrottleResult;
-        }
-        if (rc) {
-            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get throttle", true);
-        } else {
-            char *msg = NULL;
-            asprintf(&msg, "%u", val);
-            cli->sendMsg(voldRc, msg, false);
-            free(msg);
-            return 0;
-        }
-        return 0;
-    } else if (!strcmp(argv[1], "setthrottle")) {
-        if (argc != 5) {
-            cli->sendMsg(ResponseCode::CommandSyntaxError,
-                    "Usage: interface setthrottle <interface> <rx_kbps> <tx_kbps>", false);
-            return 0;
-        }
-        if (ThrottleController::setInterfaceThrottle(argv[2], atoi(argv[3]), atoi(argv[4]))) {
-            cli->sendMsg(ResponseCode::OperationFailed, "Failed to set throttle", true);
-        } else {
-            cli->sendMsg(ResponseCode::CommandOkay, "Interface throttling set", false);
-        }
-        return 0;
     } else if (!strcmp(argv[1], "driver")) {
         int rc;
         char *rbuf;
@@ -529,19 +438,13 @@
                         false);
                 return 0;
             }
-
-            char *tmp;
-            asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/use_tempaddr", argv[2]);
-
-            if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "2" : "0", 1) < 0) {
-                free(tmp);
+            int enable = !strncmp(argv[3], "enable", 7);
+            if (sInterfaceCtrl->setIPv6PrivacyExtensions(argv[2], enable) == 0) {
+                cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false);
+            } else {
                 cli->sendMsg(ResponseCode::OperationFailed,
                         "Failed to set ipv6 privacy extensions", true);
-                return 0;
             }
-
-            free(tmp);
-            cli->sendMsg(ResponseCode::CommandOkay, "IPv6 privacy extensions changed", false);
             return 0;
         } else if (!strcmp(argv[1], "ipv6")) {
             if (argc != 4) {
@@ -551,18 +454,13 @@
                 return 0;
             }
 
-            char *tmp;
-            asprintf(&tmp, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", argv[2]);
-
-            if (writeFile(tmp, !strncmp(argv[3], "enable", 7) ? "0" : "1", 1) < 0) {
-                free(tmp);
+            int enable = !strncmp(argv[3], "enable", 7);
+            if (sInterfaceCtrl->setEnableIPv6(argv[2], enable) == 0) {
+                cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false);
+            } else {
                 cli->sendMsg(ResponseCode::OperationFailed,
                         "Failed to change IPv6 state", true);
-                return 0;
             }
-
-            free(tmp);
-            cli->sendMsg(ResponseCode::CommandOkay, "IPv6 state changed", false);
             return 0;
         } else {
             cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown interface cmd", false);
@@ -827,11 +725,17 @@
 
 int CommandListener::SoftapCmd::runCommand(SocketClient *cli,
                                         int argc, char **argv) {
-    int rc = 0, flag = 0;
+    int rc = ResponseCode::SoftapStatusResult;
+    int flag = 0;
     char *retbuf = NULL;
 
+    if (sSoftapCtrl == NULL) {
+      cli->sendMsg(ResponseCode::ServiceStartFailed, "SoftAP is not available", false);
+      return -1;
+    }
     if (argc < 2) {
-        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Missing argument", false);
+        cli->sendMsg(ResponseCode::CommandSyntaxError,
+                     "Missing argument in a SoftAP command", false);
         return 0;
     }
 
@@ -841,31 +745,23 @@
         rc = sSoftapCtrl->stopSoftap();
     } else if (!strcmp(argv[1], "fwreload")) {
         rc = sSoftapCtrl->fwReloadSoftap(argc, argv);
-    } else if (!strcmp(argv[1], "clients")) {
-        rc = sSoftapCtrl->clientsSoftap(&retbuf);
-        if (!rc) {
-            cli->sendMsg(ResponseCode::CommandOkay, retbuf, false);
-            free(retbuf);
-            return 0;
-        }
     } else if (!strcmp(argv[1], "status")) {
-        asprintf(&retbuf, "Softap service %s",
-                 (sSoftapCtrl->isSoftapStarted() ? "started" : "stopped"));
-        cli->sendMsg(ResponseCode::SoftapStatusResult, retbuf, false);
+        asprintf(&retbuf, "Softap service %s running",
+                 (sSoftapCtrl->isSoftapStarted() ? "is" : "is not"));
+        cli->sendMsg(rc, retbuf, false);
         free(retbuf);
         return 0;
     } else if (!strcmp(argv[1], "set")) {
         rc = sSoftapCtrl->setSoftap(argc, argv);
     } else {
-        cli->sendMsg(ResponseCode::CommandSyntaxError, "Softap Unknown cmd", false);
+        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unrecognized SoftAP command", false);
         return 0;
     }
 
-    if (!rc) {
-        cli->sendMsg(ResponseCode::CommandOkay, "Softap operation succeeded", false);
-    } else {
-        cli->sendMsg(ResponseCode::OperationFailed, "Softap operation failed", true);
-    }
+    if (rc >= 400 && rc < 600)
+      cli->sendMsg(rc, "SoftAP command has failed", false);
+    else
+      cli->sendMsg(rc, "Ok", false);
 
     return 0;
 }
@@ -891,9 +787,10 @@
                     "Wrong number of arguments to resolver setdefaultif", false);
             return 0;
         }
-    } else if (!strcmp(argv[1], "setifdns")) { // "resolver setifdns <iface> <dns1> <dns2> ..."
-        if (argc >= 4) {
-            rc = sResolverCtrl->setInterfaceDnsServers(argv[2], &argv[3], argc - 3);
+    } else if (!strcmp(argv[1], "setifdns")) {
+        // "resolver setifdns <iface> <domains> <dns1> <dns2> ..."
+        if (argc >= 5) {
+            rc = sResolverCtrl->setInterfaceDnsServers(argv[2], argv[3], &argv[4], argc - 4);
         } else {
             cli->sendMsg(ResponseCode::CommandSyntaxError,
                     "Wrong number of arguments to resolver setifdns", false);
@@ -925,6 +822,22 @@
                     "Wrong number of arguments to resolver setdefaultif", false);
             return 0;
         }
+    } else if (!strcmp(argv[1], "setifaceforpid")) { // resolver setifaceforpid <iface> <pid>
+        if (argc == 4) {
+            rc = sResolverCtrl->setDnsInterfaceForPid(argv[2], atoi(argv[3]));
+        } else {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                    "Wrong number of arguments to resolver setifaceforpid", false);
+            return 0;
+        }
+    } else if (!strcmp(argv[1], "clearifaceforpid")) { // resolver clearifaceforpid <pid>
+        if (argc == 3) {
+            rc = sResolverCtrl->clearDnsInterfaceForPid(atoi(argv[2]));
+        } else {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                    "Wrong number of arguments to resolver clearifaceforpid", false);
+            return 0;
+        }
     } else {
         cli->sendMsg(ResponseCode::CommandSyntaxError,"Resolver unknown command", false);
         return 0;
@@ -939,47 +852,6 @@
     return 0;
 }
 
-int CommandListener::readInterfaceCounters(const char *iface, unsigned long *rx, unsigned long *tx) {
-    FILE *fp = fopen("/proc/net/dev", "r");
-    if (!fp) {
-        ALOGE("Failed to open /proc/net/dev (%s)", strerror(errno));
-        return -1;
-    }
-
-    char buffer[512];
-
-    fgets(buffer, sizeof(buffer), fp); // Header 1
-    fgets(buffer, sizeof(buffer), fp); // Header 2
-    while(fgets(buffer, sizeof(buffer), fp)) {
-        buffer[strlen(buffer)-1] = '\0';
-
-        char name[31];
-        unsigned long d;
-        sscanf(buffer, "%30s %lu %lu %lu %lu %lu %lu %lu %lu %lu",
-                name, rx, &d, &d, &d, &d, &d, &d, &d, tx);
-        char *rxString = strchr(name, ':');
-        *rxString = '\0';
-        rxString++;
-        // when the rx count gets too big it changes from "name: 999" to "name:1000"
-        // and the sscanf munge the two together.  Detect that and fix
-        // note that all the %lu will be off by one and the real tx value will be in d
-        if (*rxString != '\0') {
-            *tx = d;
-            sscanf(rxString, "%20lu", rx);
-        }
-        if (strcmp(name, iface)) {
-            continue;
-        }
-        fclose(fp);
-        return 0;
-    }
-
-    fclose(fp);
-    *rx = 0;
-    *tx = 0;
-    return 0;
-}
-
 CommandListener::BandwidthControlCmd::BandwidthControlCmd() :
     NetdCommand("bandwidth") {
 }
diff --git a/CommandListener.h b/CommandListener.h
index e8d92a8..1db81f8 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -51,10 +51,6 @@
 
 private:
 
-    static int writeFile(const char *path, const char *value, int size);
-
-    static int readInterfaceCounters(const char *iface, unsigned long *rx, unsigned long *tx);
-
     class SoftapCmd : public NetdCommand {
     public:
         SoftapCmd();
diff --git a/DnsProxyListener.cpp b/DnsProxyListener.cpp
index 7da6b43..cee8d10 100644
--- a/DnsProxyListener.cpp
+++ b/DnsProxyListener.cpp
@@ -25,9 +25,12 @@
 #include <sys/types.h>
 #include <string.h>
 #include <pthread.h>
+#include <resolv_iface.h>
+#include <net/if.h>
 
 #define LOG_TAG "DnsProxyListener"
 #define DBG 0
+#define VDBG 0
 
 #include <cutils/log.h>
 #include <sysutils/SocketClient.h>
@@ -39,18 +42,35 @@
                  FrameworkListener("dnsproxyd") {
     registerCmd(new GetAddrInfoCmd());
     registerCmd(new GetHostByAddrCmd());
+    registerCmd(new GetHostByNameCmd());
+}
+
+DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(SocketClient *c,
+                                                         char* host,
+                                                         char* service,
+                                                         struct addrinfo* hints,
+                                                         char* iface,
+                                                         pid_t pid)
+        : mClient(c),
+          mHost(host),
+          mService(service),
+          mHints(hints),
+          mIface(iface),
+          mPid(pid) {
 }
 
 DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() {
     free(mHost);
     free(mService);
     free(mHints);
+    free(mIface);
 }
 
 void DnsProxyListener::GetAddrInfoHandler::start() {
     pthread_t thread;
     pthread_create(&thread, NULL,
                    DnsProxyListener::GetAddrInfoHandler::threadStart, this);
+    pthread_detach(thread);
 }
 
 void* DnsProxyListener::GetAddrInfoHandler::threadStart(void* obj) {
@@ -69,13 +89,47 @@
         (len == 0 || c->sendData(data, len) == 0);
 }
 
+// Returns true on success
+static bool sendhostent(SocketClient *c, struct hostent *hp) {
+    bool success = true;
+    int i;
+    if (hp->h_name != NULL) {
+        success &= sendLenAndData(c, strlen(hp->h_name)+1, hp->h_name);
+    } else {
+        success &= sendLenAndData(c, 0, "") == 0;
+    }
+
+    for (i=0; hp->h_aliases[i] != NULL; i++) {
+        success &= sendLenAndData(c, strlen(hp->h_aliases[i])+1, hp->h_aliases[i]);
+    }
+    success &= sendLenAndData(c, 0, ""); // null to indicate we're done
+
+    uint32_t buf = htonl(hp->h_addrtype);
+    success &= c->sendData(&buf, sizeof(buf)) == 0;
+
+    buf = htonl(hp->h_length);
+    success &= c->sendData(&buf, sizeof(buf)) == 0;
+
+    for (i=0; hp->h_addr_list[i] != NULL; i++) {
+        success &= sendLenAndData(c, 16, hp->h_addr_list[i]);
+    }
+    success &= sendLenAndData(c, 0, ""); // null to indicate we're done
+    return success;
+}
+
 void DnsProxyListener::GetAddrInfoHandler::run() {
     if (DBG) {
-        ALOGD("GetAddrInfoHandler, now for %s / %s", mHost, mService);
+        ALOGD("GetAddrInfoHandler, now for %s / %s / %s", mHost, mService, mIface);
+    }
+
+    char tmp[IF_NAMESIZE + 1];
+    if (mIface == NULL) {
+        _resolv_get_pids_associated_interface(mPid, tmp, sizeof(tmp));
     }
 
     struct addrinfo* result = NULL;
-    uint32_t rv = getaddrinfo(mHost, mService, mHints, &result);
+    uint32_t rv = android_getaddrinfoforiface(mHost, mService, mHints, mIface ? mIface : tmp,
+            &result);
     if (rv) {
         // getaddrinfo failed
         mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
@@ -112,7 +166,7 @@
             ALOGD("argv[%i]=%s", i, argv[i]);
         }
     }
-    if (argc != 7) {
+    if (argc != 8) {
         char* msg = NULL;
         asprintf( &msg, "Invalid number of arguments to getaddrinfo: %i", argc);
         ALOGW("%s", msg);
@@ -135,11 +189,20 @@
         service = strdup(service);
     }
 
+    char* iface = argv[7];
+    if (strcmp(iface, "^") == 0) {
+        iface = NULL;
+    } else {
+        iface = strdup(iface);
+    }
+
     struct addrinfo* hints = NULL;
     int ai_flags = atoi(argv[3]);
     int ai_family = atoi(argv[4]);
     int ai_socktype = atoi(argv[5]);
     int ai_protocol = atoi(argv[6]);
+    pid_t pid = cli->getPid();
+
     if (ai_flags != -1 || ai_family != -1 ||
         ai_socktype != -1 || ai_protocol != -1) {
         hints = (struct addrinfo*) calloc(1, sizeof(struct addrinfo));
@@ -150,21 +213,139 @@
     }
 
     if (DBG) {
-        ALOGD("GetAddrInfoHandler for %s / %s",
+        ALOGD("GetAddrInfoHandler for %s / %s / %s / %d",
              name ? name : "[nullhost]",
-             service ? service : "[nullservice]");
+             service ? service : "[nullservice]",
+             iface ? iface : "[nulliface]",
+             pid);
     }
 
     cli->incRef();
     DnsProxyListener::GetAddrInfoHandler* handler =
-        new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints);
+        new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, iface, pid);
     handler->start();
 
     return 0;
 }
 
 /*******************************************************
- *                  GetHostByAddr                       *
+ *                  GetHostByName                      *
+ *******************************************************/
+DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd() :
+        NetdCommand("gethostbyname") {
+}
+
+int DnsProxyListener::GetHostByNameCmd::runCommand(SocketClient *cli,
+                                            int argc, char **argv) {
+    if (DBG) {
+        for (int i = 0; i < argc; i++) {
+            ALOGD("argv[%i]=%s", i, argv[i]);
+        }
+    }
+    if (argc != 4) {
+        char* msg = NULL;
+        asprintf(&msg, "Invalid number of arguments to gethostbyname: %i", argc);
+        ALOGW("%s", msg);
+        cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
+        free(msg);
+        return -1;
+    }
+
+    pid_t pid = cli->getPid();
+    char* iface = argv[1];
+    char* name = argv[2];
+    int af = atoi(argv[3]);
+
+    if (strcmp(iface, "^") == 0) {
+        iface = NULL;
+    } else {
+        iface = strdup(iface);
+    }
+
+    if (strcmp(name, "^") == 0) {
+        name = NULL;
+    } else {
+        name = strdup(name);
+    }
+
+    cli->incRef();
+    DnsProxyListener::GetHostByNameHandler* handler =
+            new DnsProxyListener::GetHostByNameHandler(cli, pid, iface, name, af);
+    handler->start();
+
+    return 0;
+}
+
+DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(SocketClient* c,
+                                                             pid_t pid,
+                                                             char* iface,
+                                                             char* name,
+                                                             int af)
+        : mClient(c),
+          mPid(pid),
+          mIface(iface),
+          mName(name),
+          mAf(af) {
+}
+
+DnsProxyListener::GetHostByNameHandler::~GetHostByNameHandler() {
+    free(mIface);
+    free(mName);
+}
+
+void DnsProxyListener::GetHostByNameHandler::start() {
+    pthread_t thread;
+    pthread_create(&thread, NULL,
+            DnsProxyListener::GetHostByNameHandler::threadStart, this);
+    pthread_detach(thread);
+}
+
+void* DnsProxyListener::GetHostByNameHandler::threadStart(void* obj) {
+    GetHostByNameHandler* handler = reinterpret_cast<GetHostByNameHandler*>(obj);
+    handler->run();
+    delete handler;
+    pthread_exit(NULL);
+    return NULL;
+}
+
+void DnsProxyListener::GetHostByNameHandler::run() {
+    if (DBG) {
+        ALOGD("DnsProxyListener::GetHostByNameHandler::run\n");
+    }
+
+    char iface[IF_NAMESIZE + 1];
+    if (mIface == NULL) {
+        _resolv_get_pids_associated_interface(mPid, iface, sizeof(iface));
+    }
+
+    struct hostent* hp;
+
+    hp = android_gethostbynameforiface(mName, mAf, mIface ? mIface : iface);
+
+    if (DBG) {
+        ALOGD("GetHostByNameHandler::run gethostbyname errno: %s hp->h_name = %s, name_len = %d\n",
+                hp ? "success" : strerror(errno),
+                (hp && hp->h_name) ? hp->h_name: "null",
+                (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0);
+    }
+
+    bool success = true;
+    if (hp) {
+        success = mClient->sendCode(ResponseCode::DnsProxyQueryResult) == 0;
+        success &= sendhostent(mClient, hp);
+    } else {
+        success = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, NULL, 0) == 0;
+    }
+
+    if (!success) {
+        ALOGW("GetHostByNameHandler: Error writing DNS result to client\n");
+    }
+    mClient->decRef();
+}
+
+
+/*******************************************************
+ *                  GetHostByAddr                      *
  *******************************************************/
 DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd() :
         NetdCommand("gethostbyaddr") {
@@ -177,8 +358,7 @@
             ALOGD("argv[%i]=%s", i, argv[i]);
         }
     }
-
-    if (argc != 4) {
+    if (argc != 5) {
         char* msg = NULL;
         asprintf(&msg, "Invalid number of arguments to gethostbyaddr: %i", argc);
         ALOGW("%s", msg);
@@ -190,6 +370,14 @@
     char* addrStr = argv[1];
     int addrLen = atoi(argv[2]);
     int addrFamily = atoi(argv[3]);
+    pid_t pid = cli->getPid();
+    char* iface = argv[4];
+
+    if (strcmp(iface, "^") == 0) {
+        iface = NULL;
+    } else {
+        iface = strdup(iface);
+    }
 
     void* addr = malloc(sizeof(struct in6_addr));
     errno = 0;
@@ -206,20 +394,36 @@
 
     cli->incRef();
     DnsProxyListener::GetHostByAddrHandler* handler =
-            new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily);
+            new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily, iface ,pid);
     handler->start();
 
     return 0;
 }
 
+DnsProxyListener::GetHostByAddrHandler::GetHostByAddrHandler(SocketClient* c,
+                                                             void* address,
+                                                             int   addressLen,
+                                                             int   addressFamily,
+                                                             char* iface,
+                                                             pid_t pid)
+        : mClient(c),
+          mAddress(address),
+          mAddressLen(addressLen),
+          mAddressFamily(addressFamily),
+          mIface(iface),
+          mPid(pid) {
+}
+
 DnsProxyListener::GetHostByAddrHandler::~GetHostByAddrHandler() {
     free(mAddress);
+    free(mIface);
 }
 
 void DnsProxyListener::GetHostByAddrHandler::start() {
     pthread_t thread;
     pthread_create(&thread, NULL,
                    DnsProxyListener::GetHostByAddrHandler::threadStart, this);
+    pthread_detach(thread);
 }
 
 void* DnsProxyListener::GetHostByAddrHandler::threadStart(void* obj) {
@@ -235,10 +439,16 @@
         ALOGD("DnsProxyListener::GetHostByAddrHandler::run\n");
     }
 
+    char tmp[IF_NAMESIZE + 1];
+    if (mIface == NULL) {
+        _resolv_get_pids_associated_interface(mPid, tmp, sizeof(tmp));
+    }
+
     struct hostent* hp;
 
     // NOTE gethostbyaddr should take a void* but bionic thinks it should be char*
-    hp = gethostbyaddr((char*)mAddress, mAddressLen, mAddressFamily);
+    hp = android_gethostbyaddrforiface((char*)mAddress, mAddressLen, mAddressFamily,
+            mIface ? mIface : tmp);
 
     if (DBG) {
         ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n",
@@ -247,18 +457,15 @@
                 (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0);
     }
 
-    bool failed = true;
+    bool success = true;
     if (hp) {
-        failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyQueryResult,
-                                        hp->h_name ? hp->h_name : "",
-                                        hp->h_name ? strlen(hp->h_name)+ 1 : 0);
+        success = mClient->sendCode(ResponseCode::DnsProxyQueryResult) == 0;
+        success &= sendhostent(mClient, hp);
     } else {
-        uint32_t error = h_errno;
-        failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed,
-                                        &error, sizeof(error));
+        success = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, NULL, 0) == 0;
     }
 
-    if (failed) {
+    if (!success) {
         ALOGW("GetHostByAddrHandler: Error writing DNS result to client\n");
     }
     mClient->decRef();
diff --git a/DnsProxyListener.h b/DnsProxyListener.h
index 24c3b6a..c950c02 100644
--- a/DnsProxyListener.h
+++ b/DnsProxyListener.h
@@ -40,11 +40,9 @@
         GetAddrInfoHandler(SocketClient *c,
                            char* host,
                            char* service,
-                           struct addrinfo* hints)
-            : mClient(c),
-              mHost(host),
-              mService(service),
-              mHints(hints) {}
+                           struct addrinfo* hints,
+                           char* iface,
+                           pid_t pid);
         ~GetAddrInfoHandler();
 
         static void* threadStart(void* handler);
@@ -56,6 +54,35 @@
         char* mHost;    // owned
         char* mService; // owned
         struct addrinfo* mHints;  // owned
+        char* mIface; // owned
+        pid_t mPid;
+    };
+
+    /* ------ gethostbyname ------*/
+    class GetHostByNameCmd : public NetdCommand {
+    public:
+        GetHostByNameCmd();
+        virtual ~GetHostByNameCmd() {}
+        int runCommand(SocketClient *c, int argc, char** argv);
+    };
+
+    class GetHostByNameHandler {
+    public:
+        GetHostByNameHandler(SocketClient *c,
+                            pid_t pid,
+                            char *iface,
+                            char *name,
+                            int af);
+        ~GetHostByNameHandler();
+        static void* threadStart(void* handler);
+        void start();
+    private:
+        void run();
+        SocketClient* mClient; //ref counted
+        pid_t mPid;
+        char* mIface; // owned
+        char* mName; // owned
+        int mAf;
     };
 
     /* ------ gethostbyaddr ------*/
@@ -71,11 +98,9 @@
         GetHostByAddrHandler(SocketClient *c,
                             void* address,
                             int   addressLen,
-                            int   addressFamily)
-            : mClient(c),
-              mAddress(address),
-              mAddressLen(addressLen),
-              mAddressFamily(addressFamily) {}
+                            int   addressFamily,
+                            char* iface,
+                            pid_t pid);
         ~GetHostByAddrHandler();
 
         static void* threadStart(void* handler);
@@ -87,6 +112,8 @@
         void* mAddress;    // address to lookup; owned
         int   mAddressLen; // length of address to look up
         int   mAddressFamily;  // address family
+        char* mIface; // owned
+        pid_t mPid;
     };
 };
 
diff --git a/IdletimerController.cpp b/IdletimerController.cpp
index 7623f33..54b4edd 100644
--- a/IdletimerController.cpp
+++ b/IdletimerController.cpp
@@ -99,6 +99,7 @@
 #include <errno.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <fcntl.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -107,12 +108,11 @@
 
 #define LOG_TAG "IdletimerController"
 #include <cutils/log.h>
+#include <logwrap/logwrap.h>
 
 #include "IdletimerController.h"
 #include "NetdConstants.h"
 
-extern "C" int system_nosh(const char *command);
-
 const char* IdletimerController::LOCAL_RAW_PREROUTING = "idletimer_raw_PREROUTING";
 const char* IdletimerController::LOCAL_MANGLE_POSTROUTING = "idletimer_mangle_POSTROUTING";
 
@@ -122,21 +122,11 @@
 IdletimerController::~IdletimerController() {
 }
 /* return 0 or non-zero */
-int IdletimerController::runIpxtablesCmd(const char *cmd) {
-    char *buffer;
-    size_t len = strnlen(cmd, 255);
+int IdletimerController::runIpxtablesCmd(int argc, const char **argv) {
     int res;
 
-    if (len == 255) {
-        ALOGE("command too long");
-        return -1;
-    }
-
-    asprintf(&buffer, "%s %s", IPTABLES_PATH, cmd);
-    res = system_nosh(buffer);
-    ALOGV("%s #%d", buffer, res);
-    free(buffer);
-
+    res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
+    ALOGV("runCmd() res=%d", res);
     return res;
 }
 
@@ -146,17 +136,27 @@
 
 int IdletimerController::setDefaults() {
   int res;
-  char *buffer;
-  asprintf(&buffer, "-t raw -F %s", LOCAL_RAW_PREROUTING);
-  res = runIpxtablesCmd(buffer);
-  free(buffer);
+  const char *cmd1[] = {
+      IPTABLES_PATH,
+      "-t",
+      "raw",
+      "-F",
+      LOCAL_RAW_PREROUTING
+  };
+  res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1);
 
   if (res)
     return res;
 
-  asprintf(&buffer, "-t mangle -F %s", LOCAL_MANGLE_POSTROUTING);
-  res = runIpxtablesCmd(buffer);
-  free(buffer);
+  const char *cmd2[] = {
+      IPTABLES_PATH,
+      "-t",
+      "mangle",
+      "-F",
+      LOCAL_MANGLE_POSTROUTING
+  };
+  res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2);
+
   return res;
 }
 
@@ -174,21 +174,50 @@
                                                   uint32_t timeout,
                                                   const char *classLabel) {
   int res;
-  char *buffer;
-  asprintf(&buffer, "-t raw -%c %s -i %s -j IDLETIMER"
-           " --timeout %u --label %s --send_nl_msg 1",
-           (op == IptOpAdd) ? 'A' : 'D', LOCAL_RAW_PREROUTING, iface, timeout, classLabel);
-  res = runIpxtablesCmd(buffer);
-  free(buffer);
+  char timeout_str[11]; //enough to store any 32-bit unsigned decimal
+
+  snprintf(timeout_str, sizeof(timeout_str), "%u", timeout);
+
+  const char *cmd1[] = {
+      IPTABLES_PATH,
+      "-t",
+      "raw",
+      (op == IptOpAdd) ? "-A" : "-D",
+      LOCAL_RAW_PREROUTING,
+      "-i",
+      iface,
+      "-j",
+      "IDLETIMER",
+      "--timeout",
+      timeout_str,
+      "--label",
+      classLabel,
+      "--send_nl_msg",
+      "1"
+  };
+  res = runIpxtablesCmd(ARRAY_SIZE(cmd1), cmd1);
 
   if (res)
     return res;
 
-  asprintf(&buffer, "-t mangle -%c %s -o %s -j IDLETIMER"
-           " --timeout %u --label %s --send_nl_msg 1",
-           (op == IptOpAdd) ? 'A' : 'D', LOCAL_MANGLE_POSTROUTING, iface, timeout, classLabel);
-  res = runIpxtablesCmd(buffer);
-  free(buffer);
+  const char *cmd2[] = {
+      IPTABLES_PATH,
+      "-t",
+      "mangle",
+      (op == IptOpAdd) ? "-A" : "-D",
+      LOCAL_MANGLE_POSTROUTING,
+      "-o",
+      iface,
+      "-j",
+      "IDLETIMER",
+      "--timeout",
+      timeout_str,
+      "--label",
+      classLabel,
+      "--send_nl_msg",
+      "1"
+  };
+  res = runIpxtablesCmd(ARRAY_SIZE(cmd2), cmd2);
 
   return res;
 }
diff --git a/IdletimerController.h b/IdletimerController.h
index eb2aa35..98a312e 100644
--- a/IdletimerController.h
+++ b/IdletimerController.h
@@ -36,7 +36,7 @@
  private:
     enum IptOp { IptOpAdd, IptOpDelete };
     int setDefaults();
-    int runIpxtablesCmd(const char *cmd);
+    int runIpxtablesCmd(int argc, const char **cmd);
     int modifyInterfaceIdletimer(IptOp op, const char *iface, uint32_t timeout,
                                  const char *classLabel);
 };
diff --git a/InterfaceController.cpp b/InterfaceController.cpp
index e02b517..00ab6d1 100644
--- a/InterfaceController.cpp
+++ b/InterfaceController.cpp
@@ -34,6 +34,8 @@
 #include <netutils/ifc.h>
 #include <private/android_filesystem_config.h>
 
+#include "NetdConstants.h"
+
 #include "InterfaceController.h"
 
 char if_cmd_lib_file_name[] = "/system/lib/libnetcmdiface.so";
@@ -99,3 +101,32 @@
 
 	return ret;
 }
+
+int InterfaceController::writeIPv6ProcPath(const char *interface, const char *setting, const char *value) {
+	char *path;
+	asprintf(&path, "/proc/sys/net/ipv6/conf/%s/%s", interface, setting);
+	int success = writeFile(path, value, strlen(value));
+	free(path);
+	return success;
+}
+
+int InterfaceController::setEnableIPv6(const char *interface, const int on) {
+	// When IPv6 is on, accept RAs regardless of forwarding state.
+	// When IPv6 is off, accept RAs only if forwarding is off (the default).
+	const char *accept_ra = on ? "2" : "1";
+	if (writeIPv6ProcPath(interface, "accept_ra", accept_ra)) {
+		return -1;
+	}
+
+	// When disable_ipv6 changes from 1 to 0, the kernel starts autoconf.
+	// When disable_ipv6 changes from 0 to 1, the kernel clears all autoconf
+	// addresses and routes and disables IPv6 on the interface.
+	const char *disable_ipv6 = on ? "0" : "1";
+	return writeIPv6ProcPath(interface, "disable_ipv6", disable_ipv6);
+}
+
+int InterfaceController::setIPv6PrivacyExtensions(const char *interface, const int on) {
+	// 0: disable IPv6 privacy addresses
+	// 0: enable IPv6 privacy addresses and prefer them over non-privacy ones.
+	return writeIPv6ProcPath(interface, "use_tempaddr", on ? "2" : "0");
+}
diff --git a/InterfaceController.h b/InterfaceController.h
index e31cc11..b11ab4f 100644
--- a/InterfaceController.h
+++ b/InterfaceController.h
@@ -33,12 +33,16 @@
 	InterfaceController();
 	virtual ~InterfaceController();
 	int interfaceCommand(int argc, char *argv[], char **rbuf);
+	int setEnableIPv6(const char *interface, const int on);
+	int setIPv6PrivacyExtensions(const char *interface, const int on);
 
  private:
 	void *libh_;
 	int (*sendCommand_)(int argc, char *argv[], char **rbuf);
 	int (*sendCommandInit_)(void);
 	int (*sendCommandFini_)(void);
+	int writeIPv6ProcPath(const char *interface, const char *setting,
+			      const char *value);
 };
 
 #endif
diff --git a/MDnsSdListener.cpp b/MDnsSdListener.cpp
index 52703df..9a3f4f7 100644
--- a/MDnsSdListener.cpp
+++ b/MDnsSdListener.cpp
@@ -497,6 +497,7 @@
     pthread_mutex_init(&mHeadMutex, NULL);
     socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair);
     pthread_create(&mThread, NULL, MDnsSdListener::Monitor::threadStart, this);
+    pthread_detach(mThread);
 }
 
 void *MDnsSdListener::Monitor::threadStart(void *obj) {
diff --git a/NatController.cpp b/NatController.cpp
index e44a29b..ff35d89 100644
--- a/NatController.cpp
+++ b/NatController.cpp
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
 #include <fcntl.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -28,13 +29,12 @@
 
 #define LOG_TAG "NatController"
 #include <cutils/log.h>
+#include <logwrap/logwrap.h>
 
 #include "NatController.h"
 #include "SecondaryTableController.h"
 #include "NetdConstants.h"
 
-extern "C" int system_nosh(const char *command);
-
 const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
 const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
 
@@ -45,21 +45,11 @@
 NatController::~NatController() {
 }
 
-int NatController::runCmd(const char *path, const char *cmd) {
-    char *buffer;
-    size_t len = strnlen(cmd, 255);
+int NatController::runCmd(int argc, const char **argv) {
     int res;
 
-    if (len == 255) {
-        ALOGE("command too long");
-        errno = E2BIG;
-        return -1;
-    }
-
-    asprintf(&buffer, "%s %s", path, cmd);
-    res = system_nosh(buffer);
-    ALOGV("runCmd() buffer='%s' res=%d", buffer, res);
-    free(buffer);
+    res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
+    ALOGV("runCmd() res=%d", res);
     return res;
 }
 
@@ -69,18 +59,100 @@
 }
 
 int NatController::setDefaults() {
-    if (runCmd(IPTABLES_PATH, "-F natctrl_FORWARD"))
-        return -1;
-    if (runCmd(IPTABLES_PATH, "-t nat -F natctrl_nat_POSTROUTING"))
+    const char *cmd1[] = {
+            IPTABLES_PATH,
+            "-F",
+            "natctrl_FORWARD"
+    };
+    if (runCmd(ARRAY_SIZE(cmd1), cmd1))
         return -1;
 
-    runCmd(IP_PATH, "rule flush");
-    runCmd(IP_PATH, "-6 rule flush");
-    runCmd(IP_PATH, "rule add from all lookup default prio 32767");
-    runCmd(IP_PATH, "rule add from all lookup main prio 32766");
-    runCmd(IP_PATH, "-6 rule add from all lookup default prio 32767");
-    runCmd(IP_PATH, "-6 rule add from all lookup main prio 32766");
-    runCmd(IP_PATH, "route flush cache");
+    const char *cmd2[] = {
+            IPTABLES_PATH,
+            "-t",
+            "nat",
+            "-F",
+            "natctrl_nat_POSTROUTING"
+    };
+    if (runCmd(ARRAY_SIZE(cmd2), cmd2))
+        return -1;
+
+    const char *cmd3[] = {
+            IP_PATH,
+            "rule",
+            "flush"
+    };
+    runCmd(ARRAY_SIZE(cmd3), cmd3);
+
+    const char *cmd4[] = {
+            IP_PATH,
+            "-6",
+            "rule",
+            "flush"
+    };
+    runCmd(ARRAY_SIZE(cmd4), cmd4);
+
+    const char *cmd5[] = {
+            IP_PATH,
+            "rule",
+            "add",
+            "from",
+            "all",
+            "lookup",
+            "default",
+            "prio",
+            "32767"
+    };
+    runCmd(ARRAY_SIZE(cmd5), cmd5);
+
+    const char *cmd6[] = {
+            IP_PATH,
+            "rule",
+            "add",
+            "from",
+            "all",
+            "lookup",
+            "main",
+            "prio",
+            "32766"
+    };
+    runCmd(ARRAY_SIZE(cmd6), cmd6);
+
+    const char *cmd7[] = {
+            IP_PATH,
+            "-6",
+            "rule",
+            "add",
+            "from",
+            "all",
+            "lookup",
+            "default",
+            "prio",
+            "32767"
+    };
+    runCmd(ARRAY_SIZE(cmd7), cmd7);
+
+    const char *cmd8[] = {
+            IP_PATH,
+            "-6",
+            "rule",
+            "add",
+            "from",
+            "all",
+            "lookup",
+            "main",
+            "prio",
+            "32766"
+    };
+    runCmd(ARRAY_SIZE(cmd8), cmd8);
+
+    const char *cmd9[] = {
+            IP_PATH,
+            "route",
+            "flush",
+            "cache"
+    };
+    runCmd(ARRAY_SIZE(cmd9), cmd9);
 
     natCount = 0;
 
@@ -95,7 +167,6 @@
 //  0    1       2       3       4            5
 // nat enable intface extface addrcnt nated-ipaddr/prelength
 int NatController::enableNat(const int argc, char **argv) {
-    char cmd[255];
     int i;
     int addrCount = atoi(argv[4]);
     int ret = 0;
@@ -122,7 +193,13 @@
 
             ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
         }
-        runCmd(IP_PATH, "route flush cache");
+        const char *cmd[] = {
+                IP_PATH,
+                "route",
+                "flush",
+                "cache"
+        };
+        runCmd(ARRAY_SIZE(cmd), cmd);
     }
 
     if (ret != 0 || setForwardRules(true, intIface, extIface) != 0) {
@@ -132,7 +209,13 @@
 
                 secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
             }
-            runCmd(IP_PATH, "route flush cache");
+            const char *cmd[] = {
+                    IP_PATH,
+                    "route",
+                    "flush",
+                    "cache"
+            };
+            runCmd(ARRAY_SIZE(cmd), cmd);
         }
         ALOGE("Error setting forward rules");
         errno = ENODEV;
@@ -140,18 +223,40 @@
     }
 
     /* Always make sure the drop rule is at the end */
-    snprintf(cmd, sizeof(cmd), "-D natctrl_FORWARD -j DROP");
-    runCmd(IPTABLES_PATH, cmd);
-    snprintf(cmd, sizeof(cmd), "-A natctrl_FORWARD -j DROP");
-    runCmd(IPTABLES_PATH, cmd);
+    const char *cmd1[] = {
+            IPTABLES_PATH,
+            "-D",
+            "natctrl_FORWARD",
+            "-j",
+            "DROP"
+    };
+    runCmd(ARRAY_SIZE(cmd1), cmd1);
+    const char *cmd2[] = {
+            IPTABLES_PATH,
+            "-A",
+            "natctrl_FORWARD",
+            "-j",
+            "DROP"
+    };
+    runCmd(ARRAY_SIZE(cmd2), cmd2);
 
 
     natCount++;
     // add this if we are the first added nat
     if (natCount == 1) {
-        snprintf(cmd, sizeof(cmd), "-t nat -A natctrl_nat_POSTROUTING -o %s -j MASQUERADE", extIface);
-        if (runCmd(IPTABLES_PATH, cmd)) {
-            ALOGE("Error seting postroute rule: %s", cmd);
+        const char *cmd[] = {
+                IPTABLES_PATH,
+                "-t",
+                "nat",
+                "-A",
+                "natctrl_nat_POSTROUTING",
+                "-o",
+                extIface,
+                "-j",
+                "MASQUERADE"
+        };
+        if (runCmd(ARRAY_SIZE(cmd), cmd)) {
+            ALOGE("Error seting postroute rule: iface=%s", extIface);
             // unwind what's been done, but don't care about success - what more could we do?
             for (i = 0; i < addrCount; i++) {
                 secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
@@ -167,56 +272,82 @@
 }
 
 int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) {
-    char cmd[255];
+    const char *cmd1[] = {
+            IPTABLES_PATH,
+            add ? "-A" : "-D",
+            "natctrl_FORWARD",
+            "-i",
+            extIface,
+            "-o",
+            intIface,
+            "-m",
+            "state",
+            "--state",
+            "ESTABLISHED,RELATED",
+            "-j",
+            "RETURN"
+    };
+    int rc = 0;
 
-    snprintf(cmd, sizeof(cmd),
-             "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
-             (add ? "A" : "D"),
-             extIface, intIface);
-    if (runCmd(IPTABLES_PATH, cmd) && add) {
+    if (runCmd(ARRAY_SIZE(cmd1), cmd1) && add) {
         return -1;
     }
 
-    snprintf(cmd, sizeof(cmd),
-            "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
-            (add ? "A" : "D"),
-            intIface, extIface);
-    if (runCmd(IPTABLES_PATH, cmd) && add) {
+    const char *cmd2[] = {
+            IPTABLES_PATH,
+            add ? "-A" : "-D",
+            "natctrl_FORWARD",
+            "-i",
+            intIface,
+            "-o",
+            extIface,
+            "-m",
+            "state",
+            "--state",
+            "INVALID",
+            "-j",
+            "DROP"
+    };
+
+    const char *cmd3[] = {
+            IPTABLES_PATH,
+            add ? "-A" : "-D",
+            "natctrl_FORWARD",
+            "-i",
+            intIface,
+            "-o",
+            extIface,
+            "-j",
+            "RETURN"
+    };
+
+    if (runCmd(ARRAY_SIZE(cmd2), cmd2) && add) {
         // bail on error, but only if adding
-        snprintf(cmd, sizeof(cmd),
-                "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
-                (!add ? "A" : "D"),
-                extIface, intIface);
-        runCmd(IPTABLES_PATH, cmd);
-        return -1;
+        rc = -1;
+        goto err_invalid_drop;
     }
 
-    snprintf(cmd, sizeof(cmd), "-%s natctrl_FORWARD -i %s -o %s -j RETURN", (add ? "A" : "D"),
-            intIface, extIface);
-    if (runCmd(IPTABLES_PATH, cmd) && add) {
+    if (runCmd(ARRAY_SIZE(cmd3), cmd3) && add) {
         // unwind what's been done, but don't care about success - what more could we do?
-        snprintf(cmd, sizeof(cmd),
-                "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
-                (!add ? "A" : "D"),
-                intIface, extIface);
-        runCmd(IPTABLES_PATH, cmd);
-
-        snprintf(cmd, sizeof(cmd),
-                 "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
-                 (!add ? "A" : "D"),
-                 extIface, intIface);
-        runCmd(IPTABLES_PATH, cmd);
-        return -1;
+        rc = -1;
+        goto err_return;
     }
 
     return 0;
+
+err_return:
+    cmd2[1] = "-D";
+    runCmd(ARRAY_SIZE(cmd2), cmd2);
+err_invalid_drop:
+    cmd1[1] = "-D";
+    runCmd(ARRAY_SIZE(cmd1), cmd1);
+    return rc;
 }
 
 // nat disable intface extface
 //  0    1       2       3       4            5
 // nat enable intface extface addrcnt nated-ipaddr/prelength
 int NatController::disableNat(const int argc, char **argv) {
-    char cmd[255];
     int i;
     int addrCount = atoi(argv[4]);
     const char *intIface = argv[2];
@@ -245,7 +376,13 @@
             secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
         }
 
-        runCmd(IP_PATH, "route flush cache");
+        const char *cmd[] = {
+                IP_PATH,
+                "route",
+                "flush",
+                "cache"
+        };
+        runCmd(ARRAY_SIZE(cmd), cmd);
     }
 
     if (--natCount <= 0) {
diff --git a/NatController.h b/NatController.h
index c1979bb..4330567 100644
--- a/NatController.h
+++ b/NatController.h
@@ -39,7 +39,7 @@
     SecondaryTableController *secondaryTableCtrl;
 
     int setDefaults();
-    int runCmd(const char *path, const char *cmd);
+    int runCmd(int argc, const char **argv);
     bool checkInterface(const char *iface);
     int setForwardRules(bool set, const char *intIface, const char *extIface);
 };
diff --git a/NetdConstants.cpp b/NetdConstants.cpp
index db1d4cd..1ab09a5 100644
--- a/NetdConstants.cpp
+++ b/NetdConstants.cpp
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
+#include <fcntl.h>
 #include <string.h>
+#include <sys/wait.h>
 
 #define LOG_TAG "Netd"
 
 #include <cutils/log.h>
+#include <logwrap/logwrap.h>
 
 #include "NetdConstants.h"
 
@@ -30,7 +33,7 @@
 const char * const ADD = "add";
 const char * const DEL = "del";
 
-static void logExecError(const char* argv[], int res) {
+static void logExecError(const char* argv[], int res, int status) {
     const char** argp = argv;
     std::string args = "";
     while (*argp) {
@@ -38,7 +41,25 @@
         args += ' ';
         argp++;
     }
-    ALOGE("exec() res=%d for %s", res, args.c_str());
+    ALOGE("exec() res=%d, status=%d for %s", res, status, args.c_str());
+}
+
+static int execIptablesCommand(int argc, const char *argv[], bool silent) {
+    int res;
+    int status;
+
+    res = android_fork_execvp(argc, (char **)argv, &status, false,
+        !silent);
+    if (res || !WIFEXITED(status) || WEXITSTATUS(status)) {
+        if (!silent) {
+            logExecError(argv, res, status);
+        }
+        if (res)
+            return res;
+        if (!WIFEXITED(status))
+            return ECHILD;
+    }
+    return WEXITSTATUS(status);
 }
 
 static int execIptables(IptablesTarget target, bool silent, va_list args) {
@@ -61,23 +82,11 @@
     int res = 0;
     if (target == V4 || target == V4V6) {
         argv[0] = IPTABLES_PATH;
-        int localRes = fork_and_execve(argv[0], argv);
-        if (localRes) {
-            if (!silent) {
-                logExecError(argv, localRes);
-            }
-            res |= localRes;
-        }
+        res |= execIptablesCommand(argsList.size(), argv, silent);
     }
     if (target == V6 || target == V4V6) {
         argv[0] = IP6TABLES_PATH;
-        int localRes = fork_and_execve(argv[0], argv);
-        if (localRes) {
-            if (!silent) {
-                logExecError(argv, localRes);
-            }
-            res |= localRes;
-        }
+        res |= execIptablesCommand(argsList.size(), argv, silent);
     }
     return res;
 }
@@ -97,3 +106,19 @@
     va_end(args);
     return res;
 }
+
+int writeFile(const char *path, const char *value, int size) {
+    int fd = open(path, O_WRONLY);
+    if (fd < 0) {
+        ALOGE("Failed to open %s: %s", path, strerror(errno));
+        return -1;
+    }
+
+    if (write(fd, value, size) != size) {
+        ALOGE("Failed to write %s: %s", path, strerror(errno));
+        close(fd);
+        return -1;
+    }
+    close(fd);
+    return 0;
+}
diff --git a/NetdConstants.h b/NetdConstants.h
index 8468f9b..eb59af2 100644
--- a/NetdConstants.h
+++ b/NetdConstants.h
@@ -29,11 +29,12 @@
 extern const char * const ADD;
 extern const char * const DEL;
 
-extern "C" int fork_and_execve(const char*, const char*[]);
-
 enum IptablesTarget { V4, V6, V4V6 };
 
 int execIptables(IptablesTarget target, ...);
 int execIptablesSilently(IptablesTarget target, ...);
+int writeFile(const char *path, const char *value, int size);
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
 #endif
diff --git a/ResolverController.cpp b/ResolverController.cpp
index 23554e8..13dd930 100644
--- a/ResolverController.cpp
+++ b/ResolverController.cpp
@@ -37,12 +37,12 @@
     return 0;
 }
 
-int ResolverController::setInterfaceDnsServers(const char* iface, char** servers, int numservers) {
+int ResolverController::setInterfaceDnsServers(const char* iface, const char* domains,
+        char** servers, int numservers) {
     if (DBG) {
         ALOGD("setInterfaceDnsServers iface = %s\n", iface);
     }
-
-    _resolv_set_nameservers_for_iface(iface, servers, numservers);
+    _resolv_set_nameservers_for_iface(iface, servers, numservers, domains);
 
     return 0;
 }
@@ -76,3 +76,23 @@
 
     return 0;
 }
+
+int ResolverController::setDnsInterfaceForPid(const char* iface, int pid) {
+    if (DBG) {
+        ALOGD("setDnsIfaceForPid iface = %s, pid = %d\n", iface, pid);
+    }
+
+    _resolv_set_iface_for_pid(iface, pid);
+
+    return 0;
+}
+
+int ResolverController::clearDnsInterfaceForPid(int pid) {
+    if (DBG) {
+        ALOGD("clearDnsIfaceForPid pid = %d\n", pid);
+    }
+
+    _resolv_clear_iface_for_pid(pid);
+
+    return 0;
+}
diff --git a/ResolverController.h b/ResolverController.h
index c6260da..a21e077 100644
--- a/ResolverController.h
+++ b/ResolverController.h
@@ -26,10 +26,13 @@
     virtual ~ResolverController() {};
 
     int setDefaultInterface(const char* iface);
-    int setInterfaceDnsServers(const char* iface, char** servers, int numservers);
+    int setInterfaceDnsServers(const char* iface, const char * domains, char** servers,
+            int numservers);
     int setInterfaceAddress(const char* iface, struct in_addr* addr);
     int flushDefaultDnsCache();
     int flushInterfaceDnsCache(const char* iface);
+    int setDnsInterfaceForPid(const char* iface, int pid);
+    int clearDnsInterfaceForPid(int pid);
 };
 
 #endif /* _RESOLVER_CONTROLLER_H_ */
diff --git a/SecondaryTableController.cpp b/SecondaryTableController.cpp
index 7d3de38..ce23d28 100644
--- a/SecondaryTableController.cpp
+++ b/SecondaryTableController.cpp
@@ -30,8 +30,7 @@
 #define LOG_TAG "SecondaryTablController"
 #include <cutils/log.h>
 #include <cutils/properties.h>
-
-extern "C" int system_nosh(const char *command);
+#include <logwrap/logwrap.h>
 
 #include "ResponseCode.h"
 #include "NetdConstants.h"
@@ -81,18 +80,43 @@
 
 int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface,
         char *dest, int prefix, char *gateway, int tableIndex) {
-    char *cmd;
+    char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
+    char tableIndex_str[11];
+    int ret;
+
+    //  IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4
+    snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
+    snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex + BASE_TABLE_NUMBER);
 
     if (strcmp("::", gateway) == 0) {
-        //  IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4
-        asprintf(&cmd, "%s route %s %s/%d dev %s table %d",
-                IP_PATH, action, dest, prefix, iface, tableIndex+BASE_TABLE_NUMBER);
+        const char *cmd[] = {
+                IP_PATH,
+                "route",
+                action,
+                dest_str,
+                "dev",
+                iface,
+                "table",
+                tableIndex_str
+        };
+        ret = runCmd(ARRAY_SIZE(cmd), cmd);
     } else {
-        asprintf(&cmd, "%s route %s %s/%d via %s dev %s table %d",
-                IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER);
+        const char *cmd[] = {
+                IP_PATH,
+                "route",
+                action,
+                dest_str,
+                "via",
+                gateway,
+                "dev",
+                iface,
+                "table",
+                tableIndex_str
+        };
+        ret = runCmd(ARRAY_SIZE(cmd), cmd);
     }
 
-    if (runAndFree(cli, cmd)) {
+    if (ret) {
         ALOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action,
                 IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER);
         errno = ENODEV;
@@ -157,14 +181,25 @@
 
 int SecondaryTableController::modifyFromRule(int tableIndex, const char *action,
         const char *addr) {
-    char *cmd;
+    char tableIndex_str[11];
 
     if (verifyTableIndex(tableIndex)) {
         return -1;
     }
-    asprintf(&cmd, "%s %s rule %s from %s table %d", IP_PATH, getVersion(addr),
-            action, addr, tableIndex + BASE_TABLE_NUMBER);
-    if (runAndFree(NULL, cmd)) {
+
+    snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
+            BASE_TABLE_NUMBER);
+    const char *cmd[] = {
+            IP_PATH,
+            getVersion(addr),
+            "rule",
+            action,
+            "from",
+            addr,
+            "table",
+            tableIndex_str
+    };
+    if (runCmd(ARRAY_SIZE(cmd), cmd)) {
         return -1;
     }
 
@@ -174,7 +209,7 @@
 
 int SecondaryTableController::modifyLocalRoute(int tableIndex, const char *action,
         const char *iface, const char *addr) {
-    char *cmd;
+    char tableIndex_str[11];
 
     if (verifyTableIndex(tableIndex)) {
         return -1;
@@ -182,23 +217,25 @@
 
     modifyRuleCount(tableIndex, action); // some del's will fail as the iface is already gone.
 
-    asprintf(&cmd, "%s route %s %s dev %s table %d", IP_PATH, action, addr, iface,
-            tableIndex+BASE_TABLE_NUMBER);
-    return runAndFree(NULL, cmd);
+    snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
+            BASE_TABLE_NUMBER);
+    const char *cmd[] = {
+            IP_PATH,
+            "route",
+            action,
+            addr,
+            "dev",
+            iface,
+            "table",
+            tableIndex_str
+    };
+
+    return runCmd(ARRAY_SIZE(cmd), cmd);
 }
 
-int SecondaryTableController::runAndFree(SocketClient *cli, char *cmd) {
+int SecondaryTableController::runCmd(int argc, const char **argv) {
     int ret = 0;
-    if (strlen(cmd) >= 255) {
-        if (cli != NULL) {
-            ALOGE("ip command (%s) too long", cmd);
-            errno = E2BIG;
-            cli->sendMsg(ResponseCode::CommandSyntaxError, "Too long", true);
-        }
-        free(cmd);
-        return -1;
-    }
-    ret = system_nosh(cmd);
-    free(cmd);
+
+    ret = android_fork_execvp(argc, (char **)argv, NULL, false, false);
     return ret;
 }
diff --git a/SecondaryTableController.h b/SecondaryTableController.h
index 79e0592..8531900 100644
--- a/SecondaryTableController.h
+++ b/SecondaryTableController.h
@@ -51,7 +51,7 @@
     int verifyTableIndex(int tableIndex);
     const char *getVersion(const char *addr);
 
-    int runAndFree(SocketClient *cli, char *cmd);
+    int runCmd(int argc, const char **argv);
 };
 
 #endif
diff --git a/SoftapController.cpp b/SoftapController.cpp
index 7c7b2d0..21274f4 100644
--- a/SoftapController.cpp
+++ b/SoftapController.cpp
@@ -38,129 +38,101 @@
 #include <netutils/ifc.h>
 #include <private/android_filesystem_config.h>
 #include "wifi.h"
+#include "ResponseCode.h"
 
 #include "SoftapController.h"
 
 static const char HOSTAPD_CONF_FILE[]    = "/data/misc/wifi/hostapd.conf";
+static const char HOSTAPD_BIN_FILE[]    = "/system/bin/hostapd";
 
-SoftapController::SoftapController() {
-    mPid = 0;
-    mSock = socket(AF_INET, SOCK_DGRAM, 0);
-    if (mSock < 0)
-        ALOGE("Failed to open socket");
-}
+SoftapController::SoftapController()
+    : mPid(0) {}
 
 SoftapController::~SoftapController() {
-    if (mSock >= 0)
-        close(mSock);
 }
 
 int SoftapController::startSoftap() {
     pid_t pid = 1;
-    int ret = 0;
 
     if (mPid) {
-        ALOGE("Softap already started");
-        return 0;
-    }
-    if (mSock < 0) {
-        ALOGE("Softap startap - failed to open socket");
-        return -1;
+        ALOGE("SoftAP is already running");
+        return ResponseCode::SoftapStatusResult;
     }
 
     if ((pid = fork()) < 0) {
         ALOGE("fork failed (%s)", strerror(errno));
-        return -1;
+        return ResponseCode::ServiceStartFailed;
     }
 
     if (!pid) {
         ensure_entropy_file_exists();
-        if (execl("/system/bin/hostapd", "/system/bin/hostapd",
+        if (execl(HOSTAPD_BIN_FILE, HOSTAPD_BIN_FILE,
                   "-e", WIFI_ENTROPY_FILE,
                   HOSTAPD_CONF_FILE, (char *) NULL)) {
             ALOGE("execl failed (%s)", strerror(errno));
         }
-        ALOGE("Should never get here!");
-        return -1;
+        ALOGE("SoftAP failed to start");
+        return ResponseCode::ServiceStartFailed;
     } else {
         mPid = pid;
-        ALOGD("Softap startap - Ok");
+        ALOGD("SoftAP started successfully");
         usleep(AP_BSS_START_DELAY);
     }
-    return ret;
-
+    return ResponseCode::SoftapStatusResult;
 }
 
 int SoftapController::stopSoftap() {
 
     if (mPid == 0) {
-        ALOGE("Softap already stopped");
-        return 0;
+        ALOGE("SoftAP is not running");
+        return ResponseCode::SoftapStatusResult;
     }
 
-    ALOGD("Stopping Softap service");
+    ALOGD("Stopping the SoftAP service...");
     kill(mPid, SIGTERM);
     waitpid(mPid, NULL, 0);
 
-    if (mSock < 0) {
-        ALOGE("Softap stopap - failed to open socket");
-        return -1;
-    }
     mPid = 0;
-    ALOGD("Softap service stopped");
+    ALOGD("SoftAP stopped successfully");
     usleep(AP_BSS_STOP_DELAY);
-    return 0;
+    return ResponseCode::SoftapStatusResult;
 }
 
 bool SoftapController::isSoftapStarted() {
-    return (mPid != 0 ? true : false);
+    return (mPid != 0);
 }
 
 /*
  * Arguments:
- *      argv[2] - wlan interface
- *      argv[3] - SSID
- *	argv[4] - Security
- *	argv[5] - Key
- *	argv[6] - Channel
- *	argv[7] - Preamble
- *	argv[8] - Max SCB
+ *  argv[2] - wlan interface
+ *  argv[3] - SSID
+ *  argv[4] - Security
+ *  argv[5] - Key
  */
 int SoftapController::setSoftap(int argc, char *argv[]) {
     char psk_str[2*SHA256_DIGEST_LENGTH+1];
-    int ret = 0, i = 0, fd;
-    char *ssid, *iface;
+    int ret = ResponseCode::SoftapStatusResult;
+    int i = 0;
+    int fd;
 
-    if (mSock < 0) {
-        ALOGE("Softap set - failed to open socket");
-        return -1;
-    }
     if (argc < 4) {
-        ALOGE("Softap set - missing arguments");
-        return -1;
+        ALOGE("Softap set is missing arguments. Please use: softap <wlan iface> <SSID> <wpa2?-psk|open> <passphrase>");
+        return ResponseCode::CommandSyntaxError;
     }
 
-    iface = argv[2];
-
     char *wbuf = NULL;
     char *fbuf = NULL;
 
-    if (argc > 3) {
-        ssid = argv[3];
-    } else {
-        ssid = (char *)"AndroidAP";
-    }
-
     asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
             "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n",
-            iface, ssid);
+            argv[2], argv[3]);
 
     if (argc > 4) {
         if (!strcmp(argv[4], "wpa-psk")) {
-            generatePsk(ssid, argv[5], psk_str);
+            generatePsk(argv[3], argv[5], psk_str);
             asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str);
         } else if (!strcmp(argv[4], "wpa2-psk")) {
-            generatePsk(ssid, argv[5], psk_str);
+            generatePsk(argv[3], argv[5], psk_str);
             asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);
         } else if (!strcmp(argv[4], "open")) {
             asprintf(&fbuf, "%s", wbuf);
@@ -174,11 +146,11 @@
         ALOGE("Cannot update \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
         free(wbuf);
         free(fbuf);
-        return -1;
+        return ResponseCode::OperationFailed;
     }
     if (write(fd, fbuf, strlen(fbuf)) < 0) {
         ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
-        ret = -1;
+        ret = ResponseCode::OperationFailed;
     }
     free(wbuf);
     free(fbuf);
@@ -189,7 +161,7 @@
                 HOSTAPD_CONF_FILE, strerror(errno));
         close(fd);
         unlink(HOSTAPD_CONF_FILE);
-        return -1;
+        return ResponseCode::OperationFailed;
     }
 
     if (fchown(fd, AID_SYSTEM, AID_WIFI) < 0) {
@@ -197,13 +169,47 @@
                 HOSTAPD_CONF_FILE, AID_WIFI, strerror(errno));
         close(fd);
         unlink(HOSTAPD_CONF_FILE);
-        return -1;
+        return ResponseCode::OperationFailed;
     }
 
     close(fd);
     return ret;
 }
 
+/*
+ * Arguments:
+ *	argv[2] - interface name
+ *	argv[3] - AP or P2P or STA
+ */
+int SoftapController::fwReloadSoftap(int argc, char *argv[])
+{
+    int i = 0;
+    char *fwpath = NULL;
+
+    if (argc < 4) {
+        ALOGE("SoftAP fwreload is missing arguments. Please use: softap <wlan iface> <AP|P2P|STA>");
+        return ResponseCode::CommandSyntaxError;
+    }
+
+    if (strcmp(argv[3], "AP") == 0) {
+        fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP);
+    } else if (strcmp(argv[3], "P2P") == 0) {
+        fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P);
+    } else if (strcmp(argv[3], "STA") == 0) {
+        fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA);
+    }
+    if (!fwpath)
+        return ResponseCode::CommandParameterError;
+    if (wifi_change_fw_path((const char *)fwpath)) {
+        ALOGE("Softap fwReload failed");
+        return ResponseCode::OperationFailed;
+    }
+    else {
+        ALOGD("Softap fwReload - Ok");
+    }
+    return ResponseCode::SoftapStatusResult;
+}
+
 void SoftapController::generatePsk(char *ssid, char *passphrase, char *psk_str) {
     unsigned char psk[SHA256_DIGEST_LENGTH];
     int j;
@@ -212,55 +218,6 @@
             reinterpret_cast<const unsigned char *>(ssid), strlen(ssid),
             4096, SHA256_DIGEST_LENGTH, psk);
     for (j=0; j < SHA256_DIGEST_LENGTH; j++) {
-        sprintf(&psk_str[j<<1], "%02x", psk[j]);
+        sprintf(&psk_str[j*2], "%02x", psk[j]);
     }
-    psk_str[j<<1] = '\0';
-}
-
-
-/*
- * Arguments:
- *	argv[2] - interface name
- *	argv[3] - AP or STA
- */
-int SoftapController::fwReloadSoftap(int argc, char *argv[])
-{
-    int ret, i = 0;
-    char *iface;
-    char *fwpath;
-
-    if (mSock < 0) {
-        ALOGE("Softap fwrealod - failed to open socket");
-        return -1;
-    }
-    if (argc < 4) {
-        ALOGE("Softap fwreload - missing arguments");
-        return -1;
-    }
-
-    iface = argv[2];
-
-    if (strcmp(argv[3], "AP") == 0) {
-        fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP);
-    } else if (strcmp(argv[3], "P2P") == 0) {
-        fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P);
-    } else {
-        fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA);
-    }
-    if (!fwpath)
-        return -1;
-    ret = wifi_change_fw_path((const char *)fwpath);
-    if (ret) {
-        ALOGE("Softap fwReload - failed: %d", ret);
-    }
-    else {
-        ALOGD("Softap fwReload - Ok");
-    }
-    return ret;
-}
-
-int SoftapController::clientsSoftap(char **retbuf)
-{
-    /* TODO: implement over hostapd */
-    return 0;
 }
diff --git a/SoftapController.h b/SoftapController.h
index 57241b9..38ff8ff 100644
--- a/SoftapController.h
+++ b/SoftapController.h
@@ -27,11 +27,6 @@
 #define AP_DRIVER_START_DELAY	800000
 
 class SoftapController {
-    pid_t mPid;
-    int mSock;
-
-    int addParam(int pos, const char *cmd, const char *arg);
-    int setCommand(char *iface, const char *fname, unsigned buflen=0);
 public:
     SoftapController();
     virtual ~SoftapController();
@@ -40,9 +35,10 @@
     int stopSoftap();
     bool isSoftapStarted();
     int setSoftap(int argc, char *argv[]);
-    void generatePsk(char *ssid, char *passphrase, char *psk);
     int fwReloadSoftap(int argc, char *argv[]);
-    int clientsSoftap(char **retbuf);
+private:
+    pid_t mPid;
+    void generatePsk(char *ssid, char *passphrase, char *psk);
 };
 
 #endif
diff --git a/TetherController.cpp b/TetherController.cpp
index 5f571a1..d067f11 100644
--- a/TetherController.cpp
+++ b/TetherController.cpp
@@ -158,12 +158,12 @@
             ALOGE("execl failed (%s)", strerror(errno));
         }
         ALOGE("Should never get here!");
-        free(args);
-        return 0;
+        _exit(-1);
     } else {
         close(pipefd[0]);
         mDaemonPid = pid;
         mDaemonFd = pipefd[1];
+        applyDnsInterfaces();
         ALOGD("Tethering services running");
     }
 
@@ -217,11 +217,11 @@
 
         char *args[10];
         int argc = 0;
-        args[argc++] = "/system/bin/dhcpcd";
+        args[argc++] = (char *)"/system/bin/dhcpcd";
         char host_name[128];
         if (property_get("net.hostname", host_name, NULL) && (host_name[0] != '\0'))
         {
-            args[argc++] = "-h";
+            args[argc++] = (char *)"-h";
             args[argc++] = host_name;
         }
         args[argc++] = (char*)iface;
@@ -233,7 +233,7 @@
         // TODO(BT) inform parent of the failure.
         //          Parent process need wait for child to report error status
         //          before it set mDhcpcdPid and return 0.
-        exit(-1);
+        _exit(-1);
     } else {
         mDhcpcdPid = pid;
         ALOGD("Reverse Tethering running, pid:%d", pid);
@@ -308,19 +308,67 @@
     return mDnsForwarders;
 }
 
-int TetherController::tetherInterface(const char *interface) {
-    mInterfaces->push_back(strdup(interface));
+int TetherController::applyDnsInterfaces() {
+    int i;
+    char daemonCmd[MAX_CMD_SIZE];
+
+    strcpy(daemonCmd, "update_ifaces");
+    int cmdLen = strlen(daemonCmd);
+    InterfaceCollection::iterator it;
+    bool haveInterfaces = false;
+
+    for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
+        cmdLen += (strlen(*it) + 1);
+        if (cmdLen + 1 >= MAX_CMD_SIZE) {
+            ALOGD("Too many DNS ifaces listed");
+            break;
+        }
+
+        strcat(daemonCmd, ":");
+        strcat(daemonCmd, *it);
+        haveInterfaces = true;
+    }
+
+    if ((mDaemonFd != -1) && haveInterfaces) {
+        ALOGD("Sending update msg to dnsmasq [%s]", daemonCmd);
+        if (write(mDaemonFd, daemonCmd, strlen(daemonCmd) +1) < 0) {
+            ALOGE("Failed to send update command to dnsmasq (%s)", strerror(errno));
+            return -1;
+        }
+    }
     return 0;
 }
 
+int TetherController::tetherInterface(const char *interface) {
+    ALOGD("tetherInterface(%s)", interface);
+    mInterfaces->push_back(strdup(interface));
+
+    if (applyDnsInterfaces()) {
+        InterfaceCollection::iterator it;
+        for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
+            if (!strcmp(interface, *it)) {
+                free(*it);
+                mInterfaces->erase(it);
+                break;
+            }
+        }
+        return -1;
+    } else {
+        return 0;
+    }
+}
+
 int TetherController::untetherInterface(const char *interface) {
     InterfaceCollection::iterator it;
 
+    ALOGD("untetherInterface(%s)", interface);
+
     for (it = mInterfaces->begin(); it != mInterfaces->end(); ++it) {
         if (!strcmp(interface, *it)) {
             free(*it);
             mInterfaces->erase(it);
-            return 0;
+
+            return applyDnsInterfaces();
         }
     }
     errno = ENOENT;
diff --git a/TetherController.h b/TetherController.h
index d3106eb..02cd412 100644
--- a/TetherController.h
+++ b/TetherController.h
@@ -52,6 +52,9 @@
     int tetherInterface(const char *interface);
     int untetherInterface(const char *interface);
     InterfaceCollection *getTetheredInterfaceList();
+
+private:
+    int applyDnsInterfaces();
 };
 
 #endif
diff --git a/ThrottleController.cpp b/ThrottleController.cpp
deleted file mode 100644
index 5bd7ad5..0000000
--- a/ThrottleController.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdlib.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/pkt_sched.h>
-
-#define LOG_TAG "ThrottleController"
-#include <cutils/log.h>
-
-
-#include "ThrottleController.h"
-#include "NetdConstants.h"
-
-extern "C" int system_nosh(const char *command);
-extern "C" int ifc_init(void);
-extern "C" int ifc_up(const char *name);
-extern "C" int ifc_down(const char *name);
-
-int ThrottleController::runTcCmd(const char *cmd) {
-    char *buffer;
-    size_t len = strnlen(cmd, 255);
-    int res;
-
-    if (len == 255) {
-        ALOGE("tc command too long");
-        errno = E2BIG;
-        return -1;
-    }
-
-    asprintf(&buffer, "%s %s", TC_PATH, cmd);
-    res = system_nosh(buffer);
-    free(buffer);
-    return res;
-}
-
-int ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
-    char cmd[512];
-    char ifn[65];
-    int rc;
-
-    memset(ifn, 0, sizeof(ifn));
-    strncpy(ifn, iface, sizeof(ifn)-1);
-
-    if (txKbps == -1) {
-        reset(ifn);
-        return 0;
-    }
-
-    /*
-     *
-     * Target interface configuration
-     *
-     */
-
-    /*
-     * Add root qdisc for the interface
-     */
-    sprintf(cmd, "qdisc add dev %s root handle 1: htb default 1 r2q 1000", ifn);
-    if (runTcCmd(cmd)) {
-        ALOGE("Failed to add root qdisc (%s)", strerror(errno));
-        goto fail;
-    }
-
-    /*
-     * Add our egress throttling class
-     */
-    sprintf(cmd, "class add dev %s parent 1: classid 1:1 htb rate %dkbit", ifn, txKbps);
-    if (runTcCmd(cmd)) {
-        ALOGE("Failed to add egress throttling class (%s)", strerror(errno));
-        goto fail;
-    }
-
-    /*
-     * Bring up the IFD device
-     */
-    ifc_init();
-    if (ifc_up("ifb0")) {
-        ALOGE("Failed to up ifb0 (%s)", strerror(errno));
-        goto fail;
-    }
-
-    /*
-     * Add root qdisc for IFD
-     */
-    sprintf(cmd, "qdisc add dev ifb0 root handle 1: htb default 1 r2q 1000");
-    if (runTcCmd(cmd)) {
-        ALOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
-        goto fail;
-    }
-
-    /*
-     * Add our ingress throttling class
-     */
-    sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 htb rate %dkbit", rxKbps);
-    if (runTcCmd(cmd)) {
-        ALOGE("Failed to add ingress throttling class (%s)", strerror(errno));
-        goto fail;
-    }
-
-    /*
-     * Add ingress qdisc for pkt redirection
-     */
-    sprintf(cmd, "qdisc add dev %s ingress", ifn);
-    if (runTcCmd(cmd)) {
-        ALOGE("Failed to add ingress qdisc (%s)", strerror(errno));
-        goto fail;
-    }
-
-    /*
-     * Add filter to link <ifn> -> ifb0
-     */
-    sprintf(cmd, "filter add dev %s parent ffff: protocol ip prio 10 u32 match "
-            "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
-    if (runTcCmd(cmd)) {
-        ALOGE("Failed to add ifb filter (%s)", strerror(errno));
-        goto fail;
-    }
-
-    return 0;
-fail:
-    reset(ifn);
-    return -1;
-}
-
-void ThrottleController::reset(const char *iface) {
-    char cmd[128];
-
-    sprintf(cmd, "qdisc del dev %s root", iface);
-    runTcCmd(cmd);
-    sprintf(cmd, "qdisc del dev %s ingress", iface);
-    runTcCmd(cmd);
-
-    runTcCmd("qdisc del dev ifb0 root");
-}
-
-int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
-    *rx = 0;
-    return 0;
-}
-
-int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
-    *tx = 0;
-    return 0;
-}
diff --git a/ThrottleController.h b/ThrottleController.h
deleted file mode 100644
index 3538e03..0000000
--- a/ThrottleController.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _THROTTLE_CONTROLLER_H
-#define _THROTTLE_CONTROLLER_H
-
-class ThrottleController {
-public:
-    static int setInterfaceThrottle(const char *iface, int rxKbps, int txKbps);
-    static int getInterfaceRxThrottle(const char *iface, int *rx);
-    static int getInterfaceTxThrottle(const char *iface, int *tx);
-
-private:
-    static int runTcCmd(const char *cmd);
-    static void reset(const char *iface);
-};
-
-#endif
diff --git a/logwrapper.c b/logwrapper.c
deleted file mode 100644
index e84ae89..0000000
--- a/logwrapper.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include "private/android_filesystem_config.h"
-#include "cutils/log.h"
-
-int parent(const char *tag, int parent_read) {
-    int status;
-    char buffer[4096];
-
-    int a = 0;  // start index of unprocessed data
-    int b = 0;  // end index of unprocessed data
-    int sz;
-    while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
-
-        sz += b;
-        // Log one line at a time
-        for (b = 0; b < sz; b++) {
-            if (buffer[b] == '\r') {
-                buffer[b] = '\0';
-            } else if (buffer[b] == '\n') {
-                buffer[b] = '\0';
-
-                ALOG(LOG_INFO, tag, "%s", &buffer[a]);
-                a = b + 1;
-            }
-        }
-
-        if (a == 0 && b == sizeof(buffer) - 1) {
-            // buffer is full, flush
-            buffer[b] = '\0';
-            ALOG(LOG_INFO, tag, "%s", &buffer[a]);
-            b = 0;
-        } else if (a != b) {
-            // Keep left-overs
-            b -= a;
-            memmove(buffer, &buffer[a], b);
-            a = 0;
-        } else {
-            a = 0;
-            b = 0;
-        }
-
-    }
-    // Flush remaining data
-    if (a != b) {
-        buffer[b] = '\0';
-        ALOG(LOG_INFO, tag, "%s", &buffer[a]);
-    }
-    status = 0xAAAA;
-    if (wait(&status) != -1) {  // Wait for child
-        if (WIFEXITED(status)) {
-            if (WEXITSTATUS(status) != 0) {
-                ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
-                        WEXITSTATUS(status));
-            }
-            return WEXITSTATUS(status);
-        } else if (WIFSIGNALED(status))
-            ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
-                    WTERMSIG(status));
-        else if (WIFSTOPPED(status))
-            ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
-                    WSTOPSIG(status));
-    } else
-        ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
-                strerror(errno), errno);
-    return -EAGAIN;
-}
-
-void child(int argc, const char**argv) {
-    // create null terminated argv_child array
-    char* argv_child[argc + 1];
-    memcpy(argv_child, argv, argc * sizeof(char *));
-    argv_child[argc] = NULL;
-
-    // XXX: PROTECT FROM VIKING KILLER
-    if (execv(argv_child[0], argv_child)) {
-        ALOG(LOG_ERROR, "logwrapper",
-            "executing %s failed: %s", argv_child[0], strerror(errno));
-    }
-    _exit(1);
-}
-
-int logwrap(int argc, const char* argv[])
-{
-    pid_t pid;
-
-    int parent_ptty;
-    int child_ptty;
-    char child_devname[64];  // same size as libc/unistd/ptsname_r.c
-
-    /* Use ptty instead of socketpair so that STDOUT is not buffered */
-    parent_ptty = open("/dev/ptmx", O_RDWR);
-    if (parent_ptty < 0) {
-        ALOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty");
-        return -errno;
-    }
-
-    if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
-            ptsname_r(parent_ptty, child_devname, sizeof(child_devname))) {
-        close(parent_ptty);
-        ALOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
-        return -1;
-    }
-
-    pid = fork();
-    if (pid < 0) {
-        close(parent_ptty);
-        ALOG(LOG_ERROR, "logwrapper", "Failed to fork");
-        return -errno;
-    } else if (pid == 0) {
-        /*
-         * Child
-         */
-        child_ptty = open(child_devname, O_RDWR);
-        if (child_ptty < 0) {
-            close(parent_ptty);
-            ALOG(LOG_ERROR, "logwrapper", "Problem with child ptty");
-            _exit(errno < 128 ? errno : 1);  // XXX lame
-        }
-
-        // redirect stdout and stderr
-        close(parent_ptty);
-        dup2(child_ptty, 1);
-        dup2(child_ptty, 2);
-        close(child_ptty);
-
-        child(argc, argv);
-    } else {
-        /*
-         * Parent
-         */
-        int rc = parent(argv[0], parent_ptty);
-        close(parent_ptty);
-        return rc;
-    }
-
-    return 0;
-}
-
-int fork_and_execve(const char*, char*[]);
-
-/*
- * The following is based off of bionic/libc/unistd/system.c with
- *  modifications to avoid calling /system/bin/sh -c
- */
-int system_nosh(const char *command)
-{
-    char buffer[255];
-    char *argp[32];
-    char *next = buffer;
-    char *tmp;
-    int i = 0;
-
-    if (!command)           /* just checking... */
-        return(1);
-
-    /*
-     * The command to argp splitting is from code that was
-     * reverted in Change: 11b4e9b2
-     */
-    if (strnlen(command, sizeof(buffer) - 1) == sizeof(buffer) - 1) {
-        ALOGE("command line too long while processing: %s", command);
-        errno = E2BIG;
-        return -1;
-    }
-    strcpy(buffer, command); // Command len is already checked.
-    while ((tmp = strsep(&next, " "))) {
-        argp[i++] = tmp;
-        if (i == 32) {
-            ALOGE("argument overflow while processing: %s", command);
-            errno = E2BIG;
-            return -1;
-        }
-    }
-    argp[i] = NULL;
-
-    return fork_and_execve(argp[0], argp);
-}
-
-extern char **environ;
-int fork_and_execve(const char* filename, char* argv[]) {
-    pid_t pid;
-    sig_t intsave, quitsave;
-    sigset_t mask, omask;
-    int pstat;
-
-    sigemptyset(&mask);
-    sigaddset(&mask, SIGCHLD);
-    sigprocmask(SIG_BLOCK, &mask, &omask);
-    switch (pid = vfork()) {
-    case -1:                        /* error */
-        sigprocmask(SIG_SETMASK, &omask, NULL);
-        return(-1);
-    case 0:                                 /* child */
-        sigprocmask(SIG_SETMASK, &omask, NULL);
-        execve(filename, argv, environ);
-        _exit(127);
-    }
-
-    intsave = (sig_t)  bsd_signal(SIGINT, SIG_IGN);
-    quitsave = (sig_t) bsd_signal(SIGQUIT, SIG_IGN);
-    pid = waitpid(pid, (int *)&pstat, 0);
-    sigprocmask(SIG_SETMASK, &omask, NULL);
-    (void)bsd_signal(SIGINT, intsave);
-    (void)bsd_signal(SIGQUIT, quitsave);
-    return (pid == -1 ? -1 : pstat);
-}
diff --git a/oem_iptables_hook.cpp b/oem_iptables_hook.cpp
index fbf14f8..70260f3 100644
--- a/oem_iptables_hook.cpp
+++ b/oem_iptables_hook.cpp
@@ -24,31 +24,39 @@
 
 #define LOG_TAG "OemIptablesHook"
 #include <cutils/log.h>
+#include <logwrap/logwrap.h>
 #include "NetdConstants.h"
 
-extern "C" int system_nosh(const char *command);
-
-
-static int runIptablesCmd(const char *cmd) {
-    char *buffer;
-    size_t len = strnlen(cmd, 255);
+static int runIptablesCmd(int argc, const char **argv) {
     int res;
 
-    if (len == 255) {
-        ALOGE("command too long");
-        return -1;
-    }
-
-    asprintf(&buffer, "%s %s", IPTABLES_PATH, cmd);
-    res = system_nosh(buffer);
-    free(buffer);
+    res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
     return res;
 }
 
 static bool oemCleanupHooks() {
-    runIptablesCmd("-F oem_out");
-    runIptablesCmd("-F oem_fwd");
-    runIptablesCmd("-t nat -F oem_nat_pre");
+    const char *cmd1[] = {
+            IPTABLES_PATH,
+            "-F",
+            "oem_out"
+    };
+    runIptablesCmd(ARRAY_SIZE(cmd1), cmd1);
+
+    const char *cmd2[] = {
+            IPTABLES_PATH,
+            "-F",
+            "oem_fwd"
+    };
+    runIptablesCmd(ARRAY_SIZE(cmd2), cmd2);
+
+    const char *cmd3[] = {
+            IPTABLES_PATH,
+            "-t",
+            "nat",
+            "-F",
+            "oem_nat_pre"
+    };
+    runIptablesCmd(ARRAY_SIZE(cmd3), cmd3);
     return true;
 }