am 78b00d81: Merge "Don\'t include <linux/...> header files directly."

* commit '78b00d81ebb7e2720fe17c116bcfd086bdd1f4e7':
  Don't include <linux/...> header files directly.
diff --git a/Android.mk b/Android.mk
index 655038d..582f0a6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -6,8 +6,10 @@
                   BandwidthController.cpp              \
                   CommandListener.cpp                  \
                   DnsProxyListener.cpp                 \
-                  MDnsSdListener.cpp                   \
+                  FirewallController.cpp               \
                   IdletimerController.cpp              \
+                  InterfaceController.cpp              \
+                  MDnsSdListener.cpp                   \
                   NatController.cpp                    \
                   NetdCommand.cpp                      \
                   NetdConstants.cpp                    \
@@ -40,11 +42,7 @@
 LOCAL_CFLAGS := -Werror=format
 
 LOCAL_SHARED_LIBRARIES := libstlport libsysutils libcutils libnetutils \
-                          libcrypto libhardware_legacy libmdnssd
-
-ifneq ($(BOARD_HOSTAPD_DRIVER),)
-  LOCAL_CFLAGS += -DHAVE_HOSTAPD
-endif
+                          libcrypto libhardware_legacy libmdnssd libdl
 
 ifeq ($(BOARD_HAVE_BLUETOOTH),true)
   LOCAL_SHARED_LIBRARIES := $(LOCAL_SHARED_LIBRARIES) libbluedroid
diff --git a/BandwidthController.cpp b/BandwidthController.cpp
index 31cdcab..e5d3054 100644
--- a/BandwidthController.cpp
+++ b/BandwidthController.cpp
@@ -51,6 +51,11 @@
 #define ALERT_IPT_TEMPLATE "%s %s %s -m quota2 ! --quota %lld --name %s"
 const int  BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
 const char BandwidthController::ALERT_GLOBAL_NAME[] = "globalAlert";
+const char* BandwidthController::LOCAL_INPUT = "bw_INPUT";
+const char* BandwidthController::LOCAL_FORWARD = "bw_FORWARD";
+const char* BandwidthController::LOCAL_OUTPUT = "bw_OUTPUT";
+const char* BandwidthController::LOCAL_RAW_PREROUTING = "bw_raw_PREROUTING";
+const char* BandwidthController::LOCAL_MANGLE_POSTROUTING = "bw_mangle_POSTROUTING";
 const int  BandwidthController::MAX_CMD_ARGS = 32;
 const int  BandwidthController::MAX_CMD_LEN = 1024;
 const int  BandwidthController::MAX_IFACENAME_LEN = 64;
@@ -113,42 +118,13 @@
 
 /* The cleanup commands assume flushing has been done. */
 const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
-    /* Delete hooks to custom chains. */
-    "-D INPUT -j bw_INPUT",
-    "-D OUTPUT -j bw_OUTPUT",
-    "-D FORWARD -j bw_FORWARD",
-
-    "-t raw -D bw_raw_PREROUTING",
-    "-t mangle -D bw_mangle_POSTROUTING",
-
-    "-X bw_INPUT",
-    "-X bw_OUTPUT",
-    "-X bw_FORWARD",
     "-X penalty_box",
     "-X costly_shared",
-
-    "-t raw -X bw_raw_PREROUTING",
-    "-t mangle -X bw_mangle_POSTROUTING",
 };
 
 const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
-    /* Created needed chains. */
-    "-N bw_INPUT",
-    "-A INPUT -j bw_INPUT",
-
-    "-N bw_OUTPUT",
-    "-A OUTPUT -j bw_OUTPUT",
-
-    "-N bw_FORWARD",
-    "-I FORWARD -j bw_FORWARD",
-
     "-N costly_shared",
     "-N penalty_box",
-
-    "-t raw -N bw_raw_PREROUTING",
-    "-t raw -A PREROUTING -j bw_raw_PREROUTING",
-    "-t mangle -N bw_mangle_POSTROUTING",
-    "-t mangle -A POSTROUTING -j bw_mangle_POSTROUTING",
 };
 
 const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
@@ -253,7 +229,6 @@
             IPT_SETUP_COMMANDS, RunCmdFailureBad);
 
     return 0;
-
 }
 
 int BandwidthController::enableBandwidthControl(bool force) {
diff --git a/BandwidthController.h b/BandwidthController.h
index 10e6ca2..17017d2 100644
--- a/BandwidthController.h
+++ b/BandwidthController.h
@@ -80,6 +80,12 @@
      */
     int getTetherStats(TetherStats &stats, std::string &extraProcessingInfo);
 
+    static const char* LOCAL_INPUT;
+    static const char* LOCAL_FORWARD;
+    static const char* LOCAL_OUTPUT;
+    static const char* LOCAL_RAW_PREROUTING;
+    static const char* LOCAL_MANGLE_POSTROUTING;
+
 protected:
     class QuotaInfo {
     public:
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 97e2fa2..969fa65 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -40,7 +40,8 @@
 #include "IdletimerController.h"
 #include "SecondaryTableController.h"
 #include "oem_iptables_hook.h"
-
+#include "NetdConstants.h"
+#include "FirewallController.h"
 
 TetherController *CommandListener::sTetherCtrl = NULL;
 NatController *CommandListener::sNatCtrl = NULL;
@@ -49,8 +50,79 @@
 SoftapController *CommandListener::sSoftapCtrl = NULL;
 BandwidthController * CommandListener::sBandwidthCtrl = NULL;
 IdletimerController * CommandListener::sIdletimerCtrl = NULL;
+InterfaceController *CommandListener::sInterfaceCtrl = NULL;
 ResolverController *CommandListener::sResolverCtrl = NULL;
 SecondaryTableController *CommandListener::sSecondaryTableCtrl = NULL;
+FirewallController *CommandListener::sFirewallCtrl = NULL;
+
+/**
+ * List of module chains to be created, along with explicit ordering. ORDERING
+ * IS CRITICAL, AND SHOULD BE TRIPLE-CHECKED WITH EACH CHANGE.
+ */
+static const char* FILTER_INPUT[] = {
+        // Bandwidth should always be early in input chain, to make sure we
+        // correctly count incoming traffic against data plan.
+        BandwidthController::LOCAL_INPUT,
+        FirewallController::LOCAL_INPUT,
+        NULL,
+};
+
+static const char* FILTER_FORWARD[] = {
+        OEM_IPTABLES_FILTER_FORWARD,
+        FirewallController::LOCAL_FORWARD,
+        BandwidthController::LOCAL_FORWARD,
+        NatController::LOCAL_FORWARD,
+        NULL,
+};
+
+static const char* FILTER_OUTPUT[] = {
+        OEM_IPTABLES_FILTER_OUTPUT,
+        FirewallController::LOCAL_OUTPUT,
+        BandwidthController::LOCAL_OUTPUT,
+        NULL,
+};
+
+static const char* RAW_PREROUTING[] = {
+        BandwidthController::LOCAL_RAW_PREROUTING,
+        IdletimerController::LOCAL_RAW_PREROUTING,
+        NULL,
+};
+
+static const char* MANGLE_POSTROUTING[] = {
+        BandwidthController::LOCAL_MANGLE_POSTROUTING,
+        IdletimerController::LOCAL_MANGLE_POSTROUTING,
+        NULL,
+};
+
+static const char* NAT_PREROUTING[] = {
+        OEM_IPTABLES_NAT_PREROUTING,
+        NULL,
+};
+
+static const char* NAT_POSTROUTING[] = {
+        NatController::LOCAL_NAT_POSTROUTING,
+        NULL,
+};
+
+static void createChildChains(IptablesTarget target, const char* table, const char* parentChain,
+        const char** childChains) {
+    const char** childChain = childChains;
+    do {
+        // Order is important:
+        // -D to delete any pre-existing jump rule (removes references
+        //    that would prevent -X from working)
+        // -F to flush any existing chain
+        // -X to delete any existing chain
+        // -N to create the chain
+        // -A to append the chain to parent
+
+        execIptablesSilently(target, "-t", table, "-D", parentChain, "-j", *childChain, NULL);
+        execIptablesSilently(target, "-t", table, "-F", *childChain, NULL);
+        execIptablesSilently(target, "-t", table, "-X", *childChain, NULL);
+        execIptables(target, "-t", table, "-N", *childChain, NULL);
+        execIptables(target, "-t", table, "-A", parentChain, "-j", *childChain, NULL);
+    } while (*(++childChain) != NULL);
+}
 
 CommandListener::CommandListener() :
                  FrameworkListener("netd", true) {
@@ -65,6 +137,7 @@
     registerCmd(new BandwidthControlCmd());
     registerCmd(new IdletimerControlCmd());
     registerCmd(new ResolverCmd());
+    registerCmd(new FirewallCmd());
 
     if (!sSecondaryTableCtrl)
         sSecondaryTableCtrl = new SecondaryTableController();
@@ -84,16 +157,36 @@
         sIdletimerCtrl = new IdletimerController();
     if (!sResolverCtrl)
         sResolverCtrl = new ResolverController();
+    if (!sFirewallCtrl)
+        sFirewallCtrl = new FirewallController();
+    if (!sInterfaceCtrl)
+        sInterfaceCtrl = new InterfaceController();
 
     /*
-     * This is the only time controllers are allowed to touch
-     * top-level chains in iptables.
-     * Each controller should setup custom chains and hook them into
-     * the top-level ones.
-     * THE ORDER IS IMPORTANT. TRIPPLE CHECK EACH setup function.
+     * This is the only time we touch top-level chains in iptables; controllers
+     * should only mutate rules inside of their children chains, as created by
+     * the constants above.
+     *
+     * Modules should never ACCEPT packets (except in well-justified cases);
+     * they should instead defer to any remaining modules using RETURN, or
+     * otherwise DROP/REJECT.
      */
-    /* Does DROP in nat: PREROUTING, FORWARD, OUTPUT */
+
+    // Create chains for children modules
+    createChildChains(V4V6, "filter", "INPUT", FILTER_INPUT);
+    createChildChains(V4V6, "filter", "FORWARD", FILTER_FORWARD);
+    createChildChains(V4V6, "filter", "OUTPUT", FILTER_OUTPUT);
+    createChildChains(V4V6, "raw", "PREROUTING", RAW_PREROUTING);
+    createChildChains(V4V6, "mangle", "POSTROUTING", MANGLE_POSTROUTING);
+    createChildChains(V4, "nat", "PREROUTING", NAT_PREROUTING);
+    createChildChains(V4, "nat", "POSTROUTING", NAT_POSTROUTING);
+
+    // Let each module setup their child chains
     setupOemIptablesHook();
+
+    /* When enabled, DROPs all packets except those matching rules. */
+    sFirewallCtrl->setupIptablesHooks();
+
     /* Does DROPs in FORWARD by default */
     sNatCtrl->setupIptablesHooks();
     /*
@@ -227,6 +320,22 @@
             cli->sendMsg(ResponseCode::CommandOkay, "Interface throttling set", false);
         }
         return 0;
+    } else if (!strcmp(argv[1], "driver")) {
+        int rc;
+        char *rbuf;
+
+        if (argc < 4) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                    "Usage: interface driver <interface> <cmd> <args>", false);
+            return 0;
+        }
+        rc = sInterfaceCtrl->interfaceCommand(argc, argv, &rbuf);
+        if (rc) {
+            cli->sendMsg(ResponseCode::OperationFailed, "Failed to execute command", true);
+        } else {
+            cli->sendMsg(ResponseCode::CommandOkay, rbuf, false);
+        }
+        return 0;
     } else {
         /*
          * These commands take a minimum of 3 arguments
@@ -335,8 +444,8 @@
             ifc_close();
             return 0;
         } else if (!strcmp(argv[1], "setcfg")) {
-            // arglist: iface addr prefixLength flags
-            if (argc < 5) {
+            // arglist: iface [addr prefixLength] flags
+            if (argc < 4) {
                 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
                 return 0;
             }
@@ -344,28 +453,30 @@
 
             struct in_addr addr;
             unsigned flags = 0;
-
-            if (!inet_aton(argv[3], &addr)) {
-                cli->sendMsg(ResponseCode::CommandParameterError, "Invalid address", false);
-                return 0;
-            }
+            int index = 5;
 
             ifc_init();
-            if (ifc_set_addr(argv[2], addr.s_addr)) {
-                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
-                ifc_close();
-                return 0;
-            }
 
-            //Set prefix length on a non zero address
-            if (addr.s_addr != 0 && ifc_set_prefixLength(argv[2], atoi(argv[4]))) {
-                cli->sendMsg(ResponseCode::OperationFailed, "Failed to set prefixLength", true);
-                ifc_close();
-                return 0;
+            if (!inet_aton(argv[3], &addr)) {
+                // Handle flags only case
+                index = 3;
+            } else {
+                if (ifc_set_addr(argv[2], addr.s_addr)) {
+                    cli->sendMsg(ResponseCode::OperationFailed, "Failed to set address", true);
+                    ifc_close();
+                    return 0;
+                }
+
+                // Set prefix length on a non zero address
+                if (addr.s_addr != 0 && ifc_set_prefixLength(argv[2], atoi(argv[4]))) {
+                   cli->sendMsg(ResponseCode::OperationFailed, "Failed to set prefixLength", true);
+                   ifc_close();
+                   return 0;
+               }
             }
 
             /* Process flags */
-            for (int i = 5; i < argc; i++) {
+            for (int i = index; i < argc; i++) {
                 char *flag = argv[i];
                 if (!strcmp(flag, "up")) {
                     ALOGD("Trying to bring up %s", argv[2]);
@@ -532,6 +643,12 @@
 
     if (!strcmp(argv[1], "stop")) {
         rc = sTetherCtrl->stopTethering();
+    } else if(!strcmp(argv[1], "start-reverse")) {
+        ALOGD("CommandListener::TetherCmd::run, call startReverseTethering, iface:%s", argv[2]);
+        sTetherCtrl->startReverseTethering(argv[2]);
+    } else if (!strcmp(argv[1], "stop-reverse")) {
+        ALOGD("CommandListener::TetherCmd::run, call stopReverseTethering");
+        rc = sTetherCtrl->stopReverseTethering();
     } else if (!strcmp(argv[1], "status")) {
         char *tmp = NULL;
 
@@ -757,11 +874,7 @@
         return 0;
     }
 
-    if (!strcmp(argv[1], "start")) {
-        rc = sSoftapCtrl->startDriver(argv[2]);
-    } else if (!strcmp(argv[1], "stop")) {
-        rc = sSoftapCtrl->stopDriver(argv[2]);
-    } else if (!strcmp(argv[1], "startap")) {
+    if (!strcmp(argv[1], "startap")) {
         rc = sSoftapCtrl->startSoftap();
     } else if (!strcmp(argv[1], "stopap")) {
         rc = sSoftapCtrl->stopSoftap();
@@ -1232,11 +1345,12 @@
       return 0;
     }
     if (!strcmp(argv[1], "add")) {
-        if (argc != 4) {
+        if (argc != 5) {
             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
             return 0;
         }
-        if(0 != sIdletimerCtrl->addInterfaceIdletimer(argv[2], atoi(argv[3]))) {
+        if(0 != sIdletimerCtrl->addInterfaceIdletimer(
+                                        argv[2], atoi(argv[3]), argv[4])) {
           cli->sendMsg(ResponseCode::OperationFailed, "Failed to add interface", false);
         } else {
           cli->sendMsg(ResponseCode::CommandOkay,  "Add success", false);
@@ -1244,12 +1358,13 @@
         return 0;
     }
     if (!strcmp(argv[1], "remove")) {
-        if (argc != 4) {
+        if (argc != 5) {
             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
             return 0;
         }
         // ashish: fixme timeout
-        if (0 != sIdletimerCtrl->removeInterfaceIdletimer(argv[2], atoi(argv[3]))) {
+        if (0 != sIdletimerCtrl->removeInterfaceIdletimer(
+                                        argv[2], atoi(argv[3]), argv[4])) {
           cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove interface", false);
         } else {
           cli->sendMsg(ResponseCode::CommandOkay, "Remove success", false);
@@ -1260,3 +1375,110 @@
     cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown idletimer cmd", false);
     return 0;
 }
+
+CommandListener::FirewallCmd::FirewallCmd() :
+    NetdCommand("firewall") {
+}
+
+int CommandListener::FirewallCmd::sendGenericOkFail(SocketClient *cli, int cond) {
+    if (!cond) {
+        cli->sendMsg(ResponseCode::CommandOkay, "Firewall command succeeded", false);
+    } else {
+        cli->sendMsg(ResponseCode::OperationFailed, "Firewall command failed", false);
+    }
+    return 0;
+}
+
+FirewallRule CommandListener::FirewallCmd::parseRule(const char* arg) {
+    if (!strcmp(arg, "allow")) {
+        return ALLOW;
+    } else {
+        return DENY;
+    }
+}
+
+int CommandListener::FirewallCmd::runCommand(SocketClient *cli, int argc,
+        char **argv) {
+    if (argc < 2) {
+        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing command", false);
+        return 0;
+    }
+
+    if (!strcmp(argv[1], "enable")) {
+        int res = sFirewallCtrl->enableFirewall();
+        return sendGenericOkFail(cli, res);
+    }
+    if (!strcmp(argv[1], "disable")) {
+        int res = sFirewallCtrl->disableFirewall();
+        return sendGenericOkFail(cli, res);
+    }
+    if (!strcmp(argv[1], "is_enabled")) {
+        int res = sFirewallCtrl->isFirewallEnabled();
+        return sendGenericOkFail(cli, res);
+    }
+
+    if (!strcmp(argv[1], "set_interface_rule")) {
+        if (argc != 4) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                         "Usage: firewall set_interface_rule <rmnet0> <allow|deny>", false);
+            return 0;
+        }
+
+        const char* iface = argv[2];
+        FirewallRule rule = parseRule(argv[3]);
+
+        int res = sFirewallCtrl->setInterfaceRule(iface, rule);
+        return sendGenericOkFail(cli, res);
+    }
+
+    if (!strcmp(argv[1], "set_egress_source_rule")) {
+        if (argc != 4) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                         "Usage: firewall set_egress_source_rule <192.168.0.1> <allow|deny>",
+                         false);
+            return 0;
+        }
+
+        const char* addr = argv[2];
+        FirewallRule rule = parseRule(argv[3]);
+
+        int res = sFirewallCtrl->setEgressSourceRule(addr, rule);
+        return sendGenericOkFail(cli, res);
+    }
+
+    if (!strcmp(argv[1], "set_egress_dest_rule")) {
+        if (argc != 5) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                         "Usage: firewall set_egress_dest_rule <192.168.0.1> <80> <allow|deny>",
+                         false);
+            return 0;
+        }
+
+        const char* addr = argv[2];
+        int port = atoi(argv[3]);
+        FirewallRule rule = parseRule(argv[4]);
+
+        int res = 0;
+        res |= sFirewallCtrl->setEgressDestRule(addr, PROTOCOL_TCP, port, rule);
+        res |= sFirewallCtrl->setEgressDestRule(addr, PROTOCOL_UDP, port, rule);
+        return sendGenericOkFail(cli, res);
+    }
+
+    if (!strcmp(argv[1], "set_uid_rule")) {
+        if (argc != 4) {
+            cli->sendMsg(ResponseCode::CommandSyntaxError,
+                         "Usage: firewall set_uid_rule <1000> <allow|deny>",
+                         false);
+            return 0;
+        }
+
+        int uid = atoi(argv[2]);
+        FirewallRule rule = parseRule(argv[3]);
+
+        int res = sFirewallCtrl->setUidRule(uid, rule);
+        return sendGenericOkFail(cli, res);
+    }
+
+    cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown command", false);
+    return 0;
+}
diff --git a/CommandListener.h b/CommandListener.h
index a9da6d7..faf0c21 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -27,8 +27,10 @@
 #include "SoftapController.h"
 #include "BandwidthController.h"
 #include "IdletimerController.h"
+#include "InterfaceController.h"
 #include "ResolverController.h"
 #include "SecondaryTableController.h"
+#include "FirewallController.h"
 
 class CommandListener : public FrameworkListener {
     static TetherController *sTetherCtrl;
@@ -38,8 +40,10 @@
     static SoftapController *sSoftapCtrl;
     static BandwidthController *sBandwidthCtrl;
     static IdletimerController *sIdletimerCtrl;
+    static InterfaceController *sInterfaceCtrl;
     static ResolverController *sResolverCtrl;
     static SecondaryTableController *sSecondaryTableCtrl;
+    static FirewallController *sFirewallCtrl;
 
 public:
     CommandListener();
@@ -131,6 +135,16 @@
         virtual ~ResolverCmd() {}
         int runCommand(SocketClient *c, int argc, char ** argv);
     };
+
+    class FirewallCmd: public NetdCommand {
+    public:
+        FirewallCmd();
+        virtual ~FirewallCmd() {}
+        int runCommand(SocketClient *c, int argc, char ** argv);
+    protected:
+        int sendGenericOkFail(SocketClient *cli, int cond);
+        static FirewallRule parseRule(const char* arg);
+    };
 };
 
 #endif
diff --git a/FirewallController.cpp b/FirewallController.cpp
new file mode 100644
index 0000000..0746316
--- /dev/null
+++ b/FirewallController.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2012 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "FirewallController"
+#define LOG_NDEBUG 0
+
+#include <cutils/log.h>
+
+#include "NetdConstants.h"
+#include "FirewallController.h"
+
+const char* FirewallController::LOCAL_INPUT = "fw_INPUT";
+const char* FirewallController::LOCAL_OUTPUT = "fw_OUTPUT";
+const char* FirewallController::LOCAL_FORWARD = "fw_FORWARD";
+
+FirewallController::FirewallController(void) {
+}
+
+int FirewallController::setupIptablesHooks(void) {
+    return 0;
+}
+
+int FirewallController::enableFirewall(void) {
+    int res = 0;
+
+    // flush any existing rules
+    disableFirewall();
+
+    // create default rule to drop all traffic
+    res |= execIptables(V4V6, "-A", LOCAL_INPUT, "-j", "DROP", NULL);
+    res |= execIptables(V4V6, "-A", LOCAL_OUTPUT, "-j", "REJECT", NULL);
+    res |= execIptables(V4V6, "-A", LOCAL_FORWARD, "-j", "REJECT", NULL);
+
+    return res;
+}
+
+int FirewallController::disableFirewall(void) {
+    int res = 0;
+
+    // flush any existing rules
+    res |= execIptables(V4V6, "-F", LOCAL_INPUT, NULL);
+    res |= execIptables(V4V6, "-F", LOCAL_OUTPUT, NULL);
+    res |= execIptables(V4V6, "-F", LOCAL_FORWARD, NULL);
+
+    return res;
+}
+
+int FirewallController::isFirewallEnabled(void) {
+    // TODO: verify that rules are still in place near top
+    return -1;
+}
+
+int FirewallController::setInterfaceRule(const char* iface, FirewallRule rule) {
+    const char* op;
+    if (rule == ALLOW) {
+        op = "-I";
+    } else {
+        op = "-D";
+    }
+
+    int res = 0;
+    res |= execIptables(V4V6, op, LOCAL_INPUT, "-i", iface, "-j", "RETURN", NULL);
+    res |= execIptables(V4V6, op, LOCAL_OUTPUT, "-o", iface, "-j", "RETURN", NULL);
+    return res;
+}
+
+int FirewallController::setEgressSourceRule(const char* addr, FirewallRule rule) {
+    IptablesTarget target = V4;
+    if (strchr(addr, ':')) {
+        target = V6;
+    }
+
+    const char* op;
+    if (rule == ALLOW) {
+        op = "-I";
+    } else {
+        op = "-D";
+    }
+
+    int res = 0;
+    res |= execIptables(target, op, LOCAL_INPUT, "-d", addr, "-j", "RETURN", NULL);
+    res |= execIptables(target, op, LOCAL_OUTPUT, "-s", addr, "-j", "RETURN", NULL);
+    return res;
+}
+
+int FirewallController::setEgressDestRule(const char* addr, int protocol, int port,
+        FirewallRule rule) {
+    IptablesTarget target = V4;
+    if (strchr(addr, ':')) {
+        target = V6;
+    }
+
+    char protocolStr[16];
+    sprintf(protocolStr, "%d", protocol);
+
+    char portStr[16];
+    sprintf(portStr, "%d", port);
+
+    const char* op;
+    if (rule == ALLOW) {
+        op = "-I";
+    } else {
+        op = "-D";
+    }
+
+    int res = 0;
+    res |= execIptables(target, op, LOCAL_INPUT, "-s", addr, "-p", protocolStr,
+            "--sport", portStr, "-j", "RETURN", NULL);
+    res |= execIptables(target, op, LOCAL_OUTPUT, "-d", addr, "-p", protocolStr,
+            "--dport", portStr, "-j", "RETURN", NULL);
+    return res;
+}
+
+int FirewallController::setUidRule(int uid, FirewallRule rule) {
+    char uidStr[16];
+    sprintf(uidStr, "%d", uid);
+
+    const char* op;
+    if (rule == ALLOW) {
+        op = "-I";
+    } else {
+        op = "-D";
+    }
+
+    int res = 0;
+    res |= execIptables(V4V6, op, LOCAL_INPUT, "-m", "owner", "--uid-owner", uidStr,
+            "-j", "RETURN", NULL);
+    res |= execIptables(V4V6, op, LOCAL_OUTPUT, "-m", "owner", "--uid-owner", uidStr,
+            "-j", "RETURN", NULL);
+    return res;
+}
diff --git a/FirewallController.h b/FirewallController.h
new file mode 100644
index 0000000..158e0fa
--- /dev/null
+++ b/FirewallController.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 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 _FIREWALL_CONTROLLER_H
+#define _FIREWALL_CONTROLLER_H
+
+#include <string>
+
+enum FirewallRule { ALLOW, DENY };
+
+#define PROTOCOL_TCP 6
+#define PROTOCOL_UDP 17
+
+/*
+ * Simple firewall that drops all packets except those matching explicitly
+ * defined ALLOW rules.
+ */
+class FirewallController {
+public:
+    FirewallController();
+
+    int setupIptablesHooks(void);
+
+    int enableFirewall(void);
+    int disableFirewall(void);
+    int isFirewallEnabled(void);
+
+    /* Match traffic going in/out over the given iface. */
+    int setInterfaceRule(const char*, FirewallRule);
+    /* Match traffic coming-in-to or going-out-from given address. */
+    int setEgressSourceRule(const char*, FirewallRule);
+    /* Match traffic coming-in-from or going-out-to given address, port, and protocol. */
+    int setEgressDestRule(const char*, int, int, FirewallRule);
+    /* Match traffic owned by given UID. */
+    int setUidRule(int, FirewallRule);
+
+    static const char* LOCAL_INPUT;
+    static const char* LOCAL_OUTPUT;
+    static const char* LOCAL_FORWARD;
+
+};
+
+#endif
diff --git a/IdletimerController.cpp b/IdletimerController.cpp
index efe4f09..7623f33 100644
--- a/IdletimerController.cpp
+++ b/IdletimerController.cpp
@@ -24,42 +24,65 @@
  *
  * iptables -F
  *
- * iptables -t nat -F idletimer_PREROUTING
- * iptables -t nat -F idletimer_POSTROUTING
+ * iptables -t raw -F idletimer_PREROUTING
+ * iptables -t mangle -F idletimer_POSTROUTING
  *
  *
- * iptables -t nat -N idletimer_PREROUTING
- * iptables -t nat -N idletimer_POSTROUTING
+ * iptables -t raw -N idletimer_PREROUTING
+ * iptables -t mangle -N idletimer_POSTROUTING
  *
- * iptables -t nat -D PREROUTING -j idletimer_PREROUTING
- * iptables -t nat -D POSTROUTING -j idletimer_POSTROUTING
+ * iptables -t raw -D PREROUTING -j idletimer_PREROUTING
+ * iptables -t mangle -D POSTROUTING -j idletimer_POSTROUTING
  *
  *
- * iptables -t nat -I PREROUTING -j idletimer_PREROUTING
- * iptables -t nat -I POSTROUTING -j idletimer_POSTROUTING
+ * iptables -t raw -I PREROUTING -j idletimer_PREROUTING
+ * iptables -t mangle -I POSTROUTING -j idletimer_POSTROUTING
  *
  * # For notifications to work the lable name must match the name of a valid interface.
  * # If the label name does match an interface, the rules will be a no-op.
  *
- * iptables -t nat -A idletimer_PREROUTING -i rmnet0 -j IDLETIMER  --timeout 5 --label test-chain --send_nl_msg 1
- * iptables -t nat -A idletimer_POSTROUTING -o rmnet0 -j IDLETIMER  --timeout 5 --label test-chain --send_nl_msg 1
+ * iptables -t raw -A idletimer_PREROUTING -i rmnet0 -j IDLETIMER  --timeout 5 --label test-chain --send_nl_msg 1
+ * iptables -t mangle -A idletimer_POSTROUTING -o rmnet0 -j IDLETIMER  --timeout 5 --label test-chain --send_nl_msg 1
  *
- * iptables -nxvL -t nat
+ * iptables -nxvL -t raw
+ * iptables -nxvL -t mangle
  *
  * =================
  *
  * ndc command sequence
  * ------------------
  * ndc idletimer enable
- * ndc idletimer add <iface> <timeout>
- * ndc idletimer remove <iface> <timeout>
+ * ndc idletimer add <iface> <timeout> <class label>
+ * ndc idletimer remove <iface> <timeout> <class label>
  *
  * Monitor effect on the iptables chains after each step using:
- *     iptables -nxvL -t nat
+ *     iptables -nxvL -t raw
+ *     iptables -nxvL -t mangle
  *
  * Remember that the timeout value has to be same at the time of the
  * removal.
  *
+ * =================
+ *
+ * Verifying the iptables rule
+ * ---------------------------
+ * We want to make sure the iptable rules capture every packet. It can be
+ * verified with tcpdump. First take a note of the pkts count for the two rules:
+ *
+ * adb shell iptables -t mangle -L idletimer_mangle_POSTROUTING -v && adb shell iptables -t raw -L idletimer_raw_PREROUTING -v
+ *
+ * And then, before any network traffics happen on the device, run tcpdump:
+ *
+ * adb shell tcpdump | tee tcpdump.log
+ *
+ * After a while run iptables commands again, you could then count the number
+ * of incoming and outgoing packets captured by tcpdump, and compare that with
+ * the numbers reported by iptables command. There shouldn't be too much
+ * difference on these numbers, i.e., with 2000 packets captured it should
+ * differ by less than 5.
+ *
+ * =================
+ *
  * Note that currently if the name of the iface is incorrect, iptables
  * will setup rules without checking if it is the name of a valid
  * interface (although no notifications will ever be received).  It is
@@ -90,6 +113,9 @@
 
 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";
+
 IdletimerController::IdletimerController() {
 }
 
@@ -115,26 +141,23 @@
 }
 
 bool IdletimerController::setupIptablesHooks() {
-    runIpxtablesCmd("-t nat -D PREROUTING -j idletimer_nat_PREROUTING");
-    runIpxtablesCmd("-t nat -F idletimer_nat_PREROUTING");
-    runIpxtablesCmd("-t nat -N idletimer_nat_PREROUTING");
-
-    runIpxtablesCmd("-t nat -D POSTROUTING -j idletimer_nat_POSTROUTING");
-    runIpxtablesCmd("-t nat -F idletimer_nat_POSTROUTING");
-    runIpxtablesCmd("-t nat -N idletimer_nat_POSTROUTING");
-
-    if (runIpxtablesCmd("-t nat -I PREROUTING -j idletimer_nat_PREROUTING")
-        || runIpxtablesCmd("-t nat -I POSTROUTING -j idletimer_nat_POSTROUTING")) {
-        return false;
-    }
     return true;
 }
 
 int IdletimerController::setDefaults() {
-  if (runIpxtablesCmd("-t nat -F idletimer_nat_PREROUTING")
-      || runIpxtablesCmd("-t nat -F idletimer_nat_POSTROUTING") )
-      return -1;
-  return 0;
+  int res;
+  char *buffer;
+  asprintf(&buffer, "-t raw -F %s", LOCAL_RAW_PREROUTING);
+  res = runIpxtablesCmd(buffer);
+  free(buffer);
+
+  if (res)
+    return res;
+
+  asprintf(&buffer, "-t mangle -F %s", LOCAL_MANGLE_POSTROUTING);
+  res = runIpxtablesCmd(buffer);
+  free(buffer);
+  return res;
 }
 
 int IdletimerController::enableIdletimerControl() {
@@ -148,28 +171,36 @@
 }
 
 int IdletimerController::modifyInterfaceIdletimer(IptOp op, const char *iface,
-                                                  uint32_t timeout) {
+                                                  uint32_t timeout,
+                                                  const char *classLabel) {
   int res;
   char *buffer;
-  asprintf(&buffer, "-t nat -%c idletimer_nat_PREROUTING -i %s -j IDLETIMER"
+  asprintf(&buffer, "-t raw -%c %s -i %s -j IDLETIMER"
            " --timeout %u --label %s --send_nl_msg 1",
-           (op == IptOpAdd) ? 'A' : 'D', iface, timeout, iface);
+           (op == IptOpAdd) ? 'A' : 'D', LOCAL_RAW_PREROUTING, iface, timeout, classLabel);
   res = runIpxtablesCmd(buffer);
   free(buffer);
 
-  asprintf(&buffer, "-t nat -%c idletimer_nat_POSTROUTING -o %s -j IDLETIMER"
+  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', iface, timeout, iface);
-  res |= runIpxtablesCmd(buffer);
+           (op == IptOpAdd) ? 'A' : 'D', LOCAL_MANGLE_POSTROUTING, iface, timeout, classLabel);
+  res = runIpxtablesCmd(buffer);
   free(buffer);
 
   return res;
 }
 
-int IdletimerController::addInterfaceIdletimer(const char *iface, uint32_t timeout) {
-  return modifyInterfaceIdletimer(IptOpAdd, iface, timeout);
+int IdletimerController::addInterfaceIdletimer(const char *iface,
+                                               uint32_t timeout,
+                                               const char *classLabel) {
+  return modifyInterfaceIdletimer(IptOpAdd, iface, timeout, classLabel);
 }
 
-int IdletimerController::removeInterfaceIdletimer(const char *iface, uint32_t timeout) {
-  return modifyInterfaceIdletimer(IptOpDelete, iface, timeout);
+int IdletimerController::removeInterfaceIdletimer(const char *iface,
+                                                  uint32_t timeout,
+                                                  const char *classLabel) {
+  return modifyInterfaceIdletimer(IptOpDelete, iface, timeout, classLabel);
 }
diff --git a/IdletimerController.h b/IdletimerController.h
index a55f7af..eb2aa35 100644
--- a/IdletimerController.h
+++ b/IdletimerController.h
@@ -24,15 +24,21 @@
 
     int enableIdletimerControl();
     int disableIdletimerControl();
-    int addInterfaceIdletimer(const char *iface, uint32_t timeout);
-    int removeInterfaceIdletimer(const char *iface, uint32_t timeout);
+    int addInterfaceIdletimer(const char *iface, uint32_t timeout,
+                              const char *classLabel);
+    int removeInterfaceIdletimer(const char *iface, uint32_t timeout,
+                                 const char *classLabel);
     bool setupIptablesHooks();
 
+    static const char* LOCAL_RAW_PREROUTING;
+    static const char* LOCAL_MANGLE_POSTROUTING;
+
  private:
     enum IptOp { IptOpAdd, IptOpDelete };
     int setDefaults();
     int runIpxtablesCmd(const char *cmd);
-    int modifyInterfaceIdletimer(IptOp op, const char *iface, uint32_t timeout);
+    int modifyInterfaceIdletimer(IptOp op, const char *iface, uint32_t timeout,
+                                 const char *classLabel);
 };
 
 #endif
diff --git a/InterfaceController.cpp b/InterfaceController.cpp
new file mode 100644
index 0000000..e02b517
--- /dev/null
+++ b/InterfaceController.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2012 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 <dlfcn.h>
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define LOG_TAG "InterfaceController"
+#include <cutils/log.h>
+#include <netutils/ifc.h>
+#include <private/android_filesystem_config.h>
+
+#include "InterfaceController.h"
+
+char if_cmd_lib_file_name[] = "/system/lib/libnetcmdiface.so";
+char set_cmd_func_name[] = "net_iface_send_command";
+char set_cmd_init_func_name[] = "net_iface_send_command_init";
+char set_cmd_fini_func_name[] = "net_iface_send_command_fini";
+
+InterfaceController::InterfaceController()
+	: sendCommand_(NULL) {
+	libh_ = dlopen(if_cmd_lib_file_name, RTLD_NOW | RTLD_LOCAL);
+	if (libh_ == NULL) {
+		const char *err_str = dlerror();
+		ALOGW("Warning (%s) while opening the net interface command library", err_str ? err_str : "unknown");
+	} else {
+		sendCommandInit_ = (int (*)(void))dlsym(libh_, set_cmd_init_func_name);
+		if (sendCommandInit_ == NULL) {
+			const char *err_str = dlerror();
+			ALOGW("Error (%s) while searching for the interface command init function", err_str ? err_str : "unknown");
+		} else if (sendCommandInit_()) {
+			ALOGE("Can't init the interface command API");
+			return;
+		}
+		sendCommandFini_ = (int (*)(void))dlsym(libh_, set_cmd_fini_func_name);
+		if (sendCommandFini_ == NULL) {
+			const char *err_str = dlerror();
+			ALOGW("Error (%s) while searching for the interface command fini function", err_str ? err_str : "unknown");
+		}
+		sendCommand_ = (int (*)(int, char **, char **))dlsym(libh_, set_cmd_func_name);
+		if (sendCommand_ == NULL) {
+			const char *err_str = dlerror();
+			ALOGE("Error (%s) while searching for the interface command function", err_str ? err_str : "unknown");
+			return;
+		}
+	}
+}
+
+InterfaceController::~InterfaceController() {
+	if (sendCommandFini_) {
+		if (sendCommandFini_()) {
+			ALOGE("Can't shutdown the interface command API");
+		}
+	}
+	if (libh_) {
+		int err = dlclose(libh_);
+		if (err) {
+			const char *err_str = dlerror();
+			ALOGE("Error (%s) while closing the net interface command library", err_str ? err_str : "unknown");
+		}
+	}
+}
+
+/*
+ * Arguments:
+ *	  argv[2] - wlan interface
+ *	  argv[3] - command
+ *	  argv[4] - argument
+ *	  rbuf	- returned buffer
+ */
+int InterfaceController::interfaceCommand(int argc, char *argv[], char **rbuf) {
+	int ret = -ENOSYS;
+	if (sendCommand_)
+		ret = sendCommand_(argc, argv, rbuf);
+
+	return ret;
+}
diff --git a/InterfaceController.h b/InterfaceController.h
new file mode 100644
index 0000000..e31cc11
--- /dev/null
+++ b/InterfaceController.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 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 _INTERFACE_CONTROLLER_H
+#define _INTERFACE_CONTROLLER_H
+
+#include <linux/in.h>
+#include <net/if.h>
+
+typedef struct android_wifi_priv_cmd {
+	char *buf;
+	int used_len;
+	int total_len;
+} android_wifi_priv_cmd;
+
+#define INTERFACE_MAX_BUFFER_SIZE	256
+
+class InterfaceController {
+ public:
+	InterfaceController();
+	virtual ~InterfaceController();
+	int interfaceCommand(int argc, char *argv[], char **rbuf);
+
+ private:
+	void *libh_;
+	int (*sendCommand_)(int argc, char *argv[], char **rbuf);
+	int (*sendCommandInit_)(void);
+	int (*sendCommandFini_)(void);
+};
+
+#endif
diff --git a/NatController.cpp b/NatController.cpp
index 77c4874..e44a29b 100644
--- a/NatController.cpp
+++ b/NatController.cpp
@@ -35,6 +35,9 @@
 
 extern "C" int system_nosh(const char *command);
 
+const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
+const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
+
 NatController::NatController(SecondaryTableController *ctrl) {
     secondaryTableCtrl = ctrl;
 }
@@ -61,30 +64,6 @@
 }
 
 int NatController::setupIptablesHooks() {
-    if (runCmd(IPTABLES_PATH, "-P INPUT ACCEPT"))
-        return -1;
-    if (runCmd(IPTABLES_PATH, "-P OUTPUT ACCEPT"))
-        return -1;
-    if (runCmd(IPTABLES_PATH, "-P FORWARD ACCEPT"))
-        return -1;
-
-    // Order is important!
-    // -D to delete any pre-existing jump rule, to prevent dupes (no-op if doesn't exist)
-    // -F to flush the chain (no-op if doesn't exist).
-    // -N to create the chain (no-op if already exist).
-
-    runCmd(IPTABLES_PATH, "-D FORWARD -j natctrl_FORWARD");
-    runCmd(IPTABLES_PATH, "-F natctrl_FORWARD");
-    runCmd(IPTABLES_PATH, "-N natctrl_FORWARD");
-    if (runCmd(IPTABLES_PATH, "-A FORWARD -j natctrl_FORWARD"))
-        return -1;
-
-    runCmd(IPTABLES_PATH, "-t nat -D POSTROUTING -j natctrl_nat_POSTROUTING");
-    runCmd(IPTABLES_PATH, "-t nat -F natctrl_nat_POSTROUTING");
-    runCmd(IPTABLES_PATH, "-t nat -N natctrl_nat_POSTROUTING");
-    if (runCmd(IPTABLES_PATH, "-t nat -A POSTROUTING -j natctrl_nat_POSTROUTING"))
-        return -1;
-
     setDefaults();
     return 0;
 }
diff --git a/NatController.h b/NatController.h
index 1d328e5..c1979bb 100644
--- a/NatController.h
+++ b/NatController.h
@@ -31,6 +31,9 @@
     int disableNat(const int argc, char **argv);
     int setupIptablesHooks();
 
+    static const char* LOCAL_FORWARD;
+    static const char* LOCAL_NAT_POSTROUTING;
+
 private:
     int natCount;
     SecondaryTableController *secondaryTableCtrl;
diff --git a/NetdConstants.cpp b/NetdConstants.cpp
index e57b483..db1d4cd 100644
--- a/NetdConstants.cpp
+++ b/NetdConstants.cpp
@@ -14,6 +14,12 @@
  * limitations under the License.
  */
 
+#include <string.h>
+
+#define LOG_TAG "Netd"
+
+#include <cutils/log.h>
+
 #include "NetdConstants.h"
 
 const char * const OEM_SCRIPT_PATH = "/system/bin/oem-iptables-init.sh";
@@ -23,3 +29,71 @@
 const char * const IP_PATH = "/system/bin/ip";
 const char * const ADD = "add";
 const char * const DEL = "del";
+
+static void logExecError(const char* argv[], int res) {
+    const char** argp = argv;
+    std::string args = "";
+    while (*argp) {
+        args += *argp;
+        args += ' ';
+        argp++;
+    }
+    ALOGE("exec() res=%d for %s", res, args.c_str());
+}
+
+static int execIptables(IptablesTarget target, bool silent, va_list args) {
+    /* Read arguments from incoming va_list; we expect the list to be NULL terminated. */
+    std::list<const char*> argsList;
+    argsList.push_back(NULL);
+    const char* arg;
+    do {
+        arg = va_arg(args, const char *);
+        argsList.push_back(arg);
+    } while (arg);
+
+    int i = 0;
+    const char* argv[argsList.size()];
+    std::list<const char*>::iterator it;
+    for (it = argsList.begin(); it != argsList.end(); it++, i++) {
+        argv[i] = *it;
+    }
+
+    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;
+        }
+    }
+    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;
+        }
+    }
+    return res;
+}
+
+int execIptables(IptablesTarget target, ...) {
+    va_list args;
+    va_start(args, target);
+    int res = execIptables(target, false, args);
+    va_end(args);
+    return res;
+}
+
+int execIptablesSilently(IptablesTarget target, ...) {
+    va_list args;
+    va_start(args, target);
+    int res = execIptables(target, true, args);
+    va_end(args);
+    return res;
+}
diff --git a/NetdConstants.h b/NetdConstants.h
index 9943a05..8468f9b 100644
--- a/NetdConstants.h
+++ b/NetdConstants.h
@@ -17,6 +17,9 @@
 #ifndef _NETD_CONSTANTS_H
 #define _NETD_CONSTANTS_H
 
+#include <string>
+#include <list>
+#include <stdarg.h>
 
 extern const char * const IPTABLES_PATH;
 extern const char * const IP6TABLES_PATH;
@@ -26,4 +29,11 @@
 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, ...);
+
 #endif
diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp
index 94e9240..6621a9a 100644
--- a/NetlinkHandler.cpp
+++ b/NetlinkHandler.cpp
@@ -76,10 +76,14 @@
 
     } else if (!strcmp(subsys, "xt_idletimer")) {
         int action = evt->getAction();
-        const char *iface = evt->findParam("INTERFACE");
+        const char *label = evt->findParam("LABEL");
         const char *state = evt->findParam("STATE");
+        // if no LABEL, use INTERFACE instead
+        if (label == NULL) {
+            label = evt->findParam("INTERFACE");
+        }
         if (state)
-            notifyInterfaceActivity(iface, !strcmp("active", state));
+            notifyInterfaceClassActivity(label, !strcmp("active", state));
 
 #if !LOG_NDEBUG
     } else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) {
@@ -131,12 +135,13 @@
             msg, false);
 }
 
-void NetlinkHandler::notifyInterfaceActivity(const char *name, bool isActive) {
+void NetlinkHandler::notifyInterfaceClassActivity(const char *name,
+                                                  bool isActive) {
     char msg[255];
 
-    snprintf(msg, sizeof(msg), "Iface %s %s", name, isActive ? "active" : "idle");
+    snprintf(msg, sizeof(msg), "IfaceClass %s %s",
+             isActive ? "active" : "idle", name);
     ALOGV("Broadcasting interface activity msg: %s", msg);
-    mNm->getBroadcaster()->sendBroadcast(isActive ? ResponseCode::InterfaceActive
-            : ResponseCode::InterfaceIdle,
-            msg, false);
+    mNm->getBroadcaster()->sendBroadcast(
+        ResponseCode::InterfaceClassActivity, msg, false);
 }
diff --git a/NetlinkHandler.h b/NetlinkHandler.h
index fe82934..50bface 100644
--- a/NetlinkHandler.h
+++ b/NetlinkHandler.h
@@ -38,6 +38,6 @@
     void notifyInterfaceChanged(const char *name, bool isUp);
     void notifyInterfaceLinkChanged(const char *name, bool isUp);
     void notifyQuotaLimitReached(const char *name, const char *iface);
-    void notifyInterfaceActivity(const char *name, bool isActive);
+    void notifyInterfaceClassActivity(const char *name, bool isActive);
 };
 #endif
diff --git a/NetlinkManager.h b/NetlinkManager.h
index 6515ea4..b7f011e 100644
--- a/NetlinkManager.h
+++ b/NetlinkManager.h
@@ -36,7 +36,6 @@
     int                  mUeventSock;
     int                  mRouteSock;
     int                  mQuotaSock;
-    int                  mIfaceIdleTimerSock;
 
 public:
     virtual ~NetlinkManager();
diff --git a/ResponseCode.h b/ResponseCode.h
index 5bebb0f..807f91a 100644
--- a/ResponseCode.h
+++ b/ResponseCode.h
@@ -72,7 +72,6 @@
     static const int ServiceSetHostnameSuccess      = 610;
     static const int ServiceGetAddrInfoFailed       = 611;
     static const int ServiceGetAddrInfoSuccess      = 612;
-    static const int InterfaceActive                = 613;
-    static const int InterfaceIdle                  = 614;
+    static const int InterfaceClassActivity         = 613;
 };
 #endif
diff --git a/SoftapController.cpp b/SoftapController.cpp
index ce41544..c4dcc7f 100644
--- a/SoftapController.cpp
+++ b/SoftapController.cpp
@@ -48,7 +48,6 @@
     mSock = socket(AF_INET, SOCK_DGRAM, 0);
     if (mSock < 0)
         ALOGE("Failed to open socket");
-    memset(mIface, 0, sizeof(mIface));
 }
 
 SoftapController::~SoftapController() {
@@ -56,118 +55,6 @@
         close(mSock);
 }
 
-int SoftapController::setCommand(char *iface, const char *fname, unsigned buflen) {
-#ifdef HAVE_HOSTAPD
-    return 0;
-#else
-    char tBuf[SOFTAP_MAX_BUFFER_SIZE];
-    struct iwreq wrq;
-    struct iw_priv_args *priv_ptr;
-    int i, j, ret;
-    int cmd = 0, sub_cmd = 0;
-
-    strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
-    wrq.u.data.pointer = tBuf;
-    wrq.u.data.length = sizeof(tBuf) / sizeof(struct iw_priv_args);
-    wrq.u.data.flags = 0;
-    if ((ret = ioctl(mSock, SIOCGIWPRIV, &wrq)) < 0) {
-        ALOGE("SIOCGIPRIV failed: %d", ret);
-        return ret;
-    }
-
-    priv_ptr = (struct iw_priv_args *)wrq.u.data.pointer;
-    for(i=0; i < wrq.u.data.length;i++) {
-        if (strcmp(priv_ptr[i].name, fname) == 0) {
-            cmd = priv_ptr[i].cmd;
-            break;
-        }
-    }
-
-    if (i == wrq.u.data.length) {
-        ALOGE("iface:%s, fname: %s - function not supported", iface, fname);
-        return -1;
-    }
-
-    if (cmd < SIOCDEVPRIVATE) {
-        for(j=0; j < i; j++) {
-            if ((priv_ptr[j].set_args == priv_ptr[i].set_args) &&
-                (priv_ptr[j].get_args == priv_ptr[i].get_args) &&
-                (priv_ptr[j].name[0] == '\0'))
-                break;
-        }
-        if (j == i) {
-            ALOGE("iface:%s, fname: %s - invalid private ioctl", iface, fname);
-            return -1;
-        }
-        sub_cmd = cmd;
-        cmd = priv_ptr[j].cmd;
-    }
-
-    strncpy(wrq.ifr_name, iface, sizeof(wrq.ifr_name));
-    if ((buflen == 0) && (*mBuf != 0))
-        wrq.u.data.length = strlen(mBuf) + 1;
-    else
-        wrq.u.data.length = buflen;
-    wrq.u.data.pointer = mBuf;
-    wrq.u.data.flags = sub_cmd;
-    ret = ioctl(mSock, cmd, &wrq);
-    return ret;
-#endif
-}
-
-int SoftapController::startDriver(char *iface) {
-    int ret;
-
-    if (mSock < 0) {
-        ALOGE("Softap driver start - failed to open socket");
-        return -1;
-    }
-    if (!iface || (iface[0] == '\0')) {
-        ALOGD("Softap driver start - wrong interface");
-        iface = mIface;
-    }
-
-    *mBuf = 0;
-    ret = setCommand(iface, "START");
-    if (ret < 0) {
-        ALOGE("Softap driver start: %d", ret);
-        return ret;
-    }
-#ifdef HAVE_HOSTAPD
-    ifc_init();
-    ret = ifc_up(iface);
-    ifc_close();
-#endif
-    usleep(AP_DRIVER_START_DELAY);
-    ALOGD("Softap driver start: %d", ret);
-    return ret;
-}
-
-int SoftapController::stopDriver(char *iface) {
-    int ret;
-
-    if (mSock < 0) {
-        ALOGE("Softap driver stop - failed to open socket");
-        return -1;
-    }
-    if (!iface || (iface[0] == '\0')) {
-        ALOGD("Softap driver stop - wrong interface");
-        iface = mIface;
-    }
-    *mBuf = 0;
-#ifdef HAVE_HOSTAPD
-    ifc_init();
-    ret = ifc_down(iface);
-    ifc_close();
-    if (ret < 0) {
-        ALOGE("Softap %s down: %d", iface, ret);
-    }
-#endif
-    ret = setCommand(iface, "STOP");
-    ALOGD("Softap driver stop: %d", ret);
-    return ret;
-}
-
 int SoftapController::startSoftap() {
     pid_t pid = 1;
     int ret = 0;
@@ -180,90 +67,64 @@
         ALOGE("Softap startap - failed to open socket");
         return -1;
     }
-#ifdef HAVE_HOSTAPD
+
     if ((pid = fork()) < 0) {
         ALOGE("fork failed (%s)", strerror(errno));
         return -1;
     }
-#endif
+
     if (!pid) {
-#ifdef HAVE_HOSTAPD
         ensure_entropy_file_exists();
         if (execl("/system/bin/hostapd", "/system/bin/hostapd",
                   "-e", WIFI_ENTROPY_FILE,
                   HOSTAPD_CONF_FILE, (char *) NULL)) {
             ALOGE("execl failed (%s)", strerror(errno));
         }
-#endif
         ALOGE("Should never get here!");
         return -1;
     } else {
-        *mBuf = 0;
-        ret = setCommand(mIface, "AP_BSS_START");
-        if (ret) {
-            ALOGE("Softap startap - failed: %d", ret);
-        }
-        else {
-           mPid = pid;
-           ALOGD("Softap startap - Ok");
-           usleep(AP_BSS_START_DELAY);
-        }
+        mPid = pid;
+        ALOGD("Softap startap - Ok");
+        usleep(AP_BSS_START_DELAY);
     }
     return ret;
 
 }
 
 int SoftapController::stopSoftap() {
-    int ret;
 
     if (mPid == 0) {
         ALOGE("Softap already stopped");
         return 0;
     }
 
-#ifdef HAVE_HOSTAPD
     ALOGD("Stopping Softap service");
     kill(mPid, SIGTERM);
     waitpid(mPid, NULL, 0);
-#endif
+
     if (mSock < 0) {
         ALOGE("Softap stopap - failed to open socket");
         return -1;
     }
-    *mBuf = 0;
-    ret = setCommand(mIface, "AP_BSS_STOP");
     mPid = 0;
-    ALOGD("Softap service stopped: %d", ret);
+    ALOGD("Softap service stopped");
     usleep(AP_BSS_STOP_DELAY);
-    return ret;
+    return 0;
 }
 
 bool SoftapController::isSoftapStarted() {
     return (mPid != 0 ? true : false);
 }
 
-int SoftapController::addParam(int pos, const char *cmd, const char *arg)
-{
-    if (pos < 0)
-        return pos;
-    if ((unsigned)(pos + strlen(cmd) + strlen(arg) + 1) >= sizeof(mBuf)) {
-        ALOGE("Command line is too big");
-        return -1;
-    }
-    pos += sprintf(&mBuf[pos], "%s=%s,", cmd, arg);
-    return pos;
-}
-
 /*
  * Arguments:
  *      argv[2] - wlan interface
- *      argv[3] - softap interface
- *      argv[4] - SSID
- *	argv[5] - Security
- *	argv[6] - Key
- *	argv[7] - Channel
- *	argv[8] - Preamble
- *	argv[9] - Max SCB
+ *      argv[3] - SSID
+ *	argv[4] - Security
+ *	argv[5] - Key
+ *	argv[6] - Channel
+ *	argv[7] - Preamble
+ *	argv[8] - Max SCB
  */
 int SoftapController::setSoftap(int argc, char *argv[]) {
     char psk_str[2*SHA256_DIGEST_LENGTH+1];
@@ -279,15 +140,13 @@
         return -1;
     }
 
-    strncpy(mIface, argv[3], sizeof(mIface));
     iface = argv[2];
 
-#ifdef HAVE_HOSTAPD
     char *wbuf = NULL;
     char *fbuf = NULL;
 
-    if (argc > 4) {
-        ssid = argv[4];
+    if (argc > 3) {
+        ssid = argv[3];
     } else {
         ssid = (char *)"AndroidAP";
     }
@@ -296,14 +155,14 @@
             "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n",
             iface, ssid);
 
-    if (argc > 5) {
-        if (!strcmp(argv[5], "wpa-psk")) {
-            generatePsk(ssid, argv[6], psk_str);
+    if (argc > 4) {
+        if (!strcmp(argv[4], "wpa-psk")) {
+            generatePsk(ssid, argv[5], psk_str);
             asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str);
-        } else if (!strcmp(argv[5], "wpa2-psk")) {
-            generatePsk(ssid, argv[6], psk_str);
+        } else if (!strcmp(argv[4], "wpa2-psk")) {
+            generatePsk(ssid, argv[5], psk_str);
             asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str);
-        } else if (!strcmp(argv[5], "open")) {
+        } else if (!strcmp(argv[4], "open")) {
             asprintf(&fbuf, "%s", wbuf);
         }
     } else {
@@ -340,57 +199,6 @@
         return -1;
     }
 
-#else
-    /* Create command line */
-    i = addParam(i, "ASCII_CMD", "AP_CFG");
-    if (argc > 4) {
-        ssid = argv[4];
-    } else {
-        ssid = (char *)"AndroidAP";
-    }
-    i = addParam(i, "SSID", ssid);
-    if (argc > 5) {
-        i = addParam(i, "SEC", argv[5]);
-    } else {
-        i = addParam(i, "SEC", "open");
-    }
-    if (argc > 6) {
-        generatePsk(ssid, argv[6], psk_str);
-        i = addParam(i, "KEY", psk_str);
-    } else {
-        i = addParam(i, "KEY", "12345678");
-    }
-    if (argc > 7) {
-        i = addParam(i, "CHANNEL", argv[7]);
-    } else {
-        i = addParam(i, "CHANNEL", "6");
-    }
-    if (argc > 8) {
-        i = addParam(i, "PREAMBLE", argv[8]);
-    } else {
-        i = addParam(i, "PREAMBLE", "0");
-    }
-    if (argc > 9) {
-        i = addParam(i, "MAX_SCB", argv[9]);
-    } else {
-        i = addParam(i, "MAX_SCB", "8");
-    }
-    if ((i < 0) || ((unsigned)(i + 4) >= sizeof(mBuf))) {
-        ALOGE("Softap set - command is too big");
-        return i;
-    }
-    sprintf(&mBuf[i], "END");
-
-    /* system("iwpriv eth0 WL_AP_CFG ASCII_CMD=AP_CFG,SSID=\"AndroidAP\",SEC=\"open\",KEY=12345,CHANNEL=1,PREAMBLE=0,MAX_SCB=8,END"); */
-    ret = setCommand(iface, "AP_SET_CFG");
-    if (ret) {
-        ALOGE("Softap set - failed: %d", ret);
-    }
-    else {
-        ALOGD("Softap set - Ok");
-        usleep(AP_SET_CFG_DELAY);
-    }
-#endif
     return ret;
 }
 
@@ -439,12 +247,7 @@
     }
     if (!fwpath)
         return -1;
-#ifdef HAVE_HOSTAPD
     ret = wifi_change_fw_path((const char *)fwpath);
-#else
-    sprintf(mBuf, "FW_PATH=%s", fwpath);
-    ret = setCommand(iface, "WL_FW_RELOAD");
-#endif
     if (ret) {
         ALOGE("Softap fwReload - failed: %d", ret);
     }
@@ -456,19 +259,6 @@
 
 int SoftapController::clientsSoftap(char **retbuf)
 {
-    int ret;
-
-    if (mSock < 0) {
-        ALOGE("Softap clients - failed to open socket");
-        return -1;
-    }
-    *mBuf = 0;
-    ret = setCommand(mIface, "AP_GET_STA_LIST", SOFTAP_MAX_BUFFER_SIZE);
-    if (ret) {
-        ALOGE("Softap clients - failed: %d", ret);
-    } else {
-        asprintf(retbuf, "Softap clients:%s", mBuf);
-        ALOGD("Softap clients:%s", mBuf);
-    }
-    return ret;
+    /* TODO: implement over hostapd */
+    return 0;
 }
diff --git a/SoftapController.h b/SoftapController.h
index 0d275d2..57241b9 100644
--- a/SoftapController.h
+++ b/SoftapController.h
@@ -27,8 +27,6 @@
 #define AP_DRIVER_START_DELAY	800000
 
 class SoftapController {
-    char mBuf[SOFTAP_MAX_BUFFER_SIZE];
-    char mIface[IFNAMSIZ];
     pid_t mPid;
     int mSock;
 
@@ -38,8 +36,6 @@
     SoftapController();
     virtual ~SoftapController();
 
-    int startDriver(char *iface);
-    int stopDriver(char *iface);
     int startSoftap();
     int stopSoftap();
     bool isSoftapStarted();
diff --git a/TetherController.cpp b/TetherController.cpp
index 8d14a14..5f571a1 100644
--- a/TetherController.cpp
+++ b/TetherController.cpp
@@ -38,6 +38,7 @@
     mDnsForwarders = new NetAddressCollection();
     mDaemonFd = -1;
     mDaemonPid = 0;
+    mDhcpcdPid = 0;
 }
 
 TetherController::~TetherController() {
@@ -187,6 +188,75 @@
     return 0;
 }
 
+// TODO(BT) remove
+int TetherController::startReverseTethering(const char* iface) {
+    if (mDhcpcdPid != 0) {
+        ALOGE("Reverse tethering already started");
+        errno = EBUSY;
+        return -1;
+    }
+
+    ALOGD("TetherController::startReverseTethering, Starting reverse tethering");
+
+    /*
+     * TODO: Create a monitoring thread to handle and restart
+     * the daemon if it exits prematurely
+     */
+    //cleanup the dhcp result
+    char dhcp_result_name[64];
+    snprintf(dhcp_result_name, sizeof(dhcp_result_name) - 1, "dhcp.%s.result", iface);
+    property_set(dhcp_result_name, "");
+
+    pid_t pid;
+    if ((pid = fork()) < 0) {
+        ALOGE("fork failed (%s)", strerror(errno));
+        return -1;
+    }
+
+    if (!pid) {
+
+        char *args[10];
+        int argc = 0;
+        args[argc++] = "/system/bin/dhcpcd";
+        char host_name[128];
+        if (property_get("net.hostname", host_name, NULL) && (host_name[0] != '\0'))
+        {
+            args[argc++] = "-h";
+            args[argc++] = host_name;
+        }
+        args[argc++] = (char*)iface;
+        args[argc] = NULL;
+        if (execv(args[0], args)) {
+            ALOGE("startReverseTethering, execv failed (%s)", strerror(errno));
+        }
+        ALOGE("startReverseTethering, Should never get here!");
+        // 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);
+    } else {
+        mDhcpcdPid = pid;
+        ALOGD("Reverse Tethering running, pid:%d", pid);
+    }
+    return 0;
+}
+
+// TODO(BT) remove
+int TetherController::stopReverseTethering() {
+
+    if (mDhcpcdPid == 0) {
+        ALOGE("Tethering already stopped");
+        return 0;
+    }
+
+    ALOGD("Stopping tethering services");
+
+    kill(mDhcpcdPid, SIGTERM);
+    waitpid(mDhcpcdPid, NULL, 0);
+    mDhcpcdPid = 0;
+    ALOGD("Tethering services stopped");
+    return 0;
+}
 bool TetherController::isTetheringStarted() {
     return (mDaemonPid == 0 ? false : true);
 }
@@ -212,8 +282,8 @@
             return -1;
         }
 
-        cmdLen += strlen(servers[i]);
-        if (cmdLen + 2 >= MAX_CMD_SIZE) {
+        cmdLen += (strlen(servers[i]) + 1);
+        if (cmdLen + 1 >= MAX_CMD_SIZE) {
             ALOGD("Too many DNS servers listed");
             break;
         }
diff --git a/TetherController.h b/TetherController.h
index 398a8e5..d3106eb 100644
--- a/TetherController.h
+++ b/TetherController.h
@@ -28,6 +28,7 @@
     InterfaceCollection  *mInterfaces;
     NetAddressCollection *mDnsForwarders;
     pid_t                 mDaemonPid;
+    pid_t                 mDhcpcdPid;
     int                   mDaemonFd;
 
 public:
@@ -42,6 +43,9 @@
     int stopTethering();
     bool isTetheringStarted();
 
+    int startReverseTethering(const char* iface);
+    int stopReverseTethering();
+
     int setDnsForwarders(char **servers, int numServers);
     NetAddressCollection *getDnsForwarders();
 
diff --git a/logwrapper.c b/logwrapper.c
index f5f4548..e84ae89 100644
--- a/logwrapper.c
+++ b/logwrapper.c
@@ -160,17 +160,14 @@
     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
  */
-extern char **environ;
 int system_nosh(const char *command)
 {
-    pid_t pid;
-    sig_t intsave, quitsave;
-    sigset_t mask, omask;
-    int pstat;
     char buffer[255];
     char *argp[32];
     char *next = buffer;
@@ -200,6 +197,15 @@
     }
     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);
@@ -210,7 +216,7 @@
         return(-1);
     case 0:                                 /* child */
         sigprocmask(SIG_SETMASK, &omask, NULL);
-        execve(argp[0], argp, environ);
+        execve(filename, argv, environ);
         _exit(127);
     }
 
diff --git a/ndc.c b/ndc.c
index 17750bd..29a399a 100644
--- a/ndc.c
+++ b/ndc.c
@@ -65,25 +65,40 @@
 }
 
 static int do_cmd(int sock, int argc, char **argv) {
-    char final_cmd[255] = { '0', ' ', '\0' };
+    char *final_cmd = strdup("0 ");
+    if (final_cmd == NULL) {
+        perror("strdup");
+        return errno;
+    }
+
     int i;
 
     for (i = 1; i < argc; i++) {
+        if (index(argv[i], '"')) {
+            perror("argument with embedded quotes not allowed");
+            free(final_cmd);
+            return 1;
+        }
+        bool needs_quoting = index(argv[i], ' ');
+        const char *format = needs_quoting ? "%s\"%s\"%s" : "%s%s%s";
         char *cmp;
 
-        if (!index(argv[i], ' '))
-            asprintf(&cmp, "%s%s", argv[i], (i == (argc -1)) ? "" : " ");
-        else
-            asprintf(&cmp, "\"%s\"%s", argv[i], (i == (argc -1)) ? "" : " ");
-
-        strcat(final_cmd, cmp);
-        free(cmp);
+        if (asprintf(&cmp, format, final_cmd, argv[i],
+                     (i == (argc -1)) ? "" : " ") < 0) {
+            perror("malloc");
+            free(final_cmd);
+            return errno;
+        }
+        free(final_cmd);
+        final_cmd = cmp;
     }
 
     if (write(sock, final_cmd, strlen(final_cmd) + 1) < 0) {
         perror("write");
+        free(final_cmd);
         return errno;
     }
+    free(final_cmd);
 
     return do_monitor(sock, 1);
 }
diff --git a/oem_iptables_hook.cpp b/oem_iptables_hook.cpp
index d3026a9..fbf14f8 100644
--- a/oem_iptables_hook.cpp
+++ b/oem_iptables_hook.cpp
@@ -45,48 +45,10 @@
     return res;
 }
 
-static bool oemSetupHooks() {
-    // Order is important!
-    // -N to create the chain (no-op if already exist).
-    // -D to delete any pre-existing jump rule, to prevent dupes (no-op if doesn't exist)
-    // -I to insert our jump rule into the default chain
-
-    runIptablesCmd("-N oem_out");
-    runIptablesCmd("-D OUTPUT -j oem_out");
-    if (runIptablesCmd("-I OUTPUT -j oem_out"))
-        return false;
-
-    runIptablesCmd("-N oem_fwd");
-    runIptablesCmd("-D FORWARD -j oem_fwd");
-    if (runIptablesCmd("-I FORWARD -j oem_fwd"))
-        return false;
-
-    runIptablesCmd("-t nat -N oem_nat_pre");
-    runIptablesCmd("-t nat -D PREROUTING -j oem_nat_pre");
-    if (runIptablesCmd("-t nat -I PREROUTING -j oem_nat_pre"))
-        return false;
-
-    return true;
-}
-
 static bool oemCleanupHooks() {
-    // Order is important!
-    // -D to remove ref to the chain
-    // -F to empty the chain
-    // -X to delete the chain
-
-    runIptablesCmd("-D OUTPUT -j oem_out");
     runIptablesCmd("-F oem_out");
-    runIptablesCmd("-X oem_out");
-
-    runIptablesCmd("-D FORWARD -j oem_fwd");
     runIptablesCmd("-F oem_fwd");
-    runIptablesCmd("-X oem_fwd");
-
-    runIptablesCmd("-t nat -D PREROUTING -j oem_nat_pre");
     runIptablesCmd("-t nat -F oem_nat_pre");
-    runIptablesCmd("-t nat -X oem_nat_pre");
-
     return true;
 }
 
@@ -106,7 +68,7 @@
         // The call to oemCleanupHooks() is superfluous when done on bootup,
         // but is needed for the case where netd has crashed/stopped and is
         // restarted.
-        if (oemCleanupHooks() && oemSetupHooks() && oemInitChains()) {
+        if (oemCleanupHooks() && oemInitChains()) {
             ALOGI("OEM iptable hook installed.");
         }
     }
diff --git a/oem_iptables_hook.h b/oem_iptables_hook.h
index f5696ba..bc99638 100644
--- a/oem_iptables_hook.h
+++ b/oem_iptables_hook.h
@@ -17,6 +17,10 @@
 #ifndef _OEM_IPTABLES_HOOK_H
 #define _OEM_IPTABLES_HOOK_H
 
+#define OEM_IPTABLES_FILTER_OUTPUT "oem_out"
+#define OEM_IPTABLES_FILTER_FORWARD "oem_fwd"
+#define OEM_IPTABLES_NAT_PREROUTING "oem_nat_pre"
+
 void setupOemIptablesHook();
 
 #endif